From e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 17 Apr 2019 06:17:24 +0200 Subject: ClangFormat: apply to source, most of intern Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat --- source/blender/editors/animation/CMakeLists.txt | 68 +- .../editors/animation/anim_channels_defines.c | 6705 ++++++++++---------- .../blender/editors/animation/anim_channels_edit.c | 5042 +++++++-------- source/blender/editors/animation/anim_deps.c | 623 +- source/blender/editors/animation/anim_draw.c | 986 +-- source/blender/editors/animation/anim_filter.c | 5702 +++++++++-------- source/blender/editors/animation/anim_intern.h | 3 +- source/blender/editors/animation/anim_ipo_utils.c | 322 +- source/blender/editors/animation/anim_markers.c | 2156 +++---- .../blender/editors/animation/anim_motion_paths.c | 483 +- source/blender/editors/animation/anim_ops.c | 683 +- source/blender/editors/animation/drivers.c | 1788 +++--- source/blender/editors/animation/fmodifier_ui.c | 1495 +++-- source/blender/editors/animation/keyframes_draw.c | 1681 ++--- source/blender/editors/animation/keyframes_edit.c | 1808 +++--- .../blender/editors/animation/keyframes_general.c | 1678 ++--- source/blender/editors/animation/keyframing.c | 4648 +++++++------- source/blender/editors/animation/keyingsets.c | 1522 ++--- 18 files changed, 19292 insertions(+), 18101 deletions(-) (limited to 'source/blender/editors/animation') diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index ea37aab69ea..b67298a6df6 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -16,56 +16,56 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include - ../../blenkernel - ../../blenlib - ../../blentranslation - ../../depsgraph - ../../gpu - ../../makesdna - ../../makesrna - ../../windowmanager - ../../../../intern/clog - ../../../../intern/guardedalloc - ../../../../intern/glew-mx + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../depsgraph + ../../gpu + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/clog + ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${GLEW_INCLUDE_PATH} ) set(SRC - anim_channels_defines.c - anim_channels_edit.c - anim_deps.c - anim_draw.c - anim_filter.c - anim_ipo_utils.c - anim_markers.c - anim_motion_paths.c - anim_ops.c - drivers.c - fmodifier_ui.c - keyframes_draw.c - keyframes_edit.c - keyframes_general.c - keyframing.c - keyingsets.c + anim_channels_defines.c + anim_channels_edit.c + anim_deps.c + anim_draw.c + anim_filter.c + anim_ipo_utils.c + anim_markers.c + anim_motion_paths.c + anim_ops.c + drivers.c + fmodifier_ui.c + keyframes_draw.c + keyframes_edit.c + keyframes_general.c + keyframing.c + keyingsets.c - anim_intern.h + anim_intern.h ) set(LIB - bf_blenkernel - bf_blenlib + bf_blenkernel + bf_blenlib ) if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) endif() if(WITH_PYTHON) - add_definitions(-DWITH_PYTHON) + add_definitions(-DWITH_PYTHON) endif() add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index daa2cda2e1b..78c17ac7015 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include "MEM_guardedalloc.h" @@ -83,10 +82,10 @@ // XXX constant defines to be moved elsewhere? /* extra padding for lengths (to go under scrollers) */ -#define EXTRA_SCROLL_PAD 100.0f +#define EXTRA_SCROLL_PAD 100.0f /* size of indent steps */ -#define INDENT_STEP_SIZE (0.35f * U.widget_unit) +#define INDENT_STEP_SIZE (0.35f * U.widget_unit) /* size of string buffers used for animation channel displayed names */ #define ANIM_CHAN_NAME_SIZE 256 @@ -100,163 +99,175 @@ /* Draw Backdrop ---------------------------------- */ /* get backdrop color for top-level widgets (Scene and Object only) */ -static void acf_generic_root_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) +static void acf_generic_root_color(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + float r_color[3]) { - /* darker blue for top-level widgets */ - UI_GetThemeColor3fv(TH_DOPESHEET_CHANNELOB, r_color); + /* darker blue for top-level widgets */ + UI_GetThemeColor3fv(TH_DOPESHEET_CHANNELOB, r_color); } /* backdrop for top-level widgets (Scene and Object only) */ -static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) +static void acf_generic_root_backdrop(bAnimContext *ac, + bAnimListElem *ale, + float yminc, + float ymaxc) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0; - short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - float color[3]; + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0; + short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + float color[3]; - /* set backdrop drawing color */ - acf->get_backdrop_color(ac, ale, color); + /* set backdrop drawing color */ + acf->get_backdrop_color(ac, ale, color); - /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ - UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); + /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ + UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : + (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); + UI_draw_roundbox_3fvAlpha( + true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } - /* get backdrop color for data expanders under top-level Scene/Object */ -static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) +static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + float r_color[3]) { - /* lighter color than top-level widget */ - UI_GetThemeColor3fv(TH_DOPESHEET_CHANNELSUBOB, r_color); + /* lighter color than top-level widget */ + UI_GetThemeColor3fv(TH_DOPESHEET_CHANNELSUBOB, r_color); } /* backdrop for data expanders under top-level Scene/Object */ -static void acf_generic_dataexpand_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) +static void acf_generic_dataexpand_backdrop(bAnimContext *ac, + bAnimListElem *ale, + float yminc, + float ymaxc) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - float color[3]; + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + float color[3]; - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - /* set backdrop drawing color */ - acf->get_backdrop_color(ac, ale, color); + /* set backdrop drawing color */ + acf->get_backdrop_color(ac, ale, color); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3fv(color); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fv(color); - /* no rounded corner - just rectangular box */ - immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + /* no rounded corner - just rectangular box */ + immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); - immUnbindProgram(); + immUnbindProgram(); } /* helper method to test if group colors should be drawn */ static bool acf_show_channel_colors(bAnimContext *ac) { - bool showGroupColors = false; + bool showGroupColors = false; - if (ac->sl) { - switch (ac->spacetype) { - case SPACE_ACTION: - { - SpaceAction *saction = (SpaceAction *)ac->sl; - showGroupColors = !(saction->flag & SACTION_NODRAWGCOLORS); + if (ac->sl) { + switch (ac->spacetype) { + case SPACE_ACTION: { + SpaceAction *saction = (SpaceAction *)ac->sl; + showGroupColors = !(saction->flag & SACTION_NODRAWGCOLORS); - break; - } - case SPACE_GRAPH: - { - SpaceGraph *sipo = (SpaceGraph *)ac->sl; - showGroupColors = !(sipo->flag & SIPO_NODRAWGCOLORS); + break; + } + case SPACE_GRAPH: { + SpaceGraph *sipo = (SpaceGraph *)ac->sl; + showGroupColors = !(sipo->flag & SIPO_NODRAWGCOLORS); - break; - } - } - } + break; + } + } + } - return showGroupColors; + return showGroupColors; } /* get backdrop color for generic channels */ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, float r_color[3]) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - bActionGroup *grp = NULL; - short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0; - bool showGroupColors = acf_show_channel_colors(ac); - - if (ale->type == ANIMTYPE_FCURVE) { - FCurve *fcu = (FCurve *)ale->data; - grp = fcu->grp; - } - - /* set color for normal channels - * - use 3 shades of color group/standard color for 3 indention level - * - only use group colors if allowed to, and if actually feasible - */ - if (showGroupColors && (grp) && (grp->customCol)) { - unsigned char cp[3]; - - if (indent == 2) { - copy_v3_v3_char((char *)cp, grp->cs.solid); - } - else if (indent == 1) { - copy_v3_v3_char((char *)cp, grp->cs.select); - } - else { - copy_v3_v3_char((char *)cp, grp->cs.active); - } - - /* copy the colors over, transforming from bytes to floats */ - rgb_uchar_to_float(r_color, cp); - } - else { - // FIXME: what happens when the indention is 1 greater than what it should be (due to grouping)? - int colOfs = 10 - 10 * indent; - UI_GetThemeColorShade3fv(TH_SHADE2, colOfs, r_color); - } + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + bActionGroup *grp = NULL; + short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0; + bool showGroupColors = acf_show_channel_colors(ac); + + if (ale->type == ANIMTYPE_FCURVE) { + FCurve *fcu = (FCurve *)ale->data; + grp = fcu->grp; + } + + /* set color for normal channels + * - use 3 shades of color group/standard color for 3 indention level + * - only use group colors if allowed to, and if actually feasible + */ + if (showGroupColors && (grp) && (grp->customCol)) { + unsigned char cp[3]; + + if (indent == 2) { + copy_v3_v3_char((char *)cp, grp->cs.solid); + } + else if (indent == 1) { + copy_v3_v3_char((char *)cp, grp->cs.select); + } + else { + copy_v3_v3_char((char *)cp, grp->cs.active); + } + + /* copy the colors over, transforming from bytes to floats */ + rgb_uchar_to_float(r_color, cp); + } + else { + // FIXME: what happens when the indention is 1 greater than what it should be (due to grouping)? + int colOfs = 10 - 10 * indent; + UI_GetThemeColorShade3fv(TH_SHADE2, colOfs, r_color); + } } /* get backdrop color for grease pencil channels */ static void acf_gpencil_channel_color(bAnimContext *ac, bAnimListElem *ale, float r_color[3]) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0; - bool showGroupColors = acf_show_channel_colors(ac); + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + short indent = (acf->get_indent_level) ? acf->get_indent_level(ac, ale) : 0; + bool showGroupColors = acf_show_channel_colors(ac); - if ((showGroupColors) && (ale->type == ANIMTYPE_GPLAYER)) { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - copy_v3_v3(r_color, gpl->color); - } - else { - int colOfs = 10 - 10 * indent; - UI_GetThemeColorShade3fv(TH_SHADE2, colOfs, r_color); - } + if ((showGroupColors) && (ale->type == ANIMTYPE_GPLAYER)) { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + copy_v3_v3(r_color, gpl->color); + } + else { + int colOfs = 10 - 10 * indent; + UI_GetThemeColorShade3fv(TH_SHADE2, colOfs, r_color); + } } /* backdrop for generic channels */ -static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) +static void acf_generic_channel_backdrop(bAnimContext *ac, + bAnimListElem *ale, + float yminc, + float ymaxc) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - float color[3]; + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + float color[3]; - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - /* set backdrop drawing color */ - acf->get_backdrop_color(ac, ale, color); + /* set backdrop drawing color */ + acf->get_backdrop_color(ac, ale, color); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3fv(color); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fv(color); - /* no rounded corners - just rectangular box */ - immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); + /* no rounded corners - just rectangular box */ + immRectf(pos, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); - immUnbindProgram(); + immUnbindProgram(); } /* Indention + Offset ------------------------------------------- */ @@ -264,99 +275,99 @@ static void acf_generic_channel_backdrop(bAnimContext *ac, bAnimListElem *ale, f /* indention level is always the value in the name */ static short acf_generic_indention_0(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale)) { - return 0; + return 0; } static short acf_generic_indention_1(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale)) { - return 1; + return 1; } -#if 0 // XXX not used +#if 0 // XXX not used static short acf_generic_indention_2(bAnimContext *ac, bAnimListElem *ale) { - return 2; + return 2; } #endif /* indention which varies with the grouping status */ static short acf_generic_indention_flexible(bAnimContext *UNUSED(ac), bAnimListElem *ale) { - short indent = 0; + short indent = 0; - /* grouped F-Curves need extra level of indention */ - if (ale->type == ANIMTYPE_FCURVE) { - FCurve *fcu = (FCurve *)ale->data; + /* grouped F-Curves need extra level of indention */ + if (ale->type == ANIMTYPE_FCURVE) { + FCurve *fcu = (FCurve *)ale->data; - // TODO: we need some way of specifying that the indention color should be one less... - if (fcu->grp) - indent++; - } + // TODO: we need some way of specifying that the indention color should be one less... + if (fcu->grp) + indent++; + } - /* no indention */ - return indent; + /* no indention */ + return indent; } /* basic offset for channels derived from indention */ static short acf_generic_basic_offset(bAnimContext *ac, bAnimListElem *ale) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - if (acf && acf->get_indent_level) - return acf->get_indent_level(ac, ale) * INDENT_STEP_SIZE; - else - return 0; + if (acf && acf->get_indent_level) + return acf->get_indent_level(ac, ale) * INDENT_STEP_SIZE; + else + 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; + 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_COMPOSIT: + /* no additional levels needed */ + return 0; - case NTREE_TEXTURE: - /* 2 additional levels */ - return INDENT_STEP_SIZE * 2; - } - } + case NTREE_TEXTURE: + /* 2 additional levels */ + return INDENT_STEP_SIZE * 2; + } + } - /* unknown */ - return 0; + /* 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); + short offset = acf_generic_basic_offset(ac, ale); - if (ale->id) { - /* texture animdata */ - if (GS(ale->id->name) == ID_TE) { - offset += U.widget_unit; - } - /* materials and particles animdata */ - else if (ELEM(GS(ale->id->name), ID_MA, ID_PA)) - offset += (short)(0.7f * U.widget_unit); + if (ale->id) { + /* texture animdata */ + if (GS(ale->id->name) == ID_TE) { + offset += U.widget_unit; + } + /* materials and particles animdata */ + else if (ELEM(GS(ale->id->name), ID_MA, ID_PA)) + offset += (short)(0.7f * U.widget_unit); - /* if not in Action Editor mode, action-groups (and their children) must carry some offset too... */ - else if (ac->datatype != ANIMCONT_ACTION) - offset += (short)(0.7f * U.widget_unit); + /* if not in Action Editor mode, action-groups (and their children) must carry some offset too... */ + else if (ac->datatype != ANIMCONT_ACTION) + offset += (short)(0.7f * U.widget_unit); - /* nodetree animdata */ - if (GS(ale->id->name) == ID_NT) { - offset += acf_nodetree_rootType_offset((bNodeTree *)ale->id); - } - } + /* 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 */ - return offset; + /* offset is just the normal type - i.e. based on indention */ + return offset; } /* Name ------------------------------------------- */ @@ -364,31 +375,30 @@ static short acf_generic_group_offset(bAnimContext *ac, bAnimListElem *ale) /* name for ID block entries */ static void acf_generic_idblock_name(bAnimListElem *ale, char *name) { - ID *id = (ID *)ale->data; /* data pointed to should be an ID block */ + ID *id = (ID *)ale->data; /* data pointed to should be an ID block */ - /* just copy the name... */ - if (id && name) - BLI_strncpy(name, id->name + 2, ANIM_CHAN_NAME_SIZE); + /* just copy the name... */ + if (id && name) + BLI_strncpy(name, id->name + 2, ANIM_CHAN_NAME_SIZE); } /* name property for ID block entries */ static bool acf_generic_idblock_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - RNA_id_pointer_create(ale->data, ptr); - *prop = RNA_struct_name_property(ptr->type); + RNA_id_pointer_create(ale->data, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); + return (*prop != NULL); } - /* name property for ID block entries which are just subheading "fillers" */ static bool acf_generic_idfill_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - /* actual ID we're representing is stored in ale->data not ale->id, as id gives the owner */ - RNA_id_pointer_create(ale->data, ptr); - *prop = RNA_struct_name_property(ptr->type); + /* actual ID we're representing is stored in ale->data not ale->id, as id gives the owner */ + RNA_id_pointer_create(ale->data, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); + return (*prop != NULL); } /* Settings ------------------------------------------- */ @@ -397,33 +407,35 @@ static bool acf_generic_idfill_name_prop(bAnimListElem *ale, PointerRNA *ptr, Pr /* channel type has no settings */ static bool acf_generic_none_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting) { - return false; + return false; } #endif /* check if some setting exists for this object-based data-expander (datablock only) */ -static bool acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_generic_dataexpand_setting_valid(bAnimContext *ac, + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* expand is always supported */ - case ACHANNEL_SETTING_EXPAND: - return true; + switch (setting) { + /* expand is always supported */ + case ACHANNEL_SETTING_EXPAND: + return true; - /* mute is only supported for NLA */ - case ACHANNEL_SETTING_MUTE: - return ((ac) && (ac->spacetype == SPACE_NLA)); + /* mute is only supported for NLA */ + case ACHANNEL_SETTING_MUTE: + return ((ac) && (ac->spacetype == SPACE_NLA)); - /* select is ok for most "ds*" channels (e.g. dsmat) */ - case ACHANNEL_SETTING_SELECT: - return true; + /* select is ok for most "ds*" channels (e.g. dsmat) */ + case ACHANNEL_SETTING_SELECT: + return true; - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return true; + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return true; - /* other flags are never supported */ - default: - return false; - } + /* other flags are never supported */ + default: + return false; + } } /* *********************************************** */ @@ -432,105 +444,113 @@ static bool acf_generic_dataexpand_setting_valid(bAnimContext *ac, bAnimListElem /* Animation Summary ----------------------------------- */ /* get backdrop color for summary widget */ -static void acf_summary_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) +static void acf_summary_color(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + float r_color[3]) { - /* reddish color - same as the 'action' line in NLA */ - UI_GetThemeColor3fv(TH_ANIM_ACTIVE, r_color); + /* reddish color - same as the 'action' line in NLA */ + UI_GetThemeColor3fv(TH_ANIM_ACTIVE, r_color); } /* backdrop for summary widget */ static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - float color[3]; + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + float color[3]; - /* set backdrop drawing color */ - acf->get_backdrop_color(ac, ale, color); + /* set backdrop drawing color */ + acf->get_backdrop_color(ac, ale, color); - /* rounded corners on LHS only - * - top and bottom - * - special hack: make the top a bit higher, since we are first... - */ - UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT); - UI_draw_roundbox_3fvAlpha(true, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); + /* rounded corners on LHS only + * - top and bottom + * - special hack: make the top a bit higher, since we are first... + */ + UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT); + UI_draw_roundbox_3fvAlpha( + true, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } /* name for summary entries */ static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name) { - if (name) - BLI_strncpy(name, IFACE_("Dope Sheet Summary"), ANIM_CHAN_NAME_SIZE); + if (name) + BLI_strncpy(name, IFACE_("Dope Sheet Summary"), ANIM_CHAN_NAME_SIZE); } // FIXME: this is really a temp icon I think static int acf_summary_icon(bAnimListElem *UNUSED(ale)) { - return ICON_BORDERMOVE; + return ICON_BORDERMOVE; } /* check if some setting exists for this channel */ -static bool acf_summary_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_summary_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - /* only expanded is supported, as it is used for hiding all stuff which the summary covers */ - return (setting == ACHANNEL_SETTING_EXPAND); + /* only expanded is supported, as it is used for hiding all stuff which the summary covers */ + return (setting == ACHANNEL_SETTING_EXPAND); } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_summary_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) -{ - if (setting == ACHANNEL_SETTING_EXPAND) { - /* expanded */ - *neg = true; - return ADS_FLAG_SUMMARY_COLLAPSED; - } - else { - /* unsupported */ - *neg = false; - return 0; - } +static int acf_summary_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) +{ + if (setting == ACHANNEL_SETTING_EXPAND) { + /* expanded */ + *neg = true; + return ADS_FLAG_SUMMARY_COLLAPSED; + } + else { + /* unsupported */ + *neg = false; + return 0; + } } /* get pointer to the setting */ -static void *acf_summary_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_summary_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - bAnimContext *ac = (bAnimContext *)ale->data; + bAnimContext *ac = (bAnimContext *)ale->data; - /* if data is valid, return pointer to active dopesheet's relevant flag - * - this is restricted to DopeSheet/Action Editor only - */ - if ((ac->sl) && (ac->spacetype == SPACE_ACTION) && (setting == ACHANNEL_SETTING_EXPAND)) { - SpaceAction *saction = (SpaceAction *)ac->sl; - bDopeSheet *ads = &saction->ads; + /* if data is valid, return pointer to active dopesheet's relevant flag + * - this is restricted to DopeSheet/Action Editor only + */ + 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 */ - return GET_ACF_FLAG_PTR(ads->flag, type); - } - else { - /* can't return anything useful - unsupported */ - *type = 0; - return NULL; - } + /* return pointer to DopeSheet's flag */ + return GET_ACF_FLAG_PTR(ads->flag, type); + } + else { + /* can't return anything useful - unsupported */ + *type = 0; + return NULL; + } } /* all animation summary (DopeSheet only) type define */ -static bAnimChannelType ACF_SUMMARY = -{ - "Summary", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_summary_color, /* backdrop color */ - acf_summary_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - NULL, /* offset */ - - acf_summary_name, /* name */ - NULL, /* name prop */ - acf_summary_icon, /* icon */ - - acf_summary_setting_valid, /* has setting */ - acf_summary_setting_flag, /* flag for setting */ - acf_summary_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_SUMMARY = { + "Summary", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_summary_color, /* backdrop color */ + acf_summary_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + NULL, /* offset */ + + acf_summary_name, /* name */ + NULL, /* name prop */ + acf_summary_icon, /* icon */ + + acf_summary_setting_valid, /* has setting */ + acf_summary_setting_flag, /* flag for setting */ + acf_summary_setting_ptr, /* pointer for setting */ }; /* Scene ------------------------------------------- */ @@ -538,269 +558,275 @@ static bAnimChannelType ACF_SUMMARY = // TODO: just get this from RNA? static int acf_scene_icon(bAnimListElem *UNUSED(ale)) { - return ICON_SCENE_DATA; + return ICON_SCENE_DATA; } /* check if some setting exists for this channel */ -static bool acf_scene_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_scene_setting_valid(bAnimContext *ac, + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* muted only in NLA */ - case ACHANNEL_SETTING_MUTE: - return ((ac) && (ac->spacetype == SPACE_NLA)); + switch (setting) { + /* muted only in NLA */ + case ACHANNEL_SETTING_MUTE: + return ((ac) && (ac->spacetype == SPACE_NLA)); - /* visible only in Graph Editor */ - case ACHANNEL_SETTING_VISIBLE: - return ((ac) && (ac->spacetype == SPACE_GRAPH)); + /* visible only in Graph Editor */ + case ACHANNEL_SETTING_VISIBLE: + return ((ac) && (ac->spacetype == SPACE_GRAPH)); - /* only select and expand supported otherwise */ - case ACHANNEL_SETTING_SELECT: - case ACHANNEL_SETTING_EXPAND: - return true; + /* only select and expand supported otherwise */ + case ACHANNEL_SETTING_SELECT: + case ACHANNEL_SETTING_EXPAND: + return true; - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return false; + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return false; - default: - return false; - } + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_scene_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_scene_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return SCE_DS_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return SCE_DS_SELECTED; - case ACHANNEL_SETTING_EXPAND: /* expanded */ - *neg = true; - return SCE_DS_COLLAPSED; + case ACHANNEL_SETTING_EXPAND: /* expanded */ + *neg = true; + return SCE_DS_COLLAPSED; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_scene_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Scene *scene = (Scene *)ale->data; + Scene *scene = (Scene *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return GET_ACF_FLAG_PTR(scene->flag, type); + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return GET_ACF_FLAG_PTR(scene->flag, type); - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(scene->flag, type); + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(scene->flag, type); - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (scene->adt) - return GET_ACF_FLAG_PTR(scene->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (scene->adt) + return GET_ACF_FLAG_PTR(scene->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* scene type define */ -static bAnimChannelType ACF_SCENE = -{ - "Scene", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_generic_root_color, /* backdrop color */ - acf_generic_root_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - NULL, /* offset */ - - acf_generic_idblock_name, /* name */ - acf_generic_idblock_name_prop, /* name prop */ - acf_scene_icon, /* icon */ - - acf_scene_setting_valid, /* has setting */ - acf_scene_setting_flag, /* flag for setting */ - acf_scene_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_SCENE = { + "Scene", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_generic_root_color, /* backdrop color */ + acf_generic_root_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + NULL, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_generic_idblock_name_prop, /* name prop */ + acf_scene_icon, /* icon */ + + acf_scene_setting_valid, /* has setting */ + acf_scene_setting_flag, /* flag for setting */ + acf_scene_setting_ptr, /* pointer for setting */ }; /* Object ------------------------------------------- */ static int acf_object_icon(bAnimListElem *ale) { - Base *base = (Base *)ale->data; - Object *ob = base->object; - - /* icon depends on object-type */ - switch (ob->type) { - case OB_LAMP: - return ICON_OUTLINER_OB_LIGHT; - case OB_MESH: - return ICON_OUTLINER_OB_MESH; - case OB_CAMERA: - return ICON_OUTLINER_OB_CAMERA; - case OB_CURVE: - return ICON_OUTLINER_OB_CURVE; - case OB_MBALL: - return ICON_OUTLINER_OB_META; - case OB_LATTICE: - return ICON_OUTLINER_OB_LATTICE; - case OB_SPEAKER: - return ICON_OUTLINER_OB_SPEAKER; - case OB_LIGHTPROBE: - return ICON_OUTLINER_OB_LIGHTPROBE; - case OB_ARMATURE: - return ICON_OUTLINER_OB_ARMATURE; - case OB_FONT: - return ICON_OUTLINER_OB_FONT; - case OB_SURF: - return ICON_OUTLINER_OB_SURFACE; - case OB_EMPTY: - return ICON_OUTLINER_OB_EMPTY; - case OB_GPENCIL: - return ICON_OUTLINER_OB_GREASEPENCIL; - default: - return ICON_OBJECT_DATA; - } + Base *base = (Base *)ale->data; + Object *ob = base->object; + + /* icon depends on object-type */ + switch (ob->type) { + case OB_LAMP: + return ICON_OUTLINER_OB_LIGHT; + case OB_MESH: + return ICON_OUTLINER_OB_MESH; + case OB_CAMERA: + return ICON_OUTLINER_OB_CAMERA; + case OB_CURVE: + return ICON_OUTLINER_OB_CURVE; + case OB_MBALL: + return ICON_OUTLINER_OB_META; + case OB_LATTICE: + return ICON_OUTLINER_OB_LATTICE; + case OB_SPEAKER: + return ICON_OUTLINER_OB_SPEAKER; + case OB_LIGHTPROBE: + return ICON_OUTLINER_OB_LIGHTPROBE; + case OB_ARMATURE: + return ICON_OUTLINER_OB_ARMATURE; + case OB_FONT: + return ICON_OUTLINER_OB_FONT; + case OB_SURF: + return ICON_OUTLINER_OB_SURFACE; + case OB_EMPTY: + return ICON_OUTLINER_OB_EMPTY; + case OB_GPENCIL: + return ICON_OUTLINER_OB_GREASEPENCIL; + default: + return ICON_OBJECT_DATA; + } } /* name for object */ static void acf_object_name(bAnimListElem *ale, char *name) { - Base *base = (Base *)ale->data; - Object *ob = base->object; + Base *base = (Base *)ale->data; + Object *ob = base->object; - /* just copy the name... */ - if (ob && name) - BLI_strncpy(name, ob->id.name + 2, ANIM_CHAN_NAME_SIZE); + /* just copy the name... */ + if (ob && name) + BLI_strncpy(name, ob->id.name + 2, ANIM_CHAN_NAME_SIZE); } /* name property for object */ static bool acf_object_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - RNA_id_pointer_create(ale->id, ptr); - *prop = RNA_struct_name_property(ptr->type); + RNA_id_pointer_create(ale->id, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); + return (*prop != NULL); } /* check if some setting exists for this channel */ -static bool acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting) +static bool acf_object_setting_valid(bAnimContext *ac, + bAnimListElem *ale, + eAnimChannel_Settings setting) { - Base *base = (Base *)ale->data; - Object *ob = base->object; + Base *base = (Base *)ale->data; + Object *ob = base->object; - switch (setting) { - /* muted only in NLA */ - case ACHANNEL_SETTING_MUTE: - return ((ac) && (ac->spacetype == SPACE_NLA)); + switch (setting) { + /* muted only in NLA */ + case ACHANNEL_SETTING_MUTE: + return ((ac) && (ac->spacetype == SPACE_NLA)); - /* visible only in Graph Editor */ - case ACHANNEL_SETTING_VISIBLE: - return ((ac) && (ac->spacetype == SPACE_GRAPH) && (ob->adt)); + /* visible only in Graph Editor */ + case ACHANNEL_SETTING_VISIBLE: + return ((ac) && (ac->spacetype == SPACE_GRAPH) && (ob->adt)); - /* only select and expand supported otherwise */ - case ACHANNEL_SETTING_SELECT: - case ACHANNEL_SETTING_EXPAND: - return true; + /* only select and expand supported otherwise */ + case ACHANNEL_SETTING_SELECT: + case ACHANNEL_SETTING_EXPAND: + return true; - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return ((ac) && (ac->spacetype == SPACE_GRAPH) && (ob->adt)); + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return ((ac) && (ac->spacetype == SPACE_GRAPH) && (ob->adt)); - default: - return false; - } + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_object_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_object_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return BASE_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return BASE_SELECTED; - case ACHANNEL_SETTING_EXPAND: /* expanded */ - *neg = 1; - return OB_ADS_COLLAPSED; + case ACHANNEL_SETTING_EXPAND: /* expanded */ + *neg = 1; + return OB_ADS_COLLAPSED; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return ADT_CURVES_ALWAYS_VISIBLE; + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return ADT_CURVES_ALWAYS_VISIBLE; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_object_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Base *base = (Base *)ale->data; - Object *ob = base->object; + Base *base = (Base *)ale->data; + Object *ob = base->object; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return GET_ACF_FLAG_PTR(base->flag, type); + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return GET_ACF_FLAG_PTR(base->flag, type); - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(ob->nlaflag, type); // xxx + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(ob->nlaflag, type); // xxx - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - if (ob->adt) - return GET_ACF_FLAG_PTR(ob->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + if (ob->adt) + return GET_ACF_FLAG_PTR(ob->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* object type define */ -static bAnimChannelType ACF_OBJECT = -{ - "Object", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_generic_root_color, /* backdrop color */ - acf_generic_root_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - NULL, /* offset */ - - acf_object_name, /* name */ - acf_object_name_prop, /* name prop */ - acf_object_icon, /* icon */ - - acf_object_setting_valid, /* has setting */ - acf_object_setting_flag, /* flag for setting */ - acf_object_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_OBJECT = { + "Object", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_generic_root_color, /* backdrop color */ + acf_generic_root_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + NULL, /* offset */ + + acf_object_name, /* name */ + acf_object_name_prop, /* name prop */ + acf_object_icon, /* icon */ + + acf_object_setting_valid, /* has setting */ + acf_object_setting_flag, /* flag for setting */ + acf_object_setting_ptr, /* pointer for setting */ }; /* Group ------------------------------------------- */ @@ -808,158 +834,161 @@ static bAnimChannelType ACF_OBJECT = /* get backdrop color for group widget */ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[3]) { - bActionGroup *agrp = (bActionGroup *)ale->data; - bool showGroupColors = acf_show_channel_colors(ac); + bActionGroup *agrp = (bActionGroup *)ale->data; + bool showGroupColors = acf_show_channel_colors(ac); - if (showGroupColors && agrp->customCol) { - unsigned char cp[3]; + if (showGroupColors && agrp->customCol) { + unsigned char cp[3]; - /* highlight only for active */ - if (ale->flag & AGRP_ACTIVE) - copy_v3_v3_char((char *)cp, agrp->cs.select); - else - copy_v3_v3_char((char *)cp, agrp->cs.solid); + /* highlight only for active */ + if (ale->flag & AGRP_ACTIVE) + copy_v3_v3_char((char *)cp, agrp->cs.select); + else + copy_v3_v3_char((char *)cp, agrp->cs.solid); - /* copy the colors over, transforming from bytes to floats */ - rgb_uchar_to_float(r_color, cp); - } - else { - /* highlight only for active */ - if (ale->flag & AGRP_ACTIVE) - UI_GetThemeColor3fv(TH_GROUP_ACTIVE, r_color); - else - UI_GetThemeColor3fv(TH_GROUP, r_color); - } + /* copy the colors over, transforming from bytes to floats */ + rgb_uchar_to_float(r_color, cp); + } + else { + /* highlight only for active */ + if (ale->flag & AGRP_ACTIVE) + UI_GetThemeColor3fv(TH_GROUP_ACTIVE, r_color); + else + UI_GetThemeColor3fv(TH_GROUP, r_color); + } } /* backdrop for group widget */ static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0; - short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - float color[3]; + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0; + short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + float color[3]; - /* set backdrop drawing color */ - acf->get_backdrop_color(ac, ale, color); + /* set backdrop drawing color */ + acf->get_backdrop_color(ac, ale, color); - /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ - UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); + /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ + UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); + UI_draw_roundbox_3fvAlpha( + true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8, color, 1.0f); } /* name for group entries */ static void acf_group_name(bAnimListElem *ale, char *name) { - bActionGroup *agrp = (bActionGroup *)ale->data; + bActionGroup *agrp = (bActionGroup *)ale->data; - /* just copy the name... */ - if (agrp && name) - BLI_strncpy(name, agrp->name, ANIM_CHAN_NAME_SIZE); + /* just copy the name... */ + if (agrp && name) + BLI_strncpy(name, agrp->name, ANIM_CHAN_NAME_SIZE); } /* name property for group entries */ static bool acf_group_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - RNA_pointer_create(ale->id, &RNA_ActionGroup, ale->data, ptr); - *prop = RNA_struct_name_property(ptr->type); + RNA_pointer_create(ale->id, &RNA_ActionGroup, ale->data, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); + return (*prop != NULL); } /* check if some setting exists for this channel */ -static bool acf_group_setting_valid(bAnimContext *ac, bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_group_setting_valid(bAnimContext *ac, + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - /* for now, all settings are supported, though some are only conditionally */ - switch (setting) { - /* unsupported */ - case ACHANNEL_SETTING_SOLO: /* Only available in NLA Editor for tracks */ - return false; + /* for now, all settings are supported, though some are only conditionally */ + switch (setting) { + /* unsupported */ + case ACHANNEL_SETTING_SOLO: /* Only available in NLA Editor for tracks */ + return false; - /* conditionally supported */ - case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */ - return (ac->spacetype == SPACE_GRAPH); + /* conditionally supported */ + case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */ + return (ac->spacetype == SPACE_GRAPH); - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return (ac->spacetype == SPACE_GRAPH); + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return (ac->spacetype == SPACE_GRAPH); - default: /* always supported */ - return true; - } + default: /* always supported */ + return true; + } } /* get the appropriate flag(s) for the setting when it is valid */ static int acf_group_setting_flag(bAnimContext *ac, eAnimChannel_Settings setting, bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return AGRP_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return AGRP_SELECTED; - case ACHANNEL_SETTING_EXPAND: /* expanded */ - { - /* NOTE: Graph Editor uses a different flag to everywhere else for this, - * allowing different collapsing of groups there, since sharing the flag - * proved to be a hazard for workflows... - */ - return (ac->spacetype == SPACE_GRAPH) ? - AGRP_EXPANDED_G : /* Graph Editor case */ - AGRP_EXPANDED; /* DopeSheet and elsewhere */ - } + case ACHANNEL_SETTING_EXPAND: /* expanded */ + { + /* NOTE: Graph Editor uses a different flag to everywhere else for this, + * allowing different collapsing of groups there, since sharing the flag + * proved to be a hazard for workflows... + */ + return (ac->spacetype == SPACE_GRAPH) ? AGRP_EXPANDED_G : /* Graph Editor case */ + AGRP_EXPANDED; /* DopeSheet and elsewhere */ + } - case ACHANNEL_SETTING_MUTE: /* muted */ - return AGRP_MUTED; + case ACHANNEL_SETTING_MUTE: /* muted */ + return AGRP_MUTED; - case ACHANNEL_SETTING_MOD_OFF: /* muted */ - *neg = 1; - return AGRP_MODIFIERS_OFF; + case ACHANNEL_SETTING_MOD_OFF: /* muted */ + *neg = 1; + return AGRP_MODIFIERS_OFF; - case ACHANNEL_SETTING_PROTECT: /* protected */ - return AGRP_PROTECTED; + case ACHANNEL_SETTING_PROTECT: /* protected */ + return AGRP_PROTECTED; - case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */ - *neg = 1; - return AGRP_NOTVISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */ + *neg = 1; + return AGRP_NOTVISIBLE; - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return ADT_CURVES_ALWAYS_VISIBLE; + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return ADT_CURVES_ALWAYS_VISIBLE; - default: - /* this shouldn't happen */ - return 0; - } + default: + /* this shouldn't happen */ + return 0; + } } /* get pointer to the setting */ -static void *acf_group_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_group_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - bActionGroup *agrp = (bActionGroup *)ale->data; + bActionGroup *agrp = (bActionGroup *)ale->data; - /* all flags are just in agrp->flag for now... */ - return GET_ACF_FLAG_PTR(agrp->flag, type); + /* all flags are just in agrp->flag for now... */ + return GET_ACF_FLAG_PTR(agrp->flag, type); } /* group type define */ -static bAnimChannelType ACF_GROUP = -{ - "Group", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_group_color, /* backdrop color */ - acf_group_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - acf_generic_group_offset, /* offset */ - - acf_group_name, /* name */ - acf_group_name_prop, /* name prop */ - NULL, /* icon */ - - acf_group_setting_valid, /* has setting */ - acf_group_setting_flag, /* flag for setting */ - acf_group_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_GROUP = { + "Group", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_group_color, /* backdrop color */ + acf_group_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + acf_generic_group_offset, /* offset */ + + acf_group_name, /* name */ + acf_group_name_prop, /* name prop */ + NULL, /* icon */ + + acf_group_setting_valid, /* has setting */ + acf_group_setting_flag, /* flag for setting */ + acf_group_setting_ptr, /* pointer for setting */ }; /* F-Curve ------------------------------------------- */ @@ -967,258 +996,272 @@ static bAnimChannelType ACF_GROUP = /* name for fcurve entries */ static void acf_fcurve_name(bAnimListElem *ale, char *name) { - getname_anim_fcurve(name, ale->id, ale->data); + getname_anim_fcurve(name, ale->id, ale->data); } /* "name" property for fcurve entries */ static bool acf_fcurve_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - FCurve *fcu = (FCurve *)ale->data; + FCurve *fcu = (FCurve *)ale->data; - /* Ctrl-Click Usability Convenience Hack: - * For disabled F-Curves, allow access to the RNA Path - * as our "name" so that user can perform quick fixes - */ - if (fcu->flag & FCURVE_DISABLED) { - RNA_pointer_create(ale->id, &RNA_FCurve, ale->data, ptr); - *prop = RNA_struct_find_property(ptr, "data_path"); - } - else { - /* for "normal" F-Curves - no editable name, but *prop may not be set properly yet... */ - *prop = NULL; - } + /* Ctrl-Click Usability Convenience Hack: + * For disabled F-Curves, allow access to the RNA Path + * as our "name" so that user can perform quick fixes + */ + if (fcu->flag & FCURVE_DISABLED) { + RNA_pointer_create(ale->id, &RNA_FCurve, ale->data, ptr); + *prop = RNA_struct_find_property(ptr, "data_path"); + } + else { + /* for "normal" F-Curves - no editable name, but *prop may not be set properly yet... */ + *prop = NULL; + } - return (*prop != NULL); + return (*prop != NULL); } /* check if some setting exists for this channel */ -static bool acf_fcurve_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting) +static bool acf_fcurve_setting_valid(bAnimContext *ac, + bAnimListElem *ale, + eAnimChannel_Settings setting) { - FCurve *fcu = (FCurve *)ale->data; + FCurve *fcu = (FCurve *)ale->data; - switch (setting) { - /* unsupported */ - case ACHANNEL_SETTING_SOLO: /* Solo Flag is only for NLA */ - case ACHANNEL_SETTING_EXPAND: /* F-Curves are not containers */ - case ACHANNEL_SETTING_PINNED: /* This is only for NLA Actions */ - return false; + switch (setting) { + /* unsupported */ + case ACHANNEL_SETTING_SOLO: /* Solo Flag is only for NLA */ + case ACHANNEL_SETTING_EXPAND: /* F-Curves are not containers */ + case ACHANNEL_SETTING_PINNED: /* This is only for NLA Actions */ + return false; - /* conditionally available */ - case ACHANNEL_SETTING_PROTECT: /* Protection is only valid when there's keyframes */ - if (fcu->bezt) - return true; - else - return false; // NOTE: in this special case, we need to draw ICON_ZOOMOUT + /* conditionally available */ + case ACHANNEL_SETTING_PROTECT: /* Protection is only valid when there's keyframes */ + if (fcu->bezt) + return true; + else + return false; // NOTE: in this special case, we need to draw ICON_ZOOMOUT - case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */ - return (ac->spacetype == SPACE_GRAPH); + case ACHANNEL_SETTING_VISIBLE: /* Only available in Graph Editor */ + return (ac->spacetype == SPACE_GRAPH); - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return false; + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return false; - /* always available */ - default: - return true; - } + /* always available */ + default: + return true; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_fcurve_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_fcurve_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return FCURVE_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return FCURVE_SELECTED; - case ACHANNEL_SETTING_MUTE: /* muted */ - return FCURVE_MUTED; + case ACHANNEL_SETTING_MUTE: /* muted */ + return FCURVE_MUTED; - case ACHANNEL_SETTING_PROTECT: /* protected */ - return FCURVE_PROTECTED; + case ACHANNEL_SETTING_PROTECT: /* protected */ + return FCURVE_PROTECTED; - case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */ - return FCURVE_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visibility - graph editor */ + return FCURVE_VISIBLE; - case ACHANNEL_SETTING_MOD_OFF: - *neg = 1; - return FCURVE_MOD_OFF; + case ACHANNEL_SETTING_MOD_OFF: + *neg = 1; + return FCURVE_MOD_OFF; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_fcurve_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_fcurve_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - FCurve *fcu = (FCurve *)ale->data; + FCurve *fcu = (FCurve *)ale->data; - /* all flags are just in agrp->flag for now... */ - return GET_ACF_FLAG_PTR(fcu->flag, type); + /* all flags are just in agrp->flag for now... */ + return GET_ACF_FLAG_PTR(fcu->flag, type); } /* fcurve type define */ -static bAnimChannelType ACF_FCURVE = -{ - "F-Curve", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_generic_channel_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_flexible, /* indent level */ // xxx rename this to f-curves only? - acf_generic_group_offset, /* offset */ - - acf_fcurve_name, /* name */ - acf_fcurve_name_prop, /* name prop */ - NULL, /* icon */ - - acf_fcurve_setting_valid, /* has setting */ - acf_fcurve_setting_flag, /* flag for setting */ - acf_fcurve_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_FCURVE = { + "F-Curve", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_generic_channel_color, /* backdrop color */ + acf_generic_channel_backdrop, /* backdrop */ + acf_generic_indention_flexible, + /* indent level */ // xxx rename this to f-curves only? + acf_generic_group_offset, /* offset */ + + acf_fcurve_name, /* name */ + acf_fcurve_name_prop, /* name prop */ + NULL, /* icon */ + + acf_fcurve_setting_valid, /* has setting */ + acf_fcurve_setting_flag, /* flag for setting */ + acf_fcurve_setting_ptr, /* pointer for setting */ }; /* NLA Control FCurves Expander ----------------------- */ /* get backdrop color for nla controls widget */ -static void acf_nla_controls_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) +static void acf_nla_controls_color(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + float r_color[3]) { - // TODO: give this its own theme setting? - UI_GetThemeColorShade3fv(TH_GROUP, 55, r_color); + // TODO: give this its own theme setting? + UI_GetThemeColorShade3fv(TH_GROUP, 55, r_color); } /* backdrop for nla controls expander widget */ -static void acf_nla_controls_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) +static void acf_nla_controls_backdrop(bAnimContext *ac, + bAnimListElem *ale, + float yminc, + float ymaxc) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0; - short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - float color[3]; + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + short expanded = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_EXPAND) != 0; + short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + float color[3]; - /* set backdrop drawing color */ - acf->get_backdrop_color(ac, ale, color); + /* set backdrop drawing color */ + acf->get_backdrop_color(ac, ale, color); - /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ - UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); - UI_draw_roundbox_3fvAlpha(true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5, color, 1.0f); + /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ + UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); + UI_draw_roundbox_3fvAlpha( + true, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 5, color, 1.0f); } /* name for nla controls expander entries */ static void acf_nla_controls_name(bAnimListElem *UNUSED(ale), char *name) { - BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE); + BLI_strncpy(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE); } /* check if some setting exists for this channel */ -static bool acf_nla_controls_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_nla_controls_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - /* for now, all settings are supported, though some are only conditionally */ - switch (setting) { - /* supported */ - case ACHANNEL_SETTING_EXPAND: - return true; + /* for now, all settings are supported, though some are only conditionally */ + switch (setting) { + /* supported */ + case ACHANNEL_SETTING_EXPAND: + return true; - // TODO: selected? + // TODO: selected? - default: /* unsupported */ - return false; - } + default: /* unsupported */ + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_nla_controls_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_nla_controls_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - *neg = true; - return ADT_NLA_SKEYS_COLLAPSED; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + *neg = true; + return ADT_NLA_SKEYS_COLLAPSED; - default: - /* this shouldn't happen */ - return 0; - } + default: + /* this shouldn't happen */ + return 0; + } } /* get pointer to the setting */ -static void *acf_nla_controls_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_nla_controls_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - AnimData *adt = (AnimData *)ale->data; + AnimData *adt = (AnimData *)ale->data; - /* all flags are just in adt->flag for now... */ - return GET_ACF_FLAG_PTR(adt->flag, type); + /* all flags are just in adt->flag for now... */ + return GET_ACF_FLAG_PTR(adt->flag, type); } static int acf_nla_controls_icon(bAnimListElem *UNUSED(ale)) { - return ICON_NLA; + return ICON_NLA; } /* NLA Control FCurves Expander type define */ -static bAnimChannelType ACF_NLACONTROLS = -{ - "NLA Controls Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_nla_controls_color, /* backdrop color */ - acf_nla_controls_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - acf_generic_group_offset, /* offset */ - - acf_nla_controls_name, /* name */ - NULL, /* name prop */ - acf_nla_controls_icon, /* icon */ - - acf_nla_controls_setting_valid, /* has setting */ - acf_nla_controls_setting_flag, /* flag for setting */ - acf_nla_controls_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_NLACONTROLS = { + "NLA Controls Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_nla_controls_color, /* backdrop color */ + acf_nla_controls_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + acf_generic_group_offset, /* offset */ + + acf_nla_controls_name, /* name */ + NULL, /* name prop */ + acf_nla_controls_icon, /* icon */ + + acf_nla_controls_setting_valid, /* has setting */ + acf_nla_controls_setting_flag, /* flag for setting */ + acf_nla_controls_setting_ptr, /* pointer for setting */ }; - /* NLA Control F-Curve -------------------------------- */ /* name for nla control fcurve entries */ static void acf_nla_curve_name(bAnimListElem *ale, char *name) { - NlaStrip *strip = ale->owner; - FCurve *fcu = ale->data; - PropertyRNA *prop; + NlaStrip *strip = ale->owner; + FCurve *fcu = ale->data; + PropertyRNA *prop; - /* try to get RNA property that this shortened path (relative to the strip) refers to */ - prop = RNA_struct_type_find_property(&RNA_NlaStrip, fcu->rna_path); - if (prop) { - /* "name" of this strip displays the UI identifier + the name of the NlaStrip */ - BLI_snprintf(name, 256, "%s (%s)", RNA_property_ui_name(prop), strip->name); - } - else { - /* unknown property... */ - BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index); - } + /* try to get RNA property that this shortened path (relative to the strip) refers to */ + prop = RNA_struct_type_find_property(&RNA_NlaStrip, fcu->rna_path); + if (prop) { + /* "name" of this strip displays the UI identifier + the name of the NlaStrip */ + BLI_snprintf(name, 256, "%s (%s)", RNA_property_ui_name(prop), strip->name); + } + else { + /* unknown property... */ + BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index); + } } - /* NLA Control F-Curve type define */ -static bAnimChannelType ACF_NLACURVE = -{ - "NLA Control F-Curve", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_generic_channel_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_1, /* indent level */ - acf_generic_group_offset, /* offset */ - - acf_nla_curve_name, /* name */ - acf_fcurve_name_prop, /* name prop */ - NULL, /* icon */ - - acf_fcurve_setting_valid, /* has setting */ - acf_fcurve_setting_flag, /* flag for setting */ - acf_fcurve_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_NLACURVE = { + "NLA Control F-Curve", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_generic_channel_color, /* backdrop color */ + acf_generic_channel_backdrop, /* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_group_offset, /* offset */ + + acf_nla_curve_name, /* name */ + acf_fcurve_name_prop, /* name prop */ + NULL, /* icon */ + + acf_fcurve_setting_valid, /* has setting */ + acf_fcurve_setting_flag, /* flag for setting */ + acf_fcurve_setting_ptr, /* pointer for setting */ }; /* Object Action Expander ------------------------------------------- */ @@ -1226,84 +1269,89 @@ static bAnimChannelType ACF_NLACURVE = // TODO: just get this from RNA? static int acf_fillactd_icon(bAnimListElem *UNUSED(ale)) { - return ICON_ACTION; + return ICON_ACTION; } /* check if some setting exists for this channel */ -static bool acf_fillactd_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_fillactd_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* only select and expand supported */ - case ACHANNEL_SETTING_SELECT: - case ACHANNEL_SETTING_EXPAND: - return true; + switch (setting) { + /* only select and expand supported */ + case ACHANNEL_SETTING_SELECT: + case ACHANNEL_SETTING_EXPAND: + return true; - default: - return false; - } + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_fillactd_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_fillactd_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - case ACHANNEL_SETTING_EXPAND: /* expanded */ - *neg = true; - return ACT_COLLAPSED; + case ACHANNEL_SETTING_EXPAND: /* expanded */ + *neg = true; + return ACT_COLLAPSED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_fillactd_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_fillactd_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - bAction *act = (bAction *)ale->data; - AnimData *adt = ale->adt; + bAction *act = (bAction *)ale->data; + AnimData *adt = ale->adt; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - if (adt) { - return GET_ACF_FLAG_PTR(adt->flag, type); - } - return NULL; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + if (adt) { + return GET_ACF_FLAG_PTR(adt->flag, type); + } + return NULL; - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(act->flag, type); + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(act->flag, type); - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* object action expander type define */ -static bAnimChannelType ACF_FILLACTD = -{ - "Ob-Action Filler", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idfill_name_prop, /* name prop */ - acf_fillactd_icon, /* icon */ - - acf_fillactd_setting_valid, /* has setting */ - acf_fillactd_setting_flag, /* flag for setting */ - acf_fillactd_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_FILLACTD = { + "Ob-Action Filler", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idfill_name_prop, /* name prop */ + acf_fillactd_icon, /* icon */ + + acf_fillactd_setting_valid, /* has setting */ + acf_fillactd_setting_flag, /* flag for setting */ + acf_fillactd_setting_ptr, /* pointer for setting */ }; /* Drivers Expander ------------------------------------------- */ @@ -1311,157 +1359,162 @@ static bAnimChannelType ACF_FILLACTD = // TODO: just get this from RNA? static int acf_filldrivers_icon(bAnimListElem *UNUSED(ale)) { - return ICON_DRIVER; + return ICON_DRIVER; } static void acf_filldrivers_name(bAnimListElem *UNUSED(ale), char *name) { - BLI_strncpy(name, IFACE_("Drivers"), ANIM_CHAN_NAME_SIZE); + BLI_strncpy(name, IFACE_("Drivers"), ANIM_CHAN_NAME_SIZE); } /* check if some setting exists for this channel */ // TODO: this could be made more generic -static bool acf_filldrivers_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_filldrivers_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* only expand supported */ - case ACHANNEL_SETTING_EXPAND: - return true; + switch (setting) { + /* only expand supported */ + case ACHANNEL_SETTING_EXPAND: + return true; - default: - return false; - } + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_filldrivers_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_filldrivers_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - *neg = true; - return ADT_DRIVERS_COLLAPSED; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + *neg = true; + return ADT_DRIVERS_COLLAPSED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_filldrivers_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_filldrivers_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - AnimData *adt = (AnimData *)ale->data; + AnimData *adt = (AnimData *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(adt->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(adt->flag, type); - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* drivers expander type define */ -static bAnimChannelType ACF_FILLDRIVERS = -{ - "Drivers Filler", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_generic_dataexpand_color, /* backdrop color */ - acf_generic_dataexpand_backdrop, /* backdrop */ - acf_generic_indention_1, /* indent level */ - acf_generic_basic_offset, /* offset */ - - acf_filldrivers_name, /* name */ - NULL, /* name prop */ - acf_filldrivers_icon, /* icon */ - - acf_filldrivers_setting_valid, /* has setting */ - acf_filldrivers_setting_flag, /* flag for setting */ - acf_filldrivers_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_FILLDRIVERS = { + "Drivers Filler", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_generic_dataexpand_color, /* backdrop color */ + acf_generic_dataexpand_backdrop, /* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_basic_offset, /* offset */ + + acf_filldrivers_name, /* name */ + NULL, /* name prop */ + acf_filldrivers_icon, /* icon */ + + acf_filldrivers_setting_valid, /* has setting */ + acf_filldrivers_setting_flag, /* flag for setting */ + acf_filldrivers_setting_ptr, /* pointer for setting */ }; - /* Material Expander ------------------------------------------- */ // TODO: just get this from RNA? static int acf_dsmat_icon(bAnimListElem *UNUSED(ale)) { - return ICON_MATERIAL_DATA; + return ICON_MATERIAL_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsmat_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsmat_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return MA_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return MA_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dsmat_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Material *ma = (Material *)ale->data; + Material *ma = (Material *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(ma->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(ma->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (ma->adt) - return GET_ACF_FLAG_PTR(ma->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (ma->adt) + return GET_ACF_FLAG_PTR(ma->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* material expander type define */ -static bAnimChannelType ACF_DSMAT = -{ - "Material Data Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dsmat_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsmat_setting_flag, /* flag for setting */ - acf_dsmat_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSMAT = { + "Material Data Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dsmat_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsmat_setting_flag, /* flag for setting */ + acf_dsmat_setting_ptr, /* pointer for setting */ }; /* Light Expander ------------------------------------------- */ @@ -1469,76 +1522,79 @@ static bAnimChannelType ACF_DSMAT = // TODO: just get this from RNA? static int acf_dslight_icon(bAnimListElem *UNUSED(ale)) { - return ICON_LIGHT_DATA; + return ICON_LIGHT_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dslight_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dslight_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return LA_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return LA_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_dslight_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dslight_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - Light *la = (Light *)ale->data; + Light *la = (Light *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(la->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(la->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (la->adt) - return GET_ACF_FLAG_PTR(la->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (la->adt) + return GET_ACF_FLAG_PTR(la->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* light expander type define */ -static bAnimChannelType ACF_DSLIGHT = -{ - "Light Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dslight_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dslight_setting_flag, /* flag for setting */ - acf_dslight_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSLIGHT = { + "Light Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dslight_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dslight_setting_flag, /* flag for setting */ + acf_dslight_setting_ptr, /* pointer for setting */ }; /* Texture Expander ------------------------------------------- */ @@ -1546,83 +1602,84 @@ static bAnimChannelType ACF_DSLIGHT = // TODO: just get this from RNA? static int acf_dstex_icon(bAnimListElem *UNUSED(ale)) { - return ICON_TEXTURE_DATA; + return ICON_TEXTURE_DATA; } /* offset for texture expanders */ // FIXME: soon to be obsolete? static short acf_dstex_offset(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale)) { - return 14; // XXX: simply include this in indention instead? + return 14; // XXX: simply include this in indention instead? } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dstex_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dstex_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return TEX_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return TEX_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dstex_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Tex *tex = (Tex *)ale->data; + Tex *tex = (Tex *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(tex->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(tex->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (tex->adt) - return GET_ACF_FLAG_PTR(tex->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (tex->adt) + return GET_ACF_FLAG_PTR(tex->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* texture expander type define */ -static bAnimChannelType ACF_DSTEX = -{ - "Texture Data Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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 */ - acf_generic_idfill_name_prop, /* name prop */ - acf_dstex_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dstex_setting_flag, /* flag for setting */ - acf_dstex_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSTEX = { + "Texture Data Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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 */ + acf_generic_idfill_name_prop, /* name prop */ + acf_dstex_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dstex_setting_flag, /* flag for setting */ + acf_dstex_setting_ptr, /* pointer for setting */ }; /* Camera Expander ------------------------------------------- */ @@ -1630,81 +1687,82 @@ static bAnimChannelType ACF_DSTEX = // TODO: just get this from RNA? static int acf_dscachefile_icon(bAnimListElem *ale) { - UNUSED_VARS(ale); - return ICON_FILE; + UNUSED_VARS(ale); + return ICON_FILE; } /* get the appropriate flag(s) for the setting when it is valid */ static int acf_dscachefile_setting_flag(bAnimContext *ac, eAnimChannel_Settings setting, bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return CACHEFILE_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return CACHEFILE_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } - UNUSED_VARS(ac); + UNUSED_VARS(ac); } /* get pointer to the setting */ -static void *acf_dscachefile_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dscachefile_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - CacheFile *cache_file = (CacheFile *)ale->data; + CacheFile *cache_file = (CacheFile *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(cache_file->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(cache_file->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (cache_file->adt) { - return GET_ACF_FLAG_PTR(cache_file->adt->flag, type); - } + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (cache_file->adt) { + return GET_ACF_FLAG_PTR(cache_file->adt->flag, type); + } - return NULL; + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* CacheFile expander type define. */ -static bAnimChannelType ACF_DSCACHEFILE = -{ - "Cache File Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idfill_name_prop, /* name prop */ - acf_dscachefile_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dscachefile_setting_flag, /* flag for setting */ - acf_dscachefile_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSCACHEFILE = { + "Cache File Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idfill_name_prop, /* name prop */ + acf_dscachefile_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dscachefile_setting_flag, /* flag for setting */ + acf_dscachefile_setting_ptr, /* pointer for setting */ }; /* Camera Expander ------------------------------------------- */ @@ -1712,80 +1770,81 @@ static bAnimChannelType ACF_DSCACHEFILE = // TODO: just get this from RNA? static int acf_dscam_icon(bAnimListElem *UNUSED(ale)) { - return ICON_CAMERA_DATA; + return ICON_CAMERA_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dscam_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dscam_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return CAM_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return CAM_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - return ADT_CURVES_ALWAYS_VISIBLE; + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + return ADT_CURVES_ALWAYS_VISIBLE; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dscam_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Camera *ca = (Camera *)ale->data; + Camera *ca = (Camera *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(ca->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(ca->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - if (ca->adt) - return GET_ACF_FLAG_PTR(ca->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + if (ca->adt) + return GET_ACF_FLAG_PTR(ca->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* camera expander type define */ -static bAnimChannelType ACF_DSCAM = -{ - "Camera Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idfill_name_prop, /* name prop */ - acf_dscam_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dscam_setting_flag, /* flag for setting */ - acf_dscam_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSCAM = { + "Camera Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idfill_name_prop, /* name prop */ + acf_dscam_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dscam_setting_flag, /* flag for setting */ + acf_dscam_setting_ptr, /* pointer for setting */ }; /* Curve Expander ------------------------------------------- */ @@ -1793,86 +1852,87 @@ static bAnimChannelType ACF_DSCAM = // TODO: just get this from RNA? static int acf_dscur_icon(bAnimListElem *ale) { - Curve *cu = (Curve *)ale->data; - short obtype = BKE_curve_type_get(cu); + Curve *cu = (Curve *)ale->data; + short obtype = BKE_curve_type_get(cu); - switch (obtype) { - case OB_FONT: - return ICON_FONT_DATA; - case OB_SURF: - return ICON_SURFACE_DATA; - default: - return ICON_CURVE_DATA; - } + switch (obtype) { + case OB_FONT: + return ICON_FONT_DATA; + case OB_SURF: + return ICON_SURFACE_DATA; + default: + return ICON_CURVE_DATA; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dscur_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dscur_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return CU_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return CU_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dscur_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Curve *cu = (Curve *)ale->data; + Curve *cu = (Curve *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(cu->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(cu->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (cu->adt) - return GET_ACF_FLAG_PTR(cu->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (cu->adt) + return GET_ACF_FLAG_PTR(cu->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* curve expander type define */ -static bAnimChannelType ACF_DSCUR = -{ - "Curve Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dscur_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dscur_setting_flag, /* flag for setting */ - acf_dscur_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSCUR = { + "Curve Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dscur_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dscur_setting_flag, /* flag for setting */ + acf_dscur_setting_ptr, /* pointer for setting */ }; /* Shape Key Expander ------------------------------------------- */ @@ -1880,76 +1940,77 @@ static bAnimChannelType ACF_DSCUR = // TODO: just get this from RNA? static int acf_dsskey_icon(bAnimListElem *UNUSED(ale)) { - return ICON_SHAPEKEY_DATA; + return ICON_SHAPEKEY_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsskey_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsskey_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return KEY_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return KEY_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dsskey_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Key *key = (Key *)ale->data; + Key *key = (Key *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(key->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(key->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (key->adt) - return GET_ACF_FLAG_PTR(key->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (key->adt) + return GET_ACF_FLAG_PTR(key->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* shapekey expander type define */ -static bAnimChannelType ACF_DSSKEY = -{ - "Shape Key Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dsskey_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsskey_setting_flag, /* flag for setting */ - acf_dsskey_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSSKEY = { + "Shape Key Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dsskey_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsskey_setting_flag, /* flag for setting */ + acf_dsskey_setting_ptr, /* pointer for setting */ }; /* World Expander ------------------------------------------- */ @@ -1957,76 +2018,77 @@ static bAnimChannelType ACF_DSSKEY = // TODO: just get this from RNA? static int acf_dswor_icon(bAnimListElem *UNUSED(ale)) { - return ICON_WORLD_DATA; + return ICON_WORLD_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dswor_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dswor_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return WO_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return WO_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dswor_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - World *wo = (World *)ale->data; + World *wo = (World *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(wo->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(wo->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (wo->adt) - return GET_ACF_FLAG_PTR(wo->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (wo->adt) + return GET_ACF_FLAG_PTR(wo->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* world expander type define */ -static bAnimChannelType ACF_DSWOR = -{ - "World Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idfill_name_prop, /* name prop */ - acf_dswor_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dswor_setting_flag, /* flag for setting */ - acf_dswor_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSWOR = { + "World Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idfill_name_prop, /* name prop */ + acf_dswor_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dswor_setting_flag, /* flag for setting */ + acf_dswor_setting_ptr, /* pointer for setting */ }; /* Particle Expander ------------------------------------------- */ @@ -2034,76 +2096,77 @@ static bAnimChannelType ACF_DSWOR = // TODO: just get this from RNA? static int acf_dspart_icon(bAnimListElem *UNUSED(ale)) { - return ICON_PARTICLE_DATA; + return ICON_PARTICLE_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dspart_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return PART_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return PART_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dspart_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - ParticleSettings *part = (ParticleSettings *)ale->data; + ParticleSettings *part = (ParticleSettings *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(part->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(part->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (part->adt) - return GET_ACF_FLAG_PTR(part->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (part->adt) + return GET_ACF_FLAG_PTR(part->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* particle expander type define */ -static bAnimChannelType ACF_DSPART = -{ - "Particle Data Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dspart_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dspart_setting_flag, /* flag for setting */ - acf_dspart_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSPART = { + "Particle Data Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dspart_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dspart_setting_flag, /* flag for setting */ + acf_dspart_setting_ptr, /* pointer for setting */ }; /* MetaBall Expander ------------------------------------------- */ @@ -2111,76 +2174,79 @@ static bAnimChannelType ACF_DSPART = // TODO: just get this from RNA? static int acf_dsmball_icon(bAnimListElem *UNUSED(ale)) { - return ICON_META_DATA; + return ICON_META_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsmball_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsmball_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return MB_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return MB_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_dsmball_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dsmball_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - MetaBall *mb = (MetaBall *)ale->data; + MetaBall *mb = (MetaBall *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(mb->flag2, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(mb->flag2, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (mb->adt) - return GET_ACF_FLAG_PTR(mb->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (mb->adt) + return GET_ACF_FLAG_PTR(mb->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* metaball expander type define */ -static bAnimChannelType ACF_DSMBALL = -{ - "Metaball Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dsmball_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsmball_setting_flag, /* flag for setting */ - acf_dsmball_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSMBALL = { + "Metaball Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dsmball_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsmball_setting_flag, /* flag for setting */ + acf_dsmball_setting_ptr, /* pointer for setting */ }; /* Armature Expander ------------------------------------------- */ @@ -2188,76 +2254,77 @@ static bAnimChannelType ACF_DSMBALL = // TODO: just get this from RNA? static int acf_dsarm_icon(bAnimListElem *UNUSED(ale)) { - return ICON_ARMATURE_DATA; + return ICON_ARMATURE_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsarm_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsarm_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return ARM_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return ARM_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dsarm_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - bArmature *arm = (bArmature *)ale->data; + bArmature *arm = (bArmature *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(arm->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(arm->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (arm->adt) - return GET_ACF_FLAG_PTR(arm->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (arm->adt) + return GET_ACF_FLAG_PTR(arm->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* metaball expander type define */ -static bAnimChannelType ACF_DSARM = -{ - "Armature Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dsarm_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsarm_setting_flag, /* flag for setting */ - acf_dsarm_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSARM = { + "Armature Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dsarm_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsarm_setting_flag, /* flag for setting */ + acf_dsarm_setting_ptr, /* pointer for setting */ }; /* NodeTree Expander ------------------------------------------- */ @@ -2265,87 +2332,90 @@ static bAnimChannelType ACF_DSARM = // TODO: just get this from RNA? static int acf_dsntree_icon(bAnimListElem *UNUSED(ale)) { - return ICON_NODETREE; + 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); + bNodeTree *ntree = (bNodeTree *)ale->data; + short offset = acf_generic_basic_offset(ac, ale); - offset += acf_nodetree_rootType_offset(ntree); + offset += acf_nodetree_rootType_offset(ntree); - return offset; + return offset; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsntree_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsntree_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return NTREE_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return NTREE_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_dsntree_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dsntree_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - bNodeTree *ntree = (bNodeTree *)ale->data; + bNodeTree *ntree = (bNodeTree *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(ntree->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(ntree->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (ntree->adt) - return GET_ACF_FLAG_PTR(ntree->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (ntree->adt) + return GET_ACF_FLAG_PTR(ntree->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* node tree expander type define */ -static bAnimChannelType ACF_DSNTREE = -{ - "Node Tree Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_generic_dataexpand_color, /* backdrop color */ - acf_generic_dataexpand_backdrop, /* backdrop */ - acf_generic_indention_1, /* indent level */ - acf_dsntree_offset, /* offset */ - - acf_generic_idblock_name, /* name */ - acf_generic_idblock_name_prop, /* name prop */ - acf_dsntree_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsntree_setting_flag, /* flag for setting */ - acf_dsntree_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSNTREE = { + "Node Tree Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_generic_dataexpand_color, /* backdrop color */ + acf_generic_dataexpand_backdrop, /* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_dsntree_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_generic_idblock_name_prop, /* name prop */ + acf_dsntree_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsntree_setting_flag, /* flag for setting */ + acf_dsntree_setting_ptr, /* pointer for setting */ }; /* LineStyle Expander ------------------------------------------- */ @@ -2353,76 +2423,79 @@ static bAnimChannelType ACF_DSNTREE = /* TODO: just get this from RNA? */ static int acf_dslinestyle_icon(bAnimListElem *UNUSED(ale)) { - return ICON_LINE_DATA; + return ICON_LINE_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dslinestyle_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dslinestyle_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return LS_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return LS_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_dslinestyle_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dslinestyle_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ale->data; + FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(linestyle->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(linestyle->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (linestyle->adt) - return GET_ACF_FLAG_PTR(linestyle->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (linestyle->adt) + return GET_ACF_FLAG_PTR(linestyle->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* node tree expander type define */ -static bAnimChannelType ACF_DSLINESTYLE = -{ - "Line Style Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dslinestyle_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dslinestyle_setting_flag, /* flag for setting */ - acf_dslinestyle_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSLINESTYLE = { + "Line Style Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dslinestyle_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dslinestyle_setting_flag, /* flag for setting */ + acf_dslinestyle_setting_ptr, /* pointer for setting */ }; /* Mesh Expander ------------------------------------------- */ @@ -2430,76 +2503,78 @@ static bAnimChannelType ACF_DSLINESTYLE = // TODO: just get this from RNA? static int acf_dsmesh_icon(bAnimListElem *UNUSED(ale)) { - return ICON_MESH_DATA; + return ICON_MESH_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsmesh_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsmesh_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return ME_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return ME_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dsmesh_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Mesh *me = (Mesh *)ale->data; + Mesh *me = (Mesh *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(me->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(me->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (me->adt) - return GET_ACF_FLAG_PTR(me->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (me->adt) + return GET_ACF_FLAG_PTR(me->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* node tree expander type define */ -static bAnimChannelType ACF_DSMESH = -{ - "Mesh Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_idblock_name, /* name */ - acf_generic_idblock_name_prop, /* name prop */ - acf_dsmesh_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsmesh_setting_flag, /* flag for setting */ - acf_dsmesh_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSMESH = { + "Mesh Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_idblock_name, /* name */ + acf_generic_idblock_name_prop, /* name prop */ + acf_dsmesh_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsmesh_setting_flag, /* flag for setting */ + acf_dsmesh_setting_ptr, /* pointer for setting */ }; /* Lattice Expander ------------------------------------------- */ @@ -2507,76 +2582,78 @@ static bAnimChannelType ACF_DSMESH = // TODO: just get this from RNA? static int acf_dslat_icon(bAnimListElem *UNUSED(ale)) { - return ICON_LATTICE_DATA; + return ICON_LATTICE_DATA; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dslat_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dslat_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return LT_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return LT_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dslat_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Lattice *lt = (Lattice *)ale->data; + Lattice *lt = (Lattice *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(lt->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(lt->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (lt->adt) - return GET_ACF_FLAG_PTR(lt->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (lt->adt) + return GET_ACF_FLAG_PTR(lt->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* node tree expander type define */ -static bAnimChannelType ACF_DSLAT = -{ - "Lattice Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_idblock_name, /* name */ - acf_generic_idblock_name_prop, /* name prop */ - acf_dslat_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dslat_setting_flag, /* flag for setting */ - acf_dslat_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSLAT = { + "Lattice Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_idblock_name, /* name */ + acf_generic_idblock_name_prop, /* name prop */ + acf_dslat_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dslat_setting_flag, /* flag for setting */ + acf_dslat_setting_ptr, /* pointer for setting */ }; /* Speaker Expander ------------------------------------------- */ @@ -2584,76 +2661,77 @@ static bAnimChannelType ACF_DSLAT = // TODO: just get this from RNA? static int acf_dsspk_icon(bAnimListElem *UNUSED(ale)) { - return ICON_SPEAKER; + return ICON_SPEAKER; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsspk_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsspk_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return SPK_DS_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return SPK_DS_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ static void *acf_dsspk_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) { - Speaker *spk = (Speaker *)ale->data; + Speaker *spk = (Speaker *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(spk->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(spk->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (spk->adt) - return GET_ACF_FLAG_PTR(spk->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (spk->adt) + return GET_ACF_FLAG_PTR(spk->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* speaker expander type define */ -static bAnimChannelType ACF_DSSPK = -{ - "Speaker Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dsspk_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsspk_setting_flag, /* flag for setting */ - acf_dsspk_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSSPK = { + "Speaker Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dsspk_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsspk_setting_flag, /* flag for setting */ + acf_dsspk_setting_ptr, /* pointer for setting */ }; /* GPencil Expander ------------------------------------------- */ @@ -2661,76 +2739,79 @@ static bAnimChannelType ACF_DSSPK = // TODO: just get this from RNA? static int acf_dsgpencil_icon(bAnimListElem *UNUSED(ale)) { - return ICON_GREASEPENCIL; + return ICON_GREASEPENCIL; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsgpencil_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsgpencil_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GP_DATA_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GP_DATA_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_dsgpencil_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dsgpencil_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - bGPdata *gpd = (bGPdata *)ale->data; + bGPdata *gpd = (bGPdata *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(gpd->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(gpd->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (gpd->adt) - return GET_ACF_FLAG_PTR(gpd->adt->flag, type); - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (gpd->adt) + return GET_ACF_FLAG_PTR(gpd->adt->flag, type); + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* grease pencil expander type define */ -static bAnimChannelType ACF_DSGPENCIL = -{ - "GPencil DS Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idblock_name_prop, /* name prop */ - acf_dsgpencil_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsgpencil_setting_flag, /* flag for setting */ - acf_dsgpencil_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSGPENCIL = { + "GPencil DS Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idblock_name_prop, /* name prop */ + acf_dsgpencil_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsgpencil_setting_flag, /* flag for setting */ + acf_dsgpencil_setting_ptr, /* pointer for setting */ }; /* World Expander ------------------------------------------- */ @@ -2738,77 +2819,80 @@ static bAnimChannelType ACF_DSGPENCIL = // TODO: just get this from RNA? static int acf_dsmclip_icon(bAnimListElem *UNUSED(ale)) { - return ICON_SEQUENCE; + return ICON_SEQUENCE; } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_dsmclip_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_dsmclip_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return MCLIP_DATA_EXPAND; + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return MCLIP_DATA_EXPAND; - case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ - return ADT_NLA_EVAL_OFF; + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; - case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ - *neg = true; - return ADT_CURVES_NOT_VISIBLE; + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return ADT_UI_SELECTED; + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_dsmclip_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_dsmclip_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - MovieClip *clip = (MovieClip *)ale->data; + MovieClip *clip = (MovieClip *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GET_ACF_FLAG_PTR(clip->flag, type); + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(clip->flag, type); - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ - case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ - if (clip->adt != NULL) { - return GET_ACF_FLAG_PTR(clip->adt->flag, type); - } - return NULL; + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (clip->adt != NULL) { + return GET_ACF_FLAG_PTR(clip->adt->flag, type); + } + return NULL; - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* world expander type define */ -static bAnimChannelType ACF_DSMCLIP = -{ - "Movieclip Expander", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - 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_generic_idfill_name_prop, /* name prop */ - acf_dsmclip_icon, /* icon */ - - acf_generic_dataexpand_setting_valid, /* has setting */ - acf_dsmclip_setting_flag, /* flag for setting */ - acf_dsmclip_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_DSMCLIP = { + "Movieclip Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + 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_generic_idfill_name_prop, /* name prop */ + acf_dsmclip_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dsmclip_setting_flag, /* flag for setting */ + acf_dsmclip_setting_ptr, /* pointer for setting */ }; /* ShapeKey Entry ------------------------------------------- */ @@ -2816,107 +2900,112 @@ static bAnimChannelType ACF_DSMCLIP = /* name for ShapeKey */ static void acf_shapekey_name(bAnimListElem *ale, char *name) { - KeyBlock *kb = (KeyBlock *)ale->data; + KeyBlock *kb = (KeyBlock *)ale->data; - /* just copy the name... */ - if (kb && name) { - /* if the KeyBlock had a name, use it, otherwise use the index */ - if (kb->name[0]) - BLI_strncpy(name, kb->name, ANIM_CHAN_NAME_SIZE); - else - BLI_snprintf(name, ANIM_CHAN_NAME_SIZE, IFACE_("Key %d"), ale->index); - } + /* just copy the name... */ + if (kb && name) { + /* if the KeyBlock had a name, use it, otherwise use the index */ + if (kb->name[0]) + BLI_strncpy(name, kb->name, ANIM_CHAN_NAME_SIZE); + else + BLI_snprintf(name, ANIM_CHAN_NAME_SIZE, IFACE_("Key %d"), ale->index); + } } /* name property for ShapeKey entries */ static bool acf_shapekey_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - KeyBlock *kb = (KeyBlock *)ale->data; + KeyBlock *kb = (KeyBlock *)ale->data; - /* if the KeyBlock had a name, use it, otherwise use the index */ - if (kb && kb->name[0]) { - RNA_pointer_create(ale->id, &RNA_ShapeKey, kb, ptr); - *prop = RNA_struct_name_property(ptr->type); + /* if the KeyBlock had a name, use it, otherwise use the index */ + if (kb && kb->name[0]) { + RNA_pointer_create(ale->id, &RNA_ShapeKey, kb, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); - } + return (*prop != NULL); + } - return false; + return false; } /* check if some setting exists for this channel */ -static bool acf_shapekey_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_shapekey_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted */ - case ACHANNEL_SETTING_PROTECT: /* protected */ - return true; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted */ + case ACHANNEL_SETTING_PROTECT: /* protected */ + return true; - /* nothing else is supported */ - default: - return false; - } + /* nothing else is supported */ + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_shapekey_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_shapekey_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_MUTE: /* mute */ - return KEYBLOCK_MUTE; + switch (setting) { + case ACHANNEL_SETTING_MUTE: /* mute */ + return KEYBLOCK_MUTE; - case ACHANNEL_SETTING_SELECT: /* selected */ - return KEYBLOCK_SEL; + case ACHANNEL_SETTING_SELECT: /* selected */ + return KEYBLOCK_SEL; - case ACHANNEL_SETTING_PROTECT: /* locked */ - return KEYBLOCK_LOCKED; + case ACHANNEL_SETTING_PROTECT: /* locked */ + return KEYBLOCK_LOCKED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_shapekey_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings setting, short *type) +static void *acf_shapekey_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) { - KeyBlock *kb = (KeyBlock *)ale->data; + KeyBlock *kb = (KeyBlock *)ale->data; - /* clear extra return data first */ - *type = 0; + /* clear extra return data first */ + *type = 0; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - case ACHANNEL_SETTING_MUTE: /* muted */ - case ACHANNEL_SETTING_PROTECT: /* protected */ - return GET_ACF_FLAG_PTR(kb->flag, type); + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted */ + case ACHANNEL_SETTING_PROTECT: /* protected */ + return GET_ACF_FLAG_PTR(kb->flag, type); - default: /* unsupported */ - return NULL; - } + default: /* unsupported */ + return NULL; + } } /* shapekey expander type define */ -static bAnimChannelType ACF_SHAPEKEY = -{ - "Shape Key", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_generic_channel_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - acf_generic_basic_offset, /* offset */ - - acf_shapekey_name, /* name */ - acf_shapekey_name_prop, /* name prop */ - NULL, /* icon */ - - acf_shapekey_setting_valid, /* has setting */ - acf_shapekey_setting_flag, /* flag for setting */ - acf_shapekey_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_SHAPEKEY = { + "Shape Key", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_generic_channel_color, /* backdrop color */ + acf_generic_channel_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + acf_generic_basic_offset, /* offset */ + + acf_shapekey_name, /* name */ + acf_shapekey_name_prop, /* name prop */ + NULL, /* icon */ + + acf_shapekey_setting_valid, /* has setting */ + acf_shapekey_setting_flag, /* flag for setting */ + acf_shapekey_setting_ptr, /* pointer for setting */ }; /* GPencil Datablock ------------------------------------------- */ @@ -2924,76 +3013,79 @@ static bAnimChannelType ACF_SHAPEKEY = /* get backdrop color for gpencil datablock widget */ static void acf_gpd_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) { - /* these are ID-blocks, but not exactly standalone... */ - UI_GetThemeColorShade3fv(TH_DOPESHEET_CHANNELSUBOB, 20, r_color); + /* these are ID-blocks, but not exactly standalone... */ + UI_GetThemeColorShade3fv(TH_DOPESHEET_CHANNELSUBOB, 20, r_color); } // TODO: just get this from RNA? static int acf_gpd_icon(bAnimListElem *UNUSED(ale)) { - return ICON_GREASEPENCIL; + return ICON_GREASEPENCIL; } /* check if some setting exists for this channel */ -static bool acf_gpd_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_gpd_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* only select and expand supported */ - case ACHANNEL_SETTING_SELECT: - case ACHANNEL_SETTING_EXPAND: - return true; + switch (setting) { + /* only select and expand supported */ + case ACHANNEL_SETTING_SELECT: + case ACHANNEL_SETTING_EXPAND: + return true; - default: - return false; - } + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ static int acf_gpd_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return AGRP_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return AGRP_SELECTED; - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return GP_DATA_EXPAND; + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GP_DATA_EXPAND; - default: - /* these shouldn't happen */ - return 0; - } + default: + /* these shouldn't happen */ + return 0; + } } /* get pointer to the setting */ -static void *acf_gpd_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_gpd_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - bGPdata *gpd = (bGPdata *)ale->data; + bGPdata *gpd = (bGPdata *)ale->data; - /* all flags are just in gpd->flag for now... */ - return GET_ACF_FLAG_PTR(gpd->flag, type); + /* all flags are just in gpd->flag for now... */ + return GET_ACF_FLAG_PTR(gpd->flag, type); } /* gpencil datablock type define */ -static bAnimChannelType ACF_GPD = -{ - "GPencil Datablock", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_gpd_color, /* backdrop color */ - acf_group_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - acf_generic_group_offset, /* offset */ - - acf_generic_idblock_name, /* name */ - acf_generic_idfill_name_prop, /* name prop */ - acf_gpd_icon, /* icon */ - - acf_gpd_setting_valid, /* has setting */ - acf_gpd_setting_flag, /* flag for setting */ - acf_gpd_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_GPD = { + "GPencil Datablock", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_gpd_color, /* backdrop color */ + acf_group_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + acf_generic_group_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_generic_idfill_name_prop, /* name prop */ + acf_gpd_icon, /* icon */ + + acf_gpd_setting_valid, /* has setting */ + acf_gpd_setting_flag, /* flag for setting */ + acf_gpd_setting_ptr, /* pointer for setting */ }; /* GPencil Layer ------------------------------------------- */ @@ -3001,170 +3093,177 @@ static bAnimChannelType ACF_GPD = /* name for grease pencil layer entries */ static void acf_gpl_name(bAnimListElem *ale, char *name) { - bGPDlayer *gpl = (bGPDlayer *)ale->data; + bGPDlayer *gpl = (bGPDlayer *)ale->data; - if (gpl && name) - BLI_strncpy(name, gpl->info, ANIM_CHAN_NAME_SIZE); + if (gpl && name) + BLI_strncpy(name, gpl->info, ANIM_CHAN_NAME_SIZE); } /* name property for grease pencil layer entries */ static bool acf_gpl_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - if (ale->data) { - RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, ptr); - *prop = RNA_struct_name_property(ptr->type); + if (ale->data) { + RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); - } + return (*prop != NULL); + } - return false; + return false; } /* check if some setting exists for this channel */ -static bool acf_gpl_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_gpl_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* unsupported */ - case ACHANNEL_SETTING_EXPAND: /* gpencil layers are more like F-Curves than groups */ - case ACHANNEL_SETTING_SOLO: /* nla editor only */ - return false; + switch (setting) { + /* unsupported */ + case ACHANNEL_SETTING_EXPAND: /* gpencil layers are more like F-Curves than groups */ + case ACHANNEL_SETTING_SOLO: /* nla editor only */ + return false; - /* always available */ - default: - return true; - } + /* always available */ + default: + return true; + } } /* get the appropriate flag(s) for the setting when it is valid */ static int acf_gpl_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return GP_LAYER_SELECT; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return GP_LAYER_SELECT; - case ACHANNEL_SETTING_MUTE: /* animation muting - similar to frame lock... */ - return GP_LAYER_FRAMELOCK; + case ACHANNEL_SETTING_MUTE: /* animation muting - similar to frame lock... */ + return GP_LAYER_FRAMELOCK; - case ACHANNEL_SETTING_VISIBLE: /* visibility of the layers (NOT muting) */ - *neg = true; - return GP_LAYER_HIDE; + case ACHANNEL_SETTING_VISIBLE: /* visibility of the layers (NOT muting) */ + *neg = true; + return GP_LAYER_HIDE; - case ACHANNEL_SETTING_PROTECT: /* protected */ - return GP_LAYER_LOCKED; + case ACHANNEL_SETTING_PROTECT: /* protected */ + return GP_LAYER_LOCKED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_gpl_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_gpl_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - bGPDlayer *gpl = (bGPDlayer *)ale->data; + bGPDlayer *gpl = (bGPDlayer *)ale->data; - /* all flags are just in gpl->flag for now... */ - return GET_ACF_FLAG_PTR(gpl->flag, type); + /* all flags are just in gpl->flag for now... */ + return GET_ACF_FLAG_PTR(gpl->flag, type); } /* grease pencil layer type define */ -static bAnimChannelType ACF_GPL = -{ - "GPencil Layer", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_gpencil_channel_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_flexible, /* indent level */ - acf_generic_group_offset, /* offset */ - - acf_gpl_name, /* name */ - acf_gpl_name_prop, /* name prop */ - NULL, /* icon */ - - acf_gpl_setting_valid, /* has setting */ - acf_gpl_setting_flag, /* flag for setting */ - acf_gpl_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_GPL = { + "GPencil Layer", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_gpencil_channel_color, /* backdrop color */ + acf_generic_channel_backdrop, /* backdrop */ + acf_generic_indention_flexible, /* indent level */ + acf_generic_group_offset, /* offset */ + + acf_gpl_name, /* name */ + acf_gpl_name_prop, /* name prop */ + NULL, /* icon */ + + acf_gpl_setting_valid, /* has setting */ + acf_gpl_setting_flag, /* flag for setting */ + acf_gpl_setting_ptr, /* pointer for setting */ }; - /* Mask Datablock ------------------------------------------- */ /* get backdrop color for mask datablock widget */ static void acf_mask_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) { - /* these are ID-blocks, but not exactly standalone... */ - UI_GetThemeColorShade3fv(TH_DOPESHEET_CHANNELSUBOB, 20, r_color); + /* these are ID-blocks, but not exactly standalone... */ + UI_GetThemeColorShade3fv(TH_DOPESHEET_CHANNELSUBOB, 20, r_color); } // TODO: just get this from RNA? static int acf_mask_icon(bAnimListElem *UNUSED(ale)) { - return ICON_MOD_MASK; + return ICON_MOD_MASK; } /* check if some setting exists for this channel */ -static bool acf_mask_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_mask_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* only select and expand supported */ - case ACHANNEL_SETTING_SELECT: - case ACHANNEL_SETTING_EXPAND: - return true; + switch (setting) { + /* only select and expand supported */ + case ACHANNEL_SETTING_SELECT: + case ACHANNEL_SETTING_EXPAND: + return true; - default: - return false; - } + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_mask_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_mask_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return AGRP_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return AGRP_SELECTED; - case ACHANNEL_SETTING_EXPAND: /* expanded */ - return MASK_ANIMF_EXPAND; + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return MASK_ANIMF_EXPAND; - default: - /* this shouldn't happen */ - return 0; - } + default: + /* this shouldn't happen */ + return 0; + } } /* get pointer to the setting */ -static void *acf_mask_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_mask_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - Mask *mask = (Mask *)ale->data; + Mask *mask = (Mask *)ale->data; - /* all flags are just in mask->flag for now... */ - return GET_ACF_FLAG_PTR(mask->flag, type); + /* all flags are just in mask->flag for now... */ + return GET_ACF_FLAG_PTR(mask->flag, type); } /* mask datablock type define */ -static bAnimChannelType ACF_MASKDATA = -{ - "Mask Datablock", /* type name */ - ACHANNEL_ROLE_EXPANDER, /* role */ - - acf_mask_color, /* backdrop color */ - acf_group_backdrop, /* backdrop */ - acf_generic_indention_0, /* indent level */ - acf_generic_group_offset, /* offset */ - - acf_generic_idblock_name, /* name */ - acf_generic_idfill_name_prop, /* name prop */ - acf_mask_icon, /* icon */ - - acf_mask_setting_valid, /* has setting */ - acf_mask_setting_flag, /* flag for setting */ - acf_mask_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_MASKDATA = { + "Mask Datablock", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_mask_color, /* backdrop color */ + acf_group_backdrop, /* backdrop */ + acf_generic_indention_0, /* indent level */ + acf_generic_group_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_generic_idfill_name_prop, /* name prop */ + acf_mask_icon, /* icon */ + + acf_mask_setting_valid, /* has setting */ + acf_mask_setting_flag, /* flag for setting */ + acf_mask_setting_ptr, /* pointer for setting */ }; /* Mask Layer ------------------------------------------- */ @@ -3172,86 +3271,91 @@ static bAnimChannelType ACF_MASKDATA = /* name for grease pencil layer entries */ static void acf_masklay_name(bAnimListElem *ale, char *name) { - MaskLayer *masklay = (MaskLayer *)ale->data; + MaskLayer *masklay = (MaskLayer *)ale->data; - if (masklay && name) - BLI_strncpy(name, masklay->name, ANIM_CHAN_NAME_SIZE); + if (masklay && name) + BLI_strncpy(name, masklay->name, ANIM_CHAN_NAME_SIZE); } /* name property for grease pencil layer entries */ static bool acf_masklay_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - if (ale->data) { - RNA_pointer_create(ale->id, &RNA_MaskLayer, ale->data, ptr); - *prop = RNA_struct_name_property(ptr->type); + if (ale->data) { + RNA_pointer_create(ale->id, &RNA_MaskLayer, ale->data, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); - } + return (*prop != NULL); + } - return false; + return false; } /* check if some setting exists for this channel */ -static bool acf_masklay_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), eAnimChannel_Settings setting) +static bool acf_masklay_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *UNUSED(ale), + eAnimChannel_Settings setting) { - switch (setting) { - /* unsupported */ - case ACHANNEL_SETTING_EXPAND: /* mask layers are more like F-Curves than groups */ - case ACHANNEL_SETTING_VISIBLE: /* graph editor only */ - case ACHANNEL_SETTING_SOLO: /* nla editor only */ - return false; + switch (setting) { + /* unsupported */ + case ACHANNEL_SETTING_EXPAND: /* mask layers are more like F-Curves than groups */ + case ACHANNEL_SETTING_VISIBLE: /* graph editor only */ + case ACHANNEL_SETTING_SOLO: /* nla editor only */ + return false; - /* always available */ - default: - return true; - } + /* always available */ + default: + return true; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_masklay_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_masklay_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return MASK_LAYERFLAG_SELECT; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return MASK_LAYERFLAG_SELECT; - case ACHANNEL_SETTING_PROTECT: /* protected */ - return MASK_LAYERFLAG_LOCKED; + case ACHANNEL_SETTING_PROTECT: /* protected */ + return MASK_LAYERFLAG_LOCKED; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_masklay_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_masklay_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - MaskLayer *masklay = (MaskLayer *)ale->data; + MaskLayer *masklay = (MaskLayer *)ale->data; - /* all flags are just in masklay->flag for now... */ - return GET_ACF_FLAG_PTR(masklay->flag, type); + /* all flags are just in masklay->flag for now... */ + return GET_ACF_FLAG_PTR(masklay->flag, type); } /* grease pencil layer type define */ -static bAnimChannelType ACF_MASKLAYER = -{ - "Mask Layer", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_generic_channel_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_flexible, /* indent level */ - acf_generic_group_offset, /* offset */ - - acf_masklay_name, /* name */ - acf_masklay_name_prop, /* name prop */ - NULL, /* icon */ - - acf_masklay_setting_valid, /* has setting */ - acf_masklay_setting_flag, /* flag for setting */ - acf_masklay_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_MASKLAYER = { + "Mask Layer", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_generic_channel_color, /* backdrop color */ + acf_generic_channel_backdrop, /* backdrop */ + acf_generic_indention_flexible, /* indent level */ + acf_generic_group_offset, /* offset */ + + acf_masklay_name, /* name */ + acf_masklay_name_prop, /* name prop */ + NULL, /* icon */ + + acf_masklay_setting_valid, /* has setting */ + acf_masklay_setting_flag, /* flag for setting */ + acf_masklay_setting_ptr, /* pointer for setting */ }; /* NLA Track ----------------------------------------------- */ @@ -3259,138 +3363,143 @@ static bAnimChannelType ACF_MASKLAYER = /* get backdrop color for nla track channels */ static void acf_nlatrack_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, float r_color[3]) { - NlaTrack *nlt = (NlaTrack *)ale->data; - AnimData *adt = ale->adt; - bool nonSolo = false; + NlaTrack *nlt = (NlaTrack *)ale->data; + AnimData *adt = ale->adt; + bool nonSolo = false; - /* is track enabled for solo drawing? */ - if ((adt) && (adt->flag & ADT_NLA_SOLO_TRACK)) { - if ((nlt->flag & NLATRACK_SOLO) == 0) { - /* tag for special non-solo handling */ - nonSolo = true; - } - } + /* is track enabled for solo drawing? */ + if ((adt) && (adt->flag & ADT_NLA_SOLO_TRACK)) { + if ((nlt->flag & NLATRACK_SOLO) == 0) { + /* tag for special non-solo handling */ + nonSolo = true; + } + } - /* set color for nla track */ - UI_GetThemeColorShade3fv(TH_HEADER, ((nonSolo == false) ? 20 : -20), r_color); + /* set color for nla track */ + UI_GetThemeColorShade3fv(TH_HEADER, ((nonSolo == false) ? 20 : -20), r_color); } /* name for nla track entries */ static void acf_nlatrack_name(bAnimListElem *ale, char *name) { - NlaTrack *nlt = (NlaTrack *)ale->data; + NlaTrack *nlt = (NlaTrack *)ale->data; - if (nlt && name) - BLI_strncpy(name, nlt->name, ANIM_CHAN_NAME_SIZE); + if (nlt && name) + BLI_strncpy(name, nlt->name, ANIM_CHAN_NAME_SIZE); } /* name property for nla track entries */ static bool acf_nlatrack_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - if (ale->data) { - RNA_pointer_create(ale->id, &RNA_NlaTrack, ale->data, ptr); - *prop = RNA_struct_name_property(ptr->type); + if (ale->data) { + RNA_pointer_create(ale->id, &RNA_NlaTrack, ale->data, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); - } + return (*prop != NULL); + } - return false; + return false; } /* check if some setting exists for this channel */ -static bool acf_nlatrack_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *ale, eAnimChannel_Settings setting) -{ - NlaTrack *nlt = (NlaTrack *)ale->data; - AnimData *adt = ale->adt; - - /* visibility of settings depends on various states... */ - switch (setting) { - /* always supported */ - case ACHANNEL_SETTING_SELECT: - case ACHANNEL_SETTING_SOLO: - return true; - - /* conditionally supported... */ - case ACHANNEL_SETTING_PROTECT: - case ACHANNEL_SETTING_MUTE: - /* if this track is active and we're tweaking it, don't draw these toggles */ - if (((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0) { - /* is track enabled for solo drawing? */ - if ((adt) && (adt->flag & ADT_NLA_SOLO_TRACK)) { - if (nlt->flag & NLATRACK_SOLO) { - /* ok - we've got a solo track, and this is it */ - return true; - } - else { - /* not ok - we've got a solo track, but this isn't it, so make it more obvious */ - return false; - } - } - - - /* ok - no tracks are solo'd, and this isn't being tweaked */ - return true; - } - else { - /* unsupported - this track is being tweaked */ - return false; - } - - /* unsupported */ - default: - return false; - } +static bool acf_nlatrack_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *ale, + eAnimChannel_Settings setting) +{ + NlaTrack *nlt = (NlaTrack *)ale->data; + AnimData *adt = ale->adt; + + /* visibility of settings depends on various states... */ + switch (setting) { + /* always supported */ + case ACHANNEL_SETTING_SELECT: + case ACHANNEL_SETTING_SOLO: + return true; + + /* conditionally supported... */ + case ACHANNEL_SETTING_PROTECT: + case ACHANNEL_SETTING_MUTE: + /* if this track is active and we're tweaking it, don't draw these toggles */ + if (((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0) { + /* is track enabled for solo drawing? */ + if ((adt) && (adt->flag & ADT_NLA_SOLO_TRACK)) { + if (nlt->flag & NLATRACK_SOLO) { + /* ok - we've got a solo track, and this is it */ + return true; + } + else { + /* not ok - we've got a solo track, but this isn't it, so make it more obvious */ + return false; + } + } + + /* ok - no tracks are solo'd, and this isn't being tweaked */ + return true; + } + else { + /* unsupported - this track is being tweaked */ + return false; + } + + /* unsupported */ + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_nlatrack_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_nlatrack_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_SELECT: /* selected */ - return NLATRACK_SELECTED; + switch (setting) { + case ACHANNEL_SETTING_SELECT: /* selected */ + return NLATRACK_SELECTED; - case ACHANNEL_SETTING_MUTE: /* muted */ - return NLATRACK_MUTED; + case ACHANNEL_SETTING_MUTE: /* muted */ + return NLATRACK_MUTED; - case ACHANNEL_SETTING_PROTECT: /* protected */ - return NLATRACK_PROTECTED; + case ACHANNEL_SETTING_PROTECT: /* protected */ + return NLATRACK_PROTECTED; - case ACHANNEL_SETTING_SOLO: /* solo */ - return NLATRACK_SOLO; + case ACHANNEL_SETTING_SOLO: /* solo */ + return NLATRACK_SOLO; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_nlatrack_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_nlatrack_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - NlaTrack *nlt = (NlaTrack *)ale->data; - return GET_ACF_FLAG_PTR(nlt->flag, type); + NlaTrack *nlt = (NlaTrack *)ale->data; + return GET_ACF_FLAG_PTR(nlt->flag, type); } /* nla track type define */ -static bAnimChannelType ACF_NLATRACK = -{ - "NLA Track", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_nlatrack_color, /* backdrop color */ - acf_generic_channel_backdrop, /* backdrop */ - acf_generic_indention_flexible, /* indent level */ - acf_generic_group_offset, /* offset */ // XXX? - - acf_nlatrack_name, /* name */ - acf_nlatrack_name_prop, /* name prop */ - NULL, /* icon */ - - acf_nlatrack_setting_valid, /* has setting */ - acf_nlatrack_setting_flag, /* flag for setting */ - acf_nlatrack_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_NLATRACK = { + "NLA Track", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_nlatrack_color, /* backdrop color */ + acf_generic_channel_backdrop, /* backdrop */ + acf_generic_indention_flexible, /* indent level */ + acf_generic_group_offset, + /* offset */ // XXX? + + acf_nlatrack_name, /* name */ + acf_nlatrack_name_prop, /* name prop */ + NULL, /* icon */ + + acf_nlatrack_setting_valid, /* has setting */ + acf_nlatrack_setting_flag, /* flag for setting */ + acf_nlatrack_setting_ptr, /* pointer for setting */ }; /* NLA Action ----------------------------------------------- */ @@ -3398,15 +3507,15 @@ static bAnimChannelType ACF_NLATRACK = /* icon for action depends on whether it's in tweaking mode */ static int acf_nlaaction_icon(bAnimListElem *ale) { - AnimData *adt = ale->adt; + AnimData *adt = ale->adt; - /* indicate tweaking-action state by changing the icon... */ - if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { - return ICON_ACTION_TWEAK; - } - else { - return ICON_ACTION; - } + /* indicate tweaking-action state by changing the icon... */ + if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { + return ICON_ACTION_TWEAK; + } + else { + return ICON_ACTION; + } } /* Backdrop color for nla action channel @@ -3415,151 +3524,162 @@ static int acf_nlaaction_icon(bAnimListElem *ale) */ static void acf_nlaaction_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, float r_color[3]) { - float color[4]; + float color[4]; - /* Action Line - * The alpha values action_get_color returns are only useful for drawing - * strips backgrounds but here we're doing channel list backgrounds instead - * so we ignore that and use our own when needed - */ - nla_action_get_color(ale->adt, (bAction *)ale->data, color); + /* Action Line + * The alpha values action_get_color returns are only useful for drawing + * strips backgrounds but here we're doing channel list backgrounds instead + * so we ignore that and use our own when needed + */ + nla_action_get_color(ale->adt, (bAction *)ale->data, color); - /* NOTE: since the return types only allow rgb, we cannot do the alpha-blending we'd - * like for the solo-drawing case. Hence, this method isn't actually used for drawing - * most of the channel... - */ - copy_v3_v3(r_color, color); + /* NOTE: since the return types only allow rgb, we cannot do the alpha-blending we'd + * like for the solo-drawing case. Hence, this method isn't actually used for drawing + * most of the channel... + */ + copy_v3_v3(r_color, color); } /* backdrop for nla action channel */ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - AnimData *adt = ale->adt; - short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - float color[4]; - - /* Action Line - * The alpha values action_get_color returns are only useful for drawing - * strips backgrounds but here we're doing channel list backgrounds instead - * so we ignore that and use our own when needed - */ - nla_action_get_color(adt, (bAction *)ale->data, color); - - if (adt && (adt->flag & ADT_NLA_EDIT_ON)) - color[3] = 1.0f; - else - color[3] = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; - - /* only on top left corner, to show that this channel sits on top of the preceding ones - * while still linking into the action line strip to the right - */ - UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT); - - /* draw slightly shifted up vertically to look like it has more separation from other channels, - * but we then need to slightly shorten it so that it doesn't look like it overlaps - */ - UI_draw_roundbox_4fv(true, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8, color); + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + AnimData *adt = ale->adt; + short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + float color[4]; + + /* Action Line + * The alpha values action_get_color returns are only useful for drawing + * strips backgrounds but here we're doing channel list backgrounds instead + * so we ignore that and use our own when needed + */ + nla_action_get_color(adt, (bAction *)ale->data, color); + + if (adt && (adt->flag & ADT_NLA_EDIT_ON)) + color[3] = 1.0f; + else + color[3] = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; + + /* only on top left corner, to show that this channel sits on top of the preceding ones + * while still linking into the action line strip to the right + */ + UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT); + + /* draw slightly shifted up vertically to look like it has more separation from other channels, + * but we then need to slightly shorten it so that it doesn't look like it overlaps + */ + UI_draw_roundbox_4fv(true, + offset, + yminc + NLACHANNEL_SKIP, + (float)v2d->cur.xmax, + ymaxc + NLACHANNEL_SKIP - 1, + 8, + color); } /* name for nla action entries */ static void acf_nlaaction_name(bAnimListElem *ale, char *name) { - bAction *act = (bAction *)ale->data; + bAction *act = (bAction *)ale->data; - if (name) { - if (act) { - // TODO: add special decoration when doing this in tweaking mode? - BLI_strncpy(name, act->id.name + 2, ANIM_CHAN_NAME_SIZE); - } - else { - BLI_strncpy(name, "", ANIM_CHAN_NAME_SIZE); - } - } + if (name) { + if (act) { + // TODO: add special decoration when doing this in tweaking mode? + BLI_strncpy(name, act->id.name + 2, ANIM_CHAN_NAME_SIZE); + } + else { + BLI_strncpy(name, "", ANIM_CHAN_NAME_SIZE); + } + } } /* name property for nla action entries */ static bool acf_nlaaction_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop) { - if (ale->data) { - RNA_pointer_create(ale->id, &RNA_Action, ale->data, ptr); - *prop = RNA_struct_name_property(ptr->type); + if (ale->data) { + RNA_pointer_create(ale->id, &RNA_Action, ale->data, ptr); + *prop = RNA_struct_name_property(ptr->type); - return (*prop != NULL); - } + return (*prop != NULL); + } - return false; + return false; } /* check if some setting exists for this channel */ -static bool acf_nlaaction_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *ale, eAnimChannel_Settings setting) -{ - AnimData *adt = ale->adt; - - /* visibility of settings depends on various states... */ - switch (setting) { - /* conditionally supported */ - case ACHANNEL_SETTING_PINNED: /* pinned - map/unmap */ - if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { - /* this should only appear in tweakmode */ - return true; - } - else { - return false; - } - - /* unsupported */ - default: - return false; - } +static bool acf_nlaaction_setting_valid(bAnimContext *UNUSED(ac), + bAnimListElem *ale, + eAnimChannel_Settings setting) +{ + AnimData *adt = ale->adt; + + /* visibility of settings depends on various states... */ + switch (setting) { + /* conditionally supported */ + case ACHANNEL_SETTING_PINNED: /* pinned - map/unmap */ + if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { + /* this should only appear in tweakmode */ + return true; + } + else { + return false; + } + + /* unsupported */ + default: + return false; + } } /* get the appropriate flag(s) for the setting when it is valid */ -static int acf_nlaaction_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings setting, bool *neg) +static int acf_nlaaction_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) { - /* clear extra return data first */ - *neg = false; + /* clear extra return data first */ + *neg = false; - switch (setting) { - case ACHANNEL_SETTING_PINNED: /* pinned - map/unmap */ - *neg = true; // XXX - return ADT_NLA_EDIT_NOMAP; + switch (setting) { + case ACHANNEL_SETTING_PINNED: /* pinned - map/unmap */ + *neg = true; // XXX + return ADT_NLA_EDIT_NOMAP; - default: /* unsupported */ - return 0; - } + default: /* unsupported */ + return 0; + } } /* get pointer to the setting */ -static void *acf_nlaaction_setting_ptr(bAnimListElem *ale, eAnimChannel_Settings UNUSED(setting), short *type) +static void *acf_nlaaction_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings UNUSED(setting), + short *type) { - AnimData *adt = ale->adt; - return GET_ACF_FLAG_PTR(adt->flag, type); + AnimData *adt = ale->adt; + return GET_ACF_FLAG_PTR(adt->flag, type); } /* nla action type define */ -static bAnimChannelType ACF_NLAACTION = -{ - "NLA Active Action", /* type name */ - ACHANNEL_ROLE_CHANNEL, /* role */ - - acf_nlaaction_color, /* backdrop color (NOTE: the backdrop handles this too, - * since it needs special hacks) */ - acf_nlaaction_backdrop, /* backdrop */ - acf_generic_indention_flexible, /* indent level */ - acf_generic_group_offset, /* offset */ // XXX? - - acf_nlaaction_name, /* name */ - acf_nlaaction_name_prop, /* name prop */ - acf_nlaaction_icon, /* icon */ - - acf_nlaaction_setting_valid, /* has setting */ - acf_nlaaction_setting_flag, /* flag for setting */ - acf_nlaaction_setting_ptr, /* pointer for setting */ +static bAnimChannelType ACF_NLAACTION = { + "NLA Active Action", /* type name */ + ACHANNEL_ROLE_CHANNEL, /* role */ + + acf_nlaaction_color, /* backdrop color (NOTE: the backdrop handles this too, + * since it needs special hacks) */ + acf_nlaaction_backdrop, /* backdrop */ + acf_generic_indention_flexible, /* indent level */ + acf_generic_group_offset, + /* offset */ // XXX? + + acf_nlaaction_name, /* name */ + acf_nlaaction_name_prop, /* name prop */ + acf_nlaaction_icon, /* icon */ + + acf_nlaaction_setting_valid, /* has setting */ + acf_nlaaction_setting_flag, /* flag for setting */ + acf_nlaaction_setting_ptr, /* pointer for setting */ }; - /* *********************************************** */ /* Type Registration and General Access */ @@ -3570,79 +3690,79 @@ static short ACF_INIT = 1; /* when non-zero, the list needs to be updated */ /* Initialize type info definitions */ static void ANIM_init_channel_typeinfo_data(void) { - int type = 0; + int type = 0; - /* start initializing if necessary... */ - if (ACF_INIT) { - ACF_INIT = 0; + /* start initializing if necessary... */ + if (ACF_INIT) { + ACF_INIT = 0; - /* NOTE: need to keep the order of these synchronized with the definition of - * channel types (eAnim_ChannelType) in ED_anim_api.h - */ - animchannelTypeInfo[type++] = NULL; /* None */ - animchannelTypeInfo[type++] = NULL; /* AnimData */ - animchannelTypeInfo[type++] = NULL; /* Special */ + /* NOTE: need to keep the order of these synchronized with the definition of + * channel types (eAnim_ChannelType) in ED_anim_api.h + */ + animchannelTypeInfo[type++] = NULL; /* None */ + animchannelTypeInfo[type++] = NULL; /* AnimData */ + animchannelTypeInfo[type++] = NULL; /* Special */ - animchannelTypeInfo[type++] = &ACF_SUMMARY; /* Motion Summary */ + animchannelTypeInfo[type++] = &ACF_SUMMARY; /* Motion Summary */ - animchannelTypeInfo[type++] = &ACF_SCENE; /* Scene */ - animchannelTypeInfo[type++] = &ACF_OBJECT; /* Object */ - animchannelTypeInfo[type++] = &ACF_GROUP; /* Group */ - animchannelTypeInfo[type++] = &ACF_FCURVE; /* F-Curve */ + animchannelTypeInfo[type++] = &ACF_SCENE; /* Scene */ + animchannelTypeInfo[type++] = &ACF_OBJECT; /* Object */ + animchannelTypeInfo[type++] = &ACF_GROUP; /* Group */ + animchannelTypeInfo[type++] = &ACF_FCURVE; /* F-Curve */ - animchannelTypeInfo[type++] = &ACF_NLACONTROLS; /* NLA Control FCurve Expander */ - animchannelTypeInfo[type++] = &ACF_NLACURVE; /* NLA Control FCurve Channel */ + animchannelTypeInfo[type++] = &ACF_NLACONTROLS; /* NLA Control FCurve Expander */ + animchannelTypeInfo[type++] = &ACF_NLACURVE; /* NLA Control FCurve Channel */ - animchannelTypeInfo[type++] = &ACF_FILLACTD; /* Object Action Expander */ - animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */ + animchannelTypeInfo[type++] = &ACF_FILLACTD; /* Object Action Expander */ + animchannelTypeInfo[type++] = &ACF_FILLDRIVERS; /* Drivers Expander */ - animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */ - animchannelTypeInfo[type++] = &ACF_DSLIGHT; /* Light Channel */ - animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */ - animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */ - animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */ - animchannelTypeInfo[type++] = &ACF_DSSKEY; /* ShapeKey Channel */ - animchannelTypeInfo[type++] = &ACF_DSWOR; /* World Channel */ - animchannelTypeInfo[type++] = &ACF_DSNTREE; /* NodeTree Channel */ - animchannelTypeInfo[type++] = &ACF_DSPART; /* Particle Channel */ - animchannelTypeInfo[type++] = &ACF_DSMBALL; /* MetaBall Channel */ - animchannelTypeInfo[type++] = &ACF_DSARM; /* Armature Channel */ - animchannelTypeInfo[type++] = &ACF_DSMESH; /* Mesh Channel */ - animchannelTypeInfo[type++] = &ACF_DSTEX; /* Texture Channel */ - animchannelTypeInfo[type++] = &ACF_DSLAT; /* Lattice Channel */ - animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */ - animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */ - animchannelTypeInfo[type++] = &ACF_DSGPENCIL; /* GreasePencil Channel */ - animchannelTypeInfo[type++] = &ACF_DSMCLIP; /* MovieClip Channel */ + animchannelTypeInfo[type++] = &ACF_DSMAT; /* Material Channel */ + animchannelTypeInfo[type++] = &ACF_DSLIGHT; /* Light Channel */ + animchannelTypeInfo[type++] = &ACF_DSCAM; /* Camera Channel */ + animchannelTypeInfo[type++] = &ACF_DSCACHEFILE; /* CacheFile Channel */ + animchannelTypeInfo[type++] = &ACF_DSCUR; /* Curve Channel */ + animchannelTypeInfo[type++] = &ACF_DSSKEY; /* ShapeKey Channel */ + animchannelTypeInfo[type++] = &ACF_DSWOR; /* World Channel */ + animchannelTypeInfo[type++] = &ACF_DSNTREE; /* NodeTree Channel */ + animchannelTypeInfo[type++] = &ACF_DSPART; /* Particle Channel */ + animchannelTypeInfo[type++] = &ACF_DSMBALL; /* MetaBall Channel */ + animchannelTypeInfo[type++] = &ACF_DSARM; /* Armature Channel */ + animchannelTypeInfo[type++] = &ACF_DSMESH; /* Mesh Channel */ + animchannelTypeInfo[type++] = &ACF_DSTEX; /* Texture Channel */ + animchannelTypeInfo[type++] = &ACF_DSLAT; /* Lattice Channel */ + animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */ + animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */ + animchannelTypeInfo[type++] = &ACF_DSGPENCIL; /* GreasePencil Channel */ + animchannelTypeInfo[type++] = &ACF_DSMCLIP; /* MovieClip Channel */ - animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */ + animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */ - animchannelTypeInfo[type++] = &ACF_GPD; /* Grease Pencil Datablock */ - animchannelTypeInfo[type++] = &ACF_GPL; /* Grease Pencil Layer */ + animchannelTypeInfo[type++] = &ACF_GPD; /* Grease Pencil Datablock */ + animchannelTypeInfo[type++] = &ACF_GPL; /* Grease Pencil Layer */ - animchannelTypeInfo[type++] = &ACF_MASKDATA; /* Mask Datablock */ - animchannelTypeInfo[type++] = &ACF_MASKLAYER; /* Mask Layer */ + animchannelTypeInfo[type++] = &ACF_MASKDATA; /* Mask Datablock */ + animchannelTypeInfo[type++] = &ACF_MASKLAYER; /* Mask Layer */ - animchannelTypeInfo[type++] = &ACF_NLATRACK; /* NLA Track */ - animchannelTypeInfo[type++] = &ACF_NLAACTION; /* NLA Action */ - } + animchannelTypeInfo[type++] = &ACF_NLATRACK; /* NLA Track */ + animchannelTypeInfo[type++] = &ACF_NLAACTION; /* NLA Action */ + } } /* Get type info from given channel type */ const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale) { - /* santiy checks */ - if (ale == NULL) - return NULL; + /* santiy checks */ + if (ale == NULL) + return NULL; - /* init the typeinfo if not available yet... */ - ANIM_init_channel_typeinfo_data(); + /* init the typeinfo if not available yet... */ + ANIM_init_channel_typeinfo_data(); - /* check if type is in bounds... */ - if ((ale->type >= 0) && (ale->type < ANIMTYPE_NUM_TYPES)) - return animchannelTypeInfo[ale->type]; - else - return NULL; + /* check if type is in bounds... */ + if ((ale->type >= 0) && (ale->type < ANIMTYPE_NUM_TYPES)) + return animchannelTypeInfo[ale->type]; + else + return NULL; } /* --------------------------- */ @@ -3650,29 +3770,29 @@ const bAnimChannelType *ANIM_channel_get_typeinfo(bAnimListElem *ale) /* Print debug info string for the given channel */ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - /* print indents */ - for (; indent_level > 0; indent_level--) - printf(" "); + /* print indents */ + for (; indent_level > 0; indent_level--) + printf(" "); - /* print info */ - if (acf) { - char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */ + /* print info */ + if (acf) { + char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */ - /* get UI name */ - if (acf->name) - acf->name(ale, name); - else - BLI_strncpy(name, "", sizeof(name)); + /* get UI name */ + if (acf->name) + acf->name(ale, name); + else + BLI_strncpy(name, "", sizeof(name)); - /* print type name + ui name */ - printf("ChanType: <%s> Name: \"%s\"\n", acf->channel_type_name, name); - } - else if (ale) - printf("ChanType: \n", ale->type); - else - printf("\n"); + /* print type name + ui name */ + printf("ChanType: <%s> Name: \"%s\"\n", acf->channel_type_name, name); + } + else if (ale) + printf("ChanType: \n", ale->type); + else + printf("\n"); } /* --------------------------- */ @@ -3682,361 +3802,374 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level) */ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - - /* 1) check that the setting exists for the current context */ - if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) { - /* 2) get pointer to check for flag in, and the flag to check for */ - short ptrsize; - bool negflag; - int flag; - void *ptr; - - flag = acf->setting_flag(ac, setting, &negflag); - ptr = acf->setting_ptr(ale, setting, &ptrsize); - - /* check if flag is enabled */ - if (ptr && flag) { - switch (ptrsize) { - case sizeof(int): /* integer pointer for setting */ - { - const int *val = (int *)ptr; - - if (negflag) - return ((*val) & flag) == 0; - else - return ((*val) & flag) != 0; - } - case sizeof(short): /* short pointer for setting */ - { - const short *val = (short *)ptr; - - if (negflag) - return ((*val) & flag) == 0; - else - return ((*val) & flag) != 0; - } - case sizeof(char): /* char pointer for setting */ - { - const char *val = (char *)ptr; - - if (negflag) - return ((*val) & flag) == 0; - else - return ((*val) & flag) != 0; - } - } - } - } - - /* not found... */ - return -1; + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + + /* 1) check that the setting exists for the current context */ + if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) { + /* 2) get pointer to check for flag in, and the flag to check for */ + short ptrsize; + bool negflag; + int flag; + void *ptr; + + flag = acf->setting_flag(ac, setting, &negflag); + ptr = acf->setting_ptr(ale, setting, &ptrsize); + + /* check if flag is enabled */ + if (ptr && flag) { + switch (ptrsize) { + case sizeof(int): /* integer pointer for setting */ + { + const int *val = (int *)ptr; + + if (negflag) + return ((*val) & flag) == 0; + else + return ((*val) & flag) != 0; + } + case sizeof(short): /* short pointer for setting */ + { + const short *val = (short *)ptr; + + if (negflag) + return ((*val) & flag) == 0; + else + return ((*val) & flag) != 0; + } + case sizeof(char): /* char pointer for setting */ + { + const char *val = (char *)ptr; + + if (negflag) + return ((*val) & flag) == 0; + else + return ((*val) & flag) != 0; + } + } + } + } + + /* not found... */ + return -1; } - /* quick macro for use in ANIM_channel_setting_set - set flag for setting according the mode given */ #define ACF_SETTING_SET(sval, sflag, smode) \ - { \ - if (negflag) { \ - if (smode == ACHANNEL_SETFLAG_INVERT) (sval) ^= (sflag); \ - else if (smode == ACHANNEL_SETFLAG_ADD) (sval) &= ~(sflag); \ - else (sval) |= (sflag); \ - } \ - else { \ - if (smode == ACHANNEL_SETFLAG_INVERT) (sval) ^= (sflag); \ - else if (smode == ACHANNEL_SETFLAG_ADD) (sval) |= (sflag); \ - else (sval) &= ~(sflag); \ - } \ - } (void)0 + { \ + if (negflag) { \ + if (smode == ACHANNEL_SETFLAG_INVERT) \ + (sval) ^= (sflag); \ + else if (smode == ACHANNEL_SETFLAG_ADD) \ + (sval) &= ~(sflag); \ + else \ + (sval) |= (sflag); \ + } \ + else { \ + if (smode == ACHANNEL_SETFLAG_INVERT) \ + (sval) ^= (sflag); \ + else if (smode == ACHANNEL_SETFLAG_ADD) \ + (sval) |= (sflag); \ + else \ + (sval) &= ~(sflag); \ + } \ + } \ + (void)0 /* Change value of some setting for a channel * - setting: eAnimChannel_Settings * - mode: eAnimChannels_SetFlag */ -void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode) -{ - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - - /* 1) check that the setting exists for the current context */ - if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) { - /* 2) get pointer to check for flag in, and the flag to check for */ - short ptrsize; - bool negflag; - int flag; - void *ptr; - - flag = acf->setting_flag(ac, setting, &negflag); - ptr = acf->setting_ptr(ale, setting, &ptrsize); - - /* check if flag is enabled */ - if (ptr && flag) { - switch (ptrsize) { - case sizeof(int): /* integer pointer for setting */ - { - int *val = (int *)ptr; - ACF_SETTING_SET(*val, flag, mode); - break; - } - case sizeof(short): /* short pointer for setting */ - { - short *val = (short *)ptr; - ACF_SETTING_SET(*val, flag, mode); - break; - } - case sizeof(char): /* char pointer for setting */ - { - char *val = (char *)ptr; - ACF_SETTING_SET(*val, flag, mode); - break; - } - } - } - } +void ANIM_channel_setting_set(bAnimContext *ac, + bAnimListElem *ale, + eAnimChannel_Settings setting, + eAnimChannels_SetFlag mode) +{ + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + + /* 1) check that the setting exists for the current context */ + if ((acf) && (!acf->has_setting || acf->has_setting(ac, ale, setting))) { + /* 2) get pointer to check for flag in, and the flag to check for */ + short ptrsize; + bool negflag; + int flag; + void *ptr; + + flag = acf->setting_flag(ac, setting, &negflag); + ptr = acf->setting_ptr(ale, setting, &ptrsize); + + /* check if flag is enabled */ + if (ptr && flag) { + switch (ptrsize) { + case sizeof(int): /* integer pointer for setting */ + { + int *val = (int *)ptr; + ACF_SETTING_SET(*val, flag, mode); + break; + } + case sizeof(short): /* short pointer for setting */ + { + short *val = (short *)ptr; + ACF_SETTING_SET(*val, flag, mode); + break; + } + case sizeof(char): /* char pointer for setting */ + { + char *val = (char *)ptr; + ACF_SETTING_SET(*val, flag, mode); + break; + } + } + } + } } /* --------------------------- */ // size of icons -#define ICON_WIDTH (0.85f * U.widget_unit) +#define ICON_WIDTH (0.85f * U.widget_unit) // width of sliders -#define SLIDER_WIDTH (4 * U.widget_unit) +#define SLIDER_WIDTH (4 * U.widget_unit) // min-width of rename textboxes #define RENAME_TEXT_MIN_WIDTH (U.widget_unit) - /* Helper - Check if a channel needs renaming */ -static bool achannel_is_being_renamed(const bAnimContext *ac, const bAnimChannelType *acf, size_t channel_index) +static bool achannel_is_being_renamed(const bAnimContext *ac, + const bAnimChannelType *acf, + size_t channel_index) { - if (acf->name_prop && ac->ads) { - /* if rename index matches, this channel is being renamed */ - if (ac->ads->renameIndex == channel_index + 1) { - return true; - } - } + if (acf->name_prop && ac->ads) { + /* if rename index matches, this channel is being renamed */ + if (ac->ads->renameIndex == channel_index + 1) { + return true; + } + } - /* not being renamed */ - return false; + /* not being renamed */ + return false; } - /* Draw the given channel */ -void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index) -{ - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - short selected, offset; - float y, ymid, ytext; - - /* sanity checks - don't draw anything */ - if (ELEM(NULL, acf, ale)) - return; - - /* get initial offset */ - if (acf->get_offset) - offset = acf->get_offset(ac, ale); - else - offset = 0; - - /* calculate appropriate y-coordinates for icon buttons */ - y = (ymaxc - yminc) / 2 + yminc; - ymid = y - 0.5f * ICON_WIDTH; - /* y-coordinates for text is only 4 down from middle */ - ytext = y - 0.2f * U.widget_unit; - - /* check if channel is selected */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) - selected = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); - else - selected = 0; - - /* set blending again, as may not be set in previous step */ - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPU_blend(true); - - /* step 1) draw backdrop ........................................... */ - if (acf->draw_backdrop) - acf->draw_backdrop(ac, ale, yminc, ymaxc); - - /* step 2) draw expand widget ....................................... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_EXPAND)) { - /* just skip - drawn as widget now */ - offset += ICON_WIDTH; - } - - /* step 3) draw icon ............................................... */ - if (acf->icon) { - UI_icon_draw(offset, ymid, acf->icon(ale)); - offset += ICON_WIDTH; - } - - /* turn off blending, since not needed anymore... */ - GPU_blend(false); - - /* step 4) draw special toggles ................................. - * - in Graph Editor, checkboxes for visibility in curves area - * - in NLA Editor, glowing dots for solo/not solo... - * - in Grease Pencil mode, color swatches for layer color - */ - if (ac->sl) { - if ((ac->spacetype == SPACE_GRAPH) && - (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) || - acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) - { - /* for F-Curves, draw color-preview of curve behind checkbox */ - if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { - FCurve *fcu = (FCurve *)ale->data; - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - /* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever - * color the curve has stored - */ - immUniformColor3fv(fcu->color); - - /* just a solid color rect - */ - immRectf(pos, offset, yminc, offset + ICON_WIDTH, ymaxc); - - immUnbindProgram(); - } - /* icon is drawn as widget now... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { - offset += ICON_WIDTH; - } - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) { - offset += ICON_WIDTH; - } - } - else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) { - /* just skip - drawn as widget now */ - offset += ICON_WIDTH; - } - else if (ale->type == ANIMTYPE_GPLAYER) { - /* just skip - drawn as a widget */ - offset += ICON_WIDTH; - } - } - - /* step 5) draw name ............................................... */ - /* Don't draw this if renaming... */ - if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) { - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */ - unsigned char col[4]; - - /* set text color */ - /* XXX: if active, highlight differently? */ - - if (selected) - UI_GetThemeColor4ubv(TH_TEXT_HI, col); - else - UI_GetThemeColor4ubv(TH_TEXT, col); - - /* get name */ - acf->name(ale, name); - - offset += 3; - UI_fontstyle_draw_simple(fstyle, offset, ytext, name, col); - - /* draw red underline if channel is disabled */ - if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) { - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - /* FIXME: replace hardcoded color here, and check on extents! */ - immUniformColor3f(1.0f, 0.0f, 0.0f); - - GPU_line_width(2.0f); - - immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, (float)offset, yminc); - immVertex2f(pos, (float)v2d->cur.xmax, yminc); - immEnd(); - - immUnbindProgram(); - } - } - - /* step 6) draw backdrops behind mute+protection toggles + (sliders) ....................... */ - /* reset offset - now goes from RHS of panel */ - offset = 0; - - /* TODO: when drawing sliders, make those draw instead of these toggles if not enough space */ - - if (v2d) { - short draw_sliders = 0; - float ymin_ofs = 0.0f; - float color[3]; - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - /* get and set backdrop color */ - acf->get_backdrop_color(ac, ale, color); - immUniformColor3fv(color); - - /* check if we need to show the sliders */ - if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_GRAPH)) { - switch (ac->spacetype) { - case SPACE_ACTION: - { - SpaceAction *saction = (SpaceAction *)ac->sl; - draw_sliders = (saction->flag & SACTION_SLIDERS); - break; - } - case SPACE_GRAPH: - { - SpaceGraph *sipo = (SpaceGraph *)ac->sl; - draw_sliders = (sipo->flag & SIPO_SLIDERS); - break; - } - } - } - - /* check if there's enough space for the toggles if the sliders are drawn too */ - if (!(draw_sliders) || (BLI_rcti_size_x(&v2d->mask) > ACHANNEL_BUTTON_WIDTH / 2) ) { - /* protect... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) - offset += ICON_WIDTH; - - /* mute... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) - offset += ICON_WIDTH; - if (ale->type == ANIMTYPE_GPLAYER) - offset += ICON_WIDTH; - - /* pinned... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PINNED)) - offset += ICON_WIDTH; - - /* NOTE: technically, NLA Action "pushdown" should be here too, but there are no sliders there */ - - /* NLA action channels have slightly different spacing requirements... */ - if (ale->type == ANIMTYPE_NLAACTION) - ymin_ofs = NLACHANNEL_SKIP; - } - - /* draw slider - * - even if we can draw sliders for this view, we must also check that the channel-type supports them - * (only only F-Curves really can support them for now) - * - slider should start before the toggles (if they're visible) to keep a clean line down the side - */ - if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) { - /* adjust offset */ - offset += SLIDER_WIDTH; - } - - - /* finally draw a backdrop rect behind these - * - starts from the point where the first toggle/slider starts, - * - ends past the space that might be reserved for a scroller - */ - immRectf(pos, v2d->cur.xmax - (float)offset, yminc + ymin_ofs, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc); - - immUnbindProgram(); - } +void ANIM_channel_draw( + bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc, size_t channel_index) +{ + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + short selected, offset; + float y, ymid, ytext; + + /* sanity checks - don't draw anything */ + if (ELEM(NULL, acf, ale)) + return; + + /* get initial offset */ + if (acf->get_offset) + offset = acf->get_offset(ac, ale); + else + offset = 0; + + /* calculate appropriate y-coordinates for icon buttons */ + y = (ymaxc - yminc) / 2 + yminc; + ymid = y - 0.5f * ICON_WIDTH; + /* y-coordinates for text is only 4 down from middle */ + ytext = y - 0.2f * U.widget_unit; + + /* check if channel is selected */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) + selected = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); + else + selected = 0; + + /* set blending again, as may not be set in previous step */ + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + + /* step 1) draw backdrop ........................................... */ + if (acf->draw_backdrop) + acf->draw_backdrop(ac, ale, yminc, ymaxc); + + /* step 2) draw expand widget ....................................... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_EXPAND)) { + /* just skip - drawn as widget now */ + offset += ICON_WIDTH; + } + + /* step 3) draw icon ............................................... */ + if (acf->icon) { + UI_icon_draw(offset, ymid, acf->icon(ale)); + offset += ICON_WIDTH; + } + + /* turn off blending, since not needed anymore... */ + GPU_blend(false); + + /* step 4) draw special toggles ................................. + * - in Graph Editor, checkboxes for visibility in curves area + * - in NLA Editor, glowing dots for solo/not solo... + * - in Grease Pencil mode, color swatches for layer color + */ + if (ac->sl) { + if ((ac->spacetype == SPACE_GRAPH) && + (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) || + acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) { + /* for F-Curves, draw color-preview of curve behind checkbox */ + if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { + FCurve *fcu = (FCurve *)ale->data; + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* F-Curve channels need to have a special 'color code' box drawn, which is colored with whatever + * color the curve has stored + */ + immUniformColor3fv(fcu->color); + + /* just a solid color rect + */ + immRectf(pos, offset, yminc, offset + ICON_WIDTH, ymaxc); + + immUnbindProgram(); + } + /* icon is drawn as widget now... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { + offset += ICON_WIDTH; + } + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) { + offset += ICON_WIDTH; + } + } + else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) { + /* just skip - drawn as widget now */ + offset += ICON_WIDTH; + } + else if (ale->type == ANIMTYPE_GPLAYER) { + /* just skip - drawn as a widget */ + offset += ICON_WIDTH; + } + } + + /* step 5) draw name ............................................... */ + /* Don't draw this if renaming... */ + if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */ + unsigned char col[4]; + + /* set text color */ + /* XXX: if active, highlight differently? */ + + if (selected) + UI_GetThemeColor4ubv(TH_TEXT_HI, col); + else + UI_GetThemeColor4ubv(TH_TEXT, col); + + /* get name */ + acf->name(ale, name); + + offset += 3; + UI_fontstyle_draw_simple(fstyle, offset, ytext, name, col); + + /* draw red underline if channel is disabled */ + if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE) && (ale->flag & FCURVE_DISABLED)) { + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* FIXME: replace hardcoded color here, and check on extents! */ + immUniformColor3f(1.0f, 0.0f, 0.0f); + + GPU_line_width(2.0f); + + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, (float)offset, yminc); + immVertex2f(pos, (float)v2d->cur.xmax, yminc); + immEnd(); + + immUnbindProgram(); + } + } + + /* step 6) draw backdrops behind mute+protection toggles + (sliders) ....................... */ + /* reset offset - now goes from RHS of panel */ + offset = 0; + + /* TODO: when drawing sliders, make those draw instead of these toggles if not enough space */ + + if (v2d) { + short draw_sliders = 0; + float ymin_ofs = 0.0f; + float color[3]; + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* get and set backdrop color */ + acf->get_backdrop_color(ac, ale, color); + immUniformColor3fv(color); + + /* check if we need to show the sliders */ + if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_GRAPH)) { + switch (ac->spacetype) { + case SPACE_ACTION: { + SpaceAction *saction = (SpaceAction *)ac->sl; + draw_sliders = (saction->flag & SACTION_SLIDERS); + break; + } + case SPACE_GRAPH: { + SpaceGraph *sipo = (SpaceGraph *)ac->sl; + draw_sliders = (sipo->flag & SIPO_SLIDERS); + break; + } + } + } + + /* check if there's enough space for the toggles if the sliders are drawn too */ + if (!(draw_sliders) || (BLI_rcti_size_x(&v2d->mask) > ACHANNEL_BUTTON_WIDTH / 2)) { + /* protect... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) + offset += ICON_WIDTH; + + /* mute... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) + offset += ICON_WIDTH; + if (ale->type == ANIMTYPE_GPLAYER) + offset += ICON_WIDTH; + + /* pinned... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PINNED)) + offset += ICON_WIDTH; + + /* NOTE: technically, NLA Action "pushdown" should be here too, but there are no sliders there */ + + /* NLA action channels have slightly different spacing requirements... */ + if (ale->type == ANIMTYPE_NLAACTION) + ymin_ofs = NLACHANNEL_SKIP; + } + + /* draw slider + * - even if we can draw sliders for this view, we must also check that the channel-type supports them + * (only only F-Curves really can support them for now) + * - slider should start before the toggles (if they're visible) to keep a clean line down the side + */ + if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) { + /* adjust offset */ + offset += SLIDER_WIDTH; + } + + /* finally draw a backdrop rect behind these + * - starts from the point where the first toggle/slider starts, + * - ends past the space that might be reserved for a scroller + */ + immRectf(pos, + v2d->cur.xmax - (float)offset, + yminc + ymin_ofs, + v2d->cur.xmax + EXTRA_SCROLL_PAD, + ymaxc); + + immUnbindProgram(); + } } /* ------------------ */ @@ -4044,711 +4177,803 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float /* callback for (normal) widget settings - send notifiers */ static void achannel_setting_widget_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2)) { - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); } /* callback for widget settings that need flushing */ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void *setting_wrap) { - bAnimListElem *ale_setting = (bAnimListElem *)ale_npoin; - bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - int filter; - int setting = POINTER_AS_INT(setting_wrap); - short on = 0; + bAnimListElem *ale_setting = (bAnimListElem *)ale_npoin; + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + int filter; + int setting = POINTER_AS_INT(setting_wrap); + short on = 0; - /* send notifiers before doing anything else... */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* send notifiers before doing anything else... */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - /* verify that we have a channel to operate on. */ - if (!ale_setting) { - return; - } + /* verify that we have a channel to operate on. */ + if (!ale_setting) { + return; + } - if (ale_setting->type == ANIMTYPE_GPLAYER) { - /* draw cache updates for settings that affect the visible strokes */ - if (setting == ACHANNEL_SETTING_VISIBLE) { - bGPdata *gpd = (bGPdata *)ale_setting->id; - DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - } + if (ale_setting->type == ANIMTYPE_GPLAYER) { + /* draw cache updates for settings that affect the visible strokes */ + if (setting == ACHANNEL_SETTING_VISIBLE) { + bGPdata *gpd = (bGPdata *)ale_setting->id; + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + } - /* UI updates */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); - } + /* UI updates */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + } - /* Tag for full animation update, so that the settings will have an effect. */ - if (ale_setting->id) { - DEG_id_tag_update(ale_setting->id, ID_RECALC_ANIMATION); - } - if (ale_setting->adt && ale_setting->adt->action) { - /* Action is it's own datablock, so has to be tagged specifically. */ - DEG_id_tag_update(&ale_setting->adt->action->id, ID_RECALC_ANIMATION); - } + /* Tag for full animation update, so that the settings will have an effect. */ + if (ale_setting->id) { + DEG_id_tag_update(ale_setting->id, ID_RECALC_ANIMATION); + } + if (ale_setting->adt && ale_setting->adt->action) { + /* Action is it's own datablock, so has to be tagged specifically. */ + DEG_id_tag_update(&ale_setting->adt->action->id, ID_RECALC_ANIMATION); + } - /* verify animation context */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return; + /* verify animation context */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return; - /* check if the setting is on... */ - on = ANIM_channel_setting_get(&ac, ale_setting, setting); + /* check if the setting is on... */ + on = ANIM_channel_setting_get(&ac, ale_setting, setting); - /* on == -1 means setting not found... */ - if (on == -1) { - return; - } + /* on == -1 means setting not found... */ + if (on == -1) { + return; + } - /* 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); + /* 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 */ - ANIM_flush_setting_anim_channels(&ac, &anim_data, ale_setting, setting, on); + /* call API method to flush the setting */ + ANIM_flush_setting_anim_channels(&ac, &anim_data, ale_setting, setting, on); - /* free temp data */ - ANIM_animdata_freelist(&anim_data); + /* free temp data */ + ANIM_animdata_freelist(&anim_data); } /* callback for wrapping NLA Track "solo" toggle logic */ static void achannel_nlatrack_solo_widget_cb(bContext *C, void *ale_poin, void *UNUSED(arg2)) { - bAnimListElem *ale = ale_poin; - AnimData *adt = ale->adt; - NlaTrack *nlt = ale->data; + bAnimListElem *ale = ale_poin; + AnimData *adt = ale->adt; + NlaTrack *nlt = ale->data; - /* Toggle 'solo' mode. There are several complications here which need explaining: - * - The method call is needed to perform a few additional validation operations - * to ensure that the mode is applied properly - * - BUT, since the button already toggles the value, we need to un-toggle it - * before the API call gets to it, otherwise it will end up clearing the result - * again! - */ - nlt->flag ^= NLATRACK_SOLO; - BKE_nlatrack_solo_toggle(adt, nlt); + /* Toggle 'solo' mode. There are several complications here which need explaining: + * - The method call is needed to perform a few additional validation operations + * to ensure that the mode is applied properly + * - BUT, since the button already toggles the value, we need to un-toggle it + * before the API call gets to it, otherwise it will end up clearing the result + * again! + */ + nlt->flag ^= NLATRACK_SOLO; + BKE_nlatrack_solo_toggle(adt, nlt); - /* send notifiers */ - DEG_id_tag_update(ale->id, ID_RECALC_ANIMATION); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); + /* send notifiers */ + DEG_id_tag_update(ale->id, ID_RECALC_ANIMATION); + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL); } /* callback for widget sliders - insert keyframes */ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poin) { - ID *id = (ID *)id_poin; - AnimData *adt = BKE_animdata_from_id(id); - FCurve *fcu = (FCurve *)fcu_poin; + ID *id = (ID *)id_poin; + AnimData *adt = BKE_animdata_from_id(id); + FCurve *fcu = (FCurve *)fcu_poin; - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ReportList *reports = CTX_wm_reports(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - ListBase nla_cache = {NULL, NULL}; - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - short flag = 0; - bool done = false; - float cfra; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ReportList *reports = CTX_wm_reports(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + ListBase nla_cache = {NULL, NULL}; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + short flag = 0; + bool done = false; + float cfra; - /* Get RNA pointer */ - RNA_id_pointer_create(id, &id_ptr); + /* Get RNA pointer */ + RNA_id_pointer_create(id, &id_ptr); - /* Get NLA context for value remapping */ - NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(&nla_cache, depsgraph, &id_ptr, adt, (float)CFRA); + /* Get NLA context for value remapping */ + NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context( + &nla_cache, depsgraph, &id_ptr, adt, (float)CFRA); - /* get current frame and apply NLA-mapping to it (if applicable) */ - cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + /* get current frame and apply NLA-mapping to it (if applicable) */ + cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); - /* get flags for keyframing */ - flag = ANIM_get_keyframing_flags(scene, 1); + /* get flags for keyframing */ + flag = ANIM_get_keyframing_flags(scene, 1); - /* try to resolve the path stored in the F-Curve */ - if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { - /* set the special 'replace' flag if on a keyframe */ - if (fcurve_frame_has_keyframe(fcu, cfra, 0)) - flag |= INSERTKEY_REPLACE; + /* try to resolve the path stored in the F-Curve */ + if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { + /* set the special 'replace' flag if on a keyframe */ + if (fcurve_frame_has_keyframe(fcu, cfra, 0)) + flag |= INSERTKEY_REPLACE; - /* insert a keyframe for this F-Curve */ - done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, nla_context, flag); + /* insert a keyframe for this F-Curve */ + done = insert_keyframe_direct( + depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, nla_context, flag); - if (done) { - if (adt->action != NULL) { - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - DEG_id_tag_update(id, ID_RECALC_ANIMATION_NO_FLUSH); - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - } - } + if (done) { + if (adt->action != NULL) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + DEG_id_tag_update(id, ID_RECALC_ANIMATION_NO_FLUSH); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + } + } - BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); } /* callback for shapekey widget sliders - insert keyframes */ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, void *kb_poin) { - Main *bmain = CTX_data_main(C); - Key *key = (Key *)key_poin; - KeyBlock *kb = (KeyBlock *)kb_poin; - char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb); + Main *bmain = CTX_data_main(C); + Key *key = (Key *)key_poin; + KeyBlock *kb = (KeyBlock *)kb_poin; + char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ReportList *reports = CTX_wm_reports(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - ListBase nla_cache = {NULL, NULL}; - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - short flag = 0; - bool done = false; - float cfra; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ReportList *reports = CTX_wm_reports(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + ListBase nla_cache = {NULL, NULL}; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + short flag = 0; + bool done = false; + float cfra; - /* Get RNA pointer */ - RNA_id_pointer_create((ID *)key, &id_ptr); + /* Get RNA pointer */ + RNA_id_pointer_create((ID *)key, &id_ptr); - /* Get NLA context for value remapping */ - NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(&nla_cache, depsgraph, &id_ptr, key->adt, (float)CFRA); + /* Get NLA context for value remapping */ + NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context( + &nla_cache, depsgraph, &id_ptr, key->adt, (float)CFRA); - /* get current frame and apply NLA-mapping to it (if applicable) */ - cfra = BKE_nla_tweakedit_remap(key->adt, (float)CFRA, NLATIME_CONVERT_UNMAP); + /* get current frame and apply NLA-mapping to it (if applicable) */ + cfra = BKE_nla_tweakedit_remap(key->adt, (float)CFRA, NLATIME_CONVERT_UNMAP); - /* get flags for keyframing */ - flag = ANIM_get_keyframing_flags(scene, 1); + /* get flags for keyframing */ + flag = ANIM_get_keyframing_flags(scene, 1); - /* try to resolve the path stored in the F-Curve */ - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { - /* find or create new F-Curve */ - // XXX is the group name for this ok? - bAction *act = verify_adt_action(bmain, (ID *)key, 1); - FCurve *fcu = verify_fcurve(bmain, act, NULL, &ptr, rna_path, 0, 1); + /* try to resolve the path stored in the F-Curve */ + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { + /* find or create new F-Curve */ + // XXX is the group name for this ok? + bAction *act = verify_adt_action(bmain, (ID *)key, 1); + FCurve *fcu = verify_fcurve(bmain, act, NULL, &ptr, rna_path, 0, 1); - /* set the special 'replace' flag if on a keyframe */ - if (fcurve_frame_has_keyframe(fcu, cfra, 0)) - flag |= INSERTKEY_REPLACE; + /* set the special 'replace' flag if on a keyframe */ + if (fcurve_frame_has_keyframe(fcu, cfra, 0)) + flag |= INSERTKEY_REPLACE; - /* insert a keyframe for this F-Curve */ - done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, nla_context, flag); + /* insert a keyframe for this F-Curve */ + done = insert_keyframe_direct( + depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, nla_context, flag); - if (done) - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - } + if (done) + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + } - /* free the path */ - if (rna_path) - MEM_freeN(rna_path); + /* free the path */ + if (rna_path) + MEM_freeN(rna_path); - BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); } /* callback for NLA Control Curve widget sliders - insert keyframes */ -static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_poin), void *fcu_poin) +static void achannel_setting_slider_nla_curve_cb(bContext *C, + void *UNUSED(id_poin), + void *fcu_poin) { - /* ID *id = (ID *)id_poin; */ - FCurve *fcu = (FCurve *)fcu_poin; + /* ID *id = (ID *)id_poin; */ + FCurve *fcu = (FCurve *)fcu_poin; - PointerRNA ptr; - PropertyRNA *prop; - int index; + PointerRNA ptr; + PropertyRNA *prop; + int index; - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ReportList *reports = CTX_wm_reports(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - short flag = 0; - bool done = false; - float cfra; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ReportList *reports = CTX_wm_reports(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + short flag = 0; + bool done = false; + float cfra; - /* get current frame - *no* NLA mapping should be done */ - cfra = (float)CFRA; + /* get current frame - *no* NLA mapping should be done */ + cfra = (float)CFRA; - /* get flags for keyframing */ - flag = ANIM_get_keyframing_flags(scene, 1); + /* get flags for keyframing */ + flag = ANIM_get_keyframing_flags(scene, 1); - /* get pointer and property from the slider - this should all match up with the NlaStrip required... */ - UI_context_active_but_prop_get(C, &ptr, &prop, &index); + /* get pointer and property from the slider - this should all match up with the NlaStrip required... */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (fcu && prop) { - /* set the special 'replace' flag if on a keyframe */ - if (fcurve_frame_has_keyframe(fcu, cfra, 0)) - flag |= INSERTKEY_REPLACE; + if (fcu && prop) { + /* set the special 'replace' flag if on a keyframe */ + if (fcurve_frame_has_keyframe(fcu, cfra, 0)) + flag |= INSERTKEY_REPLACE; - /* insert a keyframe for this F-Curve */ - done = insert_keyframe_direct(depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, flag); + /* insert a keyframe for this F-Curve */ + done = insert_keyframe_direct( + depsgraph, reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, flag); - if (done) - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - } + if (done) + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + } } /* Draw a widget for some setting */ -static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAnimChannelType *acf, - uiBlock *block, int xpos, int ypos, int setting) -{ - short ptrsize, butType; - bool negflag; - bool usetoggle = true; - int flag, icon; - void *ptr; - const char *tooltip; - uiBut *but = NULL; - bool enabled; - - /* get the flag and the pointer to that flag */ - flag = acf->setting_flag(ac, setting, &negflag); - ptr = acf->setting_ptr(ale, setting, &ptrsize); - enabled = ANIM_channel_setting_get(ac, ale, setting); - - /* get the base icon for the setting */ - switch (setting) { - case ACHANNEL_SETTING_VISIBLE: /* visibility eyes */ - //icon = ((enabled) ? ICON_VISIBLE_IPO_ON : ICON_VISIBLE_IPO_OFF); - icon = ICON_VISIBLE_IPO_OFF; - - if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) - tooltip = TIP_("F-Curve is visible in Graph Editor for editing"); - else if (ale->type == ANIMTYPE_GPLAYER) - tooltip = TIP_("Grease Pencil layer is visible in the viewport"); - else - tooltip = TIP_("Channels are visible in Graph Editor for editing"); - break; - - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - icon = ICON_UNPINNED; - tooltip = TIP_("Channels are visible in Graph Editor for editing"); - break; - - case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */ - icon = ICON_MODIFIER_OFF; - tooltip = TIP_("F-Curve modifiers are disabled"); - break; - - case ACHANNEL_SETTING_EXPAND: /* expanded triangle */ - //icon = ((enabled) ? ICON_TRIA_DOWN : ICON_TRIA_RIGHT); - icon = ICON_TRIA_RIGHT; - tooltip = TIP_("Make channels grouped under this channel visible"); - break; - - case ACHANNEL_SETTING_SOLO: /* NLA Tracks only */ - //icon = ((enabled) ? ICON_SOLO_OFF : ICON_SOLO_ON); - icon = ICON_SOLO_OFF; - tooltip = TIP_("NLA Track is the only one evaluated in this animation data-block, with all others muted"); - break; - - /* --- */ - - case ACHANNEL_SETTING_PROTECT: /* protected lock */ - // TODO: what about when there's no protect needed? - //icon = ((enabled) ? ICON_LOCKED : ICON_UNLOCKED); - icon = ICON_UNLOCKED; - - if (ale->datatype != ALE_NLASTRIP) - tooltip = TIP_("Editability of keyframes for this channel"); - else - tooltip = TIP_("Editability of NLA Strips in this track"); - break; - - case ACHANNEL_SETTING_MUTE: /* muted speaker */ - icon = ((enabled) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT); - usetoggle = false; - - if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { - tooltip = TIP_("Does F-Curve contribute to result"); - } - else if ((ac) && (ac->spacetype == SPACE_NLA) && (ale->type != ANIMTYPE_NLATRACK)) { - tooltip = TIP_("Temporarily disable NLA stack evaluation (i.e. only the active action is evaluated)"); - } - else if (ale->type == ANIMTYPE_GPLAYER) { - tooltip = TIP_("Lock current frame displayed by layer (i.e. disable animation playback)"); - } - else { - tooltip = TIP_("Do channels contribute to result (toggle channel muting)"); - } - break; - - case ACHANNEL_SETTING_PINNED: /* pin icon */ - //icon = ((enabled) ? ICON_PINNED : ICON_UNPINNED); - icon = ICON_UNPINNED; - - if (ale->type == ANIMTYPE_NLAACTION) { - tooltip = TIP_("Display action without any time remapping (when unpinned)"); - } - else { - /* TODO: there are no other tools which require the 'pinning' concept yet */ - tooltip = NULL; - } - break; - - default: - tooltip = NULL; - icon = 0; - break; - } - - /* type of button */ - if (usetoggle) { - if (negflag) - butType = UI_BTYPE_ICON_TOGGLE_N; - else - butType = UI_BTYPE_ICON_TOGGLE; - } - else { - if (negflag) - butType = UI_BTYPE_TOGGLE_N; - else - butType = UI_BTYPE_TOGGLE; - } - /* draw button for setting */ - if (ptr && flag) { - switch (ptrsize) { - case sizeof(int): /* integer pointer for setting */ - but = uiDefIconButBitI(block, butType, flag, 0, icon, - xpos, ypos, ICON_WIDTH, ICON_WIDTH, ptr, 0, 0, 0, 0, tooltip); - break; - - case sizeof(short): /* short pointer for setting */ - but = uiDefIconButBitS(block, butType, flag, 0, icon, - xpos, ypos, ICON_WIDTH, ICON_WIDTH, ptr, 0, 0, 0, 0, tooltip); - break; - - case sizeof(char): /* char pointer for setting */ - but = uiDefIconButBitC(block, butType, flag, 0, icon, - xpos, ypos, ICON_WIDTH, ICON_WIDTH, ptr, 0, 0, 0, 0, tooltip); - break; - } - - /* set call to send relevant notifiers and/or perform type-specific updates */ - if (but) { - switch (setting) { - /* settings needing flushing up/down hierarchy */ - case ACHANNEL_SETTING_VISIBLE: /* Graph Editor - 'visibility' toggles */ - case ACHANNEL_SETTING_PROTECT: /* General - protection flags */ - case ACHANNEL_SETTING_MUTE: /* General - muting flags */ - case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */ - case ACHANNEL_SETTING_MOD_OFF: - case ACHANNEL_SETTING_ALWAYS_VISIBLE: - UI_but_funcN_set(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), POINTER_FROM_INT(setting)); - break; - - /* settings needing special attention */ - case ACHANNEL_SETTING_SOLO: /* NLA Tracks - Solo toggle */ - UI_but_funcN_set(but, achannel_nlatrack_solo_widget_cb, MEM_dupallocN(ale), NULL); - break; - - /* no flushing */ - case ACHANNEL_SETTING_EXPAND: /* expanding - cannot flush, - * otherwise all would open/close at once */ - default: - UI_but_func_set(but, achannel_setting_widget_cb, NULL, NULL); - break; - } - } - } - - if ((ale->fcurve_owner_id != NULL && ID_IS_LINKED(ale->fcurve_owner_id)) || - (ale->id != NULL && ID_IS_LINKED(ale->id))) - { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } +static void draw_setting_widget(bAnimContext *ac, + bAnimListElem *ale, + const bAnimChannelType *acf, + uiBlock *block, + int xpos, + int ypos, + int setting) +{ + short ptrsize, butType; + bool negflag; + bool usetoggle = true; + int flag, icon; + void *ptr; + const char *tooltip; + uiBut *but = NULL; + bool enabled; + + /* get the flag and the pointer to that flag */ + flag = acf->setting_flag(ac, setting, &negflag); + ptr = acf->setting_ptr(ale, setting, &ptrsize); + enabled = ANIM_channel_setting_get(ac, ale, setting); + + /* get the base icon for the setting */ + switch (setting) { + case ACHANNEL_SETTING_VISIBLE: /* visibility eyes */ + //icon = ((enabled) ? ICON_VISIBLE_IPO_ON : ICON_VISIBLE_IPO_OFF); + icon = ICON_VISIBLE_IPO_OFF; + + if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) + tooltip = TIP_("F-Curve is visible in Graph Editor for editing"); + else if (ale->type == ANIMTYPE_GPLAYER) + tooltip = TIP_("Grease Pencil layer is visible in the viewport"); + else + tooltip = TIP_("Channels are visible in Graph Editor for editing"); + break; + + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + icon = ICON_UNPINNED; + tooltip = TIP_("Channels are visible in Graph Editor for editing"); + break; + + case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */ + icon = ICON_MODIFIER_OFF; + tooltip = TIP_("F-Curve modifiers are disabled"); + break; + + case ACHANNEL_SETTING_EXPAND: /* expanded triangle */ + //icon = ((enabled) ? ICON_TRIA_DOWN : ICON_TRIA_RIGHT); + icon = ICON_TRIA_RIGHT; + tooltip = TIP_("Make channels grouped under this channel visible"); + break; + + case ACHANNEL_SETTING_SOLO: /* NLA Tracks only */ + //icon = ((enabled) ? ICON_SOLO_OFF : ICON_SOLO_ON); + icon = ICON_SOLO_OFF; + tooltip = TIP_( + "NLA Track is the only one evaluated in this animation data-block, with all others " + "muted"); + break; + + /* --- */ + + case ACHANNEL_SETTING_PROTECT: /* protected lock */ + // TODO: what about when there's no protect needed? + //icon = ((enabled) ? ICON_LOCKED : ICON_UNLOCKED); + icon = ICON_UNLOCKED; + + if (ale->datatype != ALE_NLASTRIP) + tooltip = TIP_("Editability of keyframes for this channel"); + else + tooltip = TIP_("Editability of NLA Strips in this track"); + break; + + case ACHANNEL_SETTING_MUTE: /* muted speaker */ + icon = ((enabled) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT); + usetoggle = false; + + if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) { + tooltip = TIP_("Does F-Curve contribute to result"); + } + else if ((ac) && (ac->spacetype == SPACE_NLA) && (ale->type != ANIMTYPE_NLATRACK)) { + tooltip = TIP_( + "Temporarily disable NLA stack evaluation (i.e. only the active action is evaluated)"); + } + else if (ale->type == ANIMTYPE_GPLAYER) { + tooltip = TIP_("Lock current frame displayed by layer (i.e. disable animation playback)"); + } + else { + tooltip = TIP_("Do channels contribute to result (toggle channel muting)"); + } + break; + + case ACHANNEL_SETTING_PINNED: /* pin icon */ + //icon = ((enabled) ? ICON_PINNED : ICON_UNPINNED); + icon = ICON_UNPINNED; + + if (ale->type == ANIMTYPE_NLAACTION) { + tooltip = TIP_("Display action without any time remapping (when unpinned)"); + } + else { + /* TODO: there are no other tools which require the 'pinning' concept yet */ + tooltip = NULL; + } + break; + + default: + tooltip = NULL; + icon = 0; + break; + } + + /* type of button */ + if (usetoggle) { + if (negflag) + butType = UI_BTYPE_ICON_TOGGLE_N; + else + butType = UI_BTYPE_ICON_TOGGLE; + } + else { + if (negflag) + butType = UI_BTYPE_TOGGLE_N; + else + butType = UI_BTYPE_TOGGLE; + } + /* draw button for setting */ + if (ptr && flag) { + switch (ptrsize) { + case sizeof(int): /* integer pointer for setting */ + but = uiDefIconButBitI(block, + butType, + flag, + 0, + icon, + xpos, + ypos, + ICON_WIDTH, + ICON_WIDTH, + ptr, + 0, + 0, + 0, + 0, + tooltip); + break; + + case sizeof(short): /* short pointer for setting */ + but = uiDefIconButBitS(block, + butType, + flag, + 0, + icon, + xpos, + ypos, + ICON_WIDTH, + ICON_WIDTH, + ptr, + 0, + 0, + 0, + 0, + tooltip); + break; + + case sizeof(char): /* char pointer for setting */ + but = uiDefIconButBitC(block, + butType, + flag, + 0, + icon, + xpos, + ypos, + ICON_WIDTH, + ICON_WIDTH, + ptr, + 0, + 0, + 0, + 0, + tooltip); + break; + } + + /* set call to send relevant notifiers and/or perform type-specific updates */ + if (but) { + switch (setting) { + /* settings needing flushing up/down hierarchy */ + case ACHANNEL_SETTING_VISIBLE: /* Graph Editor - 'visibility' toggles */ + case ACHANNEL_SETTING_PROTECT: /* General - protection flags */ + case ACHANNEL_SETTING_MUTE: /* General - muting flags */ + case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */ + case ACHANNEL_SETTING_MOD_OFF: + case ACHANNEL_SETTING_ALWAYS_VISIBLE: + UI_but_funcN_set(but, + achannel_setting_flush_widget_cb, + MEM_dupallocN(ale), + POINTER_FROM_INT(setting)); + break; + + /* settings needing special attention */ + case ACHANNEL_SETTING_SOLO: /* NLA Tracks - Solo toggle */ + UI_but_funcN_set(but, achannel_nlatrack_solo_widget_cb, MEM_dupallocN(ale), NULL); + break; + + /* no flushing */ + case ACHANNEL_SETTING_EXPAND: /* expanding - cannot flush, + * otherwise all would open/close at once */ + default: + UI_but_func_set(but, achannel_setting_widget_cb, NULL, NULL); + break; + } + } + } + + if ((ale->fcurve_owner_id != NULL && ID_IS_LINKED(ale->fcurve_owner_id)) || + (ale->id != NULL && ID_IS_LINKED(ale->id))) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } } /* Draw UI widgets the given channel */ -void ANIM_channel_draw_widgets( - const bContext *C, - bAnimContext *ac, - bAnimListElem *ale, - uiBlock *block, - rctf *rect, - size_t channel_index) -{ - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - View2D *v2d = &ac->ar->v2d; - float ymid; - const short channel_height = round_fl_to_int(BLI_rctf_size_y(rect)); - const bool is_being_renamed = achannel_is_being_renamed(ac, acf, channel_index); - - /* sanity checks - don't draw anything */ - if (ELEM(NULL, acf, ale, block)) - return; - - /* get initial offset */ - short offset = rect->xmin; - if (acf->get_offset) { - offset += acf->get_offset(ac, ale); - } - - /* calculate appropriate y-coordinates for icon buttons */ - ymid = BLI_rctf_cent_y(rect) - 0.5f * ICON_WIDTH; - - /* no button backdrop behind icons */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); - - /* step 1) draw expand widget ....................................... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_EXPAND)) { - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_EXPAND); - offset += ICON_WIDTH; - } - - /* step 2) draw icon ............................................... */ - if (acf->icon) { - /* icon is not drawn here (not a widget) */ - offset += ICON_WIDTH; - } - - /* step 3) draw special toggles ................................. - * - in Graph Editor, checkboxes for visibility in curves area - * - in NLA Editor, glowing dots for solo/not solo... - * - in Grease Pencil mode, color swatches for layer color - */ - if (ac->sl) { - if ((ac->spacetype == SPACE_GRAPH) && - (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) || - acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) - { - /* pin toggle */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) { - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_ALWAYS_VISIBLE); - offset += ICON_WIDTH; - } - /* visibility toggle */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE); - offset += ICON_WIDTH; - } - } - else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) { - /* 'solo' setting for NLA Tracks */ - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO); - offset += ICON_WIDTH; - } - else if (ale->type == ANIMTYPE_GPLAYER) { +void ANIM_channel_draw_widgets(const bContext *C, + bAnimContext *ac, + bAnimListElem *ale, + uiBlock *block, + rctf *rect, + size_t channel_index) +{ + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + View2D *v2d = &ac->ar->v2d; + float ymid; + const short channel_height = round_fl_to_int(BLI_rctf_size_y(rect)); + const bool is_being_renamed = achannel_is_being_renamed(ac, acf, channel_index); + + /* sanity checks - don't draw anything */ + if (ELEM(NULL, acf, ale, block)) + return; + + /* get initial offset */ + short offset = rect->xmin; + if (acf->get_offset) { + offset += acf->get_offset(ac, ale); + } + + /* calculate appropriate y-coordinates for icon buttons */ + ymid = BLI_rctf_cent_y(rect) - 0.5f * ICON_WIDTH; + + /* no button backdrop behind icons */ + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + /* step 1) draw expand widget ....................................... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_EXPAND)) { + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_EXPAND); + offset += ICON_WIDTH; + } + + /* step 2) draw icon ............................................... */ + if (acf->icon) { + /* icon is not drawn here (not a widget) */ + offset += ICON_WIDTH; + } + + /* step 3) draw special toggles ................................. + * - in Graph Editor, checkboxes for visibility in curves area + * - in NLA Editor, glowing dots for solo/not solo... + * - in Grease Pencil mode, color swatches for layer color + */ + if (ac->sl) { + if ((ac->spacetype == SPACE_GRAPH) && + (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE) || + acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE))) { + /* pin toggle */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_ALWAYS_VISIBLE)) { + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_ALWAYS_VISIBLE); + offset += ICON_WIDTH; + } + /* visibility toggle */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) { + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE); + offset += ICON_WIDTH; + } + } + else if ((ac->spacetype == SPACE_NLA) && acf->has_setting(ac, ale, ACHANNEL_SETTING_SOLO)) { + /* 'solo' setting for NLA Tracks */ + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO); + offset += ICON_WIDTH; + } + else if (ale->type == ANIMTYPE_GPLAYER) { #if 0 - /* XXX: Maybe need a better design */ - /* color swatch for layer color */ - bGPDlayer *gpl = (bGPDlayer *)ale->data; - PointerRNA ptr; - float w = ICON_WIDTH / 2.0f; - - RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr); - - UI_block_align_begin(block); - UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); - uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset, yminc, w, ICON_WIDTH, - &ptr, "color", -1, - 0, 0, 0, 0, gpl->info); - - UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_fill_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); - uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset + w, yminc, w, ICON_WIDTH, - &ptr, "fill_color", -1, - 0, 0, 0, 0, gpl->info); - UI_block_emboss_set(block, UI_EMBOSS_NONE); - UI_block_align_end(block); - - offset += ICON_WIDTH; + /* XXX: Maybe need a better design */ + /* color swatch for layer color */ + bGPDlayer *gpl = (bGPDlayer *)ale->data; + PointerRNA ptr; + float w = ICON_WIDTH / 2.0f; + + RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr); + + UI_block_align_begin(block); + UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); + uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset, yminc, w, ICON_WIDTH, + &ptr, "color", -1, + 0, 0, 0, 0, gpl->info); + + UI_block_emboss_set(block, RNA_boolean_get(&ptr, "is_fill_visible") ? UI_EMBOSS : UI_EMBOSS_NONE); + uiDefButR(block, UI_BTYPE_COLOR, 1, "", offset + w, yminc, w, ICON_WIDTH, + &ptr, "fill_color", -1, + 0, 0, 0, 0, gpl->info); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_align_end(block); + + offset += ICON_WIDTH; #endif - } - } - - /* step 4) draw text - check if renaming widget is in use... */ - if (is_being_renamed) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - - /* draw renaming widget if we can get RNA pointer for it - * NOTE: property may only be available in some cases, even if we have - * a callback available (e.g. broken F-Curve rename) - */ - if (acf->name_prop(ale, &ptr, &prop)) { - const short margin_x = 3 * round_fl_to_int(UI_DPI_FAC); - const short width = ac->ar->winx - offset - (margin_x * 2); - uiBut *but; - - UI_block_emboss_set(block, UI_EMBOSS); - - but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + margin_x, rect->ymin, - MAX2(width, RENAME_TEXT_MIN_WIDTH), channel_height, - &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL); - - /* copy what outliner does here, see outliner_buttons */ - if (UI_but_active_only(C, ac->ar, block, but) == false) { - ac->ads->renameIndex = 0; - - /* send notifiers */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL); - } - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - } - else { - /* Cannot get property/cannot or rename for some reason, so clear rename index - * so that this doesn't hang around, and the name can be drawn normally - T47492 - */ - ac->ads->renameIndex = 0; - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); - } - } - - /* step 5) draw mute+protection toggles + (sliders) ....................... */ - /* reset offset - now goes from RHS of panel */ - offset = (int)rect->xmax; - - // TODO: when drawing sliders, make those draw instead of these toggles if not enough space - if (v2d && !is_being_renamed) { - short draw_sliders = 0; - - /* check if we need to show the sliders */ - if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_GRAPH)) { - switch (ac->spacetype) { - case SPACE_ACTION: - { - SpaceAction *saction = (SpaceAction *)ac->sl; - draw_sliders = (saction->flag & SACTION_SLIDERS); - break; - } - case SPACE_GRAPH: - { - SpaceGraph *sipo = (SpaceGraph *)ac->sl; - draw_sliders = (sipo->flag & SIPO_SLIDERS); - break; - } - } - } - - /* check if there's enough space for the toggles if the sliders are drawn too */ - if (!(draw_sliders) || (BLI_rcti_size_x(&v2d->mask) > ACHANNEL_BUTTON_WIDTH / 2) ) { - /* protect... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) { - offset -= ICON_WIDTH; - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_PROTECT); - } - /* mute... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) { - offset -= ICON_WIDTH; - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_MUTE); - } - if (ale->type == ANIMTYPE_GPLAYER) { - /* Not technically "mute" (in terms of anim channels, but this sets layer visibility instead) */ - offset -= ICON_WIDTH; - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE); - } - - /* modifiers disable */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MOD_OFF)) { - /* hack: extra spacing, to avoid touching the mute toggle */ - offset -= ICON_WIDTH * 1.2f; - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_MOD_OFF); - } - - /* ----------- */ - - /* pinned... */ - if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PINNED)) { - offset -= ICON_WIDTH; - draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_PINNED); - } - - /* NLA Action "pushdown" */ - if ((ale->type == ANIMTYPE_NLAACTION) && (ale->adt && ale->adt->action) && !(ale->adt->flag & ADT_NLA_EDIT_ON)) { - uiBut *but; - PointerRNA *opptr_b; - - UI_block_emboss_set(block, UI_EMBOSS); - - offset -= UI_UNIT_X; - but = uiDefIconButO(block, UI_BTYPE_BUT, "NLA_OT_action_pushdown", WM_OP_INVOKE_DEFAULT, ICON_NLA_PUSHDOWN, - offset, ymid, UI_UNIT_X, UI_UNIT_X, NULL); - - opptr_b = UI_but_operator_ptr_get(but); - RNA_int_set(opptr_b, "channel_index", channel_index); - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - } - } - - /* draw slider - * - even if we can draw sliders for this view, we must also check that the channel-type supports them - * (only only F-Curves really can support them for now) - * - to make things easier, we use RNA-autobuts for this so that changes are reflected immediately, - * wherever they occurred. BUT, we don't use the layout engine, otherwise we'd get wrong alignment, - * and wouldn't be able to auto-keyframe... - * - slider should start before the toggles (if they're visible) to keep a clean line down the side - */ - if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) { - /* adjust offset */ - // TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough - offset -= SLIDER_WIDTH; - - /* need backdrop behind sliders... */ - UI_block_emboss_set(block, UI_EMBOSS); - - if (ale->owner) { /* Slider using custom RNA Access ---------- */ - if (ale->type == ANIMTYPE_NLACURVE) { - NlaStrip *strip = (NlaStrip *)ale->owner; - FCurve *fcu = (FCurve *)ale->data; - PointerRNA ptr; - PropertyRNA *prop; - - /* create RNA pointers */ - RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, &ptr); - prop = RNA_struct_find_property(&ptr, fcu->rna_path); - - /* create property slider */ - if (prop) { - uiBut *but; - - /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ - but = uiDefAutoButR(block, &ptr, prop, fcu->array_index, "", ICON_NONE, offset, ymid, SLIDER_WIDTH, channel_height); - UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data); - } - } - } - else if (ale->id) { /* Slider using RNA Access --------------- */ - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - char *rna_path = NULL; - int array_index = 0; - short free_path = 0; - - /* get destination info */ - if (ale->type == ANIMTYPE_FCURVE) { - FCurve *fcu = (FCurve *)ale->data; - - rna_path = fcu->rna_path; - array_index = fcu->array_index; - } - else if (ale->type == ANIMTYPE_SHAPEKEY) { - KeyBlock *kb = (KeyBlock *)ale->data; - Key *key = (Key *)ale->id; - - rna_path = BKE_keyblock_curval_rnapath_get(key, kb); - free_path = 1; - } - - /* only if RNA-Path found */ - if (rna_path) { - /* get RNA pointer, and resolve the path */ - RNA_id_pointer_create(ale->id, &id_ptr); - - /* try to resolve the path */ - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { - uiBut *but; - - /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ - but = uiDefAutoButR(block, &ptr, prop, array_index, "", ICON_NONE, offset, ymid, SLIDER_WIDTH, channel_height); - - /* assign keyframing function according to slider type */ - if (ale->type == ANIMTYPE_SHAPEKEY) - UI_but_func_set(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data); - else - UI_but_func_set(but, achannel_setting_slider_cb, ale->id, ale->data); - } - - /* free the path if necessary */ - if (free_path) - MEM_freeN(rna_path); - } - } - else { /* Special Slider for stuff without RNA Access ---------- */ - // TODO: only implement this case when we really need it... - } - } - } + } + } + + /* step 4) draw text - check if renaming widget is in use... */ + if (is_being_renamed) { + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + + /* draw renaming widget if we can get RNA pointer for it + * NOTE: property may only be available in some cases, even if we have + * a callback available (e.g. broken F-Curve rename) + */ + if (acf->name_prop(ale, &ptr, &prop)) { + const short margin_x = 3 * round_fl_to_int(UI_DPI_FAC); + const short width = ac->ar->winx - offset - (margin_x * 2); + uiBut *but; + + UI_block_emboss_set(block, UI_EMBOSS); + + but = uiDefButR(block, + UI_BTYPE_TEXT, + 1, + "", + offset + margin_x, + rect->ymin, + MAX2(width, RENAME_TEXT_MIN_WIDTH), + channel_height, + &ptr, + RNA_property_identifier(prop), + -1, + 0, + 0, + -1, + -1, + NULL); + + /* copy what outliner does here, see outliner_buttons */ + if (UI_but_active_only(C, ac->ar, block, but) == false) { + ac->ads->renameIndex = 0; + + /* send notifiers */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_RENAME, NULL); + } + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + } + else { + /* Cannot get property/cannot or rename for some reason, so clear rename index + * so that this doesn't hang around, and the name can be drawn normally - T47492 + */ + ac->ads->renameIndex = 0; + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); + } + } + + /* step 5) draw mute+protection toggles + (sliders) ....................... */ + /* reset offset - now goes from RHS of panel */ + offset = (int)rect->xmax; + + // TODO: when drawing sliders, make those draw instead of these toggles if not enough space + if (v2d && !is_being_renamed) { + short draw_sliders = 0; + + /* check if we need to show the sliders */ + if ((ac->sl) && ELEM(ac->spacetype, SPACE_ACTION, SPACE_GRAPH)) { + switch (ac->spacetype) { + case SPACE_ACTION: { + SpaceAction *saction = (SpaceAction *)ac->sl; + draw_sliders = (saction->flag & SACTION_SLIDERS); + break; + } + case SPACE_GRAPH: { + SpaceGraph *sipo = (SpaceGraph *)ac->sl; + draw_sliders = (sipo->flag & SIPO_SLIDERS); + break; + } + } + } + + /* check if there's enough space for the toggles if the sliders are drawn too */ + if (!(draw_sliders) || (BLI_rcti_size_x(&v2d->mask) > ACHANNEL_BUTTON_WIDTH / 2)) { + /* protect... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT)) { + offset -= ICON_WIDTH; + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_PROTECT); + } + /* mute... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE)) { + offset -= ICON_WIDTH; + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_MUTE); + } + if (ale->type == ANIMTYPE_GPLAYER) { + /* Not technically "mute" (in terms of anim channels, but this sets layer visibility instead) */ + offset -= ICON_WIDTH; + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_VISIBLE); + } + + /* modifiers disable */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MOD_OFF)) { + /* hack: extra spacing, to avoid touching the mute toggle */ + offset -= ICON_WIDTH * 1.2f; + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_MOD_OFF); + } + + /* ----------- */ + + /* pinned... */ + if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PINNED)) { + offset -= ICON_WIDTH; + draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_PINNED); + } + + /* NLA Action "pushdown" */ + if ((ale->type == ANIMTYPE_NLAACTION) && (ale->adt && ale->adt->action) && + !(ale->adt->flag & ADT_NLA_EDIT_ON)) { + uiBut *but; + PointerRNA *opptr_b; + + UI_block_emboss_set(block, UI_EMBOSS); + + offset -= UI_UNIT_X; + but = uiDefIconButO(block, + UI_BTYPE_BUT, + "NLA_OT_action_pushdown", + WM_OP_INVOKE_DEFAULT, + ICON_NLA_PUSHDOWN, + offset, + ymid, + UI_UNIT_X, + UI_UNIT_X, + NULL); + + opptr_b = UI_but_operator_ptr_get(but); + RNA_int_set(opptr_b, "channel_index", channel_index); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + } + } + + /* draw slider + * - even if we can draw sliders for this view, we must also check that the channel-type supports them + * (only only F-Curves really can support them for now) + * - to make things easier, we use RNA-autobuts for this so that changes are reflected immediately, + * wherever they occurred. BUT, we don't use the layout engine, otherwise we'd get wrong alignment, + * and wouldn't be able to auto-keyframe... + * - slider should start before the toggles (if they're visible) to keep a clean line down the side + */ + if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE, ANIMTYPE_SHAPEKEY)) { + /* adjust offset */ + // TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough + offset -= SLIDER_WIDTH; + + /* need backdrop behind sliders... */ + UI_block_emboss_set(block, UI_EMBOSS); + + if (ale->owner) { /* Slider using custom RNA Access ---------- */ + if (ale->type == ANIMTYPE_NLACURVE) { + NlaStrip *strip = (NlaStrip *)ale->owner; + FCurve *fcu = (FCurve *)ale->data; + PointerRNA ptr; + PropertyRNA *prop; + + /* create RNA pointers */ + RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, &ptr); + prop = RNA_struct_find_property(&ptr, fcu->rna_path); + + /* create property slider */ + if (prop) { + uiBut *but; + + /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ + but = uiDefAutoButR(block, + &ptr, + prop, + fcu->array_index, + "", + ICON_NONE, + offset, + ymid, + SLIDER_WIDTH, + channel_height); + UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data); + } + } + } + else if (ale->id) { /* Slider using RNA Access --------------- */ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + char *rna_path = NULL; + int array_index = 0; + short free_path = 0; + + /* get destination info */ + if (ale->type == ANIMTYPE_FCURVE) { + FCurve *fcu = (FCurve *)ale->data; + + rna_path = fcu->rna_path; + array_index = fcu->array_index; + } + else if (ale->type == ANIMTYPE_SHAPEKEY) { + KeyBlock *kb = (KeyBlock *)ale->data; + Key *key = (Key *)ale->id; + + rna_path = BKE_keyblock_curval_rnapath_get(key, kb); + free_path = 1; + } + + /* only if RNA-Path found */ + if (rna_path) { + /* get RNA pointer, and resolve the path */ + RNA_id_pointer_create(ale->id, &id_ptr); + + /* try to resolve the path */ + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { + uiBut *but; + + /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ + but = uiDefAutoButR(block, + &ptr, + prop, + array_index, + "", + ICON_NONE, + offset, + ymid, + SLIDER_WIDTH, + channel_height); + + /* assign keyframing function according to slider type */ + if (ale->type == ANIMTYPE_SHAPEKEY) + UI_but_func_set(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data); + else + UI_but_func_set(but, achannel_setting_slider_cb, ale->id, ale->data); + } + + /* free the path if necessary */ + if (free_path) + MEM_freeN(rna_path); + } + } + else { /* Special Slider for stuff without RNA Access ---------- */ + // TODO: only implement this case when we really need it... + } + } + } } /* *********************************************** */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 558c5d5bfc1..c2878a64e97 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include #include @@ -59,7 +58,7 @@ #include "ED_anim_api.h" #include "ED_armature.h" -#include "ED_keyframes_edit.h" // XXX move the select modes out of there! +#include "ED_keyframes_edit.h" // XXX move the select modes out of there! #include "ED_object.h" #include "ED_screen.h" #include "ED_select_utils.h" @@ -74,178 +73,173 @@ /* Set the given animation-channel as the active one for the active context */ // TODO: extend for animdata types... -void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type) -{ - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - - /* try to build list of filtered items */ - ANIM_animdata_filter(ac, &anim_data, filter, data, datatype); - if (BLI_listbase_is_empty(&anim_data)) - return; - - /* only clear the 'active' flag for the channels of the same type */ - for (ale = anim_data.first; ale; ale = ale->next) { - /* skip if types don't match */ - if (channel_type != ale->type) - continue; - - /* flag to set depends on type */ - switch (ale->type) { - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = (bActionGroup *)ale->data; - - ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE); - break; - } - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: - { - FCurve *fcu = (FCurve *)ale->data; - - ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE); - break; - } - case ANIMTYPE_NLATRACK: - { - NlaTrack *nlt = (NlaTrack *)ale->data; - - ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); - break; - } - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - { - /* need to verify that this data is valid for now */ - if (ale->adt) { - ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE); - } - break; - } - case ANIMTYPE_GPLAYER: - { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - - ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE); - break; - } - } - } - - /* set active flag */ - if (channel_data) { - switch (channel_type) { - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = (bActionGroup *)channel_data; - agrp->flag |= AGRP_ACTIVE; - break; - } - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: - { - FCurve *fcu = (FCurve *)channel_data; - fcu->flag |= FCURVE_ACTIVE; - break; - } - case ANIMTYPE_NLATRACK: - { - NlaTrack *nlt = (NlaTrack *)channel_data; - nlt->flag |= NLATRACK_ACTIVE; - break; - } - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSNTREE: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - { - /* need to verify that this data is valid for now */ - if (ale && ale->adt) { - ale->adt->flag |= ADT_UI_ACTIVE; - } - break; - } - - case ANIMTYPE_GPLAYER: - { - bGPDlayer *gpl = (bGPDlayer *)channel_data; - gpl->flag |= GP_LAYER_ACTIVE; - break; - } - - /* unhandled currently, but may be interesting */ - case ANIMTYPE_MASKLAYER: - case ANIMTYPE_SHAPEKEY: - case ANIMTYPE_NLAACTION: - break; - - /* other types */ - default: - break; - } - } - - /* clean up */ - ANIM_animdata_freelist(&anim_data); +void ANIM_set_active_channel(bAnimContext *ac, + void *data, + eAnimCont_Types datatype, + eAnimFilter_Flags filter, + void *channel_data, + eAnim_ChannelType channel_type) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + + /* try to build list of filtered items */ + ANIM_animdata_filter(ac, &anim_data, filter, data, datatype); + if (BLI_listbase_is_empty(&anim_data)) + return; + + /* only clear the 'active' flag for the channels of the same type */ + for (ale = anim_data.first; ale; ale = ale->next) { + /* skip if types don't match */ + if (channel_type != ale->type) + continue; + + /* flag to set depends on type */ + switch (ale->type) { + case ANIMTYPE_GROUP: { + bActionGroup *agrp = (bActionGroup *)ale->data; + + ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE); + break; + } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)ale->data; + + ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE); + break; + } + case ANIMTYPE_NLATRACK: { + NlaTrack *nlt = (NlaTrack *)ale->data; + + ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); + break; + } + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: { + /* need to verify that this data is valid for now */ + if (ale->adt) { + ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE); + } + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + + ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE); + break; + } + } + } + + /* set active flag */ + if (channel_data) { + switch (channel_type) { + case ANIMTYPE_GROUP: { + bActionGroup *agrp = (bActionGroup *)channel_data; + agrp->flag |= AGRP_ACTIVE; + break; + } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)channel_data; + fcu->flag |= FCURVE_ACTIVE; + break; + } + case ANIMTYPE_NLATRACK: { + NlaTrack *nlt = (NlaTrack *)channel_data; + nlt->flag |= NLATRACK_ACTIVE; + break; + } + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: { + /* need to verify that this data is valid for now */ + if (ale && ale->adt) { + ale->adt->flag |= ADT_UI_ACTIVE; + } + break; + } + + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)channel_data; + gpl->flag |= GP_LAYER_ACTIVE; + break; + } + + /* unhandled currently, but may be interesting */ + case ANIMTYPE_MASKLAYER: + case ANIMTYPE_SHAPEKEY: + case ANIMTYPE_NLAACTION: + break; + + /* other types */ + default: + break; + } + } + + /* clean up */ + ANIM_animdata_freelist(&anim_data); } static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, bAnimListElem *ale) { - /* Armatures-Specific Feature: - * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (T38737) - */ - if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) { - if ((ale->id) && (GS(ale->id->name) == ID_OB)) { - Object *ob = (Object *)ale->id; - if (ob->type == OB_ARMATURE) { - /* Assume for now that any group with corresponding name is what we want - * (i.e. for an armature whose location is animated, things would break - * if the user were to add a bone named "Location"). - * - * TODO: check the first F-Curve or so to be sure... - */ - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); - if (agrp->flag & AGRP_SELECTED) { - ED_pose_bone_select(ob, pchan, true); - } - else { - ED_pose_bone_select(ob, pchan, false); - } - } - } - } + /* Armatures-Specific Feature: + * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (T38737) + */ + if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) { + if ((ale->id) && (GS(ale->id->name) == ID_OB)) { + Object *ob = (Object *)ale->id; + if (ob->type == OB_ARMATURE) { + /* Assume for now that any group with corresponding name is what we want + * (i.e. for an armature whose location is animated, things would break + * if the user were to add a bone named "Location"). + * + * TODO: check the first F-Curve or so to be sure... + */ + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); + if (agrp->flag & AGRP_SELECTED) { + ED_pose_bone_select(ob, pchan, true); + } + else { + ED_pose_bone_select(ob, pchan, false); + } + } + } + } } /* Deselect all animation channels @@ -254,195 +248,186 @@ static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, * - test: check if deselecting instead of selecting * - sel: eAnimChannels_SetFlag; */ -void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types datatype, bool test, eAnimChannels_SetFlag sel) -{ - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* filter data */ - /* 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 */ - if (test) { - for (ale = anim_data.first; ale; ale = ale->next) { - if (sel == 0) - break; - - switch (ale->type) { - case ANIMTYPE_SCENE: - if (ale->flag & SCE_DS_SELECTED) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - case ANIMTYPE_OBJECT: -#if 0 /* for now, do not take object selection into account, since it gets too annoying */ - if (ale->flag & SELECT) - sel = ACHANNEL_SETFLAG_CLEAR; +void ANIM_deselect_anim_channels( + bAnimContext *ac, void *data, eAnimCont_Types datatype, bool test, eAnimChannels_SetFlag sel) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data */ + /* 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 */ + if (test) { + for (ale = anim_data.first; ale; ale = ale->next) { + if (sel == 0) + break; + + switch (ale->type) { + case ANIMTYPE_SCENE: + if (ale->flag & SCE_DS_SELECTED) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + case ANIMTYPE_OBJECT: +#if 0 /* for now, do not take object selection into account, since it gets too annoying */ + if (ale->flag & SELECT) + sel = ACHANNEL_SETFLAG_CLEAR; #endif - break; - case ANIMTYPE_GROUP: - if (ale->flag & AGRP_SELECTED) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: - if (ale->flag & FCURVE_SELECTED) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - case ANIMTYPE_SHAPEKEY: - if (ale->flag & KEYBLOCK_SEL) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - case ANIMTYPE_NLATRACK: - if (ale->flag & NLATRACK_SELECTED) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSNTREE: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - { - if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - } - case ANIMTYPE_GPLAYER: - if (ale->flag & GP_LAYER_SELECT) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - case ANIMTYPE_MASKLAYER: - if (ale->flag & MASK_LAYERFLAG_SELECT) - sel = ACHANNEL_SETFLAG_CLEAR; - break; - } - } - } - - /* Now set the flags */ - for (ale = anim_data.first; ale; ale = ale->next) { - switch (ale->type) { - case ANIMTYPE_SCENE: - { - Scene *scene = (Scene *)ale->data; - - ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED); - - if (scene->adt) { - ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED); - } - break; - } - case ANIMTYPE_OBJECT: - { -#if 0 /* for now, do not take object selection into account, since it gets too annoying */ - Base *base = (Base *)ale->data; - Object *ob = base->object; - - ACHANNEL_SET_FLAG(base, sel, SELECT); - ACHANNEL_SET_FLAG(ob, sel, SELECT); - - if (ob->adt) { - ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED); - } + break; + case ANIMTYPE_GROUP: + if (ale->flag & AGRP_SELECTED) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: + if (ale->flag & FCURVE_SELECTED) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + case ANIMTYPE_SHAPEKEY: + if (ale->flag & KEYBLOCK_SEL) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + case ANIMTYPE_NLATRACK: + if (ale->flag & NLATRACK_SELECTED) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: { + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + } + case ANIMTYPE_GPLAYER: + if (ale->flag & GP_LAYER_SELECT) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + case ANIMTYPE_MASKLAYER: + if (ale->flag & MASK_LAYERFLAG_SELECT) + sel = ACHANNEL_SETFLAG_CLEAR; + break; + } + } + } + + /* Now set the flags */ + for (ale = anim_data.first; ale; ale = ale->next) { + switch (ale->type) { + case ANIMTYPE_SCENE: { + Scene *scene = (Scene *)ale->data; + + ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED); + + if (scene->adt) { + ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED); + } + break; + } + case ANIMTYPE_OBJECT: { +#if 0 /* for now, do not take object selection into account, since it gets too annoying */ + Base *base = (Base *)ale->data; + Object *ob = base->object; + + ACHANNEL_SET_FLAG(base, sel, SELECT); + ACHANNEL_SET_FLAG(ob, sel, SELECT); + + if (ob->adt) { + ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED); + } #endif - break; - } - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = (bActionGroup *)ale->data; - ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED); - select_pchan_for_action_group(ac, agrp, ale); - agrp->flag &= ~AGRP_ACTIVE; - break; - } - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: - { - FCurve *fcu = (FCurve *)ale->data; - - ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED); - fcu->flag &= ~FCURVE_ACTIVE; - break; - } - case ANIMTYPE_SHAPEKEY: - { - KeyBlock *kb = (KeyBlock *)ale->data; - - ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL); - break; - } - case ANIMTYPE_NLATRACK: - { - NlaTrack *nlt = (NlaTrack *)ale->data; - - ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED); - nlt->flag &= ~NLATRACK_ACTIVE; - break; - } - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSNTREE: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - { - /* need to verify that this data is valid for now */ - if (ale->adt) { - ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED); - ale->adt->flag &= ~ADT_UI_ACTIVE; - } - break; - } - case ANIMTYPE_GPLAYER: - { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - - ACHANNEL_SET_FLAG(gpl, sel, GP_LAYER_SELECT); - break; - } - case ANIMTYPE_MASKLAYER: - { - MaskLayer *masklay = (MaskLayer *)ale->data; - - ACHANNEL_SET_FLAG(masklay, sel, MASK_LAYERFLAG_SELECT); - break; - } - } - } - - /* Cleanup */ - ANIM_animdata_freelist(&anim_data); + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *agrp = (bActionGroup *)ale->data; + ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED); + select_pchan_for_action_group(ac, agrp, ale); + agrp->flag &= ~AGRP_ACTIVE; + break; + } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)ale->data; + + ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED); + fcu->flag &= ~FCURVE_ACTIVE; + break; + } + case ANIMTYPE_SHAPEKEY: { + KeyBlock *kb = (KeyBlock *)ale->data; + + ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL); + break; + } + case ANIMTYPE_NLATRACK: { + NlaTrack *nlt = (NlaTrack *)ale->data; + + ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED); + nlt->flag &= ~NLATRACK_ACTIVE; + break; + } + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: { + /* need to verify that this data is valid for now */ + if (ale->adt) { + ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED); + ale->adt->flag &= ~ADT_UI_ACTIVE; + } + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + + ACHANNEL_SET_FLAG(gpl, sel, GP_LAYER_SELECT); + break; + } + case ANIMTYPE_MASKLAYER: { + MaskLayer *masklay = (MaskLayer *)ale->data; + + ACHANNEL_SET_FLAG(masklay, sel, MASK_LAYERFLAG_SELECT); + break; + } + } + } + + /* Cleanup */ + ANIM_animdata_freelist(&anim_data); } /* ---------------------------- Graph Editor ------------------------------------- */ @@ -456,137 +441,140 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types d * - setting: type of setting to set * - on: whether the visibility setting has been enabled or disabled */ -void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode) -{ - bAnimListElem *ale, *match = NULL; - int prevLevel = 0, matchLevel = 0; - - /* sanity check */ - if (ELEM(NULL, anim_data, anim_data->first)) - return; - - if (setting == ACHANNEL_SETTING_ALWAYS_VISIBLE) { - return; - } - - /* find the channel that got changed */ - for (ale = anim_data->first; ale; ale = ale->next) { - /* compare data, and type as main way of identifying the channel */ - if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) { - /* we also have to check the ID, this is assigned to, since a block may have multiple users */ - /* TODO: is the owner-data more revealing? */ - if (ale->id == ale_setting->id) { - match = ale; - break; - } - } - } - if (match == NULL) { - printf("ERROR: no channel matching the one changed was found\n"); - return; - } - else { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting); - - if (acf == NULL) { - printf("ERROR: no channel info for the changed channel\n"); - return; - } - - /* get the level of the channel that was affected - * - we define the level as simply being the offset for the start of the channel - */ - matchLevel = (acf->get_offset) ? acf->get_offset(ac, ale_setting) : 0; - prevLevel = matchLevel; - } - - /* flush up? - * - * For Visibility: - * - only flush up if the current state is now enabled (positive 'on' state is default) - * (otherwise, it's too much work to force the parents to be inactive too) - * - * For everything else: - * - only flush up if the current state is now disabled (negative 'off' state is default) - * (otherwise, it's too much work to force the parents to be active too) - */ - if ( ((setting == ACHANNEL_SETTING_VISIBLE) && (mode != ACHANNEL_SETFLAG_CLEAR)) || - ((setting != ACHANNEL_SETTING_VISIBLE) && (mode == ACHANNEL_SETFLAG_CLEAR))) - { - /* go backwards in the list, until the highest-ranking element (by indention has been covered) */ - for (ale = match->prev; ale; ale = ale->prev) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - int level; - - /* if no channel info was found, skip, since this type might not have any useful info */ - if (acf == NULL) - continue; - - /* get the level of the current channel traversed - * - we define the level as simply being the offset for the start of the channel - */ - level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - - /* if the level is 'less than' (i.e. more important) the level we're matching - * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves, - * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel - * get updated below once the first 1st group is found)... - */ - if (level < prevLevel) { - /* flush the new status... */ - ANIM_channel_setting_set(ac, ale, setting, mode); - - /* store this level as the 'old' level now */ - prevLevel = level; - } - /* if the level is 'greater than' (i.e. less important) than the previous level... */ - else if (level > prevLevel) { - /* if previous level was a base-level (i.e. 0 offset / root of one hierarchy), - * stop here - */ - if (prevLevel == 0) - break; - /* otherwise, this level weaves into another sibling hierarchy to the previous one just - * finished, so skip until we get to the parent of this level - */ - else - continue; - } - } - } - - /* flush down (always) */ - { - /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */ - for (ale = match->next; ale; ale = ale->next) { - const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); - int level; - - /* if no channel info was found, skip, since this type might not have any useful info */ - if (acf == NULL) - continue; - - /* get the level of the current channel traversed - * - we define the level as simply being the offset for the start of the channel - */ - level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; - - /* if the level is 'greater than' (i.e. less important) the channel that was changed, - * flush the new status... - */ - if (level > matchLevel) - ANIM_channel_setting_set(ac, ale, setting, mode); - /* however, if the level is 'less than or equal to' the channel that was changed, - * (i.e. the current channel is as important if not more important than the changed channel) - * then we should stop, since we've found the last one of the children we should flush - */ - else - break; - - /* store this level as the 'old' level now */ - // prevLevel = level; // XXX: prevLevel is unused - } - } +void ANIM_flush_setting_anim_channels(bAnimContext *ac, + ListBase *anim_data, + bAnimListElem *ale_setting, + eAnimChannel_Settings setting, + eAnimChannels_SetFlag mode) +{ + bAnimListElem *ale, *match = NULL; + int prevLevel = 0, matchLevel = 0; + + /* sanity check */ + if (ELEM(NULL, anim_data, anim_data->first)) + return; + + if (setting == ACHANNEL_SETTING_ALWAYS_VISIBLE) { + return; + } + + /* find the channel that got changed */ + for (ale = anim_data->first; ale; ale = ale->next) { + /* compare data, and type as main way of identifying the channel */ + if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) { + /* we also have to check the ID, this is assigned to, since a block may have multiple users */ + /* TODO: is the owner-data more revealing? */ + if (ale->id == ale_setting->id) { + match = ale; + break; + } + } + } + if (match == NULL) { + printf("ERROR: no channel matching the one changed was found\n"); + return; + } + else { + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting); + + if (acf == NULL) { + printf("ERROR: no channel info for the changed channel\n"); + return; + } + + /* get the level of the channel that was affected + * - we define the level as simply being the offset for the start of the channel + */ + matchLevel = (acf->get_offset) ? acf->get_offset(ac, ale_setting) : 0; + prevLevel = matchLevel; + } + + /* flush up? + * + * For Visibility: + * - only flush up if the current state is now enabled (positive 'on' state is default) + * (otherwise, it's too much work to force the parents to be inactive too) + * + * For everything else: + * - only flush up if the current state is now disabled (negative 'off' state is default) + * (otherwise, it's too much work to force the parents to be active too) + */ + if (((setting == ACHANNEL_SETTING_VISIBLE) && (mode != ACHANNEL_SETFLAG_CLEAR)) || + ((setting != ACHANNEL_SETTING_VISIBLE) && (mode == ACHANNEL_SETFLAG_CLEAR))) { + /* go backwards in the list, until the highest-ranking element (by indention has been covered) */ + for (ale = match->prev; ale; ale = ale->prev) { + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + int level; + + /* if no channel info was found, skip, since this type might not have any useful info */ + if (acf == NULL) + continue; + + /* get the level of the current channel traversed + * - we define the level as simply being the offset for the start of the channel + */ + level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + + /* if the level is 'less than' (i.e. more important) the level we're matching + * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves, + * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel + * get updated below once the first 1st group is found)... + */ + if (level < prevLevel) { + /* flush the new status... */ + ANIM_channel_setting_set(ac, ale, setting, mode); + + /* store this level as the 'old' level now */ + prevLevel = level; + } + /* if the level is 'greater than' (i.e. less important) than the previous level... */ + else if (level > prevLevel) { + /* if previous level was a base-level (i.e. 0 offset / root of one hierarchy), + * stop here + */ + if (prevLevel == 0) + break; + /* otherwise, this level weaves into another sibling hierarchy to the previous one just + * finished, so skip until we get to the parent of this level + */ + else + continue; + } + } + } + + /* flush down (always) */ + { + /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */ + for (ale = match->next; ale; ale = ale->next) { + const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); + int level; + + /* if no channel info was found, skip, since this type might not have any useful info */ + if (acf == NULL) + continue; + + /* get the level of the current channel traversed + * - we define the level as simply being the offset for the start of the channel + */ + level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; + + /* if the level is 'greater than' (i.e. less important) the channel that was changed, + * flush the new status... + */ + if (level > matchLevel) + ANIM_channel_setting_set(ac, ale, setting, mode); + /* however, if the level is 'less than or equal to' the channel that was changed, + * (i.e. the current channel is as important if not more important than the changed channel) + * then we should stop, since we've found the last one of the children we should flush + */ + else + break; + + /* store this level as the 'old' level now */ + // prevLevel = level; // XXX: prevLevel is unused + } + } } /* -------------------------- F-Curves ------------------------------------- */ @@ -594,59 +582,59 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAn /* Delete the given F-Curve from its AnimData block */ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu) { - /* - if no AnimData, we've got nowhere to remove the F-Curve from - * (this doesn't guarantee that the F-Curve is in there, but at least we tried - * - if no F-Curve, there is nothing to remove - */ - if (ELEM(NULL, adt, fcu)) - return; - - /* remove from whatever list it came from - * - Action Group - * - Action - * - Drivers - * - TODO... some others? - */ - if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) { - /* driver F-Curve */ - BLI_remlink(&adt->drivers, fcu); - } - else if (adt->action) { - bAction *act = adt->action; - - /* remove from group or action, whichever one "owns" the F-Curve */ - if (fcu->grp) { - bActionGroup *agrp = fcu->grp; - - /* remove F-Curve from group+action */ - action_groups_remove_channel(act, fcu); - - /* if group has no more channels, remove it too, - * otherwise can have many dangling groups [#33541] - */ - if (BLI_listbase_is_empty(&agrp->channels)) { - BLI_freelinkN(&act->groups, agrp); - } - } - else { - BLI_remlink(&act->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). - */ - if (BLI_listbase_is_empty(&act->curves) && (adt->flag & ADT_NLA_EDIT_ON) == 0) { - id_us_min(&act->id); - adt->action = NULL; - } - } - - /* free the F-Curve itself */ - free_fcurve(fcu); + /* - if no AnimData, we've got nowhere to remove the F-Curve from + * (this doesn't guarantee that the F-Curve is in there, but at least we tried + * - if no F-Curve, there is nothing to remove + */ + if (ELEM(NULL, adt, fcu)) + return; + + /* remove from whatever list it came from + * - Action Group + * - Action + * - Drivers + * - TODO... some others? + */ + if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) { + /* driver F-Curve */ + BLI_remlink(&adt->drivers, fcu); + } + else if (adt->action) { + bAction *act = adt->action; + + /* remove from group or action, whichever one "owns" the F-Curve */ + if (fcu->grp) { + bActionGroup *agrp = fcu->grp; + + /* remove F-Curve from group+action */ + action_groups_remove_channel(act, fcu); + + /* if group has no more channels, remove it too, + * otherwise can have many dangling groups [#33541] + */ + if (BLI_listbase_is_empty(&agrp->channels)) { + BLI_freelinkN(&act->groups, agrp); + } + } + else { + BLI_remlink(&act->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). + */ + if (BLI_listbase_is_empty(&act->curves) && (adt->flag & ADT_NLA_EDIT_ON) == 0) { + id_us_min(&act->id); + adt->action = NULL; + } + } + + /* free the F-Curve itself */ + free_fcurve(fcu); } /* ************************************************************************** */ @@ -657,40 +645,40 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *f /* poll callback for being in an Animation Editor channels list region */ static bool animedit_poll_channels_active(bContext *C) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *sa = CTX_wm_area(C); - /* channels region test */ - /* TODO: could enhance with actually testing if channels region? */ - if (ELEM(NULL, sa, CTX_wm_region(C))) - return 0; - /* animation editor test */ - if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) - return 0; + /* channels region test */ + /* TODO: could enhance with actually testing if channels region? */ + if (ELEM(NULL, sa, CTX_wm_region(C))) + return 0; + /* animation editor test */ + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) + return 0; - return 1; + return 1; } /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - Scene *scene = CTX_data_scene(C); + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); - /* channels region test */ - /* TODO: could enhance with actually testing if channels region? */ - if (ELEM(NULL, sa, CTX_wm_region(C))) - return 0; - /* animation editor test */ - if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) - return 0; + /* channels region test */ + /* TODO: could enhance with actually testing if channels region? */ + if (ELEM(NULL, sa, CTX_wm_region(C))) + return 0; + /* animation editor test */ + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) + return 0; - /* NLA TweakMode test */ - if (sa->spacetype == SPACE_NLA) { - if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) - return 0; - } + /* NLA TweakMode test */ + if (sa->spacetype == SPACE_NLA) { + if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) + return 0; + } - return 1; + return 1; } /* ****************** Rearrange Channels Operator ******************* */ @@ -698,146 +686,144 @@ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C) /* constants for channel rearranging */ /* WARNING: don't change existing ones without modifying rearrange func accordingly */ typedef enum eRearrangeAnimChan_Mode { - REARRANGE_ANIMCHAN_TOP = -2, - REARRANGE_ANIMCHAN_UP = -1, - REARRANGE_ANIMCHAN_DOWN = 1, - REARRANGE_ANIMCHAN_BOTTOM = 2, + REARRANGE_ANIMCHAN_TOP = -2, + REARRANGE_ANIMCHAN_UP = -1, + REARRANGE_ANIMCHAN_DOWN = 1, + REARRANGE_ANIMCHAN_BOTTOM = 2, } eRearrangeAnimChan_Mode; /* defines for rearranging channels */ static const EnumPropertyItem prop_animchannel_rearrange_types[] = { - {REARRANGE_ANIMCHAN_TOP, "TOP", 0, "To Top", ""}, - {REARRANGE_ANIMCHAN_UP, "UP", 0, "Up", ""}, - {REARRANGE_ANIMCHAN_DOWN, "DOWN", 0, "Down", ""}, - {REARRANGE_ANIMCHAN_BOTTOM, "BOTTOM", 0, "To Bottom", ""}, - {0, NULL, 0, NULL, NULL}, + {REARRANGE_ANIMCHAN_TOP, "TOP", 0, "To Top", ""}, + {REARRANGE_ANIMCHAN_UP, "UP", 0, "Up", ""}, + {REARRANGE_ANIMCHAN_DOWN, "DOWN", 0, "Down", ""}, + {REARRANGE_ANIMCHAN_BOTTOM, "BOTTOM", 0, "To Bottom", ""}, + {0, NULL, 0, NULL, NULL}, }; /* Reordering "Islands" Defines ----------------------------------- */ /* Island definition - just a listbase container */ typedef struct tReorderChannelIsland { - struct tReorderChannelIsland *next, *prev; + struct tReorderChannelIsland *next, *prev; - ListBase channels; /* channels within this region with the same state */ - int flag; /* eReorderIslandFlag */ + 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 */ - REORDER_ISLAND_HIDDEN = (1 << 3), /* island is not visible */ + 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 */ + REORDER_ISLAND_HIDDEN = (1 << 3), /* island is not visible */ } eReorderIslandFlag; - /* Rearrange Methods --------------------------------------------- */ static bool rearrange_island_ok(tReorderChannelIsland *island) { - /* island must not be untouchable */ - if (island->flag & REORDER_ISLAND_UNTOUCHABLE) - return 0; + /* island must not be untouchable */ + if (island->flag & REORDER_ISLAND_UNTOUCHABLE) + return 0; - /* island should be selected to be moved */ - return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED); + /* island should be selected to be moved */ + return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED); } /* ............................. */ static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island) { - if (rearrange_island_ok(island)) { - /* remove from current position */ - BLI_remlink(list, island); + if (rearrange_island_ok(island)) { + /* remove from current position */ + BLI_remlink(list, island); - /* make it first element */ - BLI_insertlinkbefore(list, list->first, island); + /* make it first element */ + BLI_insertlinkbefore(list, list->first, island); - return 1; - } + return 1; + } - return 0; + return 0; } static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island) { - if (rearrange_island_ok(island)) { - /* moving up = moving before the previous island, otherwise we're in the same place */ - tReorderChannelIsland *prev = island->prev; + if (rearrange_island_ok(island)) { + /* moving up = moving before the previous island, otherwise we're in the same place */ + tReorderChannelIsland *prev = island->prev; - /* Skip hidden islands! */ - while (prev && prev->flag & REORDER_ISLAND_HIDDEN) { - prev = prev->prev; - } + /* Skip hidden islands! */ + while (prev && prev->flag & REORDER_ISLAND_HIDDEN) { + prev = prev->prev; + } - if (prev) { - /* remove from current position */ - BLI_remlink(list, island); + if (prev) { + /* remove from current position */ + BLI_remlink(list, island); - /* push it up */ - BLI_insertlinkbefore(list, prev, island); + /* push it up */ + BLI_insertlinkbefore(list, prev, island); - return 1; - } - } + return 1; + } + } - return 0; + return 0; } static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island) { - if (rearrange_island_ok(island)) { - /* moving down = moving after the next island, otherwise we're in the same place */ - tReorderChannelIsland *next = island->next; + if (rearrange_island_ok(island)) { + /* moving down = moving after the next island, otherwise we're in the same place */ + tReorderChannelIsland *next = island->next; - /* Skip hidden islands! */ - while (next && next->flag & REORDER_ISLAND_HIDDEN) { - next = next->next; - } + /* Skip hidden islands! */ + while (next && next->flag & REORDER_ISLAND_HIDDEN) { + next = next->next; + } - if (next) { - /* 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); + if (next) { + /* 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); + /* push it down */ + BLI_insertlinkafter(list, next, island); - return true; - } - } - /* else: no next channel, so we're at the bottom already, so can't move */ - } + return true; + } + } + /* else: no next channel, so we're at the bottom already, so can't move */ + } - return false; + return false; } static bool rearrange_island_bottom(ListBase *list, tReorderChannelIsland *island) { - if (rearrange_island_ok(island)) { - tReorderChannelIsland *last = list->last; - - /* remove island from current position */ - BLI_remlink(list, island); + if (rearrange_island_ok(island)) { + tReorderChannelIsland *last = list->last; - /* 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); + /* 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 true; - } + return true; + } - return false; + return false; } /* ............................. */ @@ -854,184 +840,187 @@ typedef bool (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *islan /* get rearranging function, given 'rearrange' mode */ static AnimChanRearrangeFp rearrange_get_mode_func(eRearrangeAnimChan_Mode mode) { - switch (mode) { - case REARRANGE_ANIMCHAN_TOP: - return rearrange_island_top; - case REARRANGE_ANIMCHAN_UP: - return rearrange_island_up; - case REARRANGE_ANIMCHAN_DOWN: - return rearrange_island_down; - case REARRANGE_ANIMCHAN_BOTTOM: - return rearrange_island_bottom; - default: - return NULL; - } + switch (mode) { + case REARRANGE_ANIMCHAN_TOP: + return rearrange_island_top; + case REARRANGE_ANIMCHAN_UP: + return rearrange_island_up; + case REARRANGE_ANIMCHAN_DOWN: + return rearrange_island_down; + case REARRANGE_ANIMCHAN_BOTTOM: + return rearrange_island_bottom; + default: + return NULL; + } } /* Rearrange Islands Generics ------------------------------------- */ /* add channel into list of islands */ -static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList, - Link *channel, eAnim_ChannelType type, +static void rearrange_animchannel_add_to_islands(ListBase *islands, + ListBase *srcList, + Link *channel, + eAnim_ChannelType type, const bool is_hidden) { - /* always try to add to last island if possible */ - tReorderChannelIsland *island = islands->last; - bool is_sel = false, is_untouchable = false; - - /* 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: - case ANIMTYPE_NLACURVE: - { - FCurve *fcu = (FCurve *)channel; - - is_sel = SEL_FCU(fcu); - break; - } - case ANIMTYPE_NLATRACK: - { - NlaTrack *nlt = (NlaTrack *)channel; - - is_sel = SEL_NLT(nlt); - break; - } - case ANIMTYPE_GPLAYER: - { - bGPDlayer *gpl = (bGPDlayer *)channel; - - is_sel = SEL_GPL(gpl); - break; - } - default: - printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", type); - return; - } - - /* do we need to add to a new island? */ - if (/* 1) no islands yet */ - (island == NULL) || - /* 2) unselected islands have single channels only - to allow up/down movement */ - ((island->flag & REORDER_ISLAND_SELECTED) == 0) || - /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */ - (is_sel == 0) || - /* 4) hidden status changes */ - ((island->flag & REORDER_ISLAND_HIDDEN) != is_hidden) - ) - { - /* 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; - if (is_hidden) - island->flag |= REORDER_ISLAND_HIDDEN; - } - - /* add channel to island - need to remove it from its existing list first though */ - BLI_remlink(srcList, channel); - BLI_addtail(&island->channels, channel); + /* always try to add to last island if possible */ + tReorderChannelIsland *island = islands->last; + bool is_sel = false, is_untouchable = false; + + /* 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: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)channel; + + is_sel = SEL_FCU(fcu); + break; + } + case ANIMTYPE_NLATRACK: { + NlaTrack *nlt = (NlaTrack *)channel; + + is_sel = SEL_NLT(nlt); + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)channel; + + is_sel = SEL_GPL(gpl); + break; + } + default: + printf( + "rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", + type); + return; + } + + /* do we need to add to a new island? */ + if (/* 1) no islands yet */ + (island == NULL) || + /* 2) unselected islands have single channels only - to allow up/down movement */ + ((island->flag & REORDER_ISLAND_SELECTED) == 0) || + /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */ + (is_sel == 0) || + /* 4) hidden status changes */ + ((island->flag & REORDER_ISLAND_HIDDEN) != is_hidden)) { + /* 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; + if (is_hidden) + island->flag |= REORDER_ISLAND_HIDDEN; + } + + /* add channel to island - need to remove it from its existing list first though */ + BLI_remlink(srcList, channel); + BLI_addtail(&island->channels, channel); } /* flatten islands out into a single list again */ static void rearrange_animchannel_flatten_islands(ListBase *islands, ListBase *srcList) { - tReorderChannelIsland *island, *isn = NULL; + tReorderChannelIsland *island, *isn = NULL; - /* make sure srcList is empty now */ - BLI_assert(BLI_listbase_is_empty(srcList)); + /* make sure srcList is empty now */ + BLI_assert(BLI_listbase_is_empty(srcList)); - /* go through merging islands */ - for (island = islands->first; island; island = isn) { - isn = island->next; + /* 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); - } + /* merge island channels back to main list, then delete the island */ + BLI_movelisttolist(srcList, &island->channels); + BLI_freelinkN(islands, island); + } } /* ............................. */ /* get a list of all bAnimListElem's of a certain type which are currently visible */ -static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, eAnim_ChannelType type) +static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, + bAnimContext *ac, + eAnim_ChannelType type) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale, *ale_next; - int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale, *ale_next; + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); - /* get all visible channels */ - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + /* get all visible channels */ + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* now, only keep the ones that are of the types we are interested in */ - for (ale = anim_data.first; ale; ale = ale_next) { - ale_next = ale->next; + /* now, only keep the ones that are of the types we are interested in */ + for (ale = anim_data.first; ale; ale = ale_next) { + ale_next = ale->next; - if (ale->type != type) { - BLI_freelinkN(&anim_data, ale); - } - } + if (ale->type != type) { + BLI_freelinkN(&anim_data, ale); + } + } - /* return cleaned up list */ - *anim_data_visible = anim_data; + /* return cleaned up list */ + *anim_data_visible = anim_data; } /* performing rearranging of channels using islands */ -static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp rearrange_func, - eRearrangeAnimChan_Mode mode, eAnim_ChannelType type, +static bool rearrange_animchannel_islands(ListBase *list, + AnimChanRearrangeFp rearrange_func, + eRearrangeAnimChan_Mode mode, + eAnim_ChannelType type, ListBase *anim_data_visible) { - ListBase islands = {NULL, NULL}; - Link *channel, *chanNext = NULL; - bool done = false; - - /* don't waste effort on an empty list */ - if (BLI_listbase_is_empty(list)) - return 0; - - /* group channels into islands */ - for (channel = list->first; channel; channel = chanNext) { - /* find out whether this channel is present in anim_data_visible or not! */ - const bool is_hidden = (BLI_findptr(anim_data_visible, channel, offsetof(bAnimListElem, data)) == NULL); - chanNext = channel->next; - rearrange_animchannel_add_to_islands(&islands, list, channel, type, is_hidden); - } - - /* 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 = true; - } - } - } - - /* ungroup islands */ - rearrange_animchannel_flatten_islands(&islands, list); - - /* did we do anything? */ - return done; + ListBase islands = {NULL, NULL}; + Link *channel, *chanNext = NULL; + bool done = false; + + /* don't waste effort on an empty list */ + if (BLI_listbase_is_empty(list)) + return 0; + + /* group channels into islands */ + for (channel = list->first; channel; channel = chanNext) { + /* find out whether this channel is present in anim_data_visible or not! */ + const bool is_hidden = + (BLI_findptr(anim_data_visible, channel, offsetof(bAnimListElem, data)) == NULL); + chanNext = channel->next; + rearrange_animchannel_add_to_islands(&islands, list, channel, type, is_hidden); + } + + /* 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 = true; + } + } + } + + /* ungroup islands */ + rearrange_animchannel_flatten_islands(&islands, list); + + /* did we do anything? */ + return done; } /* NLA Specific Stuff ----------------------------------------------------- */ @@ -1042,25 +1031,26 @@ static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp re */ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode) { - AnimChanRearrangeFp rearrange_func; - ListBase anim_data_visible = {NULL, NULL}; + AnimChanRearrangeFp rearrange_func; + ListBase anim_data_visible = {NULL, NULL}; - /* hack: invert mode so that functions will work in right order */ - mode *= -1; + /* hack: invert mode so that functions will work in right order */ + mode *= -1; - /* get rearranging function */ - rearrange_func = rearrange_get_mode_func(mode); - if (rearrange_func == NULL) - return; + /* get rearranging function */ + rearrange_func = rearrange_get_mode_func(mode); + if (rearrange_func == NULL) + return; - /* Filter visible data. */ - rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK); + /* Filter visible data. */ + rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK); - /* perform rearranging on tracks list */ - rearrange_animchannel_islands(&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible); + /* perform rearranging on tracks list */ + rearrange_animchannel_islands( + &adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible); - /* free temp data */ - BLI_freelistN(&anim_data_visible); + /* free temp data */ + BLI_freelistN(&anim_data_visible); } /* Drivers Specific Stuff ------------------------------------------------- */ @@ -1068,27 +1058,30 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn /* Change the order drivers within AnimData block * mode: REARRANGE_ANIMCHAN_* */ -static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode) +static void rearrange_driver_channels(bAnimContext *ac, + AnimData *adt, + eRearrangeAnimChan_Mode mode) { - /* get rearranging function */ - AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); - ListBase anim_data_visible = {NULL, NULL}; + /* get rearranging function */ + AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); + ListBase anim_data_visible = {NULL, NULL}; - if (rearrange_func == NULL) - return; + if (rearrange_func == NULL) + return; - /* only consider drivers if they're accessible */ - if (EXPANDED_DRVD(adt) == 0) - return; + /* only consider drivers if they're accessible */ + if (EXPANDED_DRVD(adt) == 0) + return; - /* Filter visible data. */ - rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE); + /* Filter visible data. */ + rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE); - /* perform rearranging on drivers list (drivers are really just F-Curves) */ - rearrange_animchannel_islands(&adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE, &anim_data_visible); + /* perform rearranging on drivers list (drivers are really just F-Curves) */ + rearrange_animchannel_islands( + &adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE, &anim_data_visible); - /* free temp data */ - BLI_freelistN(&anim_data_visible); + /* free temp data */ + BLI_freelistN(&anim_data_visible); } /* Action Specific Stuff ------------------------------------------------- */ @@ -1096,88 +1089,88 @@ static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, eRearrang /* make sure all action-channels belong to a group (and clear action's list) */ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp) { - bActionGroup *agrp; - FCurve *fcu; - - if (act == NULL) - return; - - /* Separate F-Curves into lists per group */ - for (agrp = act->groups.first; agrp; agrp = agrp->next) { - if (agrp->channels.first) { - fcu = agrp->channels.last; - act->curves.first = fcu->next; - - fcu = agrp->channels.first; - fcu->prev = NULL; - - fcu = agrp->channels.last; - fcu->next = NULL; - } - } - - /* Initialize memory for temp-group */ - memset(tgrp, 0, sizeof(bActionGroup)); - tgrp->flag |= (AGRP_EXPANDED | AGRP_TEMP); - BLI_strncpy(tgrp->name, "#TempGroup", sizeof(tgrp->name)); - - /* Move any action-channels not already moved, to the temp group */ - if (act->curves.first) { - /* start of list */ - fcu = act->curves.first; - fcu->prev = NULL; - tgrp->channels.first = fcu; - act->curves.first = NULL; - - /* end of list */ - fcu = act->curves.last; - fcu->next = NULL; - tgrp->channels.last = fcu; - act->curves.last = NULL; - - /* ensure that all of these get their group set to this temp group - * (so that visibility filtering works) - */ - for (fcu = tgrp->channels.first; fcu; fcu = fcu->next) { - fcu->grp = tgrp; - } - } - - /* Add temp-group to list */ - BLI_addtail(&act->groups, tgrp); + bActionGroup *agrp; + FCurve *fcu; + + if (act == NULL) + return; + + /* Separate F-Curves into lists per group */ + for (agrp = act->groups.first; agrp; agrp = agrp->next) { + if (agrp->channels.first) { + fcu = agrp->channels.last; + act->curves.first = fcu->next; + + fcu = agrp->channels.first; + fcu->prev = NULL; + + fcu = agrp->channels.last; + fcu->next = NULL; + } + } + + /* Initialize memory for temp-group */ + memset(tgrp, 0, sizeof(bActionGroup)); + tgrp->flag |= (AGRP_EXPANDED | AGRP_TEMP); + BLI_strncpy(tgrp->name, "#TempGroup", sizeof(tgrp->name)); + + /* Move any action-channels not already moved, to the temp group */ + if (act->curves.first) { + /* start of list */ + fcu = act->curves.first; + fcu->prev = NULL; + tgrp->channels.first = fcu; + act->curves.first = NULL; + + /* end of list */ + fcu = act->curves.last; + fcu->next = NULL; + tgrp->channels.last = fcu; + act->curves.last = NULL; + + /* ensure that all of these get their group set to this temp group + * (so that visibility filtering works) + */ + for (fcu = tgrp->channels.first; fcu; fcu = fcu->next) { + fcu->grp = tgrp; + } + } + + /* Add temp-group to list */ + BLI_addtail(&act->groups, tgrp); } /* link lists of channels that groups have */ static void join_groups_action_temp(bAction *act) { - bActionGroup *agrp; + bActionGroup *agrp; - for (agrp = act->groups.first; agrp; agrp = agrp->next) { - ListBase tempGroup; + for (agrp = act->groups.first; agrp; agrp = agrp->next) { + ListBase tempGroup; - /* add list of channels to action's channels */ - tempGroup = agrp->channels; - BLI_movelisttolist(&act->curves, &agrp->channels); - agrp->channels = tempGroup; + /* add list of channels to action's channels */ + tempGroup = agrp->channels; + BLI_movelisttolist(&act->curves, &agrp->channels); + agrp->channels = tempGroup; - /* clear moved flag */ - agrp->flag &= ~AGRP_MOVED; + /* clear moved flag */ + agrp->flag &= ~AGRP_MOVED; - /* if group was temporary one: - * - unassign all FCurves which were temporarily added to it - * - remove from list (but don't free as it's on the stack!) - */ - if (agrp->flag & AGRP_TEMP) { - FCurve *fcu; + /* if group was temporary one: + * - unassign all FCurves which were temporarily added to it + * - remove from list (but don't free as it's on the stack!) + */ + if (agrp->flag & AGRP_TEMP) { + FCurve *fcu; - for (fcu = agrp->channels.first; fcu; fcu = fcu->next) { - fcu->grp = NULL; - } + for (fcu = agrp->channels.first; fcu; fcu = fcu->next) { + fcu->grp = NULL; + } - BLI_remlink(&act->groups, agrp); - break; - } - } + BLI_remlink(&act->groups, agrp); + break; + } + } } /* Change the order of anim-channels within action @@ -1185,635 +1178,644 @@ static void join_groups_action_temp(bAction *act) */ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrangeAnimChan_Mode mode) { - bActionGroup tgrp; - ListBase anim_data_visible = {NULL, NULL}; - bool do_channels; + bActionGroup tgrp; + ListBase anim_data_visible = {NULL, NULL}; + bool do_channels; - /* get rearranging function */ - AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); + /* get rearranging function */ + AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); - if (rearrange_func == NULL) - return; + if (rearrange_func == NULL) + return; - /* make sure we're only operating with groups (vs a mixture of groups+curves) */ - split_groups_action_temp(act, &tgrp); + /* make sure we're only operating with groups (vs a mixture of groups+curves) */ + split_groups_action_temp(act, &tgrp); - /* Filter visible data. */ - rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GROUP); + /* Filter visible data. */ + rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GROUP); - /* 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, - &anim_data_visible) == 0); + /* 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, &anim_data_visible) == 0); - /* free temp data */ - BLI_freelistN(&anim_data_visible); + /* free temp data */ + BLI_freelistN(&anim_data_visible); - if (do_channels) { - bActionGroup *agrp; + if (do_channels) { + bActionGroup *agrp; - /* Filter visible data. */ - rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE); + /* Filter visible data. */ + rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE); - for (agrp = act->groups.first; agrp; agrp = agrp->next) { - /* only consider F-Curves if they're visible (group expanded) */ - if (EXPANDED_AGRP(ac, agrp)) { - rearrange_animchannel_islands(&agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE, - &anim_data_visible); - } - } + for (agrp = act->groups.first; agrp; agrp = agrp->next) { + /* only consider F-Curves if they're visible (group expanded) */ + if (EXPANDED_AGRP(ac, agrp)) { + rearrange_animchannel_islands( + &agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE, &anim_data_visible); + } + } - /* free temp data */ - BLI_freelistN(&anim_data_visible); - } + /* free temp data */ + BLI_freelistN(&anim_data_visible); + } - /* assemble lists into one list (and clear moved tags) */ - join_groups_action_temp(act); + /* assemble lists into one list (and clear moved tags) */ + join_groups_action_temp(act); } /* ------------------- */ -static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode) +static void rearrange_nla_control_channels(bAnimContext *ac, + AnimData *adt, + eRearrangeAnimChan_Mode mode) { - ListBase anim_data_visible = {NULL, NULL}; + ListBase anim_data_visible = {NULL, NULL}; - NlaTrack *nlt; - NlaStrip *strip; + NlaTrack *nlt; + NlaStrip *strip; - /* get rearranging function */ - AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); + /* get rearranging function */ + AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); - if (rearrange_func == NULL) - return; + if (rearrange_func == NULL) + return; - /* skip if these curves aren't being shown */ - if (adt->flag & ADT_NLA_SKEYS_COLLAPSED) - return; + /* skip if these curves aren't being shown */ + if (adt->flag & ADT_NLA_SKEYS_COLLAPSED) + return; - /* Filter visible data. */ - rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE); + /* Filter visible data. */ + rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE); - /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - for (strip = nlt->strips.first; strip; strip = strip->next) { - rearrange_animchannel_islands( - &strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE, - &anim_data_visible); - } - } + /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + for (strip = nlt->strips.first; strip; strip = strip->next) { + rearrange_animchannel_islands( + &strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE, &anim_data_visible); + } + } - /* free temp data */ - BLI_freelistN(&anim_data_visible); + /* free temp data */ + BLI_freelistN(&anim_data_visible); } /* ------------------- */ static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - /* get rearranging function */ - AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); + /* get rearranging function */ + AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); - if (rearrange_func == NULL) - return; + if (rearrange_func == NULL) + return; - /* get Grease Pencil datablocks */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + /* get Grease Pencil datablocks */ + 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) { - ListBase anim_data_visible = {NULL, NULL}; - bGPdata *gpd = ale->data; + for (ale = anim_data.first; ale; ale = ale->next) { + ListBase anim_data_visible = {NULL, NULL}; + bGPdata *gpd = ale->data; - /* only consider layers if this datablock is open */ - BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK); - if ((gpd->flag & GP_DATA_EXPAND) == 0) - continue; + /* only consider layers if this datablock is open */ + BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK); + if ((gpd->flag & GP_DATA_EXPAND) == 0) + continue; - /* Filter visible data. */ - rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER); + /* Filter visible data. */ + rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER); - /* rearrange datablock's layers */ - rearrange_animchannel_islands(&gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible); + /* rearrange datablock's layers */ + rearrange_animchannel_islands( + &gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible); - /* free visible layers data */ - BLI_freelistN(&anim_data_visible); - } + /* free visible layers data */ + BLI_freelistN(&anim_data_visible); + } - /* free GPD channel data */ - ANIM_animdata_freelist(&anim_data); + /* free GPD channel data */ + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int animchannels_rearrange_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - eRearrangeAnimChan_Mode mode; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* get mode */ - mode = RNA_enum_get(op->ptr, "direction"); - - /* method to move channels depends on the editor */ - if (ac.datatype == ANIMCONT_GPENCIL) { - /* Grease Pencil channels */ - rearrange_gpencil_channels(&ac, mode); - } - else if (ac.datatype == ANIMCONT_MASK) { - /* Grease Pencil channels */ - printf("Mask does not supported for moving yet\n"); - } - else if (ac.datatype == ANIMCONT_ACTION) { - /* Directly rearrange action's channels */ - rearrange_action_channels(&ac, ac.data, mode); - } - else { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* get animdata blocks */ - 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) { - AnimData *adt = ale->data; - - switch (ac.datatype) { - case ANIMCONT_NLA: /* NLA-tracks only */ - rearrange_nla_channels(&ac, adt, mode); - DEG_id_tag_update(ale->id, ID_RECALC_ANIMATION); - break; - - case ANIMCONT_DRIVERS: /* Drivers list only */ - rearrange_driver_channels(&ac, adt, mode); - break; - - case ANIMCONT_ACTION: /* Single Action only... */ - case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME... - { - if (adt->action) - rearrange_action_channels(&ac, adt->action, mode); - else if (G.debug & G_DEBUG) - printf("Animdata has no action\n"); - break; - } - - default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */ - { - /* NLA Control Curves */ - if (adt->nla_tracks.first) - rearrange_nla_control_channels(&ac, adt, mode); - - /* Action */ - if (adt->action) - rearrange_action_channels(&ac, adt->action, mode); - else if (G.debug & G_DEBUG) - printf("Animdata has no action\n"); - break; - } - } - } - - /* free temp data */ - ANIM_animdata_freelist(&anim_data); - } - - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - - return OPERATOR_FINISHED; + bAnimContext ac; + eRearrangeAnimChan_Mode mode; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get mode */ + mode = RNA_enum_get(op->ptr, "direction"); + + /* method to move channels depends on the editor */ + if (ac.datatype == ANIMCONT_GPENCIL) { + /* Grease Pencil channels */ + rearrange_gpencil_channels(&ac, mode); + } + else if (ac.datatype == ANIMCONT_MASK) { + /* Grease Pencil channels */ + printf("Mask does not supported for moving yet\n"); + } + else if (ac.datatype == ANIMCONT_ACTION) { + /* Directly rearrange action's channels */ + rearrange_action_channels(&ac, ac.data, mode); + } + else { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get animdata blocks */ + 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) { + AnimData *adt = ale->data; + + switch (ac.datatype) { + case ANIMCONT_NLA: /* NLA-tracks only */ + rearrange_nla_channels(&ac, adt, mode); + DEG_id_tag_update(ale->id, ID_RECALC_ANIMATION); + break; + + case ANIMCONT_DRIVERS: /* Drivers list only */ + rearrange_driver_channels(&ac, adt, mode); + break; + + case ANIMCONT_ACTION: /* Single Action only... */ + case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME... + { + if (adt->action) + rearrange_action_channels(&ac, adt->action, mode); + else if (G.debug & G_DEBUG) + printf("Animdata has no action\n"); + break; + } + + default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */ + { + /* NLA Control Curves */ + if (adt->nla_tracks.first) + rearrange_nla_control_channels(&ac, adt, mode); + + /* Action */ + if (adt->action) + rearrange_action_channels(&ac, adt->action, mode); + else if (G.debug & G_DEBUG) + printf("Animdata has no action\n"); + break; + } + } + } + + /* free temp data */ + ANIM_animdata_freelist(&anim_data); + } + + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + + return OPERATOR_FINISHED; } static void ANIM_OT_channels_move(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Move Channels"; - ot->idname = "ANIM_OT_channels_move"; - ot->description = "Rearrange selected animation channels"; + /* identifiers */ + ot->name = "Move Channels"; + ot->idname = "ANIM_OT_channels_move"; + ot->description = "Rearrange selected animation channels"; - /* api callbacks */ - ot->exec = animchannels_rearrange_exec; - ot->poll = animedit_poll_channels_nla_tweakmode_off; + /* api callbacks */ + ot->exec = animchannels_rearrange_exec; + ot->poll = animedit_poll_channels_nla_tweakmode_off; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - ot->prop = RNA_def_enum(ot->srna, "direction", prop_animchannel_rearrange_types, REARRANGE_ANIMCHAN_DOWN, "Direction", ""); + /* props */ + ot->prop = RNA_def_enum(ot->srna, + "direction", + prop_animchannel_rearrange_types, + REARRANGE_ANIMCHAN_DOWN, + "Direction", + ""); } /* ******************** Group Channel Operator ************************ */ static bool animchannels_grouping_poll(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - SpaceLink *sl; + ScrArea *sa = CTX_wm_area(C); + SpaceLink *sl; - /* channels region test */ - /* TODO: could enhance with actually testing if channels region? */ - if (ELEM(NULL, sa, CTX_wm_region(C))) - return 0; + /* channels region test */ + /* TODO: could enhance with actually testing if channels region? */ + if (ELEM(NULL, sa, CTX_wm_region(C))) + return 0; - /* animation editor test - must be suitable modes only */ - sl = CTX_wm_space_data(C); + /* animation editor test - must be suitable modes only */ + sl = CTX_wm_space_data(C); - switch (sa->spacetype) { - /* supported... */ - case SPACE_ACTION: - { - SpaceAction *saction = (SpaceAction *)sl; + switch (sa->spacetype) { + /* supported... */ + case SPACE_ACTION: { + SpaceAction *saction = (SpaceAction *)sl; - /* dopesheet and action only - all others are for other datatypes or have no groups */ - if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0) - return 0; + /* dopesheet and action only - all others are for other datatypes or have no groups */ + if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0) + return 0; - break; - } - case SPACE_GRAPH: - { - SpaceGraph *sipo = (SpaceGraph *)sl; + break; + } + case SPACE_GRAPH: { + SpaceGraph *sipo = (SpaceGraph *)sl; - /* drivers can't have groups... */ - if (sipo->mode != SIPO_MODE_ANIMATION) - return 0; + /* drivers can't have groups... */ + if (sipo->mode != SIPO_MODE_ANIMATION) + return 0; - break; - } - /* unsupported... */ - default: - return 0; - } + break; + } + /* unsupported... */ + default: + return 0; + } - return 1; + return 1; } /* ----------------------------------------------------------- */ -static void animchannels_group_channels(bAnimContext *ac, bAnimListElem *adt_ref, const char name[]) +static void animchannels_group_channels(bAnimContext *ac, + bAnimListElem *adt_ref, + const char name[]) { - AnimData *adt = adt_ref->adt; - bAction *act = adt->action; + AnimData *adt = adt_ref->adt; + bAction *act = adt->action; - if (act) { - ListBase anim_data = {NULL, NULL}; - int filter; + if (act) { + ListBase anim_data = {NULL, NULL}; + int filter; - /* find selected F-Curves to re-group */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL); - ANIM_animdata_filter(ac, &anim_data, filter, adt_ref, ANIMCONT_CHANNEL); + /* find selected F-Curves to re-group */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL); + ANIM_animdata_filter(ac, &anim_data, filter, adt_ref, ANIMCONT_CHANNEL); - if (anim_data.first) { - bActionGroup *agrp; - bAnimListElem *ale; + if (anim_data.first) { + bActionGroup *agrp; + bAnimListElem *ale; - /* create new group, which should now be part of the action */ - agrp = action_groups_add_new(act, name); - BLI_assert(agrp != NULL); + /* create new group, which should now be part of the action */ + agrp = action_groups_add_new(act, name); + BLI_assert(agrp != NULL); - /* transfer selected F-Curves across to new group */ - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->data; - bActionGroup *grp = fcu->grp; + /* transfer selected F-Curves across to new group */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->data; + bActionGroup *grp = fcu->grp; - /* remove F-Curve from group, then group too if it is now empty */ - action_groups_remove_channel(act, fcu); + /* remove F-Curve from group, then group too if it is now empty */ + action_groups_remove_channel(act, fcu); - if ((grp) && BLI_listbase_is_empty(&grp->channels)) { - BLI_freelinkN(&act->groups, grp); - } + if ((grp) && BLI_listbase_is_empty(&grp->channels)) { + BLI_freelinkN(&act->groups, grp); + } - /* add F-Curve to group */ - action_groups_add_channel(act, agrp, fcu); - } - } + /* add F-Curve to group */ + action_groups_add_channel(act, agrp, fcu); + } + } - /* cleanup */ - ANIM_animdata_freelist(&anim_data); - } + /* cleanup */ + ANIM_animdata_freelist(&anim_data); + } } static int animchannels_group_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - char name[MAX_NAME]; + bAnimContext ac; + char name[MAX_NAME]; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* get name for new group */ - RNA_string_get(op->ptr, "name", name); + /* get name for new group */ + RNA_string_get(op->ptr, "name", name); - /* XXX: name for group should never be empty... */ - if (name[0]) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + /* XXX: name for group should never be empty... */ + if (name[0]) { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - /* handle each animdata block separately, so that the regrouping doesn't flow into blocks */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + /* handle each animdata block separately, so that the regrouping doesn't flow into blocks */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - for (ale = anim_data.first; ale; ale = ale->next) { - animchannels_group_channels(&ac, ale, name); - } + for (ale = anim_data.first; ale; ale = ale->next) { + animchannels_group_channels(&ac, ale, name); + } - /* free temp data */ - ANIM_animdata_freelist(&anim_data); + /* free temp data */ + ANIM_animdata_freelist(&anim_data); - /* updatss */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - } + /* updatss */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_channels_group(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Group Channels"; - ot->idname = "ANIM_OT_channels_group"; - ot->description = "Add selected F-Curves to a new group"; + /* identifiers */ + ot->name = "Group Channels"; + ot->idname = "ANIM_OT_channels_group"; + ot->description = "Add selected F-Curves to a new group"; - /* callbacks */ - ot->invoke = WM_operator_props_popup; - ot->exec = animchannels_group_exec; - ot->poll = animchannels_grouping_poll; + /* callbacks */ + ot->invoke = WM_operator_props_popup; + ot->exec = animchannels_group_exec; + ot->poll = animchannels_grouping_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - ot->prop = RNA_def_string(ot->srna, "name", "New Group", - sizeof(((bActionGroup *)NULL)->name), - "Name", "Name of newly created group"); - /* XXX: still not too sure about this - keeping same text is confusing... */ - // RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + /* props */ + ot->prop = RNA_def_string(ot->srna, + "name", + "New Group", + sizeof(((bActionGroup *)NULL)->name), + "Name", + "Name of newly created group"); + /* XXX: still not too sure about this - keeping same text is confusing... */ + // RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); } /* ----------------------------------------------------------- */ static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; + bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* just selected F-Curves... */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + /* just selected F-Curves... */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | + ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - for (ale = anim_data.first; ale; ale = ale->next) { - /* find action for this F-Curve... */ - if (ale->adt && ale->adt->action) { - FCurve *fcu = (FCurve *)ale->data; - bAction *act = ale->adt->action; + for (ale = anim_data.first; ale; ale = ale->next) { + /* find action for this F-Curve... */ + if (ale->adt && ale->adt->action) { + FCurve *fcu = (FCurve *)ale->data; + bAction *act = ale->adt->action; - /* only proceed to remove if F-Curve is in a group... */ - if (fcu->grp) { - bActionGroup *agrp = fcu->grp; + /* only proceed to remove if F-Curve is in a group... */ + if (fcu->grp) { + bActionGroup *agrp = fcu->grp; - /* remove F-Curve from group and add at tail (ungrouped) */ - action_groups_remove_channel(act, fcu); - BLI_addtail(&act->curves, fcu); + /* remove F-Curve from group and add at tail (ungrouped) */ + action_groups_remove_channel(act, fcu); + BLI_addtail(&act->curves, fcu); - /* delete group if it is now empty */ - if (BLI_listbase_is_empty(&agrp->channels)) { - BLI_freelinkN(&act->groups, agrp); - } - } - } - } + /* delete group if it is now empty */ + if (BLI_listbase_is_empty(&agrp->channels)) { + BLI_freelinkN(&act->groups, agrp); + } + } + } + } - /* cleanup */ - ANIM_animdata_freelist(&anim_data); + /* cleanup */ + ANIM_animdata_freelist(&anim_data); - /* updates */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* updates */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_channels_ungroup(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Ungroup Channels"; - ot->idname = "ANIM_OT_channels_ungroup"; - ot->description = "Remove selected F-Curves from their current groups"; + /* identifiers */ + ot->name = "Ungroup Channels"; + ot->idname = "ANIM_OT_channels_ungroup"; + ot->description = "Remove selected F-Curves from their current groups"; - /* callbacks */ - ot->exec = animchannels_ungroup_exec; - ot->poll = animchannels_grouping_poll; + /* callbacks */ + ot->exec = animchannels_ungroup_exec; + ot->poll = animchannels_grouping_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Delete Channel Operator *********************** */ static void update_dependencies_on_delete(bAnimListElem *ale) { - ID *id = ale->id; - AnimData *adt = BKE_animdata_from_id(id); - /* TODO(sergey): Technically, if the animation element is being deleted - * from a driver we don't have to tag action. This is something we can check - * for in the future. For now just do most reliable tag whic hwas always - * happening. */ - if (adt != NULL) { - DEG_id_tag_update(id, ID_RECALC_ANIMATION); - if (adt->action != NULL) { - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION); - } - } - /* Deals with NLA and drivers. - * Doesn't cause overhead for action updates, since object will receive - * animation update after dependency graph flushes update from action to - * all its users. */ - DEG_id_tag_update(id, ID_RECALC_ANIMATION); + ID *id = ale->id; + AnimData *adt = BKE_animdata_from_id(id); + /* TODO(sergey): Technically, if the animation element is being deleted + * from a driver we don't have to tag action. This is something we can check + * for in the future. For now just do most reliable tag whic hwas always + * happening. */ + if (adt != NULL) { + DEG_id_tag_update(id, ID_RECALC_ANIMATION); + if (adt->action != NULL) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION); + } + } + /* Deals with NLA and drivers. + * Doesn't cause overhead for action updates, since object will receive + * animation update after dependency graph flushes update from action to + * all its users. */ + DEG_id_tag_update(id, ID_RECALC_ANIMATION); } static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* cannot delete in shapekey */ - if (ac.datatype == ANIMCONT_SHAPEKEY) - return OPERATOR_CANCELLED; - - - /* do groups only first (unless in Drivers mode, where there are none) */ - if (ac.datatype != ANIMCONT_DRIVERS) { - /* filter data */ - 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 */ - for (ale = anim_data.first; ale; ale = ale->next) { - /* only groups - don't check other types yet, since they may no-longer exist */ - if (ale->type == ANIMTYPE_GROUP) { - bActionGroup *agrp = (bActionGroup *)ale->data; - AnimData *adt = ale->adt; - FCurve *fcu, *fcn; - - /* skip this group if no AnimData available, as we can't safely remove the F-Curves */ - if (adt == NULL) - continue; - - /* delete all of the Group's F-Curves, but no others */ - for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcn) { - fcn = fcu->next; - - /* remove from group and action, then free */ - action_groups_remove_channel(adt->action, fcu); - free_fcurve(fcu); - } - - /* free the group itself */ - if (adt->action) { - BLI_freelinkN(&adt->action->groups, agrp); - DEG_id_tag_update_ex(CTX_data_main(C), &adt->action->id, ID_RECALC_ANIMATION); - } - else - MEM_freeN(agrp); - } - } - - /* cleanup */ - ANIM_animdata_freelist(&anim_data); - } - - /* 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); - update_dependencies_on_delete(ale); - break; - } - case ANIMTYPE_NLACURVE: - { - /* NLA Control Curve - Deleting it should disable the corresponding setting... */ - NlaStrip *strip = (NlaStrip *)ale->owner; - FCurve *fcu = (FCurve *)ale->data; - - if (STREQ(fcu->rna_path, "strip_time")) { - strip->flag &= ~NLASTRIP_FLAG_USR_TIME; - } - else if (STREQ(fcu->rna_path, "influence")) { - strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE; - } - else { - printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path); - } - - /* unlink and free the F-Curve */ - BLI_remlink(&strip->fcurves, fcu); - free_fcurve(fcu); - update_dependencies_on_delete(ale); - 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 */ - BKE_gpencil_layer_delete(gpd, gpl); - ale->update = ANIM_UPDATE_DEPS; - break; - } - case ANIMTYPE_MASKLAYER: - { - /* Mask layer */ - Mask *mask = (Mask *)ale->id; - MaskLayer *masklay = (MaskLayer *)ale->data; - - /* try to delete the layer's data and the layer itself */ - BKE_mask_layer_remove(mask, masklay); - break; - } - } - } - - /* cleanup */ - ANIM_animdata_freelist(&anim_data); - - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - DEG_relations_tag_update(CTX_data_main(C)); - - return OPERATOR_FINISHED; + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* cannot delete in shapekey */ + if (ac.datatype == ANIMCONT_SHAPEKEY) + return OPERATOR_CANCELLED; + + /* do groups only first (unless in Drivers mode, where there are none) */ + if (ac.datatype != ANIMCONT_DRIVERS) { + /* filter data */ + 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 */ + for (ale = anim_data.first; ale; ale = ale->next) { + /* only groups - don't check other types yet, since they may no-longer exist */ + if (ale->type == ANIMTYPE_GROUP) { + bActionGroup *agrp = (bActionGroup *)ale->data; + AnimData *adt = ale->adt; + FCurve *fcu, *fcn; + + /* skip this group if no AnimData available, as we can't safely remove the F-Curves */ + if (adt == NULL) + continue; + + /* delete all of the Group's F-Curves, but no others */ + for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcn) { + fcn = fcu->next; + + /* remove from group and action, then free */ + action_groups_remove_channel(adt->action, fcu); + free_fcurve(fcu); + } + + /* free the group itself */ + if (adt->action) { + BLI_freelinkN(&adt->action->groups, agrp); + DEG_id_tag_update_ex(CTX_data_main(C), &adt->action->id, ID_RECALC_ANIMATION); + } + else + MEM_freeN(agrp); + } + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); + } + + /* 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); + update_dependencies_on_delete(ale); + break; + } + case ANIMTYPE_NLACURVE: { + /* NLA Control Curve - Deleting it should disable the corresponding setting... */ + NlaStrip *strip = (NlaStrip *)ale->owner; + FCurve *fcu = (FCurve *)ale->data; + + if (STREQ(fcu->rna_path, "strip_time")) { + strip->flag &= ~NLASTRIP_FLAG_USR_TIME; + } + else if (STREQ(fcu->rna_path, "influence")) { + strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE; + } + else { + printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", + fcu->rna_path); + } + + /* unlink and free the F-Curve */ + BLI_remlink(&strip->fcurves, fcu); + free_fcurve(fcu); + update_dependencies_on_delete(ale); + 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 */ + BKE_gpencil_layer_delete(gpd, gpl); + ale->update = ANIM_UPDATE_DEPS; + break; + } + case ANIMTYPE_MASKLAYER: { + /* Mask layer */ + Mask *mask = (Mask *)ale->id; + MaskLayer *masklay = (MaskLayer *)ale->data; + + /* try to delete the layer's data and the layer itself */ + BKE_mask_layer_remove(mask, masklay); + break; + } + } + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); + + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + DEG_relations_tag_update(CTX_data_main(C)); + + return OPERATOR_FINISHED; } static void ANIM_OT_channels_delete(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Channels"; - ot->idname = "ANIM_OT_channels_delete"; - ot->description = "Delete all selected animation channels"; + /* identifiers */ + ot->name = "Delete Channels"; + ot->idname = "ANIM_OT_channels_delete"; + ot->description = "Delete all selected animation channels"; - /* api callbacks */ - ot->exec = animchannels_delete_exec; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->exec = animchannels_delete_exec; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ********************** Set Flags Operator *********************** */ /* defines for setting animation-channel flags */ static const EnumPropertyItem prop_animchannel_setflag_types[] = { - {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""}, - {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""}, - {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""}, - {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""}, - {0, NULL, 0, NULL, NULL}, + {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""}, + {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""}, + {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""}, + {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""}, + {0, NULL, 0, NULL, NULL}, }; /* defines for set animation-channel settings */ // TODO: could add some more types, but those are really quite dependent on the mode... static const EnumPropertyItem prop_animchannel_settings_types[] = { - {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""}, - {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""}, - {0, NULL, 0, NULL, NULL}, + {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""}, + {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""}, + {0, NULL, 0, NULL, NULL}, }; - /* ------------------- */ /* Set/clear a particular flag (setting) for all selected + visible channels @@ -1822,288 +1824,302 @@ static const EnumPropertyItem prop_animchannel_settings_types[] = { * onlysel: only selected channels get the flag set */ // TODO: enable a setting which turns flushing on/off? -static void setflag_anim_channels(bAnimContext *ac, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode, bool onlysel, bool flush) -{ - ListBase anim_data = {NULL, NULL}; - ListBase all_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* filter data that we need if flush is on */ - if (flush) { - /* 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 - * - 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_GRAPH) && (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); - - /* if toggling, check if disable or enable */ - if (mode == ACHANNEL_SETFLAG_TOGGLE) { - /* default to turn all on, unless we encounter one that's on... */ - mode = ACHANNEL_SETFLAG_ADD; - - /* see if we should turn off instead... */ - for (ale = anim_data.first; ale; ale = ale->next) { - /* set the setting in the appropriate way (if available) */ - if (ANIM_channel_setting_get(ac, ale, setting) > 0) { - mode = ACHANNEL_SETFLAG_CLEAR; - break; - } - } - } - - /* apply the setting */ - for (ale = anim_data.first; ale; ale = ale->next) { - /* skip channel if setting is not available */ - if (ANIM_channel_setting_get(ac, ale, setting) == -1) - continue; - - /* set the setting in the appropriate way */ - ANIM_channel_setting_set(ac, ale, setting, mode); - - /* if flush status... */ - if (flush) - ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode); - } - - ANIM_animdata_freelist(&anim_data); - BLI_freelistN(&all_data); +static void setflag_anim_channels(bAnimContext *ac, + eAnimChannel_Settings setting, + eAnimChannels_SetFlag mode, + bool onlysel, + bool flush) +{ + ListBase anim_data = {NULL, NULL}; + ListBase all_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* filter data that we need if flush is on */ + if (flush) { + /* 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 + * - 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_GRAPH) && (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); + + /* if toggling, check if disable or enable */ + if (mode == ACHANNEL_SETFLAG_TOGGLE) { + /* default to turn all on, unless we encounter one that's on... */ + mode = ACHANNEL_SETFLAG_ADD; + + /* see if we should turn off instead... */ + for (ale = anim_data.first; ale; ale = ale->next) { + /* set the setting in the appropriate way (if available) */ + if (ANIM_channel_setting_get(ac, ale, setting) > 0) { + mode = ACHANNEL_SETFLAG_CLEAR; + break; + } + } + } + + /* apply the setting */ + for (ale = anim_data.first; ale; ale = ale->next) { + /* skip channel if setting is not available */ + if (ANIM_channel_setting_get(ac, ale, setting) == -1) + continue; + + /* set the setting in the appropriate way */ + ANIM_channel_setting_set(ac, ale, setting, mode); + + /* if flush status... */ + if (flush) + ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode); + } + + ANIM_animdata_freelist(&anim_data); + BLI_freelistN(&all_data); } /* ------------------- */ static int animchannels_setflag_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - eAnimChannel_Settings setting; - eAnimChannels_SetFlag mode; - bool flush = true; + bAnimContext ac; + eAnimChannel_Settings setting; + eAnimChannels_SetFlag mode; + bool flush = true; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */ - mode = RNA_enum_get(op->ptr, "mode"); - setting = RNA_enum_get(op->ptr, "type"); + /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */ + mode = RNA_enum_get(op->ptr, "mode"); + setting = RNA_enum_get(op->ptr, "type"); - /* check if setting is flushable */ - if (setting == ACHANNEL_SETTING_EXPAND) - flush = false; + /* check if setting is flushable */ + if (setting == ACHANNEL_SETTING_EXPAND) + flush = false; - /* modify setting - * - only selected channels are affected - */ - setflag_anim_channels(&ac, setting, mode, true, flush); + /* modify setting + * - only selected channels are affected + */ + setflag_anim_channels(&ac, setting, mode, true, flush); - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } /* duplicate of 'ANIM_OT_channels_setting_toggle' for menu title only, weak! */ static void ANIM_OT_channels_setting_enable(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Enable Channel Setting"; - ot->idname = "ANIM_OT_channels_setting_enable"; - ot->description = "Enable specified setting on all selected animation channels"; + /* identifiers */ + ot->name = "Enable Channel Setting"; + ot->idname = "ANIM_OT_channels_setting_enable"; + ot->description = "Enable specified setting on all selected animation channels"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = animchannels_setflag_exec; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = animchannels_setflag_exec; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - /* flag-setting mode */ - prop = RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); - /* setting to set */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); + /* props */ + /* flag-setting mode */ + prop = RNA_def_enum( + ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + /* setting to set */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); } /* duplicate of 'ANIM_OT_channels_setting_toggle' for menu title only, weak! */ static void ANIM_OT_channels_setting_disable(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Disable Channel Setting"; - ot->idname = "ANIM_OT_channels_setting_disable"; - ot->description = "Disable specified setting on all selected animation channels"; + /* identifiers */ + ot->name = "Disable Channel Setting"; + ot->idname = "ANIM_OT_channels_setting_disable"; + ot->description = "Disable specified setting on all selected animation channels"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = animchannels_setflag_exec; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = animchannels_setflag_exec; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - /* flag-setting mode */ - prop = RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */ - /* setting to set */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); + /* props */ + /* flag-setting mode */ + prop = RNA_def_enum( + ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */ + /* setting to set */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); } static void ANIM_OT_channels_setting_toggle(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Toggle Channel Setting"; - ot->idname = "ANIM_OT_channels_setting_toggle"; - ot->description = "Toggle specified setting on all selected animation channels"; + /* identifiers */ + ot->name = "Toggle Channel Setting"; + ot->idname = "ANIM_OT_channels_setting_toggle"; + ot->description = "Toggle specified setting on all selected animation channels"; - /* api callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = animchannels_setflag_exec; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = animchannels_setflag_exec; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - /* flag-setting mode */ - prop = RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */ - /* setting to set */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); + /* props */ + /* flag-setting mode */ + prop = RNA_def_enum( + ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */ + /* setting to set */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); } static void ANIM_OT_channels_editable_toggle(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Toggle Channel Editability"; - ot->idname = "ANIM_OT_channels_editable_toggle"; - ot->description = "Toggle editability of selected channels"; + /* identifiers */ + ot->name = "Toggle Channel Editability"; + ot->idname = "ANIM_OT_channels_editable_toggle"; + ot->description = "Toggle editability of selected channels"; - /* api callbacks */ - ot->exec = animchannels_setflag_exec; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->exec = animchannels_setflag_exec; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - /* flag-setting mode */ - RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", ""); - /* setting to set */ - prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */ + /* props */ + /* flag-setting mode */ + RNA_def_enum( + ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", ""); + /* setting to set */ + prop = RNA_def_enum( + ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */ } /* ********************** Expand Channels Operator *********************** */ static int animchannels_expand_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - bool onlysel = true; + bAnimContext ac; + bool onlysel = true; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* only affect selected channels? */ - if (RNA_boolean_get(op->ptr, "all")) - onlysel = false; + /* only affect selected channels? */ + if (RNA_boolean_get(op->ptr, "all")) + onlysel = false; - /* modify setting */ - setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, false); + /* modify setting */ + setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, false); - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_channels_expand(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Expand Channels"; - ot->idname = "ANIM_OT_channels_expand"; - ot->description = "Expand (i.e. open) all selected expandable animation channels"; + /* identifiers */ + ot->name = "Expand Channels"; + ot->idname = "ANIM_OT_channels_expand"; + ot->description = "Expand (i.e. open) all selected expandable animation channels"; - /* api callbacks */ - ot->exec = animchannels_expand_exec; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->exec = animchannels_expand_exec; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)"); + /* props */ + ot->prop = RNA_def_boolean( + ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)"); } /* ********************** Collapse Channels Operator *********************** */ static int animchannels_collapse_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - bool onlysel = true; + bAnimContext ac; + bool onlysel = true; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* only affect selected channels? */ - if (RNA_boolean_get(op->ptr, "all")) - onlysel = false; + /* only affect selected channels? */ + if (RNA_boolean_get(op->ptr, "all")) + onlysel = false; - /* modify setting */ - setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, false); + /* modify setting */ + setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, false); - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_channels_collapse(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Collapse Channels"; - ot->idname = "ANIM_OT_channels_collapse"; - ot->description = "Collapse (i.e. close) all selected expandable animation channels"; + /* identifiers */ + ot->name = "Collapse Channels"; + ot->idname = "ANIM_OT_channels_collapse"; + ot->description = "Collapse (i.e. close) all selected expandable animation channels"; - /* api callbacks */ - ot->exec = animchannels_collapse_exec; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->exec = animchannels_collapse_exec; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* props */ - ot->prop = RNA_def_boolean(ot->srna, "all", true, "All", "Collapse all channels (not just selected ones)"); + /* props */ + ot->prop = RNA_def_boolean( + ot->srna, "all", true, "All", "Collapse all channels (not just selected ones)"); } /* ************ Remove All "Empty" AnimData Blocks Operator ********* */ @@ -2120,170 +2136,169 @@ static void ANIM_OT_channels_collapse(wmOperatorType *ot) static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; - - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* get animdata blocks */ - 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) { - ID *id = ale->id; - AnimData *adt = ale->data; - - bool action_empty = false; - bool nla_empty = false; - bool drivers_empty = false; - - /* sanity checks */ - BLI_assert((id != NULL) && (adt != NULL)); - - /* check if this is "empty" and can be deleted */ - /* (For now, there are only these 3 criteria) */ - - /* 1) Active Action is missing or empty */ - if (ELEM(NULL, adt->action, adt->action->curves.first)) { - action_empty = true; - } - else { - /* TODO: check for keyframe + fmodifier data on these too */ - } - - /* 2) No NLA Tracks and/or NLA Strips */ - if (adt->nla_tracks.first == NULL) { - nla_empty = true; - } - else { - NlaTrack *nlt; - - /* empty tracks? */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - if (nlt->strips.first) { - /* stop searching, as we found one that actually had stuff we don't want lost - * NOTE: nla_empty gets reset to false, as a previous track may have been empty - */ - nla_empty = false; - break; - } - else if (nlt->strips.first == NULL) { - /* this track is empty, but another one may still have stuff in it, so can't break yet */ - nla_empty = true; - } - } - } - - /* 3) Drivers */ - drivers_empty = (adt->drivers.first == NULL); - - - /* remove AnimData? */ - if (action_empty && nla_empty && drivers_empty) { - BKE_animdata_free(id, true); - } - } - - /* free temp data */ - ANIM_animdata_freelist(&anim_data); - - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - - return OPERATOR_FINISHED; + bAnimContext ac; + + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get animdata blocks */ + 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) { + ID *id = ale->id; + AnimData *adt = ale->data; + + bool action_empty = false; + bool nla_empty = false; + bool drivers_empty = false; + + /* sanity checks */ + BLI_assert((id != NULL) && (adt != NULL)); + + /* check if this is "empty" and can be deleted */ + /* (For now, there are only these 3 criteria) */ + + /* 1) Active Action is missing or empty */ + if (ELEM(NULL, adt->action, adt->action->curves.first)) { + action_empty = true; + } + else { + /* TODO: check for keyframe + fmodifier data on these too */ + } + + /* 2) No NLA Tracks and/or NLA Strips */ + if (adt->nla_tracks.first == NULL) { + nla_empty = true; + } + else { + NlaTrack *nlt; + + /* empty tracks? */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + if (nlt->strips.first) { + /* stop searching, as we found one that actually had stuff we don't want lost + * NOTE: nla_empty gets reset to false, as a previous track may have been empty + */ + nla_empty = false; + break; + } + else if (nlt->strips.first == NULL) { + /* this track is empty, but another one may still have stuff in it, so can't break yet */ + nla_empty = true; + } + } + } + + /* 3) Drivers */ + drivers_empty = (adt->drivers.first == NULL); + + /* remove AnimData? */ + if (action_empty && nla_empty && drivers_empty) { + BKE_animdata_free(id, true); + } + } + + /* free temp data */ + ANIM_animdata_freelist(&anim_data); + + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + + return OPERATOR_FINISHED; } static void ANIM_OT_channels_clean_empty(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Empty Animation Data"; - ot->idname = "ANIM_OT_channels_clean_empty"; - ot->description = "Delete all empty animation data containers from visible data-blocks"; + /* identifiers */ + ot->name = "Remove Empty Animation Data"; + ot->idname = "ANIM_OT_channels_clean_empty"; + ot->description = "Delete all empty animation data containers from visible data-blocks"; - /* api callbacks */ - ot->exec = animchannels_clean_empty_exec; - ot->poll = animedit_poll_channels_nla_tweakmode_off; + /* api callbacks */ + ot->exec = animchannels_clean_empty_exec; + ot->poll = animedit_poll_channels_nla_tweakmode_off; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************* Reenable Disabled Operator ******************* */ static bool animchannels_enable_poll(bContext *C) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *sa = CTX_wm_area(C); - /* channels region test */ - /* TODO: could enhance with actually testing if channels region? */ - if (ELEM(NULL, sa, CTX_wm_region(C))) - return 0; + /* channels region test */ + /* TODO: could enhance with actually testing if channels region? */ + if (ELEM(NULL, sa, CTX_wm_region(C))) + return 0; - /* animation editor test - Action/Dopesheet/etc. and Graph only */ - if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) - return 0; + /* animation editor test - Action/Dopesheet/etc. and Graph only */ + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) + return 0; - return 1; + return 1; } static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op)) { - bAnimContext ac; + bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* filter data */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + /* filter data */ + 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; + /* 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; + /* 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; + /* 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 */ - ale->update |= ANIM_UPDATE_DEPS; - } + /* tag everything for updates - in particular, this is needed to get drivers working again */ + ale->update |= ANIM_UPDATE_DEPS; + } - ANIM_animdata_update(&ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + ANIM_animdata_update(&ac, &anim_data); + ANIM_animdata_freelist(&anim_data); - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Revive Disabled F-Curves"; - ot->idname = "ANIM_OT_channels_fcurves_enable"; - ot->description = "Clears 'disabled' tag from all F-Curves to get broken F-Curves working again"; + /* identifiers */ + ot->name = "Revive Disabled F-Curves"; + ot->idname = "ANIM_OT_channels_fcurves_enable"; + ot->description = "Clears 'disabled' tag from all F-Curves to get broken F-Curves working again"; - /* api callbacks */ - ot->exec = animchannels_enable_exec; - ot->poll = animchannels_enable_poll; + /* api callbacks */ + ot->exec = animchannels_enable_exec; + ot->poll = animchannels_enable_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ****************** Find / Set Filter Operator ******************** */ @@ -2291,253 +2306,256 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot) /* XXX: make this generic? */ static bool animchannels_find_poll(bContext *C) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *sa = CTX_wm_area(C); - if (sa == NULL) - return 0; + if (sa == NULL) + return 0; - /* animation editor with dopesheet */ - return ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA); + /* animation editor with dopesheet */ + return ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA); } /* find_invoke() - Get initial channels */ static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *evt) { - bAnimContext ac; + bAnimContext ac; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* set initial filter text, and enable filter */ - RNA_string_set(op->ptr, "query", ac.ads->searchstr); + /* set initial filter text, and enable filter */ + RNA_string_set(op->ptr, "query", ac.ads->searchstr); - /* defer to popup */ - return WM_operator_props_popup(C, op, evt); + /* defer to popup */ + return WM_operator_props_popup(C, op, evt); } /* find_exec() - Called to set the value */ static int animchannels_find_exec(bContext *C, wmOperator *op) { - bAnimContext ac; + bAnimContext ac; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* update filter text */ - RNA_string_get(op->ptr, "query", ac.ads->searchstr); + /* update filter text */ + RNA_string_get(op->ptr, "query", ac.ads->searchstr); - /* redraw */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* redraw */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_channels_find(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Find Channels"; - ot->idname = "ANIM_OT_channels_find"; - ot->description = "Filter the set of channels shown to only include those with matching names"; + /* identifiers */ + ot->name = "Find Channels"; + ot->idname = "ANIM_OT_channels_find"; + ot->description = "Filter the set of channels shown to only include those with matching names"; - /* callbacks */ - ot->invoke = animchannels_find_invoke; - ot->exec = animchannels_find_exec; - ot->poll = animchannels_find_poll; + /* callbacks */ + ot->invoke = animchannels_find_invoke; + ot->exec = animchannels_find_exec; + ot->poll = animchannels_find_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - ot->prop = RNA_def_string(ot->srna, "query", "Query", sizeof(((bDopeSheet *)NULL)->searchstr), "", "Text to search for in channel names"); + /* properties */ + ot->prop = RNA_def_string(ot->srna, + "query", + "Query", + sizeof(((bDopeSheet *)NULL)->searchstr), + "", + "Text to search for in channel names"); } /* ********************** Select All Operator *********************** */ static int animchannels_deselectall_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* 'standard' behavior - check if selected, then apply relevant selection */ - const int action = RNA_enum_get(op->ptr, "action"); - switch (action) { - case SEL_TOGGLE: - ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD); - break; - case SEL_SELECT: - ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_ADD); - break; - case SEL_DESELECT: - ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_CLEAR); - break; - case SEL_INVERT: - ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT); - break; - default: - BLI_assert(0); - break; - } - - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); - - return OPERATOR_FINISHED; + bAnimContext ac; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* 'standard' behavior - check if selected, then apply relevant selection */ + const int action = RNA_enum_get(op->ptr, "action"); + switch (action) { + case SEL_TOGGLE: + ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD); + break; + case SEL_SELECT: + ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_ADD); + break; + case SEL_DESELECT: + ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_CLEAR); + break; + case SEL_INVERT: + ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT); + break; + default: + BLI_assert(0); + break; + } + + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; } static void ANIM_OT_channels_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select All"; - ot->idname = "ANIM_OT_channels_select_all"; - ot->description = "Toggle selection of all animation channels"; + /* identifiers */ + ot->name = "Select All"; + ot->idname = "ANIM_OT_channels_select_all"; + ot->description = "Toggle selection of all animation channels"; - /* api callbacks */ - ot->exec = animchannels_deselectall_exec; - ot->poll = animedit_poll_channels_nla_tweakmode_off; + /* api callbacks */ + ot->exec = animchannels_deselectall_exec; + ot->poll = animedit_poll_channels_nla_tweakmode_off; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - WM_operator_properties_select_all(ot); + /* properties */ + WM_operator_properties_select_all(ot); } /* ******************** Box Select Operator *********************** */ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectmode) { - ListBase anim_data = {NULL, NULL}; - 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(snla)); - ymax = 0.0f; - } - else { - ymin = 0.0f; - ymax = (float)(-ACHANNEL_HEIGHT(ac)); - } - - /* convert border-region to view coordinates */ - UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin + 2, &rectf.xmin, &rectf.ymin); - UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax - 2, &rectf.xmax, &rectf.ymax); - - /* filter data */ - 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 box select */ - for (ale = anim_data.first; ale; ale = ale->next) { - if (ac->datatype == ANIMCONT_NLA) - ymin = ymax - NLACHANNEL_STEP(snla); - else - ymin = ymax - ACHANNEL_STEP(ac); - - /* if channel is within border-select region, alter it */ - if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) { - /* set selection flags only */ - ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode); - - /* type specific actions */ - switch (ale->type) { - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = (bActionGroup *)ale->data; - select_pchan_for_action_group(ac, agrp, ale); - /* always clear active flag after doing this */ - agrp->flag &= ~AGRP_ACTIVE; - break; - } - case ANIMTYPE_NLATRACK: - { - NlaTrack *nlt = (NlaTrack *)ale->data; - - /* for now, it's easier just to do this here manually, as defining a new type - * currently adds complications when doing other stuff - */ - ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED); - break; - } - } - } - - /* set minimum extent to be the maximum of the next channel */ - ymax = ymin; - } - - /* cleanup */ - ANIM_animdata_freelist(&anim_data); + ListBase anim_data = {NULL, NULL}; + 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(snla)); + ymax = 0.0f; + } + else { + ymin = 0.0f; + ymax = (float)(-ACHANNEL_HEIGHT(ac)); + } + + /* convert border-region to view coordinates */ + UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin + 2, &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax - 2, &rectf.xmax, &rectf.ymax); + + /* filter data */ + 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 box select */ + for (ale = anim_data.first; ale; ale = ale->next) { + if (ac->datatype == ANIMCONT_NLA) + ymin = ymax - NLACHANNEL_STEP(snla); + else + ymin = ymax - ACHANNEL_STEP(ac); + + /* if channel is within border-select region, alter it */ + if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) { + /* set selection flags only */ + ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode); + + /* type specific actions */ + switch (ale->type) { + case ANIMTYPE_GROUP: { + bActionGroup *agrp = (bActionGroup *)ale->data; + select_pchan_for_action_group(ac, agrp, ale); + /* always clear active flag after doing this */ + agrp->flag &= ~AGRP_ACTIVE; + break; + } + case ANIMTYPE_NLATRACK: { + NlaTrack *nlt = (NlaTrack *)ale->data; + + /* for now, it's easier just to do this here manually, as defining a new type + * currently adds complications when doing other stuff + */ + ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED); + break; + } + } + } + + /* set minimum extent to be the maximum of the next channel */ + ymax = ymin; + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); } /* ------------------- */ static int animchannels_box_select_exec(bContext *C, wmOperator *op) { - bAnimContext ac; - rcti rect; - short selectmode = 0; - const bool select = !RNA_boolean_get(op->ptr, "deselect"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); + bAnimContext ac; + rcti rect; + short selectmode = 0; + const bool select = !RNA_boolean_get(op->ptr, "deselect"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - /* get settings from operator */ - WM_operator_properties_border_to_rcti(op, &rect); + /* get settings from operator */ + WM_operator_properties_border_to_rcti(op, &rect); - if (!extend) { - ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_CLEAR); - } + if (!extend) { + ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_CLEAR); + } - if (select) { - selectmode = ACHANNEL_SETFLAG_ADD; - } - else { - selectmode = ACHANNEL_SETFLAG_CLEAR; - } + if (select) { + selectmode = ACHANNEL_SETFLAG_ADD; + } + else { + selectmode = ACHANNEL_SETFLAG_CLEAR; + } - /* apply box_select animation channels */ - box_select_anim_channels(&ac, &rect, selectmode); + /* apply box_select animation channels */ + box_select_anim_channels(&ac, &rect, selectmode); - /* send notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); + /* send notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_channels_select_box(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Box Select"; - ot->idname = "ANIM_OT_channels_select_box"; - ot->description = "Select all animation channels within the specified region"; + /* identifiers */ + ot->name = "Box Select"; + ot->idname = "ANIM_OT_channels_select_box"; + ot->description = "Select all animation channels within the specified region"; - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = animchannels_box_select_exec; - ot->modal = WM_gesture_box_modal; - ot->cancel = WM_gesture_box_cancel; + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = animchannels_box_select_exec; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; - ot->poll = animedit_poll_channels_nla_tweakmode_off; + ot->poll = animedit_poll_channels_nla_tweakmode_off; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* rna */ - WM_operator_properties_gesture_box_select(ot); + /* rna */ + WM_operator_properties_gesture_box_select(ot); } /* ******************* Rename Operator ***************************** */ @@ -2545,114 +2563,131 @@ static void ANIM_OT_channels_select_box(wmOperatorType *ot) static bool rename_anim_channels(bAnimContext *ac, int channel_index) { - ListBase anim_data = {NULL, NULL}; - const bAnimChannelType *acf; - bAnimListElem *ale; - int filter; - bool success = false; - - /* get the channel that was clicked on */ - /* filter 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 */ - ale = BLI_findlink(&anim_data, channel_index); - if (ale == NULL) { - /* channel not found */ - if (G.debug & G_DEBUG) - printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index); - - ANIM_animdata_freelist(&anim_data); - return false; - } - - /* check that channel can be renamed */ - acf = ANIM_channel_get_typeinfo(ale); - if (acf && acf->name_prop) { - PointerRNA ptr; - PropertyRNA *prop; - - /* ok if we can get name property to edit from this channel */ - if (acf->name_prop(ale, &ptr, &prop)) { - /* actually showing the rename textfield is done on redraw, - * so here we just store the index of this channel in the - * dopesheet data, which will get utilized when drawing the - * channel... - * - * +1 factor is for backwards compat issues - */ - if (ac->ads) { - ac->ads->renameIndex = channel_index + 1; - success = true; - } - } - } - - /* free temp data and tag for refresh */ - ANIM_animdata_freelist(&anim_data); - ED_region_tag_redraw(ac->ar); - return success; + ListBase anim_data = {NULL, NULL}; + const bAnimChannelType *acf; + bAnimListElem *ale; + int filter; + bool success = false; + + /* get the channel that was clicked on */ + /* filter 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 */ + ale = BLI_findlink(&anim_data, channel_index); + if (ale == NULL) { + /* channel not found */ + if (G.debug & G_DEBUG) + printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", + channel_index); + + ANIM_animdata_freelist(&anim_data); + return false; + } + + /* check that channel can be renamed */ + acf = ANIM_channel_get_typeinfo(ale); + if (acf && acf->name_prop) { + PointerRNA ptr; + PropertyRNA *prop; + + /* ok if we can get name property to edit from this channel */ + if (acf->name_prop(ale, &ptr, &prop)) { + /* actually showing the rename textfield is done on redraw, + * so here we just store the index of this channel in the + * dopesheet data, which will get utilized when drawing the + * channel... + * + * +1 factor is for backwards compat issues + */ + if (ac->ads) { + ac->ads->renameIndex = channel_index + 1; + success = true; + } + } + } + + /* free temp data and tag for refresh */ + ANIM_animdata_freelist(&anim_data); + ED_region_tag_redraw(ac->ar); + return success; } static int animchannels_channel_get(bAnimContext *ac, const int mval[2]) { - ARegion *ar; - View2D *v2d; - int channel_index; - float x, y; - - /* get useful pointers from animation context data */ - ar = ac->ar; - v2d = &ar->v2d; - - /* figure out which channel user clicked in - * Note: although channels technically start at (y = ACHANNEL_FIRST), we need to adjust by half a channel's height - * 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); - - if (ac->datatype == ANIMCONT_NLA) { - SpaceNla *snla = (SpaceNla *)ac->sl; - UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index); - } - else { - UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); - } - - return channel_index; + ARegion *ar; + View2D *v2d; + int channel_index; + float x, y; + + /* get useful pointers from animation context data */ + ar = ac->ar; + v2d = &ar->v2d; + + /* figure out which channel user clicked in + * Note: although channels technically start at (y = ACHANNEL_FIRST), we need to adjust by half a channel's height + * 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); + + if (ac->datatype == ANIMCONT_NLA) { + SpaceNla *snla = (SpaceNla *)ac->sl; + UI_view2d_listview_view_to_cell(v2d, + NLACHANNEL_NAMEWIDTH, + NLACHANNEL_STEP(snla), + 0, + (float)NLACHANNEL_HEIGHT_HALF(snla), + x, + y, + NULL, + &channel_index); + } + else { + UI_view2d_listview_view_to_cell(v2d, + ACHANNEL_NAMEWIDTH, + ACHANNEL_STEP(ac), + 0, + (float)ACHANNEL_HEIGHT_HALF(ac), + x, + y, + NULL, + &channel_index); + } + + return channel_index; } static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - bAnimContext ac; - int channel_index; + bAnimContext ac; + int channel_index; - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; - channel_index = animchannels_channel_get(&ac, event->mval); + channel_index = animchannels_channel_get(&ac, event->mval); - /* handle click */ - if (rename_anim_channels(&ac, channel_index)) - return OPERATOR_FINISHED; - else - /* allow event to be handled by selectall operator */ - return OPERATOR_PASS_THROUGH; + /* handle click */ + if (rename_anim_channels(&ac, channel_index)) + return OPERATOR_FINISHED; + else + /* allow event to be handled by selectall operator */ + return OPERATOR_PASS_THROUGH; } static void ANIM_OT_channels_rename(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Rename Channels"; - ot->idname = "ANIM_OT_channels_rename"; - ot->description = "Rename animation channel under mouse"; + /* identifiers */ + ot->name = "Rename Channels"; + ot->idname = "ANIM_OT_channels_rename"; + ot->description = "Rename animation channel under mouse"; - /* api callbacks */ - ot->invoke = animchannels_rename_invoke; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->invoke = animchannels_rename_invoke; + ot->poll = animedit_poll_channels_active; } /* ******************** Mouse-Click Operator *********************** */ @@ -2660,357 +2695,355 @@ static void ANIM_OT_channels_rename(wmOperatorType *ot) static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, short selectmode) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - int notifierFlags = 0; - - /* get the channel that was clicked on */ - /* filter 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 */ - ale = BLI_findlink(&anim_data, channel_index); - if (ale == NULL) { - /* channel not found */ - if (G.debug & G_DEBUG) - printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n", channel_index); - - ANIM_animdata_freelist(&anim_data); - return 0; - } - - /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */ - /* TODO: should this feature be extended to work with other channel types too? */ - if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) { - /* normal channels should not behave normally in this case */ - ANIM_animdata_freelist(&anim_data); - return 0; - } - - /* action to take depends on what channel we've got */ - /* WARNING: must keep this in sync with the equivalent function in nla_channels.c */ - switch (ale->type) { - case ANIMTYPE_SCENE: - { - Scene *sce = (Scene *)ale->data; - AnimData *adt = sce->adt; - - /* set selection status */ - if (selectmode == SELECT_INVERT) { - /* swap select */ - sce->flag ^= SCE_DS_SELECTED; - if (adt) adt->flag ^= ADT_UI_SELECTED; - } - else { - sce->flag |= SCE_DS_SELECTED; - if (adt) adt->flag |= ADT_UI_SELECTED; - } - - notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); - break; - } - case ANIMTYPE_OBJECT: - { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + int notifierFlags = 0; + + /* get the channel that was clicked on */ + /* filter 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 */ + ale = BLI_findlink(&anim_data, channel_index); + if (ale == NULL) { + /* channel not found */ + if (G.debug & G_DEBUG) + printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n", + channel_index); + + ANIM_animdata_freelist(&anim_data); + return 0; + } + + /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */ + /* TODO: should this feature be extended to work with other channel types too? */ + if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) { + /* normal channels should not behave normally in this case */ + ANIM_animdata_freelist(&anim_data); + return 0; + } + + /* action to take depends on what channel we've got */ + /* WARNING: must keep this in sync with the equivalent function in nla_channels.c */ + switch (ale->type) { + case ANIMTYPE_SCENE: { + Scene *sce = (Scene *)ale->data; + AnimData *adt = sce->adt; + + /* set selection status */ + if (selectmode == SELECT_INVERT) { + /* swap select */ + sce->flag ^= SCE_DS_SELECTED; + if (adt) + adt->flag ^= ADT_UI_SELECTED; + } + else { + sce->flag |= SCE_DS_SELECTED; + if (adt) + adt->flag |= ADT_UI_SELECTED; + } + + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); + break; + } + case ANIMTYPE_OBJECT: { #if 0 - bDopeSheet *ads = (bDopeSheet *)ac->data; - Scene *sce = (Scene *)ads->source; + bDopeSheet *ads = (bDopeSheet *)ac->data; + Scene *sce = (Scene *)ads->source; #endif - ViewLayer *view_layer = ac->view_layer; - Base *base = (Base *)ale->data; - Object *ob = base->object; - AnimData *adt = ob->adt; - - /* set selection status */ - if (base->flag & BASE_SELECTABLE) { - if (selectmode == SELECT_INVERT) { - /* swap select */ - ED_object_base_select(base, BA_INVERT); - BKE_scene_object_base_flag_sync_from_base(base); - - if (adt) adt->flag ^= ADT_UI_SELECTED; - } - else { - Base *b; - - /* deselect all */ - /* TODO: should this deselect all other types of channels too? */ - for (b = view_layer->object_bases.first; b; b = b->next) { - ED_object_base_select(b, BA_DESELECT); - BKE_scene_object_base_flag_sync_from_base(b); - if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE); - } - - /* select object now */ - ED_object_base_select(base, BA_SELECT); - BKE_scene_object_base_flag_sync_from_base(base); - if (adt) adt->flag |= ADT_UI_SELECTED; - } - - /* change active object - regardless of whether it is now selected [T37883] */ - ED_object_base_activate(C, base); /* adds notifier */ - - if ((adt) && (adt->flag & ADT_UI_SELECTED)) - adt->flag |= ADT_UI_ACTIVE; - - /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */ - if (ob != CTX_data_edit_object(C)) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - - notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); - } - break; - } - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSNTREE: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - { - /* sanity checking... */ - if (ale->adt) { - /* select/deselect */ - if (selectmode == SELECT_INVERT) { - /* inverse selection status of this AnimData block only */ - ale->adt->flag ^= ADT_UI_SELECTED; - } - else { - /* select AnimData block by itself */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - ale->adt->flag |= ADT_UI_SELECTED; - } - - /* set active? */ - if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) - ale->adt->flag |= ADT_UI_ACTIVE; - } - - notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); - break; - } - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = (bActionGroup *)ale->data; - - Object *ob = NULL; - bPoseChannel *pchan = NULL; - - - /* Armatures-Specific Feature: - * Since groups are used to collect F-Curves of the same Bone by default - * (via Keying Sets) so that they can be managed better, we try to make - * things here easier for animators by mapping group selection to bone - * selection. - * - * Only do this if "Only Selected" dopesheet filter is not active, or else it - * becomes too unpredictable/tricky to manage - */ - if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) { - if ((ale->id) && (GS(ale->id->name) == ID_OB)) { - ob = (Object *)ale->id; - - if (ob->type == OB_ARMATURE) { - /* Assume for now that any group with corresponding name is what we want - * (i.e. for an armature whose location is animated, things would break - * if the user were to add a bone named "Location"). - * - * TODO: check the first F-Curve or so to be sure... - */ - pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); - } - } - } - - /* select/deselect group */ - if (selectmode == SELECT_INVERT) { - /* inverse selection status of this group only */ - agrp->flag ^= AGRP_SELECTED; - } - else if (selectmode == -1) { - /* select all in group (and deselect everything else) */ - FCurve *fcu; - - /* deselect all other channels */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - if (pchan) ED_pose_deselect_all(ob, SEL_DESELECT, false); - - /* only select channels in group and group itself */ - for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) - fcu->flag |= FCURVE_SELECTED; - agrp->flag |= AGRP_SELECTED; - } - else { - /* select group by itself */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - if (pchan) ED_pose_deselect_all(ob, SEL_DESELECT, false); - - agrp->flag |= AGRP_SELECTED; - } - - /* if group is selected now, make group the 'active' one in the visible list */ - if (agrp->flag & AGRP_SELECTED) { - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); - if (pchan) ED_pose_bone_select(ob, pchan, true); - } - else { - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP); - if (pchan) ED_pose_bone_select(ob, pchan, false); - } - - notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); - break; - } - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: - { - FCurve *fcu = (FCurve *)ale->data; - - /* select/deselect */ - if (selectmode == SELECT_INVERT) { - /* inverse selection status of this F-Curve only */ - fcu->flag ^= FCURVE_SELECTED; - } - else { - /* select F-Curve by itself */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - fcu->flag |= FCURVE_SELECTED; - } - - /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */ - if (fcu->flag & FCURVE_SELECTED) - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); - - notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); - break; - } - case ANIMTYPE_SHAPEKEY: - { - KeyBlock *kb = (KeyBlock *)ale->data; - - /* select/deselect */ - if (selectmode == SELECT_INVERT) { - /* inverse selection status of this ShapeKey only */ - kb->flag ^= KEYBLOCK_SEL; - } - else { - /* select ShapeKey by itself */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - kb->flag |= KEYBLOCK_SEL; - } - - notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); - break; - } - case ANIMTYPE_NLACONTROLS: - { - AnimData *adt = (AnimData *)ale->data; - - /* toggle expand - * - Although the triangle widget already allows this, since there's nothing else that can be done here now, - * let's just use it for easier expand/collapse for now - */ - adt->flag ^= ADT_NLA_SKEYS_COLLAPSED; - - notifierFlags |= (ND_ANIMCHAN | NA_EDITED); - break; - } - case ANIMTYPE_GPDATABLOCK: - { - bGPdata *gpd = (bGPdata *)ale->data; - - /* toggle expand - * - although the triangle widget already allows this, the whole channel can also be used for this purpose - */ - gpd->flag ^= GP_DATA_EXPAND; - - notifierFlags |= (ND_ANIMCHAN | NA_EDITED); - break; - } - case ANIMTYPE_GPLAYER: - { - bGPdata *gpd = (bGPdata *)ale->id; - bGPDlayer *gpl = (bGPDlayer *)ale->data; - - /* select/deselect */ - if (selectmode == SELECT_INVERT) { - /* invert selection status of this layer only */ - gpl->flag ^= GP_LAYER_SELECT; - } - else { - /* select layer by itself */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - gpl->flag |= GP_LAYER_SELECT; - } - - /* change active layer, if this is selected (since we must always have an active layer) */ - if (gpl->flag & GP_LAYER_SELECT) { - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER); - /* update other layer status */ - BKE_gpencil_layer_setactive(gpd, gpl); - } - - /* Grease Pencil updates */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); - notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Editors updates */ - break; - } - case ANIMTYPE_MASKDATABLOCK: - { - Mask *mask = (Mask *)ale->data; - - /* toggle expand - * - although the triangle widget already allows this, the whole channel can also be used for this purpose - */ - mask->flag ^= MASK_ANIMF_EXPAND; - - notifierFlags |= (ND_ANIMCHAN | NA_EDITED); - break; - } - case ANIMTYPE_MASKLAYER: - { - MaskLayer *masklay = (MaskLayer *)ale->data; - - /* select/deselect */ - if (selectmode == SELECT_INVERT) { - /* invert selection status of this layer only */ - masklay->flag ^= MASK_LAYERFLAG_SELECT; - } - else { - /* select layer by itself */ - ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - masklay->flag |= MASK_LAYERFLAG_SELECT; - } - - notifierFlags |= (ND_ANIMCHAN | NA_EDITED); - break; - } - default: - if (G.debug & G_DEBUG) - printf("Error: Invalid channel type in mouse_anim_channels()\n"); - break; - } - - /* free channels */ - ANIM_animdata_freelist(&anim_data); - - /* return notifier flags */ - return notifierFlags; + ViewLayer *view_layer = ac->view_layer; + Base *base = (Base *)ale->data; + Object *ob = base->object; + AnimData *adt = ob->adt; + + /* set selection status */ + if (base->flag & BASE_SELECTABLE) { + if (selectmode == SELECT_INVERT) { + /* swap select */ + ED_object_base_select(base, BA_INVERT); + BKE_scene_object_base_flag_sync_from_base(base); + + if (adt) + adt->flag ^= ADT_UI_SELECTED; + } + else { + Base *b; + + /* deselect all */ + /* TODO: should this deselect all other types of channels too? */ + for (b = view_layer->object_bases.first; b; b = b->next) { + ED_object_base_select(b, BA_DESELECT); + BKE_scene_object_base_flag_sync_from_base(b); + if (b->object->adt) + b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE); + } + + /* select object now */ + ED_object_base_select(base, BA_SELECT); + BKE_scene_object_base_flag_sync_from_base(base); + if (adt) + adt->flag |= ADT_UI_SELECTED; + } + + /* change active object - regardless of whether it is now selected [T37883] */ + ED_object_base_activate(C, base); /* adds notifier */ + + if ((adt) && (adt->flag & ADT_UI_SELECTED)) + adt->flag |= ADT_UI_ACTIVE; + + /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */ + if (ob != CTX_data_edit_object(C)) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); + } + break; + } + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: { + /* sanity checking... */ + if (ale->adt) { + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this AnimData block only */ + ale->adt->flag ^= ADT_UI_SELECTED; + } + else { + /* select AnimData block by itself */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); + ale->adt->flag |= ADT_UI_SELECTED; + } + + /* set active? */ + if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) + ale->adt->flag |= ADT_UI_ACTIVE; + } + + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *agrp = (bActionGroup *)ale->data; + + Object *ob = NULL; + bPoseChannel *pchan = NULL; + + /* Armatures-Specific Feature: + * Since groups are used to collect F-Curves of the same Bone by default + * (via Keying Sets) so that they can be managed better, we try to make + * things here easier for animators by mapping group selection to bone + * selection. + * + * Only do this if "Only Selected" dopesheet filter is not active, or else it + * becomes too unpredictable/tricky to manage + */ + if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) { + if ((ale->id) && (GS(ale->id->name) == ID_OB)) { + ob = (Object *)ale->id; + + if (ob->type == OB_ARMATURE) { + /* Assume for now that any group with corresponding name is what we want + * (i.e. for an armature whose location is animated, things would break + * if the user were to add a bone named "Location"). + * + * TODO: check the first F-Curve or so to be sure... + */ + pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); + } + } + } + + /* select/deselect group */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this group only */ + agrp->flag ^= AGRP_SELECTED; + } + else if (selectmode == -1) { + /* select all in group (and deselect everything else) */ + FCurve *fcu; + + /* deselect all other channels */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); + if (pchan) + ED_pose_deselect_all(ob, SEL_DESELECT, false); + + /* only select channels in group and group itself */ + for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) + fcu->flag |= FCURVE_SELECTED; + agrp->flag |= AGRP_SELECTED; + } + else { + /* select group by itself */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); + if (pchan) + ED_pose_deselect_all(ob, SEL_DESELECT, false); + + agrp->flag |= AGRP_SELECTED; + } + + /* if group is selected now, make group the 'active' one in the visible list */ + if (agrp->flag & AGRP_SELECTED) { + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + if (pchan) + ED_pose_bone_select(ob, pchan, true); + } + else { + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP); + if (pchan) + ED_pose_bone_select(ob, pchan, false); + } + + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); + break; + } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)ale->data; + + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this F-Curve only */ + fcu->flag ^= FCURVE_SELECTED; + } + else { + /* select F-Curve by itself */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); + fcu->flag |= FCURVE_SELECTED; + } + + /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */ + if (fcu->flag & FCURVE_SELECTED) + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); + + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); + break; + } + case ANIMTYPE_SHAPEKEY: { + KeyBlock *kb = (KeyBlock *)ale->data; + + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* inverse selection status of this ShapeKey only */ + kb->flag ^= KEYBLOCK_SEL; + } + else { + /* select ShapeKey by itself */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); + kb->flag |= KEYBLOCK_SEL; + } + + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); + break; + } + case ANIMTYPE_NLACONTROLS: { + AnimData *adt = (AnimData *)ale->data; + + /* toggle expand + * - Although the triangle widget already allows this, since there's nothing else that can be done here now, + * let's just use it for easier expand/collapse for now + */ + adt->flag ^= ADT_NLA_SKEYS_COLLAPSED; + + notifierFlags |= (ND_ANIMCHAN | NA_EDITED); + break; + } + case ANIMTYPE_GPDATABLOCK: { + bGPdata *gpd = (bGPdata *)ale->data; + + /* toggle expand + * - although the triangle widget already allows this, the whole channel can also be used for this purpose + */ + gpd->flag ^= GP_DATA_EXPAND; + + notifierFlags |= (ND_ANIMCHAN | NA_EDITED); + break; + } + case ANIMTYPE_GPLAYER: { + bGPdata *gpd = (bGPdata *)ale->id; + bGPDlayer *gpl = (bGPDlayer *)ale->data; + + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* invert selection status of this layer only */ + gpl->flag ^= GP_LAYER_SELECT; + } + else { + /* select layer by itself */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); + gpl->flag |= GP_LAYER_SELECT; + } + + /* change active layer, if this is selected (since we must always have an active layer) */ + if (gpl->flag & GP_LAYER_SELECT) { + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER); + /* update other layer status */ + BKE_gpencil_layer_setactive(gpd, gpl); + } + + /* Grease Pencil updates */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); + notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Editors updates */ + break; + } + case ANIMTYPE_MASKDATABLOCK: { + Mask *mask = (Mask *)ale->data; + + /* toggle expand + * - although the triangle widget already allows this, the whole channel can also be used for this purpose + */ + mask->flag ^= MASK_ANIMF_EXPAND; + + notifierFlags |= (ND_ANIMCHAN | NA_EDITED); + break; + } + case ANIMTYPE_MASKLAYER: { + MaskLayer *masklay = (MaskLayer *)ale->data; + + /* select/deselect */ + if (selectmode == SELECT_INVERT) { + /* invert selection status of this layer only */ + masklay->flag ^= MASK_LAYERFLAG_SELECT; + } + else { + /* select layer by itself */ + ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); + masklay->flag |= MASK_LAYERFLAG_SELECT; + } + + notifierFlags |= (ND_ANIMCHAN | NA_EDITED); + break; + } + default: + if (G.debug & G_DEBUG) + printf("Error: Invalid channel type in mouse_anim_channels()\n"); + break; + } + + /* free channels */ + ANIM_animdata_freelist(&anim_data); + + /* return notifier flags */ + return notifierFlags; } /* ------------------- */ @@ -3018,177 +3051,188 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, /* handle clicking */ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - bAnimContext ac; - ARegion *ar; - View2D *v2d; - int channel_index; - int notifierFlags = 0; - short selectmode; - float x, y; - - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - /* get useful pointers from animation context data */ - ar = ac.ar; - v2d = &ar->v2d; - - /* select mode is either replace (deselect all, then add) or add/extend */ - if (RNA_boolean_get(op->ptr, "extend")) { - selectmode = SELECT_INVERT; - } - else if (RNA_boolean_get(op->ptr, "children_only")) { - /* this is a bit of a special case for ActionGroups only... - * should it be removed or extended to all instead? */ - selectmode = -1; - } - else { - selectmode = SELECT_REPLACE; - } - - /* figure out which channel user clicked in - * - * Note: - * although channels technically start at (y = ACHANNEL_FIRST), - * we need to adjust by half a channel's height 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, event->mval[0], event->mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(&ac), 0, (float)ACHANNEL_HEIGHT_HALF(&ac), x, y, NULL, &channel_index); - - /* handle mouse-click in the relevant channel then */ - notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode); - - /* set notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL); - - return OPERATOR_FINISHED; + bAnimContext ac; + ARegion *ar; + View2D *v2d; + int channel_index; + int notifierFlags = 0; + short selectmode; + float x, y; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get useful pointers from animation context data */ + ar = ac.ar; + v2d = &ar->v2d; + + /* select mode is either replace (deselect all, then add) or add/extend */ + if (RNA_boolean_get(op->ptr, "extend")) { + selectmode = SELECT_INVERT; + } + else if (RNA_boolean_get(op->ptr, "children_only")) { + /* this is a bit of a special case for ActionGroups only... + * should it be removed or extended to all instead? */ + selectmode = -1; + } + else { + selectmode = SELECT_REPLACE; + } + + /* figure out which channel user clicked in + * + * Note: + * although channels technically start at (y = ACHANNEL_FIRST), + * we need to adjust by half a channel's height 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, event->mval[0], event->mval[1], &x, &y); + UI_view2d_listview_view_to_cell(v2d, + ACHANNEL_NAMEWIDTH, + ACHANNEL_STEP(&ac), + 0, + (float)ACHANNEL_HEIGHT_HALF(&ac), + x, + y, + NULL, + &channel_index); + + /* handle mouse-click in the relevant channel then */ + notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode); + + /* set notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL); + + return OPERATOR_FINISHED; } static void ANIM_OT_channels_click(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Mouse Click on Channels"; - ot->idname = "ANIM_OT_channels_click"; - ot->description = "Handle mouse-clicks over animation channels"; + /* identifiers */ + ot->name = "Mouse Click on Channels"; + ot->idname = "ANIM_OT_channels_click"; + ot->description = "Handle mouse-clicks over animation channels"; - /* api callbacks */ - ot->invoke = animchannels_mouseclick_invoke; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->invoke = animchannels_mouseclick_invoke; + ot->poll = animedit_poll_channels_active; - /* flags */ - ot->flag = OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_UNDO; - /* properties */ - /* NOTE: don't save settings, otherwise, can end up with some weird behavior (sticky extend) */ - prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", ""); // SHIFTKEY - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + /* NOTE: don't save settings, otherwise, can end up with some weird behavior (sticky extend) */ + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", ""); // SHIFTKEY + RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", ""); // CTRLKEY|SHIFTKEY - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "children_only", false, "Select Children Only", ""); // CTRLKEY|SHIFTKEY + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool extend) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - bool success = false; - FCurve *fcu; - int i; - - /* get the channel that was clicked on */ - /* filter 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 */ - ale = BLI_findlink(&anim_data, channel_index); - if (ale == NULL) { - /* channel not found */ - if (G.debug & G_DEBUG) - printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index); - - ANIM_animdata_freelist(&anim_data); - return false; - } - - fcu = (FCurve *)ale->key_data; - success = (fcu != NULL); - - ANIM_animdata_freelist(&anim_data); - - /* F-Curve may not have any keyframes */ - if (fcu && fcu->bezt) { - BezTriple *bezt; - - if (!extend) { - filter = (ANIMFILTER_DATA_VISIBLE); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu_inner = (FCurve *)ale->key_data; - - if (fcu_inner != NULL && fcu_inner->bezt != NULL) { - for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) { - bezt->f2 = bezt->f1 = bezt->f3 = 0; - } - } - } - - ANIM_animdata_freelist(&anim_data); - } - - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - bezt->f2 = bezt->f1 = bezt->f3 = SELECT; - } - } - - /* free temp data and tag for refresh */ - ED_region_tag_redraw(ac->ar); - return success; -} - -static int animchannels_channel_select_keys_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - bAnimContext ac; - int channel_index; - bool extend = RNA_boolean_get(op->ptr, "extend"); - - /* get editor data */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return OPERATOR_CANCELLED; - - channel_index = animchannels_channel_get(&ac, event->mval); - - /* handle click */ - if (select_anim_channel_keys(&ac, channel_index, extend)) { - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - return OPERATOR_FINISHED; - } - else - /* allow event to be handled by selectall operator */ - return OPERATOR_PASS_THROUGH; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + bool success = false; + FCurve *fcu; + int i; + + /* get the channel that was clicked on */ + /* filter 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 */ + ale = BLI_findlink(&anim_data, channel_index); + if (ale == NULL) { + /* channel not found */ + if (G.debug & G_DEBUG) + printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", + channel_index); + + ANIM_animdata_freelist(&anim_data); + return false; + } + + fcu = (FCurve *)ale->key_data; + success = (fcu != NULL); + + ANIM_animdata_freelist(&anim_data); + + /* F-Curve may not have any keyframes */ + if (fcu && fcu->bezt) { + BezTriple *bezt; + + if (!extend) { + filter = (ANIMFILTER_DATA_VISIBLE); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu_inner = (FCurve *)ale->key_data; + + if (fcu_inner != NULL && fcu_inner->bezt != NULL) { + for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) { + bezt->f2 = bezt->f1 = bezt->f3 = 0; + } + } + } + + ANIM_animdata_freelist(&anim_data); + } + + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + bezt->f2 = bezt->f1 = bezt->f3 = SELECT; + } + } + + /* free temp data and tag for refresh */ + ED_region_tag_redraw(ac->ar); + return success; +} + +static int animchannels_channel_select_keys_invoke(bContext *C, + wmOperator *op, + const wmEvent *event) +{ + bAnimContext ac; + int channel_index; + bool extend = RNA_boolean_get(op->ptr, "extend"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + channel_index = animchannels_channel_get(&ac, event->mval); + + /* handle click */ + if (select_anim_channel_keys(&ac, channel_index, extend)) { + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + return OPERATOR_FINISHED; + } + else + /* allow event to be handled by selectall operator */ + return OPERATOR_PASS_THROUGH; } static void ANIM_OT_channel_select_keys(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Select Channel keyframes"; - ot->idname = "ANIM_OT_channel_select_keys"; - ot->description = "Select all keyframes of channel under mouse"; + /* identifiers */ + ot->name = "Select Channel keyframes"; + ot->idname = "ANIM_OT_channel_select_keys"; + ot->description = "Select all keyframes of channel under mouse"; - /* api callbacks */ - ot->invoke = animchannels_channel_select_keys_invoke; - ot->poll = animedit_poll_channels_active; + /* api callbacks */ + ot->invoke = animchannels_channel_select_keys_invoke; + ot->poll = animedit_poll_channels_active; - prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ************************************************************************** */ @@ -3196,41 +3240,41 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot) void ED_operatortypes_animchannels(void) { - WM_operatortype_append(ANIM_OT_channels_select_all); - WM_operatortype_append(ANIM_OT_channels_select_box); + WM_operatortype_append(ANIM_OT_channels_select_all); + WM_operatortype_append(ANIM_OT_channels_select_box); - WM_operatortype_append(ANIM_OT_channels_click); - WM_operatortype_append(ANIM_OT_channel_select_keys); - WM_operatortype_append(ANIM_OT_channels_rename); + WM_operatortype_append(ANIM_OT_channels_click); + WM_operatortype_append(ANIM_OT_channel_select_keys); + WM_operatortype_append(ANIM_OT_channels_rename); - WM_operatortype_append(ANIM_OT_channels_find); + WM_operatortype_append(ANIM_OT_channels_find); - WM_operatortype_append(ANIM_OT_channels_setting_enable); - WM_operatortype_append(ANIM_OT_channels_setting_disable); - WM_operatortype_append(ANIM_OT_channels_setting_toggle); + WM_operatortype_append(ANIM_OT_channels_setting_enable); + WM_operatortype_append(ANIM_OT_channels_setting_disable); + WM_operatortype_append(ANIM_OT_channels_setting_toggle); - WM_operatortype_append(ANIM_OT_channels_delete); + WM_operatortype_append(ANIM_OT_channels_delete); - /* XXX does this need to be a separate operator? */ - WM_operatortype_append(ANIM_OT_channels_editable_toggle); + /* XXX does this need to be a separate operator? */ + WM_operatortype_append(ANIM_OT_channels_editable_toggle); - WM_operatortype_append(ANIM_OT_channels_move); + WM_operatortype_append(ANIM_OT_channels_move); - WM_operatortype_append(ANIM_OT_channels_expand); - WM_operatortype_append(ANIM_OT_channels_collapse); + WM_operatortype_append(ANIM_OT_channels_expand); + WM_operatortype_append(ANIM_OT_channels_collapse); - WM_operatortype_append(ANIM_OT_channels_fcurves_enable); + WM_operatortype_append(ANIM_OT_channels_fcurves_enable); - WM_operatortype_append(ANIM_OT_channels_clean_empty); + WM_operatortype_append(ANIM_OT_channels_clean_empty); - WM_operatortype_append(ANIM_OT_channels_group); - WM_operatortype_append(ANIM_OT_channels_ungroup); + WM_operatortype_append(ANIM_OT_channels_group); + WM_operatortype_append(ANIM_OT_channels_ungroup); } // TODO: check on a poll callback for this, to get hotkeys into menus void ED_keymap_animchannels(wmKeyConfig *keyconf) { - WM_keymap_ensure(keyconf, "Animation Channels", 0, 0); + WM_keymap_ensure(keyconf, "Animation Channels", 0, 0); } /* ************************************************************************** */ diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index dfb1a456364..53fec2e1ef7 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include "MEM_guardedalloc.h" @@ -59,58 +58,68 @@ */ void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale) { - ID *id; - FCurve *fcu; - AnimData *adt; - - id = ale->id; - if (!id) - return; - - /* tag AnimData for refresh so that other views will update in realtime with these changes */ - adt = BKE_animdata_from_id(id); - if (adt) { - DEG_id_tag_update(id, ID_RECALC_ANIMATION); - if (adt->action != NULL) { - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION); - } - } - - /* Tag copy on the main object if updating anything directly inside AnimData */ - if (ELEM(ale->type, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) { - DEG_id_tag_update(id, ID_RECALC_ANIMATION); - return; - } - - /* update data */ - fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL; - - if (fcu && fcu->rna_path) { - /* if we have an fcurve, call the update for the property we - * are editing, this is then expected to do the proper redraws - * and depsgraph updates */ - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - - RNA_id_pointer_create(id, &id_ptr); - - if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) - RNA_property_update_main(bmain, scene, &ptr, prop); - } - else { - /* in other case we do standard depsgraph update, ideally - * we'd be calling property update functions here too ... */ - DEG_id_tag_update(id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); // XXX or do we want something more restrictive? - } + ID *id; + FCurve *fcu; + AnimData *adt; + + id = ale->id; + if (!id) + return; + + /* tag AnimData for refresh so that other views will update in realtime with these changes */ + adt = BKE_animdata_from_id(id); + if (adt) { + DEG_id_tag_update(id, ID_RECALC_ANIMATION); + if (adt->action != NULL) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION); + } + } + + /* Tag copy on the main object if updating anything directly inside AnimData */ + if (ELEM(ale->type, + ANIMTYPE_ANIMDATA, + ANIMTYPE_NLAACTION, + ANIMTYPE_NLATRACK, + ANIMTYPE_NLACURVE)) { + DEG_id_tag_update(id, ID_RECALC_ANIMATION); + return; + } + + /* update data */ + fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL; + + if (fcu && fcu->rna_path) { + /* if we have an fcurve, call the update for the property we + * are editing, this is then expected to do the proper redraws + * and depsgraph updates */ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + + RNA_id_pointer_create(id, &id_ptr); + + if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) + RNA_property_update_main(bmain, scene, &ptr, prop); + } + else { + /* in other case we do standard depsgraph update, ideally + * we'd be calling property update functions here too ... */ + DEG_id_tag_update(id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | + ID_RECALC_ANIMATION); // XXX or do we want something more restrictive? + } } /* tags the given ID block for refreshes (if applicable) due to * Animation Editor editing */ void ANIM_id_update(Main *bmain, ID *id) { - if (id) { - DEG_id_tag_update_ex(bmain, id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); // XXX or do we want something more restrictive? - } + if (id) { + DEG_id_tag_update_ex( + bmain, + id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | + ID_RECALC_ANIMATION); // XXX or do we want something more restrictive? + } } /* **************************** animation data <-> data syncing ******************************** */ @@ -126,161 +135,165 @@ void ANIM_id_update(Main *bmain, ID *id) /* perform syncing updates for Action Groups */ static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp) { - bActionGroup *agrp = (bActionGroup *)ale->data; - ID *owner_id = ale->id; - - /* major priority is selection status - * so we need both a group and an owner - */ - if (ELEM(NULL, agrp, owner_id)) - return; - - /* for standard Objects, check if group is the name of some bone */ - if (GS(owner_id->name) == ID_OB) { - Object *ob = (Object *)owner_id; - - /* check if there are bones, and whether the name matches any - * NOTE: this feature will only really work if groups by default contain the F-Curves for a single bone - */ - if (ob->pose) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); - bArmature *arm = ob->data; - - if (pchan) { - bActionGroup *bgrp; - - /* if one matches, sync the selection status */ - if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) - agrp->flag |= AGRP_SELECTED; - else - agrp->flag &= ~AGRP_SELECTED; - - /* also sync active group status */ - if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) { - /* if no previous F-Curve has active flag, then we're the first and only one to get it */ - if (*active_agrp == NULL) { - agrp->flag |= AGRP_ACTIVE; - *active_agrp = agrp; - } - else { - /* someone else has already taken it - set as not active */ - agrp->flag &= ~AGRP_ACTIVE; - } - } - else { - /* this can't possibly be active now */ - agrp->flag &= ~AGRP_ACTIVE; - } - - /* sync group colors */ - bgrp = (bActionGroup *)BLI_findlink(&ob->pose->agroups, (pchan->agrp_index - 1)); - if (bgrp) { - agrp->customCol = bgrp->customCol; - action_group_colors_sync(agrp, bgrp); - } - } - } - } + bActionGroup *agrp = (bActionGroup *)ale->data; + ID *owner_id = ale->id; + + /* major priority is selection status + * so we need both a group and an owner + */ + if (ELEM(NULL, agrp, owner_id)) + return; + + /* for standard Objects, check if group is the name of some bone */ + if (GS(owner_id->name) == ID_OB) { + Object *ob = (Object *)owner_id; + + /* check if there are bones, and whether the name matches any + * NOTE: this feature will only really work if groups by default contain the F-Curves for a single bone + */ + if (ob->pose) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); + bArmature *arm = ob->data; + + if (pchan) { + bActionGroup *bgrp; + + /* if one matches, sync the selection status */ + if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) + agrp->flag |= AGRP_SELECTED; + else + agrp->flag &= ~AGRP_SELECTED; + + /* also sync active group status */ + if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) { + /* if no previous F-Curve has active flag, then we're the first and only one to get it */ + if (*active_agrp == NULL) { + agrp->flag |= AGRP_ACTIVE; + *active_agrp = agrp; + } + else { + /* someone else has already taken it - set as not active */ + agrp->flag &= ~AGRP_ACTIVE; + } + } + else { + /* this can't possibly be active now */ + agrp->flag &= ~AGRP_ACTIVE; + } + + /* sync group colors */ + bgrp = (bActionGroup *)BLI_findlink(&ob->pose->agroups, (pchan->agrp_index - 1)); + if (bgrp) { + agrp->customCol = bgrp->customCol; + action_group_colors_sync(agrp, bgrp); + } + } + } + } } /* perform syncing updates for F-Curves */ -static void animchan_sync_fcurve(bAnimContext *UNUSED(ac), bAnimListElem *ale, FCurve **active_fcurve) +static void animchan_sync_fcurve(bAnimContext *UNUSED(ac), + bAnimListElem *ale, + FCurve **active_fcurve) { - FCurve *fcu = (FCurve *)ale->data; - ID *owner_id = ale->id; - - /* major priority is selection status, so refer to the checks done in anim_filter.c - * skip_fcurve_selected_data() for reference about what's going on here... - */ - if (ELEM(NULL, fcu, fcu->rna_path, owner_id)) - return; - - if (GS(owner_id->name) == ID_SCE) { - Scene *scene = (Scene *)owner_id; - - /* only affect if F-Curve involves sequence_editor.sequences */ - if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq; - char *seq_name; - - /* get strip name, and check if this strip is selected */ - seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); - seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); - if (seq_name) MEM_freeN(seq_name); - - /* update selection status */ - if (seq) { - if (seq->flag & SELECT) - fcu->flag |= FCURVE_SELECTED; - else - fcu->flag &= ~FCURVE_SELECTED; - } - } - } - else if (GS(owner_id->name) == ID_NT) { - bNodeTree *ntree = (bNodeTree *)owner_id; - - /* check for selected nodes */ - if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) { - bNode *node; - char *node_name; - - /* get strip name, and check if this strip is selected */ - node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); - node = nodeFindNodebyName(ntree, node_name); - if (node_name) MEM_freeN(node_name); - - /* update selection/active status */ - if (node) { - /* update selection status */ - if (node->flag & NODE_SELECT) - fcu->flag |= FCURVE_SELECTED; - else - fcu->flag &= ~FCURVE_SELECTED; - - /* update active status */ - /* XXX: this may interfere with setting bones as active if both exist at once; - * then again, if that's the case, production setups aren't likely to be animating - * nodes while working with bones? - */ - if (node->flag & NODE_ACTIVE) { - if (*active_fcurve == NULL) { - fcu->flag |= FCURVE_ACTIVE; - *active_fcurve = fcu; - } - else { - fcu->flag &= ~FCURVE_ACTIVE; - } - } - else { - fcu->flag &= ~FCURVE_ACTIVE; - } - } - } - } + FCurve *fcu = (FCurve *)ale->data; + ID *owner_id = ale->id; + + /* major priority is selection status, so refer to the checks done in anim_filter.c + * skip_fcurve_selected_data() for reference about what's going on here... + */ + if (ELEM(NULL, fcu, fcu->rna_path, owner_id)) + return; + + if (GS(owner_id->name) == ID_SCE) { + Scene *scene = (Scene *)owner_id; + + /* only affect if F-Curve involves sequence_editor.sequences */ + if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { + Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq; + char *seq_name; + + /* get strip name, and check if this strip is selected */ + seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); + seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); + if (seq_name) + MEM_freeN(seq_name); + + /* update selection status */ + if (seq) { + if (seq->flag & SELECT) + fcu->flag |= FCURVE_SELECTED; + else + fcu->flag &= ~FCURVE_SELECTED; + } + } + } + else if (GS(owner_id->name) == ID_NT) { + bNodeTree *ntree = (bNodeTree *)owner_id; + + /* check for selected nodes */ + if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) { + bNode *node; + char *node_name; + + /* get strip name, and check if this strip is selected */ + node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); + node = nodeFindNodebyName(ntree, node_name); + if (node_name) + MEM_freeN(node_name); + + /* update selection/active status */ + if (node) { + /* update selection status */ + if (node->flag & NODE_SELECT) + fcu->flag |= FCURVE_SELECTED; + else + fcu->flag &= ~FCURVE_SELECTED; + + /* update active status */ + /* XXX: this may interfere with setting bones as active if both exist at once; + * then again, if that's the case, production setups aren't likely to be animating + * nodes while working with bones? + */ + if (node->flag & NODE_ACTIVE) { + if (*active_fcurve == NULL) { + fcu->flag |= FCURVE_ACTIVE; + *active_fcurve = fcu; + } + else { + fcu->flag &= ~FCURVE_ACTIVE; + } + } + else { + fcu->flag &= ~FCURVE_ACTIVE; + } + } + } + } } /* perform syncing updates for GPencil Layers */ static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale) { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - - /* Make sure the selection flags agree with the "active" flag. - * The selection flags are used in the Dopesheet only, whereas - * the active flag is used everywhere else. Hence, we try to - * sync these here so that it all seems to be have as the user - * expects - T50184 - * - * Assume that we only really do this when the active status changes. - * (NOTE: This may prove annoying if it means selection is always lost) - */ - if (gpl->flag & GP_LAYER_ACTIVE) { - gpl->flag |= GP_LAYER_SELECT; - } - else { - gpl->flag &= ~GP_LAYER_SELECT; - } + bGPDlayer *gpl = (bGPDlayer *)ale->data; + + /* Make sure the selection flags agree with the "active" flag. + * The selection flags are used in the Dopesheet only, whereas + * the active flag is used everywhere else. Hence, we try to + * sync these here so that it all seems to be have as the user + * expects - T50184 + * + * Assume that we only really do this when the active status changes. + * (NOTE: This may prove annoying if it means selection is always lost) + */ + if (gpl->flag & GP_LAYER_ACTIVE) { + gpl->flag |= GP_LAYER_SELECT; + } + else { + gpl->flag &= ~GP_LAYER_SELECT; + } } /* ---------------- */ @@ -288,131 +301,135 @@ static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale) /* Main call to be exported to animation editors */ void ANIM_sync_animchannels_to_data(const bContext *C) { - bAnimContext ac; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - bActionGroup *active_agrp = NULL; - FCurve *active_fcurve = NULL; - - /* get animation context info for filtering the channels */ - if (ANIM_animdata_get_context(C, &ac) == 0) - return; - - /* filter data */ - /* NOTE: we want all channels, since we want to be able to set selection status on some of them even when collapsed - * However, don't include duplicates so that selection statuses don't override each other - */ - filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS; - ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - /* flush settings as appropriate depending on the types of the channels */ - for (ale = anim_data.first; ale; ale = ale->next) { - switch (ale->type) { - case ANIMTYPE_GROUP: - animchan_sync_group(&ac, ale, &active_agrp); - break; - - case ANIMTYPE_FCURVE: - animchan_sync_fcurve(&ac, ale, &active_fcurve); - break; - - case ANIMTYPE_GPLAYER: - animchan_sync_gplayer(&ac, ale); - break; - } - } - - ANIM_animdata_freelist(&anim_data); + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + bActionGroup *active_agrp = NULL; + FCurve *active_fcurve = NULL; + + /* get animation context info for filtering the channels */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return; + + /* filter data */ + /* NOTE: we want all channels, since we want to be able to set selection status on some of them even when collapsed + * However, don't include duplicates so that selection statuses don't override each other + */ + filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS; + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* flush settings as appropriate depending on the types of the channels */ + for (ale = anim_data.first; ale; ale = ale->next) { + switch (ale->type) { + case ANIMTYPE_GROUP: + animchan_sync_group(&ac, ale, &active_agrp); + break; + + case ANIMTYPE_FCURVE: + animchan_sync_fcurve(&ac, ale, &active_fcurve); + break; + + case ANIMTYPE_GPLAYER: + animchan_sync_gplayer(&ac, ale); + break; + } + } + + ANIM_animdata_freelist(&anim_data); } void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data) { - bAnimListElem *ale; + bAnimListElem *ale; - if (ELEM(ac->datatype, ANIMCONT_MASK)) { + if (ELEM(ac->datatype, ANIMCONT_MASK)) { #ifdef DEBUG - /* quiet assert */ - for (ale = anim_data->first; ale; ale = ale->next) { - ale->update = 0; - } + /* quiet assert */ + for (ale = anim_data->first; ale; ale = ale->next) { + ale->update = 0; + } #endif - return; - } - - for (ale = anim_data->first; ale; ale = ale->next) { - if (ale->type == ANIMTYPE_GPLAYER) { - bGPDlayer *gpl = ale->data; - - if (ale->update & ANIM_UPDATE_ORDER) { - ale->update &= ~ANIM_UPDATE_ORDER; - if (gpl) { - //gpencil_sort_frames(gpl); - } - } - - if (ale->update & ANIM_UPDATE_DEPS) { - ale->update &= ~ANIM_UPDATE_DEPS; - ANIM_list_elem_update(ac->bmain, ac->scene, ale); - } - /* disable handles to avoid crash */ - if (ale->update & ANIM_UPDATE_HANDLES) { - ale->update &= ~ANIM_UPDATE_HANDLES; - } - } - else if (ale->datatype == ALE_FCURVE) { - FCurve *fcu = ale->key_data; - - if (ale->update & ANIM_UPDATE_ORDER) { - ale->update &= ~ANIM_UPDATE_ORDER; - if (fcu) - sort_time_fcurve(fcu); - } - - if (ale->update & ANIM_UPDATE_HANDLES) { - ale->update &= ~ANIM_UPDATE_HANDLES; - if (fcu) - calchandles_fcurve(fcu); - } - - if (ale->update & ANIM_UPDATE_DEPS) { - ale->update &= ~ANIM_UPDATE_DEPS; - ANIM_list_elem_update(ac->bmain, ac->scene, ale); - } - } - else if (ELEM(ale->type, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) { - if (ale->update & ANIM_UPDATE_DEPS) { - ale->update &= ~ANIM_UPDATE_DEPS; - ANIM_list_elem_update(ac->bmain, ac->scene, ale); - } - } - else if (ale->update) { + return; + } + + for (ale = anim_data->first; ale; ale = ale->next) { + if (ale->type == ANIMTYPE_GPLAYER) { + bGPDlayer *gpl = ale->data; + + if (ale->update & ANIM_UPDATE_ORDER) { + ale->update &= ~ANIM_UPDATE_ORDER; + if (gpl) { + //gpencil_sort_frames(gpl); + } + } + + if (ale->update & ANIM_UPDATE_DEPS) { + ale->update &= ~ANIM_UPDATE_DEPS; + ANIM_list_elem_update(ac->bmain, ac->scene, ale); + } + /* disable handles to avoid crash */ + if (ale->update & ANIM_UPDATE_HANDLES) { + ale->update &= ~ANIM_UPDATE_HANDLES; + } + } + else if (ale->datatype == ALE_FCURVE) { + FCurve *fcu = ale->key_data; + + if (ale->update & ANIM_UPDATE_ORDER) { + ale->update &= ~ANIM_UPDATE_ORDER; + if (fcu) + sort_time_fcurve(fcu); + } + + if (ale->update & ANIM_UPDATE_HANDLES) { + ale->update &= ~ANIM_UPDATE_HANDLES; + if (fcu) + calchandles_fcurve(fcu); + } + + if (ale->update & ANIM_UPDATE_DEPS) { + ale->update &= ~ANIM_UPDATE_DEPS; + ANIM_list_elem_update(ac->bmain, ac->scene, ale); + } + } + else if (ELEM(ale->type, + ANIMTYPE_ANIMDATA, + ANIMTYPE_NLAACTION, + ANIMTYPE_NLATRACK, + ANIMTYPE_NLACURVE)) { + if (ale->update & ANIM_UPDATE_DEPS) { + ale->update &= ~ANIM_UPDATE_DEPS; + ANIM_list_elem_update(ac->bmain, ac->scene, ale); + } + } + else if (ale->update) { #if 0 - if (G.debug & G_DEBUG) { - printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n", - __func__, ale->update, ale->type, ale->data); - } + if (G.debug & G_DEBUG) { + printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n", + __func__, ale->update, ale->type, ale->data); + } #endif - /* Prevent crashes in cases where it can't be handled */ - ale->update = 0; - } + /* Prevent crashes in cases where it can't be handled */ + ale->update = 0; + } - BLI_assert(ale->update == 0); - } + BLI_assert(ale->update == 0); + } } void ANIM_animdata_freelist(ListBase *anim_data) { #ifndef NDEBUG - bAnimListElem *ale, *ale_next; - for (ale = anim_data->first; ale; ale = ale_next) { - ale_next = ale->next; - BLI_assert(ale->update == 0); - MEM_freeN(ale); - } - BLI_listbase_clear(anim_data); + bAnimListElem *ale, *ale_next; + for (ale = anim_data->first; ale; ale = ale_next) { + ale_next = ale->next; + BLI_assert(ale->update == 0); + MEM_freeN(ale); + } + BLI_listbase_clear(anim_data); #else - BLI_freelistN(anim_data); + BLI_freelistN(anim_data); #endif } diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 2b168aa9463..11c768a8efd 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -65,88 +65,87 @@ /* Draw current frame number in a little green box beside the current frame indicator */ void ANIM_draw_cfra_number(const bContext *C, View2D *v2d, short flag) { - Scene *scene = CTX_data_scene(C); - const float time = scene->r.cfra + scene->r.subframe; - const float cfra = (float)(time * scene->r.framelen); - const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0; - - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - unsigned char col[4]; - float color[4]; - float xscale, x, y; - char numstr[32] = " t "; /* t is the character to start replacing from */ - float hlen; - int slen; - - /* because the frame number text is subject to the same scaling as the contents of the view */ - UI_view2d_scale_get(v2d, &xscale, NULL); - GPU_matrix_push(); - GPU_matrix_scale_2f(1.0f / xscale, 1.0f); - - /* get timecode string - * - padding on str-buf passed so that it doesn't sit on the frame indicator - */ - if (show_time) { - BLI_timecode_string_from_time(&numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style); - } - else { - BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra); - } - - slen = UI_fontstyle_string_width(fstyle, numstr) - 1; - hlen = slen * 0.5f; - - /* get starting coordinates for drawing */ - x = cfra * xscale; - y = -0.1f * U.widget_unit; - - /* draw green box around/behind text */ - UI_GetThemeColor4fv(TH_CFRAME, color); - color[3] = 3.0f; - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa(true, - x - hlen - 0.1f * U.widget_unit, - y + 3.0f, - x + hlen + 0.1f * U.widget_unit, - y -3.0f + U.widget_unit, - 0.1f * U.widget_unit, - color); - - /* draw current frame number */ - UI_GetThemeColor4ubv(TH_TEXT_HI, col); - UI_fontstyle_draw_simple(fstyle, - x - hlen - 0.15f * U.widget_unit, - y + 0.28f * U.widget_unit, - numstr, col); - - /* restore view transform */ - GPU_matrix_pop(); + Scene *scene = CTX_data_scene(C); + const float time = scene->r.cfra + scene->r.subframe; + const float cfra = (float)(time * scene->r.framelen); + const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0; + + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + unsigned char col[4]; + float color[4]; + float xscale, x, y; + char numstr[32] = " t "; /* t is the character to start replacing from */ + float hlen; + int slen; + + /* because the frame number text is subject to the same scaling as the contents of the view */ + UI_view2d_scale_get(v2d, &xscale, NULL); + GPU_matrix_push(); + GPU_matrix_scale_2f(1.0f / xscale, 1.0f); + + /* get timecode string + * - padding on str-buf passed so that it doesn't sit on the frame indicator + */ + if (show_time) { + BLI_timecode_string_from_time( + &numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style); + } + else { + BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra); + } + + slen = UI_fontstyle_string_width(fstyle, numstr) - 1; + hlen = slen * 0.5f; + + /* get starting coordinates for drawing */ + x = cfra * xscale; + y = -0.1f * U.widget_unit; + + /* draw green box around/behind text */ + UI_GetThemeColor4fv(TH_CFRAME, color); + color[3] = 3.0f; + + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa(true, + x - hlen - 0.1f * U.widget_unit, + y + 3.0f, + x + hlen + 0.1f * U.widget_unit, + y - 3.0f + U.widget_unit, + 0.1f * U.widget_unit, + color); + + /* draw current frame number */ + UI_GetThemeColor4ubv(TH_TEXT_HI, col); + UI_fontstyle_draw_simple( + fstyle, x - hlen - 0.15f * U.widget_unit, y + 0.28f * U.widget_unit, numstr, col); + + /* restore view transform */ + GPU_matrix_pop(); } /* General call for drawing current frame indicator in animation editor */ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag) { - Scene *scene = CTX_data_scene(C); + Scene *scene = CTX_data_scene(C); - const float time = scene->r.cfra + scene->r.subframe; - const float x = (float)(time * scene->r.framelen); + const float time = scene->r.cfra + scene->r.subframe; + const float x = (float)(time * scene->r.framelen); - GPU_line_width((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0); + GPU_line_width((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0); - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - /* Draw a light green line to indicate current frame */ - immUniformThemeColor(TH_CFRAME); + /* Draw a light green line to indicate current frame */ + immUniformThemeColor(TH_CFRAME); - immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */ - immVertex2f(pos, x, v2d->cur.ymax); - immEnd(); - immUnbindProgram(); + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */ + immVertex2f(pos, x, v2d->cur.ymax); + immEnd(); + immUnbindProgram(); } /* *************************************************** */ @@ -156,34 +155,35 @@ void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag) /* Draw preview range 'curtains' for highlighting where the animation data is */ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width) { - Scene *scene = CTX_data_scene(C); - - /* only draw this if preview range is set */ - if (PRVRANGEON) { - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPU_blend(true); - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShadeAlpha(TH_ANIM_PREVIEW_RANGE, -25, -30); - /* XXX: Fix this hardcoded color (anim_active) */ - //immUniformColor4f(0.8f, 0.44f, 0.1f, 0.2f); - - /* only draw two separate 'curtains' if there's no overlap between them */ - if (PSFRA < PEFRA + end_frame_width) { - immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); - immRectf(pos, (float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); - } - else { - immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); - } - - immUnbindProgram(); - - GPU_blend(false); - } + Scene *scene = CTX_data_scene(C); + + /* only draw this if preview range is set */ + if (PRVRANGEON) { + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_ANIM_PREVIEW_RANGE, -25, -30); + /* XXX: Fix this hardcoded color (anim_active) */ + //immUniformColor4f(0.8f, 0.44f, 0.1f, 0.2f); + + /* only draw two separate 'curtains' if there's no overlap between them */ + if (PSFRA < PEFRA + end_frame_width) { + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax); + immRectf(pos, (float)(PEFRA + end_frame_width), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + } + else { + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + } + + immUnbindProgram(); + + GPU_blend(false); + } } /* *************************************************** */ @@ -193,39 +193,40 @@ void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width) // TODO: Should we still show these when preview range is enabled? void ANIM_draw_framerange(Scene *scene, View2D *v2d) { - /* draw darkened area outside of active timeline frame range */ - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPU_blend(true); + /* draw darkened area outside of active timeline frame range */ + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShadeAlpha(TH_BACK, -25, -100); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_BACK, -25, -100); - if (SFRA < EFRA) { - immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax); - immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); - } - else { - immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); - } + if (SFRA < EFRA) { + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax); + immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + } + else { + immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); + } - GPU_blend(false); + GPU_blend(false); - /* thin lines where the actual frames are */ - immUniformThemeColorShade(TH_BACK, -60); + /* thin lines where the actual frames are */ + immUniformThemeColorShade(TH_BACK, -60); - immBegin(GPU_PRIM_LINES, 4); + immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, (float)SFRA, v2d->cur.ymin); - immVertex2f(pos, (float)SFRA, v2d->cur.ymax); + immVertex2f(pos, (float)SFRA, v2d->cur.ymin); + immVertex2f(pos, (float)SFRA, v2d->cur.ymax); - immVertex2f(pos, (float)EFRA, v2d->cur.ymin); - immVertex2f(pos, (float)EFRA, v2d->cur.ymax); + immVertex2f(pos, (float)EFRA, v2d->cur.ymin); + immVertex2f(pos, (float)EFRA, v2d->cur.ymax); - immEnd(); - immUnbindProgram(); + immEnd(); + immUnbindProgram(); } /* *************************************************** */ @@ -235,28 +236,33 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d) // TODO: do not supply return this if the animdata tells us that there is no mapping to perform AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale) { - /* sanity checks */ - if (ac == NULL) - return NULL; - - /* abort if rendering - we may get some race condition issues... */ - if (G.is_rendering) return NULL; - - /* apart from strictly keyframe-related contexts, this shouldn't even happen */ - // XXX: nla and channel here may not be necessary... - if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_SHAPEKEY, ANIMCONT_DOPESHEET, - ANIMCONT_FCURVES, ANIMCONT_NLA, ANIMCONT_CHANNEL)) - { - /* handling depends on the type of animation-context we've got */ - if (ale) { - /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */ - if (ale->type != ANIMTYPE_NLACURVE) - return ale->adt; - } - } - - /* cannot handle... */ - return NULL; + /* sanity checks */ + if (ac == NULL) + return NULL; + + /* abort if rendering - we may get some race condition issues... */ + if (G.is_rendering) + return NULL; + + /* apart from strictly keyframe-related contexts, this shouldn't even happen */ + // XXX: nla and channel here may not be necessary... + if (ELEM(ac->datatype, + ANIMCONT_ACTION, + ANIMCONT_SHAPEKEY, + ANIMCONT_DOPESHEET, + ANIMCONT_FCURVES, + ANIMCONT_NLA, + ANIMCONT_CHANNEL)) { + /* handling depends on the type of animation-context we've got */ + if (ale) { + /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */ + if (ale->type != ANIMTYPE_NLACURVE) + return ale->adt; + } + } + + /* cannot handle... */ + return NULL; } /* ------------------- */ @@ -264,65 +270,64 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale) /* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */ static short bezt_nlamapping_restore(KeyframeEditData *ked, BezTriple *bezt) { - /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */ - AnimData *adt = (AnimData *)ked->data; - short only_keys = (short)ked->i1; + /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */ + AnimData *adt = (AnimData *)ked->data; + short only_keys = (short)ked->i1; - /* adjust BezTriple handles only if allowed to */ - if (only_keys == 0) { - bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP); - bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP); - } + /* adjust BezTriple handles only if allowed to */ + if (only_keys == 0) { + bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP); + bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP); + } - bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP); + bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP); - return 0; + return 0; } /* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", * i.e. mapping points to NLA-mapped global time */ static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt) { - /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */ - AnimData *adt = (AnimData *)ked->data; - short only_keys = (short)ked->i1; + /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */ + AnimData *adt = (AnimData *)ked->data; + short only_keys = (short)ked->i1; - /* adjust BezTriple handles only if allowed to */ - if (only_keys == 0) { - bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP); - bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP); - } + /* adjust BezTriple handles only if allowed to */ + if (only_keys == 0) { + bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP); + bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP); + } - bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP); + bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP); - return 0; + return 0; } - /* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve * - restore = whether to map points back to non-mapped time * - only_keys = whether to only adjust the location of the center point of beztriples */ void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys) { - KeyframeEditData ked = {{NULL}}; - KeyframeEditFunc map_cb; - - /* init edit data - * - AnimData is stored in 'data' - * - only_keys is stored in 'i1' - */ - ked.data = (void *)adt; - ked.i1 = (int)only_keys; - - /* get editing callback */ - if (restore) - map_cb = bezt_nlamapping_restore; - else - map_cb = bezt_nlamapping_apply; - - /* apply to F-Curve */ - ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, map_cb, NULL); + KeyframeEditData ked = {{NULL}}; + KeyframeEditFunc map_cb; + + /* init edit data + * - AnimData is stored in 'data' + * - only_keys is stored in 'i1' + */ + ked.data = (void *)adt; + ked.i1 = (int)only_keys; + + /* get editing callback */ + if (restore) + map_cb = bezt_nlamapping_restore; + else + map_cb = bezt_nlamapping_apply; + + /* apply to F-Curve */ + ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, map_cb, NULL); } /* *************************************************** */ @@ -331,329 +336,328 @@ void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, boo /* Get flags used for normalization in ANIM_unit_mapping_get_factor. */ short ANIM_get_normalization_flags(bAnimContext *ac) { - if (ac->sl->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = (SpaceGraph *) ac->sl; - bool use_normalization = (sipo->flag & SIPO_NORMALIZE) != 0; - bool freeze_normalization = (sipo->flag & SIPO_NORMALIZE_FREEZE) != 0; - return use_normalization - ? (ANIM_UNITCONV_NORMALIZE | (freeze_normalization ? ANIM_UNITCONV_NORMALIZE_FREEZE : 0)) - : 0; - } - - return 0; + if (ac->sl->spacetype == SPACE_GRAPH) { + SpaceGraph *sipo = (SpaceGraph *)ac->sl; + bool use_normalization = (sipo->flag & SIPO_NORMALIZE) != 0; + bool freeze_normalization = (sipo->flag & SIPO_NORMALIZE_FREEZE) != 0; + return use_normalization ? (ANIM_UNITCONV_NORMALIZE | + (freeze_normalization ? ANIM_UNITCONV_NORMALIZE_FREEZE : 0)) : + 0; + } + + return 0; } static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset) { - float factor = 1.0f, offset = 0.0f; - - if (flag & ANIM_UNITCONV_RESTORE) { - if (r_offset) - *r_offset = fcu->prev_offset; - - return 1.0f / fcu->prev_norm_factor; - } - - if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) { - if (r_offset) - *r_offset = fcu->prev_offset; - if (fcu->prev_norm_factor == 0.0f) { - /* Happens when Auto Normalize was disabled before - * any curves were displayed. - */ - return 1.0f; - } - return fcu->prev_norm_factor; - } - - if (G.moving & G_TRANSFORM_FCURVES) { - if (r_offset) - *r_offset = fcu->prev_offset; - if (fcu->prev_norm_factor == 0.0f) { - /* Same as above. */ - return 1.0f; - } - return fcu->prev_norm_factor; - } - - fcu->prev_norm_factor = 1.0f; - if (fcu->bezt) { - const bool use_preview_only = PRVRANGEON; - const BezTriple *bezt; - int i; - float max_coord = -FLT_MAX; - float min_coord = FLT_MAX; - float range; - - if (fcu->totvert < 1) { - return 1.0f; - } - - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0], - scene->r.psfra, - scene->r.pefra)) - { - continue; - } - - if (i == 0) { - /* We ignore extrapolation flags and handle here, and use the - * control point position only. so we normalize "interesting" - * part of the curve. - * - * Here we handle left extrapolation. - */ - max_coord = max_ff(max_coord, bezt->vec[1][1]); - - min_coord = min_ff(min_coord, bezt->vec[1][1]); - } - else { - const BezTriple *prev_bezt = bezt - 1; - if (prev_bezt->ipo == BEZT_IPO_CONST) { - /* Constant interpolation: previous CV value is used up - * to the current keyframe. - */ - max_coord = max_ff(max_coord, bezt->vec[1][1]); - min_coord = min_ff(min_coord, bezt->vec[1][1]); - } - else if (prev_bezt->ipo == BEZT_IPO_LIN) { - /* Linear interpolation: min/max using both previous and - * and current CV. - */ - max_coord = max_ff(max_coord, bezt->vec[1][1]); - min_coord = min_ff(min_coord, bezt->vec[1][1]); - max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); - min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); - } - else if (prev_bezt->ipo == BEZT_IPO_BEZ) { - const int resol = fcu->driver - ? 32 - : min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), 32); - if (resol < 2) { - max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); - min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); - } - else { - float data[120]; - float v1[2], v2[2], v3[2], v4[2]; - - v1[0] = prev_bezt->vec[1][0]; - v1[1] = prev_bezt->vec[1][1]; - v2[0] = prev_bezt->vec[2][0]; - v2[1] = prev_bezt->vec[2][1]; - - v3[0] = bezt->vec[0][0]; - v3[1] = bezt->vec[0][1]; - v4[0] = bezt->vec[1][0]; - v4[1] = bezt->vec[1][1]; - - correct_bezpart(v1, v2, v3, v4); - - BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3); - BKE_curve_forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3); - - for (int j = 0; j <= resol; ++j) { - const float *fp = &data[j * 3]; - max_coord = max_ff(max_coord, fp[1]); - min_coord = min_ff(min_coord, fp[1]); - } - } - } - } - } - - if (max_coord > min_coord) { - range = max_coord - min_coord; - if (range > FLT_EPSILON) { - factor = 2.0f / range; - } - offset = -min_coord - range / 2.0f; - } - else if (max_coord == min_coord) { - factor = 1.0f; - offset = -min_coord; - } - } - BLI_assert(factor != 0.0f); - if (r_offset) { - *r_offset = offset; - } - - fcu->prev_norm_factor = factor; - fcu->prev_offset = offset; - return factor; + float factor = 1.0f, offset = 0.0f; + + if (flag & ANIM_UNITCONV_RESTORE) { + if (r_offset) + *r_offset = fcu->prev_offset; + + return 1.0f / fcu->prev_norm_factor; + } + + if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) { + if (r_offset) + *r_offset = fcu->prev_offset; + if (fcu->prev_norm_factor == 0.0f) { + /* Happens when Auto Normalize was disabled before + * any curves were displayed. + */ + return 1.0f; + } + return fcu->prev_norm_factor; + } + + if (G.moving & G_TRANSFORM_FCURVES) { + if (r_offset) + *r_offset = fcu->prev_offset; + if (fcu->prev_norm_factor == 0.0f) { + /* Same as above. */ + return 1.0f; + } + return fcu->prev_norm_factor; + } + + fcu->prev_norm_factor = 1.0f; + if (fcu->bezt) { + const bool use_preview_only = PRVRANGEON; + const BezTriple *bezt; + int i; + float max_coord = -FLT_MAX; + float min_coord = FLT_MAX; + float range; + + if (fcu->totvert < 1) { + return 1.0f; + } + + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) { + continue; + } + + if (i == 0) { + /* We ignore extrapolation flags and handle here, and use the + * control point position only. so we normalize "interesting" + * part of the curve. + * + * Here we handle left extrapolation. + */ + max_coord = max_ff(max_coord, bezt->vec[1][1]); + + min_coord = min_ff(min_coord, bezt->vec[1][1]); + } + else { + const BezTriple *prev_bezt = bezt - 1; + if (prev_bezt->ipo == BEZT_IPO_CONST) { + /* Constant interpolation: previous CV value is used up + * to the current keyframe. + */ + max_coord = max_ff(max_coord, bezt->vec[1][1]); + min_coord = min_ff(min_coord, bezt->vec[1][1]); + } + else if (prev_bezt->ipo == BEZT_IPO_LIN) { + /* Linear interpolation: min/max using both previous and + * and current CV. + */ + max_coord = max_ff(max_coord, bezt->vec[1][1]); + min_coord = min_ff(min_coord, bezt->vec[1][1]); + max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); + min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); + } + else if (prev_bezt->ipo == BEZT_IPO_BEZ) { + const int resol = fcu->driver ? + 32 : + min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), + 32); + if (resol < 2) { + max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); + min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); + } + else { + float data[120]; + float v1[2], v2[2], v3[2], v4[2]; + + v1[0] = prev_bezt->vec[1][0]; + v1[1] = prev_bezt->vec[1][1]; + v2[0] = prev_bezt->vec[2][0]; + v2[1] = prev_bezt->vec[2][1]; + + v3[0] = bezt->vec[0][0]; + v3[1] = bezt->vec[0][1]; + v4[0] = bezt->vec[1][0]; + v4[1] = bezt->vec[1][1]; + + correct_bezpart(v1, v2, v3, v4); + + BKE_curve_forward_diff_bezier( + v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3); + BKE_curve_forward_diff_bezier( + v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3); + + for (int j = 0; j <= resol; ++j) { + const float *fp = &data[j * 3]; + max_coord = max_ff(max_coord, fp[1]); + min_coord = min_ff(min_coord, fp[1]); + } + } + } + } + } + + if (max_coord > min_coord) { + range = max_coord - min_coord; + if (range > FLT_EPSILON) { + factor = 2.0f / range; + } + offset = -min_coord - range / 2.0f; + } + else if (max_coord == min_coord) { + factor = 1.0f; + offset = -min_coord; + } + } + BLI_assert(factor != 0.0f); + if (r_offset) { + *r_offset = offset; + } + + fcu->prev_norm_factor = factor; + fcu->prev_offset = offset; + return factor; } /* Get unit conversion factor for given ID + F-Curve */ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset) { - if (flag & ANIM_UNITCONV_NORMALIZE) { - return normalization_factor_get(scene, fcu, flag, r_offset); - } - - if (r_offset) - *r_offset = 0.0f; - - /* sanity checks */ - if (id && fcu && fcu->rna_path) { - PointerRNA ptr, id_ptr; - PropertyRNA *prop; - - /* get RNA property that F-Curve affects */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { - /* rotations: radians <-> degrees? */ - if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) { - /* 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 (flag & ANIM_UNITCONV_RESTORE) - return DEG2RADF(1.0f); /* degrees to radians */ - else - return RAD2DEGF(1.0f); /* radians to degrees */ - } - } - - /* TODO: other rotation types here as necessary */ - } - } - - /* no mapping needs to occur... */ - return 1.0f; + if (flag & ANIM_UNITCONV_NORMALIZE) { + return normalization_factor_get(scene, fcu, flag, r_offset); + } + + if (r_offset) + *r_offset = 0.0f; + + /* sanity checks */ + if (id && fcu && fcu->rna_path) { + PointerRNA ptr, id_ptr; + PropertyRNA *prop; + + /* get RNA property that F-Curve affects */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { + /* rotations: radians <-> degrees? */ + if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) { + /* 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 (flag & ANIM_UNITCONV_RESTORE) + return DEG2RADF(1.0f); /* degrees to radians */ + else + return RAD2DEGF(1.0f); /* radians to degrees */ + } + } + + /* TODO: other rotation types here as necessary */ + } + } + + /* no mapping needs to occur... */ + return 1.0f; } static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prevfra) { - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Mask *mask = CTX_data_edit_mask(C); - bDopeSheet ads = {NULL}; - DLRBT_Tree keys; - ActKeyColumn *aknext, *akprev; - float cfranext, cfraprev; - bool donenext = false, doneprev = false; - int nextcount = 0, prevcount = 0; - - cfranext = cfraprev = (float)(CFRA); - - /* init binarytree-list for getting keyframes */ - BLI_dlrbTree_init(&keys); - - /* seed up dummy dopesheet context with flags to perform necessary filtering */ - if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) { - /* only selected channels are included */ - ads.filterflag |= ADS_FILTER_ONLYSEL; - } - - /* populate tree with keyframe nodes */ - scene_to_keylist(&ads, scene, &keys, 0); - gpencil_to_keylist(&ads, scene->gpd, &keys, false); - - if (ob) { - ob_to_keylist(&ads, ob, &keys, 0); - gpencil_to_keylist(&ads, ob->data, &keys, false); - } - - if (mask) { - MaskLayer *masklay = BKE_mask_layer_active(mask); - mask_to_keylist(&ads, masklay, &keys); - } - - /* find matching keyframe in the right direction */ - do { - aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext); - - if (aknext) { - if (CFRA == (int)aknext->cfra) { - /* make this the new starting point for the search and ignore */ - cfranext = aknext->cfra; - } - else { - /* this changes the frame, so set the frame and we're done */ - if (++nextcount == U.view_frame_keyframes) - donenext = true; - } - cfranext = aknext->cfra; - } - } while ((aknext != NULL) && (donenext == false)); - - do { - akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev); - - if (akprev) { - if (CFRA == (int)akprev->cfra) { - /* make this the new starting point for the search */ - } - else { - /* this changes the frame, so set the frame and we're done */ - if (++prevcount == U.view_frame_keyframes) - doneprev = true; - } - cfraprev = akprev->cfra; - } - } while ((akprev != NULL) && (doneprev == false)); - - /* free temp stuff */ - BLI_dlrbTree_free(&keys); - - /* any success? */ - if (doneprev || donenext) { - if (doneprev) - *prevfra = cfraprev; - else - *prevfra = CFRA - (cfranext - CFRA); - - if (donenext) - *nextfra = cfranext; - else - *nextfra = CFRA + (CFRA - cfraprev); - - return true; - } - - return false; + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Mask *mask = CTX_data_edit_mask(C); + bDopeSheet ads = {NULL}; + DLRBT_Tree keys; + ActKeyColumn *aknext, *akprev; + float cfranext, cfraprev; + bool donenext = false, doneprev = false; + int nextcount = 0, prevcount = 0; + + cfranext = cfraprev = (float)(CFRA); + + /* init binarytree-list for getting keyframes */ + BLI_dlrbTree_init(&keys); + + /* seed up dummy dopesheet context with flags to perform necessary filtering */ + if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) { + /* only selected channels are included */ + ads.filterflag |= ADS_FILTER_ONLYSEL; + } + + /* populate tree with keyframe nodes */ + scene_to_keylist(&ads, scene, &keys, 0); + gpencil_to_keylist(&ads, scene->gpd, &keys, false); + + if (ob) { + ob_to_keylist(&ads, ob, &keys, 0); + gpencil_to_keylist(&ads, ob->data, &keys, false); + } + + if (mask) { + MaskLayer *masklay = BKE_mask_layer_active(mask); + mask_to_keylist(&ads, masklay, &keys); + } + + /* find matching keyframe in the right direction */ + do { + aknext = (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfranext); + + if (aknext) { + if (CFRA == (int)aknext->cfra) { + /* make this the new starting point for the search and ignore */ + cfranext = aknext->cfra; + } + else { + /* this changes the frame, so set the frame and we're done */ + if (++nextcount == U.view_frame_keyframes) + donenext = true; + } + cfranext = aknext->cfra; + } + } while ((aknext != NULL) && (donenext == false)); + + do { + akprev = (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfraprev); + + if (akprev) { + if (CFRA == (int)akprev->cfra) { + /* make this the new starting point for the search */ + } + else { + /* this changes the frame, so set the frame and we're done */ + if (++prevcount == U.view_frame_keyframes) + doneprev = true; + } + cfraprev = akprev->cfra; + } + } while ((akprev != NULL) && (doneprev == false)); + + /* free temp stuff */ + BLI_dlrbTree_free(&keys); + + /* any success? */ + if (doneprev || donenext) { + if (doneprev) + *prevfra = cfraprev; + else + *prevfra = CFRA - (cfranext - CFRA); + + if (donenext) + *nextfra = cfranext; + else + *nextfra = CFRA + (CFRA - cfraprev); + + return true; + } + + return false; } void ANIM_center_frame(struct bContext *C, int smooth_viewtx) { - ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - float w = BLI_rctf_size_x(&ar->v2d.cur); - rctf newrct; - int nextfra, prevfra; - - switch (U.view_frame_type) { - case ZOOM_FRAME_MODE_SECONDS: - { - const float fps = FPS; - newrct.xmax = scene->r.cfra + U.view_frame_seconds * fps + 1; - newrct.xmin = scene->r.cfra - U.view_frame_seconds * fps - 1; - newrct.ymax = ar->v2d.cur.ymax; - newrct.ymin = ar->v2d.cur.ymin; - break; - } - - /* hardest case of all, look for all keyframes around frame and display those */ - case ZOOM_FRAME_MODE_KEYFRAMES: - if (find_prev_next_keyframes(C, &nextfra, &prevfra)) { - newrct.xmax = nextfra; - newrct.xmin = prevfra; - newrct.ymax = ar->v2d.cur.ymax; - newrct.ymin = ar->v2d.cur.ymin; - break; - } - /* else drop through, keep range instead */ - ATTR_FALLTHROUGH; - - case ZOOM_FRAME_MODE_KEEP_RANGE: - default: - newrct.xmax = scene->r.cfra + (w / 2); - newrct.xmin = scene->r.cfra - (w / 2); - newrct.ymax = ar->v2d.cur.ymax; - newrct.ymin = ar->v2d.cur.ymin; - break; - } - - UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + float w = BLI_rctf_size_x(&ar->v2d.cur); + rctf newrct; + int nextfra, prevfra; + + switch (U.view_frame_type) { + case ZOOM_FRAME_MODE_SECONDS: { + const float fps = FPS; + newrct.xmax = scene->r.cfra + U.view_frame_seconds * fps + 1; + newrct.xmin = scene->r.cfra - U.view_frame_seconds * fps - 1; + newrct.ymax = ar->v2d.cur.ymax; + newrct.ymin = ar->v2d.cur.ymin; + break; + } + + /* hardest case of all, look for all keyframes around frame and display those */ + case ZOOM_FRAME_MODE_KEYFRAMES: + if (find_prev_next_keyframes(C, &nextfra, &prevfra)) { + newrct.xmax = nextfra; + newrct.xmin = prevfra; + newrct.ymax = ar->v2d.cur.ymax; + newrct.ymin = ar->v2d.cur.ymin; + break; + } + /* else drop through, keep range instead */ + ATTR_FALLTHROUGH; + + case ZOOM_FRAME_MODE_KEEP_RANGE: + default: + newrct.xmax = scene->r.cfra + (w / 2); + newrct.xmin = scene->r.cfra - (w / 2); + newrct.ymax = ar->v2d.cur.ymax; + newrct.ymin = ar->v2d.cur.ymin; + break; + } + + UI_view2d_smooth_view(C, ar, &newrct, smooth_viewtx); } /* *************************************************** */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index dad0727a82d..57ea5ad81f5 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -21,7 +21,6 @@ * \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 @@ -96,7 +95,7 @@ #include "ED_anim_api.h" #include "ED_markers.h" -#include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */ +#include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */ /* ************************************************************ */ /* Blender Context <-> Animation Context mapping */ @@ -106,18 +105,18 @@ /* Get vertical scaling factor (i.e. typically used for keyframe size) */ static void animedit_get_yscale_factor(bAnimContext *ac) { - bTheme *btheme = UI_GetTheme(); - - /* grab scale factor directly from action editor setting - * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally - * since it is a float, and the theme settings methods can only handle chars. - */ - ac->yscale_fac = btheme->space_action.keyframe_scale_fac; - - /* clamp to avoid problems with uninitialised values... */ - if (ac->yscale_fac < 0.1f) - ac->yscale_fac = 1.0f; - //printf("yscale_fac = %f\n", ac->yscale_fac); + bTheme *btheme = UI_GetTheme(); + + /* grab scale factor directly from action editor setting + * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally + * since it is a float, and the theme settings methods can only handle chars. + */ + ac->yscale_fac = btheme->space_action.keyframe_scale_fac; + + /* clamp to avoid problems with uninitialised values... */ + if (ac->yscale_fac < 0.1f) + ac->yscale_fac = 1.0f; + //printf("yscale_fac = %f\n", ac->yscale_fac); } /* ----------- Private Stuff - Action Editor ------------- */ @@ -126,144 +125,144 @@ static void animedit_get_yscale_factor(bAnimContext *ac) /* Note: there's a similar function in key.c (BKE_key_from_object) */ static Key *actedit_get_shapekeys(bAnimContext *ac) { - ViewLayer *view_layer = ac->view_layer; - Object *ob; - Key *key; + ViewLayer *view_layer = ac->view_layer; + Object *ob; + Key *key; - ob = OBACT(view_layer); - if (ob == NULL) - return NULL; + ob = OBACT(view_layer); + if (ob == NULL) + return NULL; - /* XXX pinning is not available in 'ShapeKey' mode... */ - //if (saction->pin) return NULL; + /* XXX pinning is not available in 'ShapeKey' mode... */ + //if (saction->pin) return NULL; - /* shapekey data is stored with geometry data */ - key = BKE_key_from_object(ob); + /* shapekey data is stored with geometry data */ + key = BKE_key_from_object(ob); - if (key) { - if (key->type == KEY_RELATIVE) - return key; - } + if (key) { + if (key->type == KEY_RELATIVE) + return key; + } - return NULL; + return NULL; } /* Get data being edited in Action Editor (depending on current 'mode') */ static bool 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' */ - /* if not pinned, sync with active object */ - if (/*saction->pin == 0*/ true) { - if (ac->obact && ac->obact->adt) - saction->action = ac->obact->adt->action; - else - saction->action = NULL; - } - - ac->datatype = ANIMCONT_ACTION; - ac->data = saction->action; - - ac->mode = saction->mode; - return true; - - case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */ - ac->datatype = ANIMCONT_SHAPEKEY; - ac->data = actedit_get_shapekeys(ac); - - /* if not pinned, sync with active object */ - if (/*saction->pin == 0*/ true) { - Key *key = (Key *)ac->data; - - if (key && key->adt) - saction->action = key->adt->action; - else - saction->action = NULL; - } - - ac->mode = saction->mode; - return true; - - case SACTCONT_GPENCIL: /* Grease Pencil */ /* XXX review how this mode is handled... */ - /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - saction->ads.source = (ID *)ac->scene; - - ac->datatype = ANIMCONT_GPENCIL; - ac->data = &saction->ads; - - ac->mode = saction->mode; - return true; - - case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */ - /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - saction->ads.source = (ID *)ac->scene; - - ac->datatype = ANIMCONT_CHANNEL; - ac->data = &saction->ads; - - ac->mode = saction->mode; - return true; - - case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */ - { - /* TODO, other methods to get the mask */ - // Sequence *seq = BKE_sequencer_active_get(ac->scene); - //MovieClip *clip = ac->scene->clip; -// struct Mask *mask = seq ? seq->mask : NULL; - - /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - saction->ads.source = (ID *)ac->scene; - - ac->datatype = ANIMCONT_MASK; - ac->data = &saction->ads; - - ac->mode = saction->mode; - return true; - } - - case SACTCONT_DOPESHEET: /* DopeSheet */ - /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - saction->ads.source = (ID *)ac->scene; - - ac->datatype = ANIMCONT_DOPESHEET; - ac->data = &saction->ads; - - ac->mode = saction->mode; - return true; - - case SACTCONT_TIMELINE: /* Timeline */ - /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - saction->ads.source = (ID *)ac->scene; - - /* sync scene's "selected keys only" flag with our "only selected" flag - * XXX: This is a workaround for T55525. We shouldn't really be syncing the flags like this, - * but it's a simpler fix for now than also figuring out how the next/prev keyframe tools - * should work in the 3D View if we allowed full access to the timeline's dopesheet filters - * (i.e. we'd have to figure out where to host those settings, to be on a scene level like - * this flag currently is, along with several other unknowns) - */ - if (ac->scene->flag & SCE_KEYS_NO_SELONLY) - saction->ads.filterflag &= ~ADS_FILTER_ONLYSEL; - else - saction->ads.filterflag |= ADS_FILTER_ONLYSEL; - - ac->datatype = ANIMCONT_TIMELINE; - ac->data = &saction->ads; - - ac->mode = saction->mode; - return true; - - default: /* unhandled yet */ - ac->datatype = ANIMCONT_NONE; - ac->data = NULL; - - ac->mode = -1; - return false; - } + /* get dopesheet */ + ac->ads = &saction->ads; + + /* sync settings with current view status, then return appropriate data */ + switch (saction->mode) { + case SACTCONT_ACTION: /* 'Action Editor' */ + /* if not pinned, sync with active object */ + if (/*saction->pin == 0*/ true) { + if (ac->obact && ac->obact->adt) + saction->action = ac->obact->adt->action; + else + saction->action = NULL; + } + + ac->datatype = ANIMCONT_ACTION; + ac->data = saction->action; + + ac->mode = saction->mode; + return true; + + case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */ + ac->datatype = ANIMCONT_SHAPEKEY; + ac->data = actedit_get_shapekeys(ac); + + /* if not pinned, sync with active object */ + if (/*saction->pin == 0*/ true) { + Key *key = (Key *)ac->data; + + if (key && key->adt) + saction->action = key->adt->action; + else + saction->action = NULL; + } + + ac->mode = saction->mode; + return true; + + case SACTCONT_GPENCIL: /* Grease Pencil */ /* XXX review how this mode is handled... */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + saction->ads.source = (ID *)ac->scene; + + ac->datatype = ANIMCONT_GPENCIL; + ac->data = &saction->ads; + + ac->mode = saction->mode; + return true; + + case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + saction->ads.source = (ID *)ac->scene; + + ac->datatype = ANIMCONT_CHANNEL; + ac->data = &saction->ads; + + ac->mode = saction->mode; + return true; + + case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */ + { + /* TODO, other methods to get the mask */ + // Sequence *seq = BKE_sequencer_active_get(ac->scene); + //MovieClip *clip = ac->scene->clip; + // struct Mask *mask = seq ? seq->mask : NULL; + + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + saction->ads.source = (ID *)ac->scene; + + ac->datatype = ANIMCONT_MASK; + ac->data = &saction->ads; + + ac->mode = saction->mode; + return true; + } + + case SACTCONT_DOPESHEET: /* DopeSheet */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + saction->ads.source = (ID *)ac->scene; + + ac->datatype = ANIMCONT_DOPESHEET; + ac->data = &saction->ads; + + ac->mode = saction->mode; + return true; + + case SACTCONT_TIMELINE: /* Timeline */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + saction->ads.source = (ID *)ac->scene; + + /* sync scene's "selected keys only" flag with our "only selected" flag + * XXX: This is a workaround for T55525. We shouldn't really be syncing the flags like this, + * but it's a simpler fix for now than also figuring out how the next/prev keyframe tools + * should work in the 3D View if we allowed full access to the timeline's dopesheet filters + * (i.e. we'd have to figure out where to host those settings, to be on a scene level like + * this flag currently is, along with several other unknowns) + */ + if (ac->scene->flag & SCE_KEYS_NO_SELONLY) + saction->ads.filterflag &= ~ADS_FILTER_ONLYSEL; + else + saction->ads.filterflag |= ADS_FILTER_ONLYSEL; + + ac->datatype = ANIMCONT_TIMELINE; + ac->data = &saction->ads; + + ac->mode = saction->mode; + return true; + + default: /* unhandled yet */ + ac->datatype = ANIMCONT_NONE; + ac->data = NULL; + + ac->mode = -1; + return false; + } } /* ----------- Private Stuff - Graph Editor ------------- */ @@ -271,50 +270,50 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction) /* Get data being edited in Graph Editor (depending on current 'mode') */ static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo) { - /* init dopesheet data if non-existent (i.e. for old files) */ - if (sipo->ads == NULL) { - 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) - sipo->ads->filterflag |= ADS_FILTER_SELEDIT; - else - sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT; - - /* sync settings with current view status, then return appropriate data */ - switch (sipo->mode) { - case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */ - /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - sipo->ads->source = (ID *)ac->scene; - sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS; - - ac->datatype = ANIMCONT_FCURVES; - ac->data = sipo->ads; - - ac->mode = sipo->mode; - return true; - - case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */ - /* update scene-pointer (no need to check for pinning yet, as not implemented) */ - sipo->ads->source = (ID *)ac->scene; - sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS; - - ac->datatype = ANIMCONT_DRIVERS; - ac->data = sipo->ads; - - ac->mode = sipo->mode; - return true; - - default: /* unhandled yet */ - ac->datatype = ANIMCONT_NONE; - ac->data = NULL; - - ac->mode = -1; - return false; - } + /* init dopesheet data if non-existent (i.e. for old files) */ + if (sipo->ads == NULL) { + 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) + sipo->ads->filterflag |= ADS_FILTER_SELEDIT; + else + sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT; + + /* sync settings with current view status, then return appropriate data */ + switch (sipo->mode) { + case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + sipo->ads->source = (ID *)ac->scene; + sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS; + + ac->datatype = ANIMCONT_FCURVES; + ac->data = sipo->ads; + + ac->mode = sipo->mode; + return true; + + case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + sipo->ads->source = (ID *)ac->scene; + sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS; + + ac->datatype = ANIMCONT_DRIVERS; + ac->data = sipo->ads; + + ac->mode = sipo->mode; + return true; + + default: /* unhandled yet */ + ac->datatype = ANIMCONT_NONE; + ac->data = NULL; + + ac->mode = -1; + return false; + } } /* ----------- Private Stuff - NLA Editor ------------- */ @@ -322,20 +321,20 @@ static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo) /* Get data being edited in Graph Editor (depending on current 'mode') */ static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla) { - /* init dopesheet data if non-existent (i.e. for old files) */ - if (snla->ads == NULL) - snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet"); - ac->ads = snla->ads; + /* init dopesheet data if non-existent (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) */ - snla->ads->source = (ID *)ac->scene; - snla->ads->filterflag |= ADS_FILTER_ONLYNLA; + /* sync settings with current view status, then return appropriate data */ + /* update scene-pointer (no need to check for pinning yet, as not implemented) */ + snla->ads->source = (ID *)ac->scene; + snla->ads->filterflag |= ADS_FILTER_ONLYNLA; - ac->datatype = ANIMCONT_NLA; - ac->data = snla->ads; + ac->datatype = ANIMCONT_NLA; + ac->data = snla->ads; - return true; + return true; } /* ----------- Public API --------------- */ @@ -346,35 +345,32 @@ static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla) */ bool ANIM_animdata_context_getdata(bAnimContext *ac) { - SpaceLink *sl = ac->sl; - bool ok = false; - - /* context depends on editor we are currently in */ - if (sl) { - switch (ac->spacetype) { - case SPACE_ACTION: - { - SpaceAction *saction = (SpaceAction *)sl; - ok = actedit_get_context(ac, saction); - break; - } - case SPACE_GRAPH: - { - SpaceGraph *sipo = (SpaceGraph *)sl; - ok = graphedit_get_context(ac, sipo); - break; - } - case SPACE_NLA: - { - SpaceNla *snla = (SpaceNla *)sl; - ok = nlaedit_get_context(ac, snla); - break; - } - } - } - - /* check if there's any valid data */ - return (ok && ac->data); + SpaceLink *sl = ac->sl; + bool ok = false; + + /* context depends on editor we are currently in */ + if (sl) { + switch (ac->spacetype) { + case SPACE_ACTION: { + SpaceAction *saction = (SpaceAction *)sl; + ok = actedit_get_context(ac, saction); + break; + } + case SPACE_GRAPH: { + SpaceGraph *sipo = (SpaceGraph *)sl; + ok = graphedit_get_context(ac, sipo); + break; + } + case SPACE_NLA: { + SpaceNla *snla = (SpaceNla *)sl; + ok = nlaedit_get_context(ac, snla); + break; + } + } + } + + /* check if there's any valid data */ + return (ok && ac->data); } /* Obtain current anim-data context from Blender Context info @@ -384,37 +380,38 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac) */ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) { - Main *bmain = CTX_data_main(C); - 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 */ - if (ac == NULL) return false; - memset(ac, 0, sizeof(bAnimContext)); - - /* get useful default context settings from context */ - ac->bmain = bmain; - ac->scene = scene; - if (scene) { - ac->markers = ED_context_get_markers(C); - } - ac->depsgraph = CTX_data_depsgraph(C); - ac->view_layer = CTX_data_view_layer(C); - ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL; - ac->sa = sa; - ac->ar = ar; - ac->sl = sl; - ac->spacetype = (sa) ? sa->spacetype : 0; - ac->regiontype = (ar) ? ar->regiontype : 0; - - /* initialise default y-scale factor */ - animedit_get_yscale_factor(ac); - - /* get data context info */ - // XXX: if the below fails, try to grab this info from context instead... (to allow for scripting) - return ANIM_animdata_context_getdata(ac); + Main *bmain = CTX_data_main(C); + 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 */ + if (ac == NULL) + return false; + memset(ac, 0, sizeof(bAnimContext)); + + /* get useful default context settings from context */ + ac->bmain = bmain; + ac->scene = scene; + if (scene) { + ac->markers = ED_context_get_markers(C); + } + ac->depsgraph = CTX_data_depsgraph(C); + ac->view_layer = CTX_data_view_layer(C); + ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL; + ac->sa = sa; + ac->ar = ar; + ac->sl = sl; + ac->spacetype = (sa) ? sa->spacetype : 0; + ac->regiontype = (ar) ? ar->regiontype : 0; + + /* initialise default y-scale factor */ + animedit_get_yscale_factor(ac); + + /* get data context info */ + // XXX: if the below fails, try to grab this info from context instead... (to allow for scripting) + return ANIM_animdata_context_getdata(ac); } /* ************************************************************ */ @@ -439,24 +436,25 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) * one case below. */ #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; \ - } \ - \ - { \ - (void) _doSubChannels; \ - } + { \ + 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; \ + } \ +\ + { \ + (void)_doSubChannels; \ + } /* ... standard sub-channel filtering can go on here now ... */ #define END_ANIMFILTER_SUBCHANNELS \ - filter_mode = _filter; \ - } (void)0 + filter_mode = _filter; \ + } \ + (void)0 /* ............................... */ @@ -500,36 +498,38 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) * 4B) normal keyframes: only when there is an active action */ #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \ - { \ - if ((id)->adt) { \ - if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \ - if (filter_mode & ANIMFILTER_ANIMDATA) { \ - adtOk \ - } \ - else if (ads->filterflag & ADS_FILTER_ONLYNLA) { \ - if (ANIMDATA_HAS_NLA(id)) { \ - nlaOk \ - } \ - else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || ANIMDATA_HAS_KEYS(id)) { \ - nlaOk \ - } \ - } \ - else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) { \ - if (ANIMDATA_HAS_DRIVERS(id)) { \ - driversOk \ - } \ - } \ - else { \ - if (ANIMDATA_HAS_NLA(id)) { \ - nlaKeysOk \ - } \ - if (ANIMDATA_HAS_KEYS(id)) { \ - keysOk \ - } \ - } \ - } \ - } \ - } (void)0 + { \ + if ((id)->adt) { \ + if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || \ + !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \ + if (filter_mode & ANIMFILTER_ANIMDATA) { \ + adtOk \ + } \ + else if (ads->filterflag & ADS_FILTER_ONLYNLA) { \ + if (ANIMDATA_HAS_NLA(id)) { \ + nlaOk \ + } \ + else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || ANIMDATA_HAS_KEYS(id)) { \ + nlaOk \ + } \ + } \ + else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) { \ + if (ANIMDATA_HAS_DRIVERS(id)) { \ + driversOk \ + } \ + } \ + else { \ + if (ANIMDATA_HAS_NLA(id)) { \ + nlaKeysOk \ + } \ + if (ANIMDATA_HAS_KEYS(id)) { \ + keysOk \ + } \ + } \ + } \ + } \ + } \ + (void)0 /* ............................... */ @@ -539,32 +539,35 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) * ! 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, fcurve_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, fcurve_owner_id); \ - if (ale) { \ - BLI_addtail(anim_data, ale); \ - items ++; \ - ale_statement \ - } \ - } (void)0 +#define ANIMCHANNEL_NEW_CHANNEL_FULL( \ + channel_data, channel_type, owner_id, fcurve_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, fcurve_owner_id); \ + if (ale) { \ + BLI_addtail(anim_data, ale); \ + items++; \ + ale_statement \ + } \ + } \ + (void)0 #define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id, fcurve_owner_id) \ - ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, fcurve_owner_id, {}) + ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, fcurve_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) ) + (!(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE)) /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ #define ANIMCHANNEL_SELOK(test_func) \ - (!(filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) || \ - ((filter_mode & ANIMFILTER_SEL) && test_func) || \ - ((filter_mode & ANIMFILTER_UNSEL) && test_func == 0) ) + (!(filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) || \ + ((filter_mode & ANIMFILTER_SEL) && test_func) || \ + ((filter_mode & ANIMFILTER_UNSEL) && test_func == 0)) /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes * - _SELEDIT means that only selected curves will have visible+editable keyframes @@ -575,414 +578,386 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) * 3) test_func (i.e. selection test) - only if selected, this test will pass */ #define ANIMCHANNEL_SELEDITOK(test_func) \ - (!(filter_mode & ANIMFILTER_SELEDIT) || \ - !(filter_mode & ANIMFILTER_FOREDIT) || \ - (test_func) ) + (!(filter_mode & ANIMFILTER_SELEDIT) || !(filter_mode & ANIMFILTER_FOREDIT) || (test_func)) /* ----------- 'Private' Stuff --------------- */ /* this function allocates memory for a new bAnimListElem struct for the * provided animation channel-data. */ -static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owner_id, ID *fcurve_owner_id) +static bAnimListElem *make_new_animlistelem(void *data, + short datatype, + ID *owner_id, + ID *fcurve_owner_id) { - bAnimListElem *ale = NULL; - - /* only allocate memory if there is data to convert */ - if (data) { - /* allocate and set generic data */ - ale = MEM_callocN(sizeof(bAnimListElem), "bAnimListElem"); - - ale->data = data; - ale->type = datatype; - - ale->id = owner_id; - ale->adt = BKE_animdata_from_id(owner_id); - ale->fcurve_owner_id = fcurve_owner_id; - - /* do specifics */ - switch (datatype) { - case ANIMTYPE_SUMMARY: - { - /* nothing to include for now... this is just a dummy wrappy around all the other channels - * in the DopeSheet, and gets included at the start of the list - */ - ale->key_data = NULL; - ale->datatype = ALE_ALL; - break; - } - case ANIMTYPE_SCENE: - { - Scene *sce = (Scene *)data; - - ale->flag = sce->flag; - - ale->key_data = sce; - ale->datatype = ALE_SCE; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_OBJECT: - { - Base *base = (Base *)data; - Object *ob = base->object; - - ale->flag = ob->flag; - - ale->key_data = ob; - ale->datatype = ALE_OB; - - ale->adt = BKE_animdata_from_id(&ob->id); - break; - } - case ANIMTYPE_FILLACTD: - { - bAction *act = (bAction *)data; - - ale->flag = act->flag; - - ale->key_data = act; - ale->datatype = ALE_ACT; - break; - } - case ANIMTYPE_FILLDRIVERS: - { - AnimData *adt = (AnimData *)data; - - ale->flag = adt->flag; - - // XXX... drivers don't show summary for now - ale->key_data = NULL; - ale->datatype = ALE_NONE; - break; - } - case ANIMTYPE_DSMAT: - { - Material *ma = (Material *)data; - AnimData *adt = ma->adt; - - ale->flag = FILTER_MAT_OBJD(ma); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSLAM: - { - Light *la = (Light *)data; - AnimData *adt = la->adt; - - ale->flag = FILTER_LAM_OBJD(la); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSCAM: - { - Camera *ca = (Camera *)data; - AnimData *adt = ca->adt; - - ale->flag = FILTER_CAM_OBJD(ca); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSCACHEFILE: - { - CacheFile *cache_file = (CacheFile *)data; - AnimData *adt = cache_file->adt; - - ale->flag = FILTER_CACHEFILE_OBJD(cache_file); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSCUR: - { - Curve *cu = (Curve *)data; - AnimData *adt = cu->adt; - - ale->flag = FILTER_CUR_OBJD(cu); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSARM: - { - bArmature *arm = (bArmature *)data; - AnimData *adt = arm->adt; - - ale->flag = FILTER_ARM_OBJD(arm); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSMESH: - { - Mesh *me = (Mesh *)data; - AnimData *adt = me->adt; - - ale->flag = FILTER_MESH_OBJD(me); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSLAT: - { - Lattice *lt = (Lattice *)data; - AnimData *adt = lt->adt; - - ale->flag = FILTER_LATTICE_OBJD(lt); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSSPK: - { - Speaker *spk = (Speaker *)data; - AnimData *adt = spk->adt; - - ale->flag = FILTER_SPK_OBJD(spk); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSSKEY: - { - Key *key = (Key *)data; - AnimData *adt = key->adt; - - ale->flag = FILTER_SKE_OBJD(key); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSWOR: - { - World *wo = (World *)data; - AnimData *adt = wo->adt; - - ale->flag = FILTER_WOR_SCED(wo); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSNTREE: - { - bNodeTree *ntree = (bNodeTree *)data; - AnimData *adt = ntree->adt; - - ale->flag = FILTER_NTREE_DATA(ntree); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSLINESTYLE: - { - FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data; - AnimData *adt = linestyle->adt; - - ale->flag = FILTER_LS_SCED(linestyle); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSPART: - { - ParticleSettings *part = (ParticleSettings *)ale->data; - AnimData *adt = part->adt; - - ale->flag = FILTER_PART_OBJD(part); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSTEX: - { - Tex *tex = (Tex *)data; - AnimData *adt = tex->adt; - - ale->flag = FILTER_TEX_DATA(tex); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSGPENCIL: - { - bGPdata *gpd = (bGPdata *)data; - AnimData *adt = gpd->adt; - - /* NOTE: we just reuse the same expand filter for this case */ - ale->flag = EXPANDED_GPD(gpd); - - // XXX: currently, this is only used for access to its animation data - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_DSMCLIP: - { - MovieClip *clip = (MovieClip *)data; - AnimData *adt = clip->adt; - - ale->flag = EXPANDED_MCLIP(clip); - - ale->key_data = (adt) ? adt->action : NULL; - ale->datatype = ALE_ACT; - - ale->adt = BKE_animdata_from_id(data); - break; - } - case ANIMTYPE_NLACONTROLS: - { - AnimData *adt = (AnimData *)data; - - ale->flag = adt->flag; - - ale->key_data = NULL; - ale->datatype = ALE_NONE; - break; - } - case ANIMTYPE_GROUP: - { - bActionGroup *agrp = (bActionGroup *)data; - - ale->flag = agrp->flag; - - ale->key_data = NULL; - ale->datatype = ALE_GROUP; - break; - } - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: /* practically the same as ANIMTYPE_FCURVE. - * Differences are applied post-creation */ - { - FCurve *fcu = (FCurve *)data; - - ale->flag = fcu->flag; - - ale->key_data = fcu; - ale->datatype = ALE_FCURVE; - break; - } - case ANIMTYPE_SHAPEKEY: - { - KeyBlock *kb = (KeyBlock *)data; - Key *key = (Key *)ale->id; - - ale->flag = kb->flag; - - /* whether we have keyframes depends on whether there is a Key block to find it from */ - if (key) { - /* index of shapekey is defined by place in key's list */ - ale->index = BLI_findindex(&key->block, kb); - - /* the corresponding keyframes are from the animdata */ - if (ale->adt && ale->adt->action) { - bAction *act = ale->adt->action; - char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb); - - /* try to find the F-Curve which corresponds to this exactly, - * then free the MEM_alloc'd string - */ - if (rna_path) { - ale->key_data = (void *)list_find_fcurve(&act->curves, rna_path, 0); - MEM_freeN(rna_path); - } - } - ale->datatype = (ale->key_data) ? ALE_FCURVE : ALE_NONE; - } - break; - } - case ANIMTYPE_GPLAYER: - { - bGPDlayer *gpl = (bGPDlayer *)data; - - ale->flag = gpl->flag; - - ale->key_data = NULL; - ale->datatype = ALE_GPFRAME; - break; - } - case ANIMTYPE_MASKLAYER: - { - MaskLayer *masklay = (MaskLayer *)data; - - ale->flag = masklay->flag; - - ale->key_data = NULL; - ale->datatype = ALE_MASKLAY; - break; - } - case ANIMTYPE_NLATRACK: - { - NlaTrack *nlt = (NlaTrack *)data; - - ale->flag = nlt->flag; - - ale->key_data = &nlt->strips; - ale->datatype = ALE_NLASTRIP; - break; - } - case ANIMTYPE_NLAACTION: - { - /* nothing to include for now... nothing editable from NLA-perspective here */ - ale->key_data = NULL; - ale->datatype = ALE_NONE; - break; - } - } - } - - /* return created datatype */ - return ale; + bAnimListElem *ale = NULL; + + /* only allocate memory if there is data to convert */ + if (data) { + /* allocate and set generic data */ + ale = MEM_callocN(sizeof(bAnimListElem), "bAnimListElem"); + + ale->data = data; + ale->type = datatype; + + ale->id = owner_id; + ale->adt = BKE_animdata_from_id(owner_id); + ale->fcurve_owner_id = fcurve_owner_id; + + /* do specifics */ + switch (datatype) { + case ANIMTYPE_SUMMARY: { + /* nothing to include for now... this is just a dummy wrappy around all the other channels + * in the DopeSheet, and gets included at the start of the list + */ + ale->key_data = NULL; + ale->datatype = ALE_ALL; + break; + } + case ANIMTYPE_SCENE: { + Scene *sce = (Scene *)data; + + ale->flag = sce->flag; + + ale->key_data = sce; + ale->datatype = ALE_SCE; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_OBJECT: { + Base *base = (Base *)data; + Object *ob = base->object; + + ale->flag = ob->flag; + + ale->key_data = ob; + ale->datatype = ALE_OB; + + ale->adt = BKE_animdata_from_id(&ob->id); + break; + } + case ANIMTYPE_FILLACTD: { + bAction *act = (bAction *)data; + + ale->flag = act->flag; + + ale->key_data = act; + ale->datatype = ALE_ACT; + break; + } + case ANIMTYPE_FILLDRIVERS: { + AnimData *adt = (AnimData *)data; + + ale->flag = adt->flag; + + // XXX... drivers don't show summary for now + ale->key_data = NULL; + ale->datatype = ALE_NONE; + break; + } + case ANIMTYPE_DSMAT: { + Material *ma = (Material *)data; + AnimData *adt = ma->adt; + + ale->flag = FILTER_MAT_OBJD(ma); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSLAM: { + Light *la = (Light *)data; + AnimData *adt = la->adt; + + ale->flag = FILTER_LAM_OBJD(la); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSCAM: { + Camera *ca = (Camera *)data; + AnimData *adt = ca->adt; + + ale->flag = FILTER_CAM_OBJD(ca); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSCACHEFILE: { + CacheFile *cache_file = (CacheFile *)data; + AnimData *adt = cache_file->adt; + + ale->flag = FILTER_CACHEFILE_OBJD(cache_file); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSCUR: { + Curve *cu = (Curve *)data; + AnimData *adt = cu->adt; + + ale->flag = FILTER_CUR_OBJD(cu); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSARM: { + bArmature *arm = (bArmature *)data; + AnimData *adt = arm->adt; + + ale->flag = FILTER_ARM_OBJD(arm); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSMESH: { + Mesh *me = (Mesh *)data; + AnimData *adt = me->adt; + + ale->flag = FILTER_MESH_OBJD(me); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSLAT: { + Lattice *lt = (Lattice *)data; + AnimData *adt = lt->adt; + + ale->flag = FILTER_LATTICE_OBJD(lt); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSSPK: { + Speaker *spk = (Speaker *)data; + AnimData *adt = spk->adt; + + ale->flag = FILTER_SPK_OBJD(spk); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSSKEY: { + Key *key = (Key *)data; + AnimData *adt = key->adt; + + ale->flag = FILTER_SKE_OBJD(key); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSWOR: { + World *wo = (World *)data; + AnimData *adt = wo->adt; + + ale->flag = FILTER_WOR_SCED(wo); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSNTREE: { + bNodeTree *ntree = (bNodeTree *)data; + AnimData *adt = ntree->adt; + + ale->flag = FILTER_NTREE_DATA(ntree); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSLINESTYLE: { + FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data; + AnimData *adt = linestyle->adt; + + ale->flag = FILTER_LS_SCED(linestyle); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSPART: { + ParticleSettings *part = (ParticleSettings *)ale->data; + AnimData *adt = part->adt; + + ale->flag = FILTER_PART_OBJD(part); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSTEX: { + Tex *tex = (Tex *)data; + AnimData *adt = tex->adt; + + ale->flag = FILTER_TEX_DATA(tex); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSGPENCIL: { + bGPdata *gpd = (bGPdata *)data; + AnimData *adt = gpd->adt; + + /* NOTE: we just reuse the same expand filter for this case */ + ale->flag = EXPANDED_GPD(gpd); + + // XXX: currently, this is only used for access to its animation data + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_DSMCLIP: { + MovieClip *clip = (MovieClip *)data; + AnimData *adt = clip->adt; + + ale->flag = EXPANDED_MCLIP(clip); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } + case ANIMTYPE_NLACONTROLS: { + AnimData *adt = (AnimData *)data; + + ale->flag = adt->flag; + + ale->key_data = NULL; + ale->datatype = ALE_NONE; + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *agrp = (bActionGroup *)data; + + ale->flag = agrp->flag; + + ale->key_data = NULL; + ale->datatype = ALE_GROUP; + break; + } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: /* practically the same as ANIMTYPE_FCURVE. + * Differences are applied post-creation */ + { + FCurve *fcu = (FCurve *)data; + + ale->flag = fcu->flag; + + ale->key_data = fcu; + ale->datatype = ALE_FCURVE; + break; + } + case ANIMTYPE_SHAPEKEY: { + KeyBlock *kb = (KeyBlock *)data; + Key *key = (Key *)ale->id; + + ale->flag = kb->flag; + + /* whether we have keyframes depends on whether there is a Key block to find it from */ + if (key) { + /* index of shapekey is defined by place in key's list */ + ale->index = BLI_findindex(&key->block, kb); + + /* the corresponding keyframes are from the animdata */ + if (ale->adt && ale->adt->action) { + bAction *act = ale->adt->action; + char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb); + + /* try to find the F-Curve which corresponds to this exactly, + * then free the MEM_alloc'd string + */ + if (rna_path) { + ale->key_data = (void *)list_find_fcurve(&act->curves, rna_path, 0); + MEM_freeN(rna_path); + } + } + ale->datatype = (ale->key_data) ? ALE_FCURVE : ALE_NONE; + } + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)data; + + ale->flag = gpl->flag; + + ale->key_data = NULL; + ale->datatype = ALE_GPFRAME; + break; + } + case ANIMTYPE_MASKLAYER: { + MaskLayer *masklay = (MaskLayer *)data; + + ale->flag = masklay->flag; + + ale->key_data = NULL; + ale->datatype = ALE_MASKLAY; + break; + } + case ANIMTYPE_NLATRACK: { + NlaTrack *nlt = (NlaTrack *)data; + + ale->flag = nlt->flag; + + ale->key_data = &nlt->strips; + ale->datatype = ALE_NLASTRIP; + break; + } + case ANIMTYPE_NLAACTION: { + /* nothing to include for now... nothing editable from NLA-perspective here */ + ale->key_data = NULL; + ale->datatype = ALE_NONE; + break; + } + } + } + + /* return created datatype */ + return ale; } /* ----------------------------------------- */ @@ -992,154 +967,160 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne */ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode) { - if (fcu->grp != NULL && fcu->grp->flag & ADT_CURVES_ALWAYS_VISIBLE) { - return false; - } - /* hidden items should be skipped if we only care about visible data, - * but we aren't interested in hidden stuff */ - const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN); - - if (GS(owner_id->name) == ID_OB) { - Object *ob = (Object *)owner_id; - - /* only consider if F-Curve involves pose.bones */ - if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) { - bPoseChannel *pchan; - char *bone_name; - - /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (bone_name) MEM_freeN(bone_name); - - /* 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 (skip_hidden) { - bArmature *arm = (bArmature *)ob->data; - - /* skipping - not visible on currently visible layers */ - if ((arm->layer & pchan->bone->layer) == 0) - return true; - /* skipping - is currently hidden */ - if (pchan->bone->flag & BONE_HIDDEN_P) - return true; - } - - /* can only add this F-Curve if it is selected */ - if (ads->filterflag & ADS_FILTER_ONLYSEL) { - if ((pchan->bone->flag & BONE_SELECTED) == 0) - return true; - } - } - } - } - else if (GS(owner_id->name) == ID_SCE) { - Scene *scene = (Scene *)owner_id; - - /* only consider if F-Curve involves sequence_editor.sequences */ - if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq = NULL; - char *seq_name; - - if (ed) { - /* get strip name, and check if this strip is selected */ - seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); - seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); - if (seq_name) MEM_freeN(seq_name); - } - - /* can only add this F-Curve if it is selected */ - if (ads->filterflag & ADS_FILTER_ONLYSEL) { - if ((seq == NULL) || (seq->flag & SELECT) == 0) - return true; - } - } - } - else if (GS(owner_id->name) == ID_NT) { - bNodeTree *ntree = (bNodeTree *)owner_id; - - /* check for selected nodes */ - if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) { - bNode *node; - char *node_name; - - /* get strip name, and check if this strip is selected */ - node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); - node = nodeFindNodebyName(ntree, node_name); - if (node_name) MEM_freeN(node_name); - - /* can only add this F-Curve if it is selected */ - if (ads->filterflag & ADS_FILTER_ONLYSEL) { - if ((node) && (node->flag & NODE_SELECT) == 0) - return true; - } - } - } - - return false; + if (fcu->grp != NULL && fcu->grp->flag & ADT_CURVES_ALWAYS_VISIBLE) { + return false; + } + /* hidden items should be skipped if we only care about visible data, + * but we aren't interested in hidden stuff */ + const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) && + !(ads->filterflag & ADS_FILTER_INCL_HIDDEN); + + if (GS(owner_id->name) == ID_OB) { + Object *ob = (Object *)owner_id; + + /* only consider if F-Curve involves pose.bones */ + if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) { + bPoseChannel *pchan; + char *bone_name; + + /* get bone-name, and check if this bone is selected */ + bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name) + MEM_freeN(bone_name); + + /* 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 (skip_hidden) { + bArmature *arm = (bArmature *)ob->data; + + /* skipping - not visible on currently visible layers */ + if ((arm->layer & pchan->bone->layer) == 0) + return true; + /* skipping - is currently hidden */ + if (pchan->bone->flag & BONE_HIDDEN_P) + return true; + } + + /* can only add this F-Curve if it is selected */ + if (ads->filterflag & ADS_FILTER_ONLYSEL) { + if ((pchan->bone->flag & BONE_SELECTED) == 0) + return true; + } + } + } + } + else if (GS(owner_id->name) == ID_SCE) { + Scene *scene = (Scene *)owner_id; + + /* only consider if F-Curve involves sequence_editor.sequences */ + if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { + Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq = NULL; + char *seq_name; + + if (ed) { + /* get strip name, and check if this strip is selected */ + seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); + seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); + if (seq_name) + MEM_freeN(seq_name); + } + + /* can only add this F-Curve if it is selected */ + if (ads->filterflag & ADS_FILTER_ONLYSEL) { + if ((seq == NULL) || (seq->flag & SELECT) == 0) + return true; + } + } + } + else if (GS(owner_id->name) == ID_NT) { + bNodeTree *ntree = (bNodeTree *)owner_id; + + /* check for selected nodes */ + if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) { + bNode *node; + char *node_name; + + /* get strip name, and check if this strip is selected */ + node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); + node = nodeFindNodebyName(ntree, node_name); + if (node_name) + MEM_freeN(node_name); + + /* can only add this F-Curve if it is selected */ + if (ads->filterflag & ADS_FILTER_ONLYSEL) { + if ((node) && (node->flag & NODE_SELECT) == 0) + return true; + } + } + } + + return false; } /* Helper for name-based filtering - Perform "partial/fuzzy matches" (as in 80a7efd) */ static bool name_matches_dopesheet_filter(bDopeSheet *ads, char *name) { - if (ads->flag & ADS_FLAG_FUZZY_NAMES) { - /* full fuzzy, multi-word, case insensitive matches */ - const size_t str_len = strlen(ads->searchstr); - const int words_max = (str_len / 2) + 1; - - int (*words)[2] = BLI_array_alloca(words, words_max); - const int words_len = BLI_string_find_split_words(ads->searchstr, str_len, ' ', words, words_max); - bool found = false; - - /* match name against all search words */ - for (int index = 0; index < words_len; index++) { - if (BLI_strncasestr(name, ads->searchstr + words[index][0], words[index][1])) { - found = true; - break; - } - } - - /* if we have a match somewhere, this returns true */ - return found; - } - else { - /* fallback/default - just case insensitive, but starts from start of word */ - return BLI_strcasestr(name, ads->searchstr) != NULL; - } + if (ads->flag & ADS_FLAG_FUZZY_NAMES) { + /* full fuzzy, multi-word, case insensitive matches */ + const size_t str_len = strlen(ads->searchstr); + const int words_max = (str_len / 2) + 1; + + int(*words)[2] = BLI_array_alloca(words, words_max); + const int words_len = BLI_string_find_split_words( + ads->searchstr, str_len, ' ', words, words_max); + bool found = false; + + /* match name against all search words */ + for (int index = 0; index < words_len; index++) { + if (BLI_strncasestr(name, ads->searchstr + words[index][0], words[index][1])) { + found = true; + break; + } + } + + /* if we have a match somewhere, this returns true */ + return found; + } + else { + /* fallback/default - just case insensitive, but starts from start of word */ + return BLI_strcasestr(name, ads->searchstr) != NULL; + } } /* (Display-)Name-based F-Curve filtering * NOTE: when this function returns true, the F-Curve is to be skipped */ -static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id) +static bool skip_fcurve_with_name( + bDopeSheet *ads, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id) { - bAnimListElem ale_dummy = {NULL}; - const bAnimChannelType *acf; - - /* create a dummy wrapper for the F-Curve, so we can get typeinfo for it */ - ale_dummy.type = channel_type; - ale_dummy.owner = owner; - 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 !name_matches_dopesheet_filter(ads, name); - } - - /* just let this go... */ - return true; + bAnimListElem ale_dummy = {NULL}; + const bAnimChannelType *acf; + + /* create a dummy wrapper for the F-Curve, so we can get typeinfo for it */ + ale_dummy.type = channel_type; + ale_dummy.owner = owner; + 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 !name_matches_dopesheet_filter(ads, name); + } + + /* just let this go... */ + return true; } /** @@ -1149,247 +1130,271 @@ static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, eAnim_ChannelTyp */ static bool fcurve_has_errors(FCurve *fcu) { - /* F-Curve disabled - path eval error */ - if (fcu->flag & FCURVE_DISABLED) { - return true; - } - - /* driver? */ - if (fcu->driver) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - - /* error flag on driver usually means that there is an error - * BUT this may not hold with PyDrivers as this flag gets cleared - * if no critical errors prevent the driver from working... - */ - if (driver->flag & DRIVER_FLAG_INVALID) - return true; - - /* check variables for other things that need linting... */ - // TODO: maybe it would be more efficient just to have a quick flag for this? - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - if (dtar->flag & DTAR_FLAG_INVALID) - return true; - } - DRIVER_TARGETS_LOOPER_END; - } - } - - /* no errors found */ - return false; + /* F-Curve disabled - path eval error */ + if (fcu->flag & FCURVE_DISABLED) { + return true; + } + + /* driver? */ + if (fcu->driver) { + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + + /* error flag on driver usually means that there is an error + * BUT this may not hold with PyDrivers as this flag gets cleared + * if no critical errors prevent the driver from working... + */ + if (driver->flag & DRIVER_FLAG_INVALID) + return true; + + /* check variables for other things that need linting... */ + // TODO: maybe it would be more efficient just to have a quick flag for this? + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (dtar->flag & DTAR_FLAG_INVALID) + return true; + } + DRIVER_TARGETS_LOOPER_END; + } + } + + /* no errors found */ + return false; } /* find the next F-Curve that is usable for inclusion */ -static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, eAnim_ChannelType channel_type, int filter_mode, void *owner, ID *owner_id) +static FCurve *animfilter_fcurve_next(bDopeSheet *ads, + FCurve *first, + eAnim_ChannelType channel_type, + int filter_mode, + void *owner, + ID *owner_id) { - bActionGroup *grp = (channel_type == ANIMTYPE_FCURVE) ? owner : NULL; - FCurve *fcu = NULL; - - /* loop over F-Curves - assume that the caller of this has already checked that these should be included - * 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/Sequence-Strip/Node Based F-Curves: - * - the 'Only Selected' and 'Include Hidden' data filters should be applied to sub-ID data which - * can be independently selected/hidden, such as Pose-Channels, Sequence Strips, and Nodes. - * Since these checks were traditionally done as first check for objects, we do the same here - * - we currently use an 'approximate' method for getting these F-Curves that doesn't require - * carefully checking the entire path - * - this will also affect things like Drivers, and also works for Bone Constraints - */ - if (ads && owner_id) { - if ((filter_mode & ANIMFILTER_TMP_IGNORE_ONLYSEL) == 0) { - if ((ads->filterflag & ADS_FILTER_ONLYSEL) || (ads->filterflag & ADS_FILTER_INCL_HIDDEN) == 0) { - 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_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->searchstr[0] != '\0')) && (owner_id) ) { - if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id)) - continue; - } - - /* error-based filtering... */ - if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) { - /* skip if no errors... */ - if (fcurve_has_errors(fcu) == false) - continue; - } - - /* this F-Curve can be used, so return it */ - return fcu; - } - } - } - } - } - - /* no (more) F-Curves from the list are suitable... */ - return NULL; + bActionGroup *grp = (channel_type == ANIMTYPE_FCURVE) ? owner : NULL; + FCurve *fcu = NULL; + + /* loop over F-Curves - assume that the caller of this has already checked that these should be included + * 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/Sequence-Strip/Node Based F-Curves: + * - the 'Only Selected' and 'Include Hidden' data filters should be applied to sub-ID data which + * can be independently selected/hidden, such as Pose-Channels, Sequence Strips, and Nodes. + * Since these checks were traditionally done as first check for objects, we do the same here + * - we currently use an 'approximate' method for getting these F-Curves that doesn't require + * carefully checking the entire path + * - this will also affect things like Drivers, and also works for Bone Constraints + */ + if (ads && owner_id) { + if ((filter_mode & ANIMFILTER_TMP_IGNORE_ONLYSEL) == 0) { + if ((ads->filterflag & ADS_FILTER_ONLYSEL) || + (ads->filterflag & ADS_FILTER_INCL_HIDDEN) == 0) { + 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_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->searchstr[0] != '\0')) && (owner_id)) { + if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id)) + continue; + } + + /* error-based filtering... */ + if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) { + /* skip if no errors... */ + if (fcurve_has_errors(fcu) == false) + continue; + } + + /* this F-Curve can be used, so return it */ + return fcu; + } + } + } + } + } + + /* no (more) F-Curves from the list are suitable... */ + return NULL; } -static size_t animfilter_fcurves(ListBase *anim_data, bDopeSheet *ads, - FCurve *first, eAnim_ChannelType fcurve_type, +static size_t animfilter_fcurves(ListBase *anim_data, + bDopeSheet *ads, + FCurve *first, + eAnim_ChannelType fcurve_type, int filter_mode, - void *owner, ID *owner_id, ID *fcurve_owner_id) + void *owner, + ID *owner_id, + ID *fcurve_owner_id) { - FCurve *fcu; - size_t items = 0; - - /* loop over every F-Curve able to be included - * - this for-loop works like this: - * 1) the starting F-Curve is assigned to the fcu pointer so that we have a starting point to search from - * 2) the first valid F-Curve to start from (which may include the one given as 'first') in the remaining - * list of F-Curves is found, and verified to be non-null - * 3) the F-Curve referenced by fcu pointer is added to the list - * 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 = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, owner, owner_id)) ); fcu = fcu->next) { - if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) { - /* NLA Control Curve - Basically the same as normal F-Curves, - * except we need to set some stuff differently */ - ANIMCHANNEL_NEW_CHANNEL_FULL(fcu, ANIMTYPE_NLACURVE, owner_id, fcurve_owner_id, { - ale->owner = owner; /* strip */ - ale->adt = NULL; /* to prevent time mapping from causing problems */ - }); - } - else { - /* Normal FCurve */ - ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id, fcurve_owner_id); - } - } - - /* return the number of items added to the list */ - return items; + FCurve *fcu; + size_t items = 0; + + /* loop over every F-Curve able to be included + * - this for-loop works like this: + * 1) the starting F-Curve is assigned to the fcu pointer so that we have a starting point to search from + * 2) the first valid F-Curve to start from (which may include the one given as 'first') in the remaining + * list of F-Curves is found, and verified to be non-null + * 3) the F-Curve referenced by fcu pointer is added to the list + * 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 = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, owner, owner_id))); + fcu = fcu->next) { + if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) { + /* NLA Control Curve - Basically the same as normal F-Curves, + * except we need to set some stuff differently */ + ANIMCHANNEL_NEW_CHANNEL_FULL(fcu, ANIMTYPE_NLACURVE, owner_id, fcurve_owner_id, { + ale->owner = owner; /* strip */ + ale->adt = NULL; /* to prevent time mapping from causing problems */ + }); + } + else { + /* Normal FCurve */ + ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id, 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) +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 ( - /* care about hierarchy but group isn't expanded */ - ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp) == 0) && - /* care about selection status */ - (filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) ) - { - /* 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 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, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id); - - /* filter list, starting from this F-Curve */ - tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id, &act->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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + 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 ( + /* care about hierarchy but group isn't expanded */ + ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp) == 0) && + /* care about selection status */ + (filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL))) { + /* 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 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, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id); + + /* filter list, starting from this F-Curve */ + tmp_items += animfilter_fcurves( + &tmp_data, ads, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id, &act->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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } -static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, ID *owner_id) +static size_t animfilter_action(bAnimContext *ac, + ListBase *anim_data, + bDopeSheet *ads, + bAction *act, + int filter_mode, + ID *owner_id) { - bActionGroup *agrp; - 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... - */ - if ((filter_mode & ANIMFILTER_FOREDIT) && ID_IS_LINKED(act)) - return 0; - - /* 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; - - /* action group's channels */ - items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id); - } - - /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */ - if (!(filter_mode & ANIMFILTER_ACTGROUPED)) { - FCurve *firstfcu = (lastchan) ? (lastchan->next) : (act->curves.first); - items += animfilter_fcurves(anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, NULL, owner_id, &act->id); - } - - /* return the number of items added to the list */ - return items; + bActionGroup *agrp; + 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... + */ + if ((filter_mode & ANIMFILTER_FOREDIT) && ID_IS_LINKED(act)) + return 0; + + /* 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; + + /* action group's channels */ + items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id); + } + + /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */ + if (!(filter_mode & ANIMFILTER_ACTGROUPED)) { + FCurve *firstfcu = (lastchan) ? (lastchan->next) : (act->curves.first); + items += animfilter_fcurves( + anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, NULL, owner_id, &act->id); + } + + /* return the number of items added to the list */ + return items; } /* Include NLA-Data for NLA-Editor: @@ -1400,863 +1405,916 @@ static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeShee * - 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 size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id) +static size_t animfilter_nla(bAnimContext *UNUSED(ac), + ListBase *anim_data, + bDopeSheet *ads, + AnimData *adt, + int filter_mode, + ID *owner_id) { - NlaTrack *nlt; - NlaTrack *first = NULL, *next = NULL; - size_t items = 0; - - /* if showing channels, include active action */ - 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, NULL, - { - ale->data = adt->action ? adt->action : NULL; - }); - } - } - - /* first track to include will be the last one if we're filtering by channels */ - first = adt->nla_tracks.last; - } - else { - /* first track to include will the first one (as per normal) */ - first = adt->nla_tracks.first; - } - - /* 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_LIST_CHANNELS) - next = nlt->prev; - else - next = nlt->next; - - /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now - * - active track should still get shown though (even though it has disabled flag set) - */ - // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel - if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && (adt->act_track != nlt)) - continue; - - /* only work with this channel and its subchannels if it is editable */ - if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) { - /* only include this track if selected in a way consistent with the filtering requirements */ - if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) { - /* only include if this track is active */ - if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) { - /* name based filtering... */ - if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) { - bool track_ok = false, strip_ok = false; - - /* check if the name of the track, or the strips it has are ok... */ - track_ok = name_matches_dopesheet_filter(ads, nlt->name); - - if (track_ok == false) { - NlaStrip *strip; - for (strip = nlt->strips.first; strip; strip = strip->next) { - if (name_matches_dopesheet_filter(ads, strip->name)) { - strip_ok = true; - break; - } - } - } - - /* skip if both fail this test... */ - if (!track_ok && !strip_ok) { - continue; - } - } - - /* add the track now that it has passed all our tests */ - ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id, NULL); - } - } - } - } - - /* return the number of items added to the list */ - return items; + NlaTrack *nlt; + NlaTrack *first = NULL, *next = NULL; + size_t items = 0; + + /* if showing channels, include active action */ + 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, NULL, { + ale->data = adt->action ? adt->action : NULL; + }); + } + } + + /* first track to include will be the last one if we're filtering by channels */ + first = adt->nla_tracks.last; + } + else { + /* first track to include will the first one (as per normal) */ + first = adt->nla_tracks.first; + } + + /* 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_LIST_CHANNELS) + next = nlt->prev; + else + next = nlt->next; + + /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now + * - active track should still get shown though (even though it has disabled flag set) + */ + // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel + if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && + (adt->act_track != nlt)) + continue; + + /* only work with this channel and its subchannels if it is editable */ + if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) { + /* only include this track if selected in a way consistent with the filtering requirements */ + if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) { + /* only include if this track is active */ + if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) { + /* name based filtering... */ + if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) { + bool track_ok = false, strip_ok = false; + + /* check if the name of the track, or the strips it has are ok... */ + track_ok = name_matches_dopesheet_filter(ads, nlt->name); + + if (track_ok == false) { + NlaStrip *strip; + for (strip = nlt->strips.first; strip; strip = strip->next) { + if (name_matches_dopesheet_filter(ads, strip->name)) { + strip_ok = true; + break; + } + } + } + + /* skip if both fail this test... */ + if (!track_ok && !strip_ok) { + continue; + } + } + + /* add the track now that it has passed all our tests */ + ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id, NULL); + } + } + } + } + + /* return the number of items added to the list */ + return items; } /* Include the control FCurves per NLA Strip in the channel list * NOTE: This is includes the expander too... */ -static size_t animfilter_nla_controls(ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id) +static size_t animfilter_nla_controls( + ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id) { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - size_t items = 0; - - /* add control curves from each NLA strip... */ - /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */ - BEGIN_ANIMFILTER_SUBCHANNELS(((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0)) - { - NlaTrack *nlt; - NlaStrip *strip; - - /* for now, we only go one level deep - so controls on grouped FCurves are not handled */ - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - for (strip = nlt->strips.first; strip; strip = strip->next) { - /* pass strip as the "owner", so that the name lookups (used while filtering) will resolve */ - /* NLA tracks are coming from AnimData, so owner of f-curves - * is the same as owner of animation data. */ - tmp_items += animfilter_fcurves(&tmp_data, ads, strip->fcurves.first, ANIMTYPE_NLACURVE, - filter_mode, strip, owner_id, owner_id); - } - } - } - END_ANIMFILTER_SUBCHANNELS; - - /* did we find anything? */ - if (tmp_items) { - /* add the expander as a channel first */ - if (filter_mode & ANIMFILTER_LIST_CHANNELS) { - /* currently these channels cannot be selected, so they should be skipped */ - if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) { - ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add control curves from each NLA strip... */ + /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */ + BEGIN_ANIMFILTER_SUBCHANNELS(((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0)) + { + NlaTrack *nlt; + NlaStrip *strip; + + /* for now, we only go one level deep - so controls on grouped FCurves are not handled */ + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + for (strip = nlt->strips.first; strip; strip = strip->next) { + /* pass strip as the "owner", so that the name lookups (used while filtering) will resolve */ + /* NLA tracks are coming from AnimData, so owner of f-curves + * is the same as owner of animation data. */ + tmp_items += animfilter_fcurves(&tmp_data, + ads, + strip->fcurves.first, + ANIMTYPE_NLACURVE, + filter_mode, + strip, + owner_id, + owner_id); + } + } + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* add the expander as a channel first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* currently these channels cannot be selected, so they should be skipped */ + if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) { + ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } /* determine what animation data from AnimData block should get displayed */ -static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode) +static size_t animfilter_block_data( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode) { - AnimData *adt = BKE_animdata_from_id(id); - size_t items = 0; - - /* image object datablocks have no anim-data so check for NULL */ - if (adt) { - IdAdtTemplate *iat = (IdAdtTemplate *)id; - - /* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed - * in a few places in the 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 */ - if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(adt)) ) { - ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id, NULL); - } - }, - { /* NLA */ - items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id); - }, - { /* Drivers */ - items += animfilter_fcurves(anim_data, ads, adt->drivers.first, ANIMTYPE_FCURVE, - filter_mode, NULL, id, id); - }, - { /* NLA Control Keyframes */ - items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id); - }, - { /* Keyframes */ - items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id); - } - ); - } - - return items; + AnimData *adt = BKE_animdata_from_id(id); + size_t items = 0; + + /* image object datablocks have no anim-data so check for NULL */ + if (adt) { + IdAdtTemplate *iat = (IdAdtTemplate *)id; + + /* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed + * in a few places in the 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 */ + if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(adt))) { + ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id, NULL); + } + }, + { /* NLA */ + items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id); + }, + { /* Drivers */ + items += animfilter_fcurves( + anim_data, ads, adt->drivers.first, ANIMTYPE_FCURVE, filter_mode, NULL, id, id); + }, + { /* NLA Control Keyframes */ + items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id); + }, + { /* Keyframes */ + items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id); + }); + } + + return items; } - - /* Include ShapeKey Data for ShapeKey Editor */ -static size_t 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) { - size_t items = 0; - - /* check if channels or only F-Curves */ - if (filter_mode & ANIMFILTER_LIST_CHANNELS) { - KeyBlock *kb; - - /* loop through the channels adding ShapeKeys as appropriate */ - for (kb = key->block.first; kb; kb = kb->next) { - /* skip the first one, since that's the non-animatable basis */ - if (kb == key->block.first) continue; - - /* only work with this channel and its subchannels if it is editable */ - if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) { - /* only include this track if selected in a way consistent with the filtering requirements */ - if (ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) { - // TODO: consider 'active' too? - - /* owner-id here must be key so that the F-Curve can be resolved... */ - ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key, NULL); - } - } - } - } - else { - /* just use the action associated with the shapekey */ - // TODO: somehow manage to pass dopesheet info down here too? - if (key->adt) { - if (filter_mode & ANIMFILTER_ANIMDATA) { - if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt)) ) { - ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key, NULL); - } - } - else if (key->adt->action) { - items = animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key); - } - } - } - - /* return the number of items added to the list */ - return items; + size_t items = 0; + + /* check if channels or only F-Curves */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + KeyBlock *kb; + + /* loop through the channels adding ShapeKeys as appropriate */ + for (kb = key->block.first; kb; kb = kb->next) { + /* skip the first one, since that's the non-animatable basis */ + if (kb == key->block.first) + continue; + + /* only work with this channel and its subchannels if it is editable */ + if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) { + /* only include this track if selected in a way consistent with the filtering requirements */ + if (ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb))) { + // TODO: consider 'active' too? + + /* owner-id here must be key so that the F-Curve can be resolved... */ + ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key, NULL); + } + } + } + } + else { + /* just use the action associated with the shapekey */ + // TODO: somehow manage to pass dopesheet info down here too? + if (key->adt) { + if (filter_mode & ANIMFILTER_ANIMDATA) { + if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt))) { + ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key, NULL); + } + } + else if (key->adt->action) { + items = animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key); + } + } + } + + /* return the number of items added to the list */ + return items; } /* Helper for Grease Pencil - layers within a datablock */ -static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode) +static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, + bDopeSheet *ads, + bGPdata *gpd, + int filter_mode) { - bGPDlayer *gpl; - size_t items = 0; - - /* loop over layers as the conditions are acceptable (top-Down order) */ - for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { - /* 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)) { - /* skip layer if the name doesn't match the filter string */ - if ((ads) && (ads->searchstr[0] != '\0')) { - if (name_matches_dopesheet_filter(ads, gpl->info) == false) - continue; - } - /* add to list */ - ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd, NULL); - } - } - } - } - - return items; + bGPDlayer *gpl; + size_t items = 0; + + /* loop over layers as the conditions are acceptable (top-Down order) */ + for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { + /* 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)) { + /* skip layer if the name doesn't match the filter string */ + if ((ads) && (ads->searchstr[0] != '\0')) { + if (name_matches_dopesheet_filter(ads, gpl->info) == false) + continue; + } + /* add to list */ + ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd, NULL); + } + } + } + } + + return items; } /* Helper for Grease Pencil - Grease Pencil datablock - GP Frames */ -static size_t animdata_filter_gpencil_data(ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode) +static size_t animdata_filter_gpencil_data(ListBase *anim_data, + bDopeSheet *ads, + bGPdata *gpd, + int filter_mode) { - size_t items = 0; - - /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation), - * for convenience, this will return GP Datablocks instead. This may cause issues down - * the track, but for now, this will do... - */ - if (filter_mode & ANIMFILTER_ANIMDATA) { - /* just add GPD as a channel - this will add everything needed */ - ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd, NULL); - } - else { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - - /* add gpencil animation channels */ - BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) - { - tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, 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, NULL); - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - } - - return items; + size_t items = 0; + + /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation), + * for convenience, this will return GP Datablocks instead. This may cause issues down + * the track, but for now, this will do... + */ + if (filter_mode & ANIMFILTER_ANIMDATA) { + /* just add GPD as a channel - this will add everything needed */ + ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd, NULL); + } + else { + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + + /* add gpencil animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) + { + tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, 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, NULL); + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + } + + return items; } /* Grab all Grease Pencil datablocks in file */ // TODO: should this be amalgamated with the dopesheet filtering code? -static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, void *UNUSED(data), int filter_mode) +static size_t animdata_filter_gpencil(bAnimContext *ac, + ListBase *anim_data, + void *UNUSED(data), + int filter_mode) { - bDopeSheet *ads = ac->ads; - size_t items = 0; - - if (ads->filterflag & ADS_FILTER_GP_3DONLY) { - Scene *scene = (Scene *)ads->source; - ViewLayer *view_layer = (ViewLayer *)ac->view_layer; - Base *base; - - /* Active scene's GPencil block first - No parent item needed... */ - if (scene->gpd) { - items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode); - } - - /* Objects in the scene */ - for (base = view_layer->object_bases.first; base; base = base->next) { - /* Only consider this object if it has got some GP data (saving on all the other tests) */ - if (base->object && (base->object->type == OB_GPENCIL)) { - Object *ob = base->object; - - /* firstly, check if object can be included, by the following factors: - * - if only visible, must check for layer and also viewport visibility - * --> while tools may demand only visible, user setting takes priority - * 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 (this is done recursively as we - * try to add the channels) - */ - 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 ((base->flag & BASE_VISIBLE) == 0) continue; - - /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEW) continue; - } - - /* check selection and object type filters */ - if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED) /*|| (base == scene->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->filter_grp != NULL) { - if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) - continue; - } - - /* finally, include this object's grease pencil datablock */ - /* XXX: Should we store these under expanders per item? */ - items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode); - } - } - } - else { - bGPdata *gpd; - - /* Grab all Grease Pencil datablocks directly from main, - * but only those that seem to be useful somewhere */ - for (gpd = ac->bmain->gpencils.first; gpd; gpd = gpd->id.next) { - /* only show if gpd is used by something... */ - if (ID_REAL_USERS(gpd) < 1) - continue; - - /* add GP frames from this datablock */ - items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode); - } - } - - /* return the number of items added to the list */ - return items; + bDopeSheet *ads = ac->ads; + size_t items = 0; + + if (ads->filterflag & ADS_FILTER_GP_3DONLY) { + Scene *scene = (Scene *)ads->source; + ViewLayer *view_layer = (ViewLayer *)ac->view_layer; + Base *base; + + /* Active scene's GPencil block first - No parent item needed... */ + if (scene->gpd) { + items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode); + } + + /* Objects in the scene */ + for (base = view_layer->object_bases.first; base; base = base->next) { + /* Only consider this object if it has got some GP data (saving on all the other tests) */ + if (base->object && (base->object->type == OB_GPENCIL)) { + Object *ob = base->object; + + /* firstly, check if object can be included, by the following factors: + * - if only visible, must check for layer and also viewport visibility + * --> while tools may demand only visible, user setting takes priority + * 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 (this is done recursively as we + * try to add the channels) + */ + 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 ((base->flag & BASE_VISIBLE) == 0) + continue; + + /* outliner restrict-flag */ + if (ob->restrictflag & OB_RESTRICT_VIEW) + continue; + } + + /* check selection and object type filters */ + if ((ads->filterflag & ADS_FILTER_ONLYSEL) && + !((base->flag & BASE_SELECTED) /*|| (base == scene->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->filter_grp != NULL) { + if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) + continue; + } + + /* finally, include this object's grease pencil datablock */ + /* XXX: Should we store these under expanders per item? */ + items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode); + } + } + } + else { + bGPdata *gpd; + + /* Grab all Grease Pencil datablocks directly from main, + * but only those that seem to be useful somewhere */ + for (gpd = ac->bmain->gpencils.first; gpd; gpd = gpd->id.next) { + /* only show if gpd is used by something... */ + if (ID_REAL_USERS(gpd) < 1) + continue; + + /* add GP frames from this datablock */ + items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode); + } + } + + /* return the number of items added to the list */ + return items; } /* Helper for Grease Pencil data integrated with main DopeSheet */ -static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode) +static size_t animdata_filter_ds_gpencil( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode) { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - size_t items = 0; - - /* add relevant animation channels for Grease Pencil */ - BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) - { - /* add animation channels */ - tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode); - - /* add Grease Pencil layers */ - // TODO: do these need a separate expander? - // XXX: what order should these go in? - } - 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 */ - // XXX: active check here needs checking - if (ANIMCHANNEL_ACTIVEOK(gpd)) { - ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_DSGPENCIL, gpd, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add relevant animation channels for Grease Pencil */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) + { + /* add animation channels */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode); + + /* add Grease Pencil layers */ + // TODO: do these need a separate expander? + // XXX: what order should these go in? + } + 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 */ + // XXX: active check here needs checking + if (ANIMCHANNEL_ACTIVEOK(gpd)) { + ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_DSGPENCIL, gpd, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } /* Helper for Cache File data integrated with main DopeSheet */ -static size_t animdata_filter_ds_cachefile(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode) +static size_t animdata_filter_ds_cachefile( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode) { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - size_t items = 0; - - /* add relevant animation channels for Cache File */ - BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_CACHEFILE_OBJD(cache_file)) - { - /* add animation channels */ - tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, 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 */ - // XXX: active check here needs checking - if (ANIMCHANNEL_ACTIVEOK(cache_file)) { - ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* add relevant animation channels for Cache File */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_CACHEFILE_OBJD(cache_file)) + { + /* add animation channels */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, 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 */ + // XXX: active check here needs checking + if (ANIMCHANNEL_ACTIVEOK(cache_file)) { + ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } /* Helper for Mask Editing - mask layers */ static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode) { - MaskLayer *masklay_act = BKE_mask_layer_active(mask); - MaskLayer *masklay; - size_t items = 0; - - /* loop over layers as the conditions are acceptable */ - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - /* only if selected */ - if (ANIMCHANNEL_SELOK(SEL_MASKLAY(masklay)) ) { - /* only if editable */ - if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_MASK(masklay)) { - /* active... */ - if (!(filter_mode & ANIMFILTER_ACTIVE) || (masklay_act == masklay)) { - /* add to list */ - ANIMCHANNEL_NEW_CHANNEL(masklay, ANIMTYPE_MASKLAYER, mask, NULL); - } - } - } - } - - return items; + MaskLayer *masklay_act = BKE_mask_layer_active(mask); + MaskLayer *masklay; + size_t items = 0; + + /* loop over layers as the conditions are acceptable */ + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + /* only if selected */ + if (ANIMCHANNEL_SELOK(SEL_MASKLAY(masklay))) { + /* only if editable */ + if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_MASK(masklay)) { + /* active... */ + if (!(filter_mode & ANIMFILTER_ACTIVE) || (masklay_act == masklay)) { + /* add to list */ + ANIMCHANNEL_NEW_CHANNEL(masklay, ANIMTYPE_MASKLAYER, mask, NULL); + } + } + } + } + + return items; } /* Grab all mask data */ -static size_t animdata_filter_mask(Main *bmain, ListBase *anim_data, void *UNUSED(data), int filter_mode) +static size_t animdata_filter_mask(Main *bmain, + ListBase *anim_data, + void *UNUSED(data), + int filter_mode) { - Mask *mask; - size_t items = 0; - - /* for now, grab mask datablocks directly from main */ - // XXX: this is not good... - for (mask = bmain->masks.first; mask; mask = mask->id.next) { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - - /* only show if mask is used by something... */ - if (ID_REAL_USERS(mask) < 1) - continue; - - /* add mask animation channels */ - BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_MASK(mask)) - { - tmp_items += animdata_filter_mask_data(&tmp_data, mask, filter_mode); - } - END_ANIMFILTER_SUBCHANNELS; - - /* did we find anything? */ - if (tmp_items) { - /* include data-expand widget first */ - if (filter_mode & ANIMFILTER_LIST_CHANNELS) { - /* add mask datablock as channel too (if for drawing, and it has layers) */ - ANIMCHANNEL_NEW_CHANNEL(mask, ANIMTYPE_MASKDATABLOCK, NULL, NULL); - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - } - - /* return the number of items added to the list */ - return items; + Mask *mask; + size_t items = 0; + + /* for now, grab mask datablocks directly from main */ + // XXX: this is not good... + for (mask = bmain->masks.first; mask; mask = mask->id.next) { + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + + /* only show if mask is used by something... */ + if (ID_REAL_USERS(mask) < 1) + continue; + + /* add mask animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_MASK(mask)) + { + tmp_items += animdata_filter_mask_data(&tmp_data, mask, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include data-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* add mask datablock as channel too (if for drawing, and it has layers) */ + ANIMCHANNEL_NEW_CHANNEL(mask, ANIMTYPE_MASKDATABLOCK, NULL, NULL); + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + } + + /* return the 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 */ -static size_t animdata_filter_ds_nodetree_group(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, bNodeTree *ntree, int filter_mode) +static size_t animdata_filter_ds_nodetree_group(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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + 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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } -static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, bNodeTree *ntree, int filter_mode) +static size_t animdata_filter_ds_nodetree(bAnimContext *ac, + ListBase *anim_data, + bDopeSheet *ads, + ID *owner_id, + bNodeTree *ntree, + int filter_mode) { - bNode *node; - size_t items = 0; - - items += animdata_filter_ds_nodetree_group(ac, anim_data, ads, owner_id, ntree, filter_mode); - - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_GROUP) { - if (node->id) { - if ((ads->filterflag & ADS_FILTER_ONLYSEL) && (node->flag & NODE_SELECT) == 0) { - continue; - } - /* Recurse into the node group */ - items += animdata_filter_ds_nodetree(ac, anim_data, ads, owner_id, (bNodeTree *) node->id, - filter_mode | ANIMFILTER_TMP_IGNORE_ONLYSEL); - } - } - } - - return items; + bNode *node; + size_t items = 0; + + items += animdata_filter_ds_nodetree_group(ac, anim_data, ads, owner_id, ntree, filter_mode); + + for (node = ntree->nodes.first; node; node = node->next) { + if (node->type == NODE_GROUP) { + if (node->id) { + if ((ads->filterflag & ADS_FILTER_ONLYSEL) && (node->flag & NODE_SELECT) == 0) { + continue; + } + /* Recurse into the node group */ + items += animdata_filter_ds_nodetree(ac, + anim_data, + ads, + owner_id, + (bNodeTree *)node->id, + filter_mode | ANIMFILTER_TMP_IGNORE_ONLYSEL); + } + } + } + + return items; } -static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) +static size_t animdata_filter_ds_linestyle( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) { - ViewLayer *view_layer; - FreestyleLineSet *lineset; - size_t items = 0; - - for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { - if (lineset->linestyle) { - lineset->linestyle->id.tag |= LIB_TAG_DOIT; - } - } - } - - for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - /* skip render layers without Freestyle enabled */ - if ((view_layer->flag & VIEW_LAYER_FREESTYLE) == 0) { - continue; - } - - /* loop over linesets defined in the render layer */ - for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { - FreestyleLineStyle *linestyle = lineset->linestyle; - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - - if ((linestyle == NULL) || - !(linestyle->id.tag & LIB_TAG_DOIT)) - { - continue; - } - linestyle->id.tag &= ~LIB_TAG_DOIT; - - /* add scene-level animation channels */ - BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_LS_SCED(linestyle)) - { - /* animation data filtering */ - tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)linestyle, filter_mode); - } - END_ANIMFILTER_SUBCHANNELS; - - /* did we find anything? */ - if (tmp_items) { - /* include anim-expand widget first */ - if (filter_mode & ANIMFILTER_LIST_CHANNELS) { - /* check if filtering by active status */ - if (ANIMCHANNEL_ACTIVEOK(linestyle)) { - ANIMCHANNEL_NEW_CHANNEL(linestyle, ANIMTYPE_DSLINESTYLE, sce, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - } - } - - /* return the number of items added to the list */ - return items; + ViewLayer *view_layer; + FreestyleLineSet *lineset; + size_t items = 0; + + for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { + for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { + if (lineset->linestyle) { + lineset->linestyle->id.tag |= LIB_TAG_DOIT; + } + } + } + + for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { + /* skip render layers without Freestyle enabled */ + if ((view_layer->flag & VIEW_LAYER_FREESTYLE) == 0) { + continue; + } + + /* loop over linesets defined in the render layer */ + for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { + FreestyleLineStyle *linestyle = lineset->linestyle; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + + if ((linestyle == NULL) || !(linestyle->id.tag & LIB_TAG_DOIT)) { + continue; + } + linestyle->id.tag &= ~LIB_TAG_DOIT; + + /* add scene-level animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_LS_SCED(linestyle)) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)linestyle, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include anim-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by active status */ + if (ANIMCHANNEL_ACTIVEOK(linestyle)) { + ANIMCHANNEL_NEW_CHANNEL(linestyle, ANIMTYPE_DSLINESTYLE, sce, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + } + } + + /* return the number of items added to the list */ + return items; } -static size_t animdata_filter_ds_texture(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, - Tex *tex, ID *owner_id, int filter_mode) +static size_t animdata_filter_ds_texture(bAnimContext *ac, + ListBase *anim_data, + bDopeSheet *ads, + Tex *tex, + ID *owner_id, + int filter_mode) { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - size_t items = 0; - - /* 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_LIST_CHANNELS) { - /* check if filtering by active status */ - if (ANIMCHANNEL_ACTIVEOK(tex)) { - ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* 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_LIST_CHANNELS) { + /* check if filtering by active status */ + if (ANIMCHANNEL_ACTIVEOK(tex)) { + ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } /* NOTE: owner_id is the direct owner of the texture stack in question * It used to be Material/Light/World before the Blender Internal removal for 2.8 */ -static size_t animdata_filter_ds_textures(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) { - MTex **mtex = NULL; - size_t items = 0; - int a = 0; - - /* get datatype specific data first */ - if (owner_id == NULL) - return 0; - - switch (GS(owner_id->name)) { - case ID_PA: - { - ParticleSettings *part = (ParticleSettings *)owner_id; - mtex = (MTex **)(&part->mtex); - break; - } - default: - { - /* invalid/unsupported option */ - if (G.debug & G_DEBUG) - printf("ERROR: Unsupported owner_id (i.e. texture stack) for filter textures - %s\n", owner_id->name); - return 0; - } - } - - /* 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; - - /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */ - if (tex == NULL) - continue; - - /* add texture's anim channels */ - items += animdata_filter_ds_texture(ac, anim_data, ads, tex, owner_id, filter_mode); - } - - /* return the number of items added to the list */ - return items; + MTex **mtex = NULL; + size_t items = 0; + int a = 0; + + /* get datatype specific data first */ + if (owner_id == NULL) + return 0; + + switch (GS(owner_id->name)) { + case ID_PA: { + ParticleSettings *part = (ParticleSettings *)owner_id; + mtex = (MTex **)(&part->mtex); + break; + } + default: { + /* invalid/unsupported option */ + if (G.debug & G_DEBUG) + printf("ERROR: Unsupported owner_id (i.e. texture stack) for filter textures - %s\n", + owner_id->name); + return 0; + } + } + + /* 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; + + /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */ + if (tex == NULL) + continue; + + /* add texture's anim channels */ + items += animdata_filter_ds_texture(ac, anim_data, ads, tex, owner_id, filter_mode); + } + + /* return the number of items added to the list */ + return items; } - -static size_t animdata_filter_ds_material(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Material *ma, int filter_mode) +static size_t animdata_filter_ds_material( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Material *ma, int filter_mode) { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - size_t items = 0; - - /* 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); - - /* 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); - } - END_ANIMFILTER_SUBCHANNELS; - - /* did we find anything? */ - if (tmp_items) { - /* include material-expand widget first */ - if (filter_mode & ANIMFILTER_LIST_CHANNELS) { - /* check if filtering by active status */ - if (ANIMCHANNEL_ACTIVEOK(ma)) { - ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - return items; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + /* 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); + + /* 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); + } + END_ANIMFILTER_SUBCHANNELS; + + /* did we find anything? */ + if (tmp_items) { + /* include material-expand widget first */ + if (filter_mode & ANIMFILTER_LIST_CHANNELS) { + /* check if filtering by active status */ + if (ANIMCHANNEL_ACTIVEOK(ma)) { + ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + return items; } -static size_t animdata_filter_ds_materials(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) +static size_t animdata_filter_ds_materials( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) { - bool has_nested = false; - size_t items = 0; - int a = 0; - - /* first pass: take the materials referenced via the Material slots of the object */ - for (a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - - /* if material is valid, try to add relevant contents from here */ - if (ma) { - /* add channels */ - items += animdata_filter_ds_material(ac, anim_data, ads, ma, filter_mode); - - /* for optimising second pass - check if there's a nested material here to come back for */ - if (has_nested == false) { - has_nested = (give_node_material(ma) != NULL); - } - } - } - - /* second pass: go through a second time looking for "nested" materials (material.material references) - * - * NOTE: here we ignore the expanded status of the parent, as it could be too confusing as to why these are - * disappearing/not available, since the relationships between these is not that clear - */ - if (has_nested) { - for (a = 1; a <= ob->totcol; a++) { - Material *base = give_current_material(ob, a); - Material *ma = give_node_material(base); - - /* add channels from the nested material if it exists - * - skip if the same material is referenced in its node tree - * (which is common for BI materials) as that results in - * confusing duplicates - */ - if ((ma) && (ma != base)) { - items += animdata_filter_ds_material(ac, anim_data, ads, ma, filter_mode); - } - } - } - - /* return the number of items added to the list */ - return items; + bool has_nested = false; + size_t items = 0; + int a = 0; + + /* first pass: take the materials referenced via the Material slots of the object */ + for (a = 1; a <= ob->totcol; a++) { + Material *ma = give_current_material(ob, a); + + /* if material is valid, try to add relevant contents from here */ + if (ma) { + /* add channels */ + items += animdata_filter_ds_material(ac, anim_data, ads, ma, filter_mode); + + /* for optimising second pass - check if there's a nested material here to come back for */ + if (has_nested == false) { + has_nested = (give_node_material(ma) != NULL); + } + } + } + + /* second pass: go through a second time looking for "nested" materials (material.material references) + * + * NOTE: here we ignore the expanded status of the parent, as it could be too confusing as to why these are + * disappearing/not available, since the relationships between these is not that clear + */ + if (has_nested) { + for (a = 1; a <= ob->totcol; a++) { + Material *base = give_current_material(ob, a); + Material *ma = give_node_material(base); + + /* add channels from the nested material if it exists + * - skip if the same material is referenced in its node tree + * (which is common for BI materials) as that results in + * confusing duplicates + */ + if ((ma) && (ma != base)) { + items += animdata_filter_ds_material(ac, anim_data, ads, ma, filter_mode); + } + } + } + + /* return the number of items added to the list */ + return items; } - /* ............ */ /* Temporary context for modifier linked-data channel extraction */ typedef struct tAnimFilterModifiersContext { - bAnimContext *ac; /* anim editor context */ - bDopeSheet *ads; /* dopesheet filtering settings */ + bAnimContext *ac; /* anim editor context */ + bDopeSheet *ads; /* dopesheet filtering settings */ - ListBase tmp_data; /* list of channels created (but not yet added to the main list) */ - size_t items; /* number of channels created */ + ListBase tmp_data; /* list of channels created (but not yet added to the main list) */ + size_t items; /* number of channels created */ - int filter_mode; /* flags for stuff we want to filter */ + int filter_mode; /* flags for stuff we want to filter */ } tAnimFilterModifiersContext; - /* dependency walker callback for modifier dependencies */ -static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cb_flag)) +static void animfilter_modifier_idpoin_cb(void *afm_ptr, + Object *ob, + ID **idpoin, + int UNUSED(cb_flag)) { - tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr; - ID *owner_id = &ob->id; - ID *id = *idpoin; - - /* NOTE: the walker only guarantees to give us all the ID-ptr *slots*, - * not just the ones which are actually used, so be careful! - */ - if (id == NULL) - return; - - /* check if this is something we're interested in... */ - switch (GS(id->name)) { - case ID_TE: /* Textures */ - { - Tex *tex = (Tex *)id; - if (!(afm->ads->filterflag & ADS_FILTER_NOTEX)) { - afm->items += animdata_filter_ds_texture(afm->ac, &afm->tmp_data, afm->ads, tex, owner_id, afm->filter_mode); - } - break; - } - - /* TODO: images? */ - default: - break; - } + tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr; + ID *owner_id = &ob->id; + ID *id = *idpoin; + + /* NOTE: the walker only guarantees to give us all the ID-ptr *slots*, + * not just the ones which are actually used, so be careful! + */ + if (id == NULL) + return; + + /* check if this is something we're interested in... */ + switch (GS(id->name)) { + case ID_TE: /* Textures */ + { + Tex *tex = (Tex *)id; + if (!(afm->ads->filterflag & ADS_FILTER_NOTEX)) { + afm->items += animdata_filter_ds_texture( + afm->ac, &afm->tmp_data, afm->ads, tex, owner_id, afm->filter_mode); + } + break; + } + + /* TODO: images? */ + default: + break; + } } /* animation linked to data used by modifiers @@ -2266,861 +2324,886 @@ static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin * attached to any other objects/materials/etc. in the scene */ // TODO: do we want an expander for this? -static size_t animdata_filter_ds_modifiers(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) +static size_t animdata_filter_ds_modifiers( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) { - tAnimFilterModifiersContext afm = {NULL}; - size_t items = 0; - - /* 1) create a temporary "context" containing all the info we have here to pass to the callback - * use to walk through the dependencies of the modifiers - * - * ! Assumes that all other unspecified values (i.e. accumulation buffers) are zero'd out properly - */ - afm.ac = ac; - afm.ads = ads; - afm.filter_mode = filter_mode; - - /* 2) walk over dependencies */ - modifiers_foreachIDLink(ob, animfilter_modifier_idpoin_cb, &afm); - - /* 3) extract data from the context, merging it back into the standard list */ - if (afm.items) { - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &afm.tmp_data); - BLI_assert(BLI_listbase_is_empty(&afm.tmp_data)); - items += afm.items; - } - - return items; + tAnimFilterModifiersContext afm = {NULL}; + size_t items = 0; + + /* 1) create a temporary "context" containing all the info we have here to pass to the callback + * use to walk through the dependencies of the modifiers + * + * ! Assumes that all other unspecified values (i.e. accumulation buffers) are zero'd out properly + */ + afm.ac = ac; + afm.ads = ads; + afm.filter_mode = filter_mode; + + /* 2) walk over dependencies */ + modifiers_foreachIDLink(ob, animfilter_modifier_idpoin_cb, &afm); + + /* 3) extract data from the context, merging it back into the standard list */ + if (afm.items) { + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &afm.tmp_data); + BLI_assert(BLI_listbase_is_empty(&afm.tmp_data)); + items += afm.items; + } + + return items; } /* ............ */ - -static size_t animdata_filter_ds_particles(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) +static size_t animdata_filter_ds_particles( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) { - ParticleSystem *psys; - size_t items = 0; - - 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; - - /* add particle-system's animation data to temp collection */ - BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part)) - { - /* particle system's animation data */ - tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode); - - /* textures */ - if (!(ads->filterflag & ADS_FILTER_NOTEX)) - tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)psys->part, filter_mode); - } - END_ANIMFILTER_SUBCHANNELS; - - /* 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)) { - ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - } - - /* return the number of items added to the list */ - return items; + ParticleSystem *psys; + size_t items = 0; + + 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; + + /* add particle-system's animation data to temp collection */ + BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part)) + { + /* particle system's animation data */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode); + + /* textures */ + if (!(ads->filterflag & ADS_FILTER_NOTEX)) + tmp_items += animdata_filter_ds_textures( + ac, &tmp_data, ads, (ID *)psys->part, filter_mode); + } + END_ANIMFILTER_SUBCHANNELS; + + /* 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)) { + ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + } + + /* return the number of items added to the list */ + return items; } - -static size_t animdata_filter_ds_obdata(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) +static size_t animdata_filter_ds_obdata( + 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; - - IdAdtTemplate *iat = ob->data; - short type = 0, expanded = 0; - - /* get settings based on data type */ - switch (ob->type) { - case OB_CAMERA: /* ------- Camera ------------ */ - { - Camera *ca = (Camera *)ob->data; - - if (ads->filterflag & ADS_FILTER_NOCAM) - return 0; - - type = ANIMTYPE_DSCAM; - expanded = FILTER_CAM_OBJD(ca); - break; - } - case OB_LAMP: /* ---------- Light ----------- */ - { - Light *la = (Light *)ob->data; - - if (ads->filterflag & ADS_FILTER_NOLAM) - return 0; - - type = ANIMTYPE_DSLAM; - expanded = FILTER_LAM_OBJD(la); - 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) - return 0; - - type = ANIMTYPE_DSCUR; - expanded = FILTER_CUR_OBJD(cu); - break; - } - case OB_MBALL: /* ------- MetaBall ---------- */ - { - MetaBall *mb = (MetaBall *)ob->data; - - if (ads->filterflag & ADS_FILTER_NOMBA) - return 0; - - type = ANIMTYPE_DSMBALL; - expanded = FILTER_MBALL_OBJD(mb); - break; - } - case OB_ARMATURE: /* ------- Armature ---------- */ - { - bArmature *arm = (bArmature *)ob->data; - - if (ads->filterflag & ADS_FILTER_NOARM) - return 0; - - type = ANIMTYPE_DSARM; - expanded = FILTER_ARM_OBJD(arm); - break; - } - case OB_MESH: /* ------- Mesh ---------- */ - { - Mesh *me = (Mesh *)ob->data; - - if (ads->filterflag & ADS_FILTER_NOMESH) - return 0; - - type = ANIMTYPE_DSMESH; - expanded = FILTER_MESH_OBJD(me); - break; - } - case OB_LATTICE: /* ---- Lattice ---- */ - { - Lattice *lt = (Lattice *)ob->data; - - if (ads->filterflag & ADS_FILTER_NOLAT) - return 0; - - type = ANIMTYPE_DSLAT; - expanded = FILTER_LATTICE_OBJD(lt); - break; - } - case OB_SPEAKER: /* ---------- Speaker ----------- */ - { - Speaker *spk = (Speaker *)ob->data; - - type = ANIMTYPE_DSSPK; - expanded = FILTER_SPK_OBJD(spk); - break; - } - } - - /* 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: /* light - textures + nodetree */ - { - Light *la = ob->data; - bNodeTree *ntree = la->nodetree; - - /* nodetree */ - if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) - tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, &la->id, ntree, 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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + + IdAdtTemplate *iat = ob->data; + short type = 0, expanded = 0; + + /* get settings based on data type */ + switch (ob->type) { + case OB_CAMERA: /* ------- Camera ------------ */ + { + Camera *ca = (Camera *)ob->data; + + if (ads->filterflag & ADS_FILTER_NOCAM) + return 0; + + type = ANIMTYPE_DSCAM; + expanded = FILTER_CAM_OBJD(ca); + break; + } + case OB_LAMP: /* ---------- Light ----------- */ + { + Light *la = (Light *)ob->data; + + if (ads->filterflag & ADS_FILTER_NOLAM) + return 0; + + type = ANIMTYPE_DSLAM; + expanded = FILTER_LAM_OBJD(la); + 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) + return 0; + + type = ANIMTYPE_DSCUR; + expanded = FILTER_CUR_OBJD(cu); + break; + } + case OB_MBALL: /* ------- MetaBall ---------- */ + { + MetaBall *mb = (MetaBall *)ob->data; + + if (ads->filterflag & ADS_FILTER_NOMBA) + return 0; + + type = ANIMTYPE_DSMBALL; + expanded = FILTER_MBALL_OBJD(mb); + break; + } + case OB_ARMATURE: /* ------- Armature ---------- */ + { + bArmature *arm = (bArmature *)ob->data; + + if (ads->filterflag & ADS_FILTER_NOARM) + return 0; + + type = ANIMTYPE_DSARM; + expanded = FILTER_ARM_OBJD(arm); + break; + } + case OB_MESH: /* ------- Mesh ---------- */ + { + Mesh *me = (Mesh *)ob->data; + + if (ads->filterflag & ADS_FILTER_NOMESH) + return 0; + + type = ANIMTYPE_DSMESH; + expanded = FILTER_MESH_OBJD(me); + break; + } + case OB_LATTICE: /* ---- Lattice ---- */ + { + Lattice *lt = (Lattice *)ob->data; + + if (ads->filterflag & ADS_FILTER_NOLAT) + return 0; + + type = ANIMTYPE_DSLAT; + expanded = FILTER_LATTICE_OBJD(lt); + break; + } + case OB_SPEAKER: /* ---------- Speaker ----------- */ + { + Speaker *spk = (Speaker *)ob->data; + + type = ANIMTYPE_DSSPK; + expanded = FILTER_SPK_OBJD(spk); + break; + } + } + + /* 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: /* light - textures + nodetree */ + { + Light *la = ob->data; + bNodeTree *ntree = la->nodetree; + + /* nodetree */ + if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) + tmp_items += animdata_filter_ds_nodetree( + ac, &tmp_data, ads, &la->id, ntree, 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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } /* shapekey-level animation */ -static size_t animdata_filter_ds_keyanim(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode) +static size_t animdata_filter_ds_keyanim( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode) { - 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; - - /* 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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return 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; + + /* 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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the 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) +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); - }, - { /* NLA Strip Controls - no dedicated channel for now (XXX) */ }, - { /* 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; - - /* 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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + 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); + }, + {/* NLA Strip Controls - no dedicated channel for now (XXX) */}, + { /* 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; + + /* 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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added to the list */ + return items; } /* get animation channels from object2 */ -static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +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; - - /* filter data contained under object first */ - BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_OBJC(ob)) - { - Key *key = BKE_key_from_object(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); - } - - /* 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); - } - - /* modifiers */ - if ((ob->modifiers.first) && !(ads->filterflag & ADS_FILTER_NOMODIFIERS)) { - tmp_items += animdata_filter_ds_modifiers(ac, &tmp_data, ads, ob, filter_mode); - } - - /* materials */ - if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) { - tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode); - } - - /* object data */ - if (ob->data) { - tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode); - } - - /* particles */ - if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) { - tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode); - } - - /* grease pencil */ - if ((ob->type == OB_GPENCIL) && - (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) - { - tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode); - } - } - 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 & BASE_SELECTED))) { - /* check if filtering by active status */ - if (ANIMCHANNEL_ACTIVEOK(ob)) { - ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob, NULL); - } - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added */ - return items; + ListBase tmp_data = {NULL, NULL}; + Object *ob = base->object; + size_t tmp_items = 0; + size_t items = 0; + + /* filter data contained under object first */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_OBJC(ob)) + { + Key *key = BKE_key_from_object(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); + } + + /* 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); + } + + /* modifiers */ + if ((ob->modifiers.first) && !(ads->filterflag & ADS_FILTER_NOMODIFIERS)) { + tmp_items += animdata_filter_ds_modifiers(ac, &tmp_data, ads, ob, filter_mode); + } + + /* materials */ + if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) { + tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode); + } + + /* object data */ + if (ob->data) { + tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode); + } + + /* particles */ + if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) { + tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode); + } + + /* grease pencil */ + if ((ob->type == OB_GPENCIL) && (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { + tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode); + } + } + 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 & BASE_SELECTED))) { + /* check if filtering by active status */ + if (ANIMCHANNEL_ACTIVEOK(ob)) { + ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob, NULL); + } + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added */ + return items; } -static size_t animdata_filter_ds_world(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode) +static size_t animdata_filter_ds_world( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode) { - 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); - - /* nodes */ - if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) - tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)wo, wo->nodetree, 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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return 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); + + /* nodes */ + if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) + tmp_items += animdata_filter_ds_nodetree( + ac, &tmp_data, ads, (ID *)wo, wo->nodetree, 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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the 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) +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); - }, - { /* NLA Strip Controls - no dedicated channel for now (XXX) */ }, - { /* Keyframes */ - type = ANIMTYPE_FILLACTD; - cdata = adt->action; - expanded = EXPANDED_ACTC(adt->action); - }); - - /* 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; - - /* 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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added to the list */ - return items; + 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); + }, + {/* NLA Strip Controls - no dedicated channel for now (XXX) */}, + { /* Keyframes */ + type = ANIMTYPE_FILLACTD; + cdata = adt->action; + expanded = EXPANDED_ACTC(adt->action); + }); + + /* 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; + + /* 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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the 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) +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; - bGPdata *gpd = sce->gpd; - 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) && !(ads->filterflag & ADS_FILTER_NOWOR)) { - tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode); - } - - /* nodetree */ - if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) { - tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode); - } - - /* line styles */ - if ((ads->filterflag & ADS_FILTER_NOLINESTYLE) == 0) { - tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode); - } - - /* grease pencil */ - if ((gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { - tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, gpd, filter_mode); - } - - /* TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here */ - } - 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, NULL); - } - } - - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - - /* return the number of items added */ - return items; + 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; + bGPdata *gpd = sce->gpd; + 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) && !(ads->filterflag & ADS_FILTER_NOWOR)) { + tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode); + } + + /* nodetree */ + if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) { + tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode); + } + + /* line styles */ + if ((ads->filterflag & ADS_FILTER_NOLINESTYLE) == 0) { + tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode); + } + + /* grease pencil */ + if ((gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { + tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, gpd, filter_mode); + } + + /* TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here */ + } + 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, NULL); + } + } + + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + + /* return the number of items added */ + return items; } -static size_t animdata_filter_ds_movieclip(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, MovieClip *clip, int filter_mode) +static size_t animdata_filter_ds_movieclip( + bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, MovieClip *clip, int filter_mode) { - ListBase tmp_data = {NULL, NULL}; - size_t tmp_items = 0; - size_t items = 0; - /* add world animation channels */ - BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_MCLIP(clip)) - { - /* animation data filtering */ - tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)clip, 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(clip)) { - ANIMCHANNEL_NEW_CHANNEL(clip, ANIMTYPE_DSMCLIP, clip, NULL); - } - } - /* now add the list of collected channels */ - BLI_movelisttolist(anim_data, &tmp_data); - BLI_assert(BLI_listbase_is_empty(&tmp_data)); - items += tmp_items; - } - /* return the number of items added to the list */ - return items; + ListBase tmp_data = {NULL, NULL}; + size_t tmp_items = 0; + size_t items = 0; + /* add world animation channels */ + BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_MCLIP(clip)) + { + /* animation data filtering */ + tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)clip, 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(clip)) { + ANIMCHANNEL_NEW_CHANNEL(clip, ANIMTYPE_DSMCLIP, clip, NULL); + } + } + /* now add the list of collected channels */ + BLI_movelisttolist(anim_data, &tmp_data); + BLI_assert(BLI_listbase_is_empty(&tmp_data)); + items += tmp_items; + } + /* return the number of items added to the list */ + return items; } -static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode) +static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, + ListBase *anim_data, + bDopeSheet *ads, + int filter_mode) { - size_t items = 0; - MovieClip *clip; - for (clip = ac->bmain->movieclips.first; clip != NULL; clip = clip->id.next) { - /* only show if gpd is used by something... */ - if (ID_REAL_USERS(clip) < 1) { - continue; - } - items += animdata_filter_ds_movieclip(ac, anim_data, ads, clip, filter_mode); - } - /* return the number of items added to the list */ - return items; + size_t items = 0; + MovieClip *clip; + for (clip = ac->bmain->movieclips.first; clip != NULL; clip = clip->id.next) { + /* only show if gpd is used by something... */ + if (ID_REAL_USERS(clip) < 1) { + continue; + } + items += animdata_filter_ds_movieclip(ac, anim_data, ads, clip, filter_mode); + } + /* return the number of items added to the list */ + return items; } /* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_mode) { - Object *ob = base->object; - - if (base->object == NULL) - return false; - - /* firstly, check if object can be included, by the following factors: - * - if only visible, must check for layer and also viewport visibility - * --> while tools may demand only visible, user setting takes priority - * 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 (this is done recursively as we - * try to add the channels) - */ - 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 ((base->flag & BASE_VISIBLE) == 0) - return false; - - /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEW) - return false; - } - - /* if only F-Curves with visible flags set can be shown, check that - * datablock hasn't been set to invisible - */ - if (filter_mode & ANIMFILTER_CURVE_VISIBLE) { - if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) - return false; - } - - /* Pinned curves are visible regardless of selection flags. */ - if ((ob->adt) && (ob->adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) { - return true; - } - - /* Special case. - * We don't do recursive checks for pin, but we need to deal with tricky - * setup like animated camera lens without animated camera location. - * Without such special handle here we wouldn't be able to bin such - * camera data only animation to the editor. - */ - if (ob->adt == NULL && ob->data != NULL) { - AnimData *data_adt = BKE_animdata_from_id(ob->data); - if (data_adt != NULL && (data_adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) { - return true; - } - } - - /* check selection and object type filters */ - if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED) /*|| (base == sce->basact)*/)) { - /* only selected should be shown */ - return false; - } - - /* 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->filter_grp != NULL) { - if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) - return false; - } - - /* no reason to exclude this object... */ - return true; + Object *ob = base->object; + + if (base->object == NULL) + return false; + + /* firstly, check if object can be included, by the following factors: + * - if only visible, must check for layer and also viewport visibility + * --> while tools may demand only visible, user setting takes priority + * 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 (this is done recursively as we + * try to add the channels) + */ + 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 ((base->flag & BASE_VISIBLE) == 0) + return false; + + /* outliner restrict-flag */ + if (ob->restrictflag & OB_RESTRICT_VIEW) + return false; + } + + /* if only F-Curves with visible flags set can be shown, check that + * datablock hasn't been set to invisible + */ + if (filter_mode & ANIMFILTER_CURVE_VISIBLE) { + if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) + return false; + } + + /* Pinned curves are visible regardless of selection flags. */ + if ((ob->adt) && (ob->adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) { + return true; + } + + /* Special case. + * We don't do recursive checks for pin, but we need to deal with tricky + * setup like animated camera lens without animated camera location. + * Without such special handle here we wouldn't be able to bin such + * camera data only animation to the editor. + */ + if (ob->adt == NULL && ob->data != NULL) { + AnimData *data_adt = BKE_animdata_from_id(ob->data); + if (data_adt != NULL && (data_adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) { + return true; + } + } + + /* check selection and object type filters */ + if ((ads->filterflag & ADS_FILTER_ONLYSEL) && + !((base->flag & BASE_SELECTED) /*|| (base == sce->basact)*/)) { + /* only selected should be shown */ + return false; + } + + /* 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->filter_grp != NULL) { + if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) + return false; + } + + /* no reason to exclude this object... */ + return true; } /* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */ static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr) { - const Base *b1 = *((const Base **)base1_ptr); - const Base *b2 = *((const Base **)base2_ptr); + const Base *b1 = *((const Base **)base1_ptr); + const Base *b2 = *((const Base **)base2_ptr); - return strcmp(b1->object->id.name + 2, b2->object->id.name + 2); + return strcmp(b1->object->id.name + 2, b2->object->id.name + 2); } /* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */ -static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, ViewLayer *view_layer, int filter_mode, size_t *r_usable_bases) +static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, + ViewLayer *view_layer, + int filter_mode, + size_t *r_usable_bases) { - /* Create an array with space for all the bases, but only containing the usable ones */ - size_t tot_bases = BLI_listbase_count(&view_layer->object_bases); - size_t num_bases = 0; - - Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases"); - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (animdata_filter_base_is_ok(ads, base, filter_mode)) { - sorted_bases[num_bases++] = base; - } - } - - /* Sort this list of pointers (based on the names) */ - qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp); - - /* Return list of sorted bases */ - *r_usable_bases = num_bases; - return sorted_bases; + /* Create an array with space for all the bases, but only containing the usable ones */ + size_t tot_bases = BLI_listbase_count(&view_layer->object_bases); + size_t num_bases = 0; + + Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases"); + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (animdata_filter_base_is_ok(ads, base, filter_mode)) { + sorted_bases[num_bases++] = base; + } + } + + /* Sort this list of pointers (based on the names) */ + qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp); + + /* Return list of sorted bases */ + *r_usable_bases = num_bases; + return sorted_bases; } - // 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 size_t 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 *scene = (Scene *)ads->source; - ViewLayer *view_layer = (ViewLayer *)ac->view_layer; - size_t items = 0; - - /* check that we do indeed have a scene */ - if ((ads->source == NULL) || (GS(ads->source->name) != ID_SCE)) { - printf("Dope Sheet Error: No scene!\n"); - if (G.debug & G_DEBUG) - printf("\tPointer = %p, Name = '%s'\n", (void *)ads->source, (ads->source) ? ads->source->name : NULL); - return 0; - } - - /* augment the filter-flags with settings based on the dopesheet filterflags - * so that some temp settings can get added automagically... - */ - if (ads->filterflag & ADS_FILTER_SELEDIT) { - /* only selected F-Curves should get their keyframes considered for editability */ - filter_mode |= ANIMFILTER_SELEDIT; - } - - /* Cache files level animations (frame duration and such). */ - if (!(ads->filterflag2 & ADS_FILTER_NOCACHEFILES) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) { - CacheFile *cache_file = ac->bmain->cachefiles.first; - for (; cache_file; cache_file = cache_file->id.next) { - items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode); - } - } - - /* movie clip's animation */ - items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode); - - /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */ - items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode); - - /* If filtering for channel drawing, we want the objects in alphabetical order, - * to make it easier to predict where items are in the hierarchy - * - This order only really matters if we need to show all channels in the list (e.g. for drawing) - * (XXX: What about lingering "active" flags? The order may now become unpredictable) - * - Don't do this if this behavior has been turned off (i.e. due to it being too slow) - * - Don't do this if there's just a single object - */ - if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) && - (view_layer->object_bases.first != view_layer->object_bases.last)) - { - /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */ - // TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... - Base **sorted_bases; - size_t num_bases; - - sorted_bases = animdata_filter_ds_sorted_bases(ads, view_layer, filter_mode, &num_bases); - if (sorted_bases) { - /* Add the necessary channels for these bases... */ - for (size_t i = 0; i < num_bases; i++) { - items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode); - } - - // TODO: store something to validate whether any changes are needed? - - /* free temporary data */ - MEM_freeN(sorted_bases); - } - } - else { - /* Filter and add contents of each base (i.e. object) without them sorting first - * NOTE: This saves performance in cases where order doesn't matter - */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if (animdata_filter_base_is_ok(ads, base, filter_mode)) { - /* since we're still here, this object should be usable */ - items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); - } - } - } - - /* return the number of items in the list */ - return items; + Scene *scene = (Scene *)ads->source; + ViewLayer *view_layer = (ViewLayer *)ac->view_layer; + size_t items = 0; + + /* check that we do indeed have a scene */ + if ((ads->source == NULL) || (GS(ads->source->name) != ID_SCE)) { + printf("Dope Sheet Error: No scene!\n"); + if (G.debug & G_DEBUG) + printf("\tPointer = %p, Name = '%s'\n", + (void *)ads->source, + (ads->source) ? ads->source->name : NULL); + return 0; + } + + /* augment the filter-flags with settings based on the dopesheet filterflags + * so that some temp settings can get added automagically... + */ + if (ads->filterflag & ADS_FILTER_SELEDIT) { + /* only selected F-Curves should get their keyframes considered for editability */ + filter_mode |= ANIMFILTER_SELEDIT; + } + + /* Cache files level animations (frame duration and such). */ + if (!(ads->filterflag2 & ADS_FILTER_NOCACHEFILES) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) { + CacheFile *cache_file = ac->bmain->cachefiles.first; + for (; cache_file; cache_file = cache_file->id.next) { + items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode); + } + } + + /* movie clip's animation */ + items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode); + + /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */ + items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode); + + /* If filtering for channel drawing, we want the objects in alphabetical order, + * to make it easier to predict where items are in the hierarchy + * - This order only really matters if we need to show all channels in the list (e.g. for drawing) + * (XXX: What about lingering "active" flags? The order may now become unpredictable) + * - Don't do this if this behavior has been turned off (i.e. due to it being too slow) + * - Don't do this if there's just a single object + */ + if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) && + (view_layer->object_bases.first != view_layer->object_bases.last)) { + /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */ + // TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... + Base **sorted_bases; + size_t num_bases; + + sorted_bases = animdata_filter_ds_sorted_bases(ads, view_layer, filter_mode, &num_bases); + if (sorted_bases) { + /* Add the necessary channels for these bases... */ + for (size_t i = 0; i < num_bases; i++) { + items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode); + } + + // TODO: store something to validate whether any changes are needed? + + /* free temporary data */ + MEM_freeN(sorted_bases); + } + } + else { + /* Filter and add contents of each base (i.e. object) without them sorting first + * NOTE: This saves performance in cases where order doesn't matter + */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (animdata_filter_base_is_ok(ads, base, filter_mode)) { + /* since we're still here, this object should be usable */ + items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); + } + } + } + + /* return the number of items in the list */ + return items; } /* 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, size_t *items) +static short animdata_filter_dopesheet_summary(bAnimContext *ac, + ListBase *anim_data, + int filter_mode, + size_t *items) { - bDopeSheet *ads = NULL; - - /* get the DopeSheet information to use - * - we should only need to deal with the DopeSheet/Action Editor, - * since all the other Animation Editors won't have this concept - * being applicable. - */ - if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) { - SpaceAction *saction = (SpaceAction *)ac->sl; - ads = &saction->ads; - } - else { - /* invalid space type - skip this summary channels */ - return 1; - } - - /* dopesheet summary - * - 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 - */ - if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) { - bAnimListElem *ale = make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL, NULL); - if (ale) { - BLI_addtail(anim_data, ale); - (*items)++; - } - - /* if summary is collapsed, don't show other channels beneath this - * - this check is put inside the summary check so that it doesn't interfere with normal operation - */ - if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED) - return 0; - } - - /* the other channels beneath this can be shown */ - return 1; + bDopeSheet *ads = NULL; + + /* get the DopeSheet information to use + * - we should only need to deal with the DopeSheet/Action Editor, + * since all the other Animation Editors won't have this concept + * being applicable. + */ + if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) { + SpaceAction *saction = (SpaceAction *)ac->sl; + ads = &saction->ads; + } + else { + /* invalid space type - skip this summary channels */ + return 1; + } + + /* dopesheet summary + * - 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 + */ + if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) { + bAnimListElem *ale = make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL, NULL); + if (ale) { + BLI_addtail(anim_data, ale); + (*items)++; + } + + /* if summary is collapsed, don't show other channels beneath this + * - this check is put inside the summary check so that it doesn't interfere with normal operation + */ + if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED) + return 0; + } + + /* the other channels beneath this can be shown */ + 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) +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 */ - /* NOTE: only common channel-types have been handled for now. More can be added as necessary */ - 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; - - case ANIMTYPE_DSCACHEFILE: - items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode); - break; - - case ANIMTYPE_ANIMDATA: - items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode); - break; - - default: - printf("ERROR: Unsupported channel type (%d) in animdata_filter_animchan()\n", channel->type); - break; - } - - return items; + size_t items = 0; + + /* data to filter depends on channel type */ + /* NOTE: only common channel-types have been handled for now. More can be added as necessary */ + 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; + + case ANIMTYPE_DSCACHEFILE: + items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode); + break; + + case ANIMTYPE_ANIMDATA: + items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode); + break; + + default: + printf("ERROR: Unsupported channel type (%d) in animdata_filter_animchan()\n", + channel->type); + break; + } + + return items; } /* ----------- Cleanup API --------------- */ @@ -3128,57 +3211,57 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD /* Remove entries with invalid types in animation channel list */ static size_t animdata_filter_remove_invalid(ListBase *anim_data) { - bAnimListElem *ale, *next; - size_t items = 0; + bAnimListElem *ale, *next; + size_t items = 0; - /* only keep entries with valid types */ - for (ale = anim_data->first; ale; ale = next) { - next = ale->next; + /* only keep entries with valid types */ + for (ale = anim_data->first; ale; ale = next) { + next = ale->next; - if (ale->type == ANIMTYPE_NONE) - BLI_freelinkN(anim_data, ale); - else - items++; - } + if (ale->type == ANIMTYPE_NONE) + BLI_freelinkN(anim_data, ale); + else + items++; + } - return items; + return items; } /* Remove duplicate entries in animation channel list */ static size_t animdata_filter_remove_duplis(ListBase *anim_data) { - bAnimListElem *ale, *next; - GSet *gs; - size_t items = 0; - - /* build new hashtable to efficiently store and retrieve which entries have been - * encountered already while searching - */ - gs = BLI_gset_ptr_new(__func__); - - /* loop through items, removing them from the list if a similar item occurs already */ - for (ale = anim_data->first; ale; ale = next) { - next = ale->next; - - /* check if hash has any record of an entry like this - * - just use ale->data for now, though it would be nicer to involve - * ale->type in combination too to capture corner cases (where same data performs differently) - */ - if (BLI_gset_add(gs, ale->data)) { - /* this entry is 'unique' and can be kept */ - items++; - } - else { - /* this entry isn't needed anymore */ - BLI_freelinkN(anim_data, ale); - } - } - - /* free the hash... */ - BLI_gset_free(gs, NULL); - - /* return the number of items still in the list */ - return items; + bAnimListElem *ale, *next; + GSet *gs; + size_t items = 0; + + /* build new hashtable to efficiently store and retrieve which entries have been + * encountered already while searching + */ + gs = BLI_gset_ptr_new(__func__); + + /* loop through items, removing them from the list if a similar item occurs already */ + for (ale = anim_data->first; ale; ale = next) { + next = ale->next; + + /* check if hash has any record of an entry like this + * - just use ale->data for now, though it would be nicer to involve + * ale->type in combination too to capture corner cases (where same data performs differently) + */ + if (BLI_gset_add(gs, ale->data)) { + /* this entry is 'unique' and can be kept */ + items++; + } + else { + /* this entry isn't needed anymore */ + BLI_freelinkN(anim_data, ale); + } + } + + /* free the hash... */ + BLI_gset_free(gs, NULL); + + /* return the number of items still in the list */ + return items; } /* ----------- Public API --------------- */ @@ -3190,128 +3273,125 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data) * will be placed for use. * filter_mode: how should the data be filtered - bitmapping accessed flags */ -size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype) +size_t ANIM_animdata_filter(bAnimContext *ac, + ListBase *anim_data, + eAnimFilter_Flags filter_mode, + void *data, + eAnimCont_Types datatype) { - size_t items = 0; - - /* only filter data if there's somewhere to put it */ - if (data && anim_data) { - /* firstly filter the data */ - switch (datatype) { - /* Action-Editing Modes */ - case ANIMCONT_ACTION: /* 'Action Editor' */ - { - Object *obact = ac->obact; - SpaceAction *saction = (SpaceAction *)ac->sl; - bDopeSheet *ads = (saction) ? &saction->ads : NULL; - - /* specially check for AnimData filter... [#36687] */ - if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) { - /* all channels here are within the same AnimData block, hence this special case */ - if (LIKELY(obact->adt)) { - ANIMCHANNEL_NEW_CHANNEL(obact->adt, ANIMTYPE_ANIMDATA, (ID *)obact, NULL); - } - } - else { - /* 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 += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact); - } - - break; - } - case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */ - { - Key *key = (Key *)data; - - /* specially check for AnimData filter... [#36687] */ - if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) { - /* all channels here are within the same AnimData block, hence this special case */ - if (LIKELY(key->adt)) { - ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, (ID *)key, NULL); - } - } - else { - /* 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_shapekey(ac, anim_data, key, filter_mode); - } - - break; - } - - - /* Modes for Specialty Data Types (i.e. not keyframes) */ - case ANIMCONT_GPENCIL: - { - if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) - items = animdata_filter_gpencil(ac, anim_data, data, filter_mode); - break; - } - case ANIMCONT_MASK: - { - if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) - items = animdata_filter_mask(ac->bmain, anim_data, data, filter_mode); - break; - } - - - /* DopeSheet Based Modes */ - case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */ - { - /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */ - if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) - items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode); - break; - } - case ANIMCONT_FCURVES: /* Graph Editor -> F-Curves/Animation Editing */ - case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */ - case ANIMCONT_NLA: /* NLA Editor */ - { - /* all of these editors use the basic DopeSheet data for filtering options, - * but don't have all the same features */ - items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode); - break; - } - - - /* Timeline Mode - Basically the same as dopesheet, except we only have the summary for now */ - case ANIMCONT_TIMELINE: - { - /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */ - if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) - items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode); - break; - } - - /* Special/Internal Use */ - 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; - } - - /* unhandled */ - default: - { - printf("ANIM_animdata_filter() - Invalid datatype argument %u\n", datatype); - break; - } - } - - /* remove any 'weedy' entries */ - items = animdata_filter_remove_invalid(anim_data); - - /* remove duplicates (if required) */ - if (filter_mode & ANIMFILTER_NODUPLIS) - items = animdata_filter_remove_duplis(anim_data); - } - - /* return the number of items in the list */ - return items; + size_t items = 0; + + /* only filter data if there's somewhere to put it */ + if (data && anim_data) { + /* firstly filter the data */ + switch (datatype) { + /* Action-Editing Modes */ + case ANIMCONT_ACTION: /* 'Action Editor' */ + { + Object *obact = ac->obact; + SpaceAction *saction = (SpaceAction *)ac->sl; + bDopeSheet *ads = (saction) ? &saction->ads : NULL; + + /* specially check for AnimData filter... [#36687] */ + if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) { + /* all channels here are within the same AnimData block, hence this special case */ + if (LIKELY(obact->adt)) { + ANIMCHANNEL_NEW_CHANNEL(obact->adt, ANIMTYPE_ANIMDATA, (ID *)obact, NULL); + } + } + else { + /* 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 += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact); + } + + break; + } + case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */ + { + Key *key = (Key *)data; + + /* specially check for AnimData filter... [#36687] */ + if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) { + /* all channels here are within the same AnimData block, hence this special case */ + if (LIKELY(key->adt)) { + ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, (ID *)key, NULL); + } + } + else { + /* 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_shapekey(ac, anim_data, key, filter_mode); + } + + break; + } + + /* Modes for Specialty Data Types (i.e. not keyframes) */ + case ANIMCONT_GPENCIL: { + if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) + items = animdata_filter_gpencil(ac, anim_data, data, filter_mode); + break; + } + case ANIMCONT_MASK: { + if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) + items = animdata_filter_mask(ac->bmain, anim_data, data, filter_mode); + break; + } + + /* DopeSheet Based Modes */ + case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */ + { + /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */ + if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) + items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode); + break; + } + case ANIMCONT_FCURVES: /* Graph Editor -> F-Curves/Animation Editing */ + case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */ + case ANIMCONT_NLA: /* NLA Editor */ + { + /* all of these editors use the basic DopeSheet data for filtering options, + * but don't have all the same features */ + items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode); + break; + } + + /* Timeline Mode - Basically the same as dopesheet, except we only have the summary for now */ + case ANIMCONT_TIMELINE: { + /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */ + if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) + items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode); + break; + } + + /* Special/Internal Use */ + 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; + } + + /* unhandled */ + default: { + printf("ANIM_animdata_filter() - Invalid datatype argument %u\n", datatype); + break; + } + } + + /* remove any 'weedy' entries */ + items = animdata_filter_remove_invalid(anim_data); + + /* remove duplicates (if required) */ + if (filter_mode & ANIMFILTER_NODUPLIS) + items = animdata_filter_remove_duplis(anim_data); + } + + /* return the number of items in the list */ + return items; } /* ************************************************************ */ diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h index 4661d19378a..7fb5540fdf7 100644 --- a/source/blender/editors/animation/anim_intern.h +++ b/source/blender/editors/animation/anim_intern.h @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #ifndef __ANIM_INTERN_H__ #define __ANIM_INTERN_H__ @@ -79,4 +78,4 @@ void ANIM_OT_driver_button_edit(struct wmOperatorType *ot); void ANIM_OT_copy_driver_button(struct wmOperatorType *ot); void ANIM_OT_paste_driver_button(struct wmOperatorType *ot); -#endif /* __ANIM_INTERN_H__ */ +#endif /* __ANIM_INTERN_H__ */ diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 03cc4855a4b..fd22fa16fe8 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -21,14 +21,12 @@ * \ingroup edanimation */ - /* This file contains code for presenting F-Curves and other animation data * in the UI (especially for use in the Animation Editors). * * -- Joshua Leung, Dec 2008 */ - #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -51,172 +49,176 @@ */ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) { - int icon = 0; - - /* sanity checks */ - if (name == NULL) - return icon; - else if (ELEM(NULL, id, fcu, fcu->rna_path)) { - if (fcu == NULL) - strcpy(name, IFACE_("")); - else if (fcu->rna_path == NULL) - strcpy(name, IFACE_("")); - else /* id == NULL */ - BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index); - } - else { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - - /* get RNA pointer, and resolve the path */ - RNA_id_pointer_create(id, &id_ptr); - - /* try to resolve the path */ - if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { - const char *structname = NULL, *propname = NULL; - char arrayindbuf[16]; - const char *arrayname = NULL; - short free_structname = 0; - - /* For now, name will consist of 3 parts: struct-name, property name, array index - * There are several options possible: - * 1) .. - * i.e. Bone1.Location.X, or Object.Location.X - * 2) () - * i.e. X Location (Bone1), or X Location (Object) - * - * Currently, option 2 is in use, to try and make it easier to quickly identify F-Curves (it does have - * problems with looking rather odd though). Option 1 is better in terms of revealing a consistent sense of - * hierarchy though, which isn't so clear with option 2. - */ - - /* for structname - * - 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" */ - char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones["); - char *constName = BLI_str_quoted_substrN(fcu->rna_path, "constraints["); - - /* assemble the string to display in the UI... */ - structname = BLI_sprintfN("%s : %s", pchanName, constName); - free_structname = 1; - - /* free the temp names */ - if (pchanName) MEM_freeN(pchanName); - if (constName) MEM_freeN(constName); - } - 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 */ - structname = RNA_property_string_get_alloc(&ptr, nameprop, NULL, 0, NULL); - free_structname = 1; - } - else - structname = RNA_struct_ui_name(ptr.type); - } - - /* Property Name is straightforward */ - propname = RNA_property_ui_name(prop); - - /* Array Index - only if applicable */ - if (RNA_property_array_check(prop)) { - char c = RNA_property_array_item_char(prop, fcu->array_index); - - /* we need to write the index to a temp buffer (in py syntax) */ - if (c) BLI_snprintf(arrayindbuf, sizeof(arrayindbuf), "%c ", c); - else BLI_snprintf(arrayindbuf, sizeof(arrayindbuf), "[%d]", fcu->array_index); - - arrayname = &arrayindbuf[0]; - } - else { - /* no array index */ - arrayname = ""; - } - - /* putting this all together into the buffer */ - /* XXX we need to check for invalid names... - * 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) - MEM_freeN((void *)structname); - - - /* Icon for this property's owner: - * use the struct's icon if it is set - */ - icon = RNA_struct_ui_icon(ptr.type); - - /* valid path - remove the invalid tag since we now know how to use it saving - * users manual effort to reenable using "Revive Disabled FCurves" [#29629] - */ - fcu->flag &= ~FCURVE_DISABLED; - } - else { - /* invalid path */ - BLI_snprintf(name, 256, "\"%s[%d]\"", fcu->rna_path, fcu->array_index); - - /* icon for this should be the icon for the base ID */ - /* TODO: or should we just use the error icon? */ - icon = RNA_struct_ui_icon(id_ptr.type); - - /* tag F-Curve as disabled - as not usable path */ - fcu->flag |= FCURVE_DISABLED; - } - } - - /* return the icon that the active data had */ - return icon; + int icon = 0; + + /* sanity checks */ + if (name == NULL) + return icon; + else if (ELEM(NULL, id, fcu, fcu->rna_path)) { + if (fcu == NULL) + strcpy(name, IFACE_("")); + else if (fcu->rna_path == NULL) + strcpy(name, IFACE_("")); + else /* id == NULL */ + BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index); + } + else { + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + + /* get RNA pointer, and resolve the path */ + RNA_id_pointer_create(id, &id_ptr); + + /* try to resolve the path */ + if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { + const char *structname = NULL, *propname = NULL; + char arrayindbuf[16]; + const char *arrayname = NULL; + short free_structname = 0; + + /* For now, name will consist of 3 parts: struct-name, property name, array index + * There are several options possible: + * 1) .. + * i.e. Bone1.Location.X, or Object.Location.X + * 2) () + * i.e. X Location (Bone1), or X Location (Object) + * + * Currently, option 2 is in use, to try and make it easier to quickly identify F-Curves (it does have + * problems with looking rather odd though). Option 1 is better in terms of revealing a consistent sense of + * hierarchy though, which isn't so clear with option 2. + */ + + /* for structname + * - 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" */ + char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones["); + char *constName = BLI_str_quoted_substrN(fcu->rna_path, "constraints["); + + /* assemble the string to display in the UI... */ + structname = BLI_sprintfN("%s : %s", pchanName, constName); + free_structname = 1; + + /* free the temp names */ + if (pchanName) + MEM_freeN(pchanName); + if (constName) + MEM_freeN(constName); + } + 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 */ + structname = RNA_property_string_get_alloc(&ptr, nameprop, NULL, 0, NULL); + free_structname = 1; + } + else + structname = RNA_struct_ui_name(ptr.type); + } + + /* Property Name is straightforward */ + propname = RNA_property_ui_name(prop); + + /* Array Index - only if applicable */ + if (RNA_property_array_check(prop)) { + char c = RNA_property_array_item_char(prop, fcu->array_index); + + /* we need to write the index to a temp buffer (in py syntax) */ + if (c) + BLI_snprintf(arrayindbuf, sizeof(arrayindbuf), "%c ", c); + else + BLI_snprintf(arrayindbuf, sizeof(arrayindbuf), "[%d]", fcu->array_index); + + arrayname = &arrayindbuf[0]; + } + else { + /* no array index */ + arrayname = ""; + } + + /* putting this all together into the buffer */ + /* XXX we need to check for invalid names... + * 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) + MEM_freeN((void *)structname); + + /* Icon for this property's owner: + * use the struct's icon if it is set + */ + icon = RNA_struct_ui_icon(ptr.type); + + /* valid path - remove the invalid tag since we now know how to use it saving + * users manual effort to reenable using "Revive Disabled FCurves" [#29629] + */ + fcu->flag &= ~FCURVE_DISABLED; + } + else { + /* invalid path */ + BLI_snprintf(name, 256, "\"%s[%d]\"", fcu->rna_path, fcu->array_index); + + /* icon for this should be the icon for the base ID */ + /* TODO: or should we just use the error icon? */ + icon = RNA_struct_ui_icon(id_ptr.type); + + /* tag F-Curve as disabled - as not usable path */ + fcu->flag |= FCURVE_DISABLED; + } + } + + /* return the icon that the active data had */ + return icon; } /* ------------------------------- Color Codes for F-Curve Channels ---------------------------- */ /* step between the major distinguishable color bands of the primary colors */ -#define HSV_BANDWIDTH 0.3f +#define HSV_BANDWIDTH 0.3f /* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */ // void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out) void getcolor_fcurve_rainbow(int cur, int tot, float out[3]) { - float hsv[3], fac; - int grouping; - - /* we try to divide the color into groupings of n colors, - * where n is: - * 3 - for 'odd' numbers of curves - there should be a majority of triplets of curves - * 4 - for 'even' numbers of curves - there should be a majority of quartets of curves - * so the base color is simply one of the three primary colors - */ - grouping = (4 - (tot % 2)); - hsv[0] = HSV_BANDWIDTH * (float)(cur % grouping); - - /* 'Value' (i.e. darkness) needs to vary so that larger sets of three will be - * 'darker' (i.e. smaller value), so that they don't look that similar to previous ones. - * However, only a range of 0.3 to 1.0 is really usable to avoid clashing - * with some other stuff - */ - fac = ((float)cur / (float)tot) * 0.7f; - - /* the base color can get offset a bit so that the colors aren't so identical */ - hsv[0] += fac * HSV_BANDWIDTH; - if (hsv[0] > 1.0f) hsv[0] = fmod(hsv[0], 1.0f); - - /* saturation adjustments for more visible range */ - hsv[1] = ((hsv[0] > 0.5f) && (hsv[0] < 0.8f)) ? 0.5f : 0.6f; - - /* value is fixed at 1.0f, otherwise we cannot clearly see the curves... */ - hsv[2] = 1.0f; - - /* finally, conver this to RGB colors */ - hsv_to_rgb_v(hsv, out); + float hsv[3], fac; + int grouping; + + /* we try to divide the color into groupings of n colors, + * where n is: + * 3 - for 'odd' numbers of curves - there should be a majority of triplets of curves + * 4 - for 'even' numbers of curves - there should be a majority of quartets of curves + * so the base color is simply one of the three primary colors + */ + grouping = (4 - (tot % 2)); + hsv[0] = HSV_BANDWIDTH * (float)(cur % grouping); + + /* 'Value' (i.e. darkness) needs to vary so that larger sets of three will be + * 'darker' (i.e. smaller value), so that they don't look that similar to previous ones. + * However, only a range of 0.3 to 1.0 is really usable to avoid clashing + * with some other stuff + */ + fac = ((float)cur / (float)tot) * 0.7f; + + /* the base color can get offset a bit so that the colors aren't so identical */ + hsv[0] += fac * HSV_BANDWIDTH; + if (hsv[0] > 1.0f) + hsv[0] = fmod(hsv[0], 1.0f); + + /* saturation adjustments for more visible range */ + hsv[1] = ((hsv[0] > 0.5f) && (hsv[0] < 0.8f)) ? 0.5f : 0.6f; + + /* value is fixed at 1.0f, otherwise we cannot clearly see the curves... */ + hsv[2] = 1.0f; + + /* finally, conver this to RGB colors */ + hsv_to_rgb_v(hsv, out); } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 7a9bb1df477..beffa47b2c5 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -76,24 +76,24 @@ /* helper function for getting the list of markers to work on */ static ListBase *context_get_markers(Scene *scene, ScrArea *sa) { - /* local marker sets... */ - if (sa) { - if (sa->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)sa->spacedata.first; - - /* local markers can only be shown when there's only a single active action to grab them from - * - flag only takes effect when there's an action, otherwise it can get too confusing? - */ - if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && (saction->action)) { - if (saction->flag & SACTION_POSEMARKERS_SHOW) { - return &saction->action->markers; - } - } - } - } - - /* default to using the scene's markers */ - return &scene->markers; + /* local marker sets... */ + if (sa) { + if (sa->spacetype == SPACE_ACTION) { + SpaceAction *saction = (SpaceAction *)sa->spacedata.first; + + /* local markers can only be shown when there's only a single active action to grab them from + * - flag only takes effect when there's an action, otherwise it can get too confusing? + */ + if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && (saction->action)) { + if (saction->flag & SACTION_POSEMARKERS_SHOW) { + return &saction->action->markers; + } + } + } + } + + /* default to using the scene's markers */ + return &scene->markers; } /* ............. */ @@ -101,16 +101,16 @@ static ListBase *context_get_markers(Scene *scene, ScrArea *sa) /* public API for getting markers from context */ ListBase *ED_context_get_markers(const bContext *C) { - return context_get_markers(CTX_data_scene(C), CTX_wm_area(C)); + return context_get_markers(CTX_data_scene(C), CTX_wm_area(C)); } /* public API for getting markers from "animation" context */ ListBase *ED_animcontext_get_markers(const bAnimContext *ac) { - if (ac) - return context_get_markers(ac->scene, ac->sa); - else - return NULL; + if (ac) + return context_get_markers(ac->scene, ac->sa); + else + return NULL; } /* --------------------------------- */ @@ -125,48 +125,43 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac) * (which is delta transform for grab/extend, and scale factor for scale) * \param 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) +int ED_markers_post_apply_transform( + ListBase *markers, Scene *scene, int mode, float value, char side) { - TimeMarker *marker; - float cfra = (float)CFRA; - int changed_tot = 0; - - /* sanity check - no markers, or locked markers */ - if ((scene->toolsettings->lock_markers) || - (markers == NULL)) - { - return changed_tot; - } - - /* 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 += round_fl_to_int(value); - changed_tot++; - } - break; - } - case TFM_TIME_SCALE: - { - /* rescale the distance between the marker and the current frame */ - marker->frame = cfra + round_fl_to_int((float)(marker->frame - cfra) * value); - changed_tot++; - break; - } - } - } - } - - return changed_tot; + TimeMarker *marker; + float cfra = (float)CFRA; + int changed_tot = 0; + + /* sanity check - no markers, or locked markers */ + if ((scene->toolsettings->lock_markers) || (markers == NULL)) { + return changed_tot; + } + + /* 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 += round_fl_to_int(value); + changed_tot++; + } + break; + } + case TFM_TIME_SCALE: { + /* rescale the distance between the marker and the current frame */ + marker->frame = cfra + round_fl_to_int((float)(marker->frame - cfra) * value); + changed_tot++; + break; + } + } + } + } + + return changed_tot; } /* --------------------------------- */ @@ -175,58 +170,57 @@ int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, f /* XXX for select, the min_dist should be small */ TimeMarker *ED_markers_find_nearest_marker(ListBase *markers, float x) { - TimeMarker *marker, *nearest = NULL; - float dist, min_dist = 1000000; + TimeMarker *marker, *nearest = NULL; + float dist, min_dist = 1000000; - if (markers) { - for (marker = markers->first; marker; marker = marker->next) { - dist = fabsf((float)marker->frame - x); + if (markers) { + for (marker = markers->first; marker; marker = marker->next) { + dist = fabsf((float)marker->frame - x); - if (dist < min_dist) { - min_dist = dist; - nearest = marker; - } - } - } + if (dist < min_dist) { + min_dist = dist; + nearest = marker; + } + } + } - return nearest; + return nearest; } /* Return the time of the marker that occurs on a frame closest to the given time */ int ED_markers_find_nearest_marker_time(ListBase *markers, float x) { - TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x); - return (nearest) ? (nearest->frame) : round_fl_to_int(x); + TimeMarker *nearest = ED_markers_find_nearest_marker(markers, x); + return (nearest) ? (nearest->frame) : round_fl_to_int(x); } - void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *last) { - TimeMarker *marker; - float min, max; - - /* sanity check */ - //printf("markers = %p - %p, %p\n", markers, markers->first, markers->last); - if (ELEM(NULL, markers, markers->first, markers->last)) { - *first = 0.0f; - *last = 0.0f; - return; - } - - min = FLT_MAX; - max = -FLT_MAX; - for (marker = markers->first; marker; marker = marker->next) { - if (!sel || (marker->flag & SELECT)) { - if (marker->frame < min) - min = (float)marker->frame; - if (marker->frame > max) - max = (float)marker->frame; - } - } - - /* set the min/max values */ - *first = min; - *last = max; + TimeMarker *marker; + float min, max; + + /* sanity check */ + //printf("markers = %p - %p, %p\n", markers, markers->first, markers->last); + if (ELEM(NULL, markers, markers->first, markers->last)) { + *first = 0.0f; + *last = 0.0f; + return; + } + + min = FLT_MAX; + max = -FLT_MAX; + for (marker = markers->first; marker; marker = marker->next) { + if (!sel || (marker->flag & SELECT)) { + if (marker->frame < min) + min = (float)marker->frame; + if (marker->frame > max) + max = (float)marker->frame; + } + } + + /* set the min/max values */ + *first = min; + *last = max; } /* --------------------------------- */ @@ -234,31 +228,33 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *la /* Adds a marker to list of cfra elems */ static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel) { - CfraElem *ce, *cen; - - /* should this one only be considered if it is selected? */ - if ((only_sel) && ((marker->flag & SELECT) == 0)) - return; - - /* insertion sort - try to find a previous cfra elem */ - for (ce = lb->first; ce; ce = ce->next) { - if (ce->cfra == marker->frame) { - /* do because of double keys */ - if (marker->flag & SELECT) - ce->sel = marker->flag; - return; - } - else if (ce->cfra > marker->frame) { - break; - } - } - - cen = MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); - if (ce) BLI_insertlinkbefore(lb, ce, cen); - else BLI_addtail(lb, cen); - - cen->cfra = marker->frame; - cen->sel = marker->flag; + CfraElem *ce, *cen; + + /* should this one only be considered if it is selected? */ + if ((only_sel) && ((marker->flag & SELECT) == 0)) + return; + + /* insertion sort - try to find a previous cfra elem */ + for (ce = lb->first; ce; ce = ce->next) { + if (ce->cfra == marker->frame) { + /* do because of double keys */ + if (marker->flag & SELECT) + ce->sel = marker->flag; + return; + } + else if (ce->cfra > marker->frame) { + break; + } + } + + cen = MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); + if (ce) + BLI_insertlinkbefore(lb, ce, cen); + else + BLI_addtail(lb, cen); + + cen->cfra = marker->frame; + cen->sel = marker->flag; } /* This function makes a list of all the markers. The only_sel @@ -267,47 +263,47 @@ static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only */ void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel) { - TimeMarker *marker; - - if (lb) { - /* Clear the list first, since callers have no way of knowing - * whether this terminated early otherwise. This may lead - * to crashes if the user didn't clear the memory first. - */ - lb->first = lb->last = NULL; - } - else { - return; - } - - if (markers == NULL) { - return; - } - - for (marker = markers->first; marker; marker = marker->next) - add_marker_to_cfra_elem(lb, marker, only_sel); + TimeMarker *marker; + + if (lb) { + /* Clear the list first, since callers have no way of knowing + * whether this terminated early otherwise. This may lead + * to crashes if the user didn't clear the memory first. + */ + lb->first = lb->last = NULL; + } + else { + return; + } + + if (markers == NULL) { + return; + } + + for (marker = markers->first; marker; marker = marker->next) + add_marker_to_cfra_elem(lb, marker, only_sel); } void ED_markers_deselect_all(ListBase *markers, int action) { - if (action == SEL_TOGGLE) { - action = ED_markers_get_first_selected(markers) ? SEL_DESELECT : SEL_SELECT; - } - - for (TimeMarker *marker = markers->first; marker; marker = marker->next) { - if (action == SEL_SELECT) { - marker->flag |= SELECT; - } - else if (action == SEL_DESELECT) { - marker->flag &= ~SELECT; - } - else if (action == SEL_INVERT) { - marker->flag ^= SELECT; - } - else { - BLI_assert(0); - } - } + if (action == SEL_TOGGLE) { + action = ED_markers_get_first_selected(markers) ? SEL_DESELECT : SEL_SELECT; + } + + for (TimeMarker *marker = markers->first; marker; marker = marker->next) { + if (action == SEL_SELECT) { + marker->flag |= SELECT; + } + else if (action == SEL_DESELECT) { + marker->flag &= ~SELECT; + } + else if (action == SEL_INVERT) { + marker->flag ^= SELECT; + } + else { + BLI_assert(0); + } + } } /* --------------------------------- */ @@ -315,16 +311,16 @@ void ED_markers_deselect_all(ListBase *markers, int action) /* Get the first selected marker */ TimeMarker *ED_markers_get_first_selected(ListBase *markers) { - TimeMarker *marker; + TimeMarker *marker; - if (markers) { - for (marker = markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) - return marker; - } - } + if (markers) { + for (marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) + return marker; + } + } - return NULL; + return NULL; } /* --------------------------------- */ @@ -334,226 +330,229 @@ TimeMarker *ED_markers_get_first_selected(ListBase *markers) */ void debug_markers_print_list(ListBase *markers) { - TimeMarker *marker; + TimeMarker *marker; - if (markers == NULL) { - printf("No markers list to print debug for\n"); - return; - } + if (markers == NULL) { + printf("No markers list to print debug for\n"); + return; + } - printf("List of markers follows: -----\n"); + printf("List of markers follows: -----\n"); - for (marker = markers->first; marker; marker = marker->next) { - printf("\t'%s' on %d at %p with %u\n", marker->name, marker->frame, (void *)marker, marker->flag); - } + for (marker = markers->first; marker; marker = marker->next) { + printf( + "\t'%s' on %d at %p with %u\n", marker->name, marker->frame, (void *)marker, marker->flag); + } - printf("End of list ------------------\n"); + printf("End of list ------------------\n"); } /* ************* Marker Drawing ************ */ -static void draw_marker_name( - const uiFontStyle *fstyle, TimeMarker *marker, const char *name, - int cfra, const float xpos, const float ypixels) +static void draw_marker_name(const uiFontStyle *fstyle, + TimeMarker *marker, + const char *name, + int cfra, + const float xpos, + const float ypixels) { - unsigned char text_col[4]; - float x, y; - - /* minimal y coordinate which wouldn't be occluded by scroll */ - int min_y = 17.0f * UI_DPI_FAC; - - if (marker->flag & SELECT) { - UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); - x = xpos + 4.0f * UI_DPI_FAC; - y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC; - y = max_ii(y, min_y); - } - else { - UI_GetThemeColor4ubv(TH_TEXT, text_col); - if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) { - x = xpos + 8.0f * UI_DPI_FAC; - y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC; - y = max_ii(y, min_y); - } - else { - x = xpos + 8.0f * UI_DPI_FAC; - y = 17.0f * UI_DPI_FAC; - } - } + unsigned char text_col[4]; + float x, y; + + /* minimal y coordinate which wouldn't be occluded by scroll */ + int min_y = 17.0f * UI_DPI_FAC; + + if (marker->flag & SELECT) { + UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); + x = xpos + 4.0f * UI_DPI_FAC; + y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC; + y = max_ii(y, min_y); + } + else { + UI_GetThemeColor4ubv(TH_TEXT, text_col); + if ((marker->frame <= cfra) && (marker->frame + 5 > cfra)) { + x = xpos + 8.0f * UI_DPI_FAC; + y = (ypixels <= 39.0f * UI_DPI_FAC) ? (ypixels - 10.0f * UI_DPI_FAC) : 29.0f * UI_DPI_FAC; + y = max_ii(y, min_y); + } + else { + x = xpos + 8.0f * UI_DPI_FAC; + y = 17.0f * UI_DPI_FAC; + } + } #ifdef DURIAN_CAMERA_SWITCH - if (marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) { - text_col[3] = 100; - } + if (marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) { + text_col[3] = 100; + } #endif - UI_fontstyle_draw_simple(fstyle, x, y, name, text_col); + UI_fontstyle_draw_simple(fstyle, x, y, name, text_col); } static void draw_marker_line(const float color[4], float x, float ymin, float ymax) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - immUniformColor4fv(color); - immUniform1i("colors_len", 0); /* "simple" mode */ - immUniform1f("dash_width", 6.0f); - immUniform1f("dash_factor", 0.5f); + immUniformColor4fv(color); + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); - immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, x, ymin); - immVertex2f(pos, x, ymax); - immEnd(); + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, x, ymin); + immVertex2f(pos, x, ymax); + immEnd(); - immUnbindProgram(); + immUnbindProgram(); } /* function to draw markers */ -static void draw_marker( - const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int flag, - /* avoid re-calculating each time */ - const float ypixels, const float xscale, int height) +static void draw_marker(const uiFontStyle *fstyle, + TimeMarker *marker, + int cfra, + int flag, + /* avoid re-calculating each time */ + const float ypixels, + const float xscale, + int height) { - const float xpos = marker->frame * xscale; + const float xpos = marker->frame * xscale; #ifdef DURIAN_CAMERA_SWITCH - const float yoffs = (marker->camera) ? 0.2f * UI_DPI_ICON_SIZE : 0.0f; + const float yoffs = (marker->camera) ? 0.2f * UI_DPI_ICON_SIZE : 0.0f; #else - const float yoffs = 0.0f; + const float yoffs = 0.0f; #endif - int icon_id; + int icon_id; - GPU_blend(true); - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - /* vertical line - dotted */ + /* vertical line - dotted */ #ifdef DURIAN_CAMERA_SWITCH - if ((marker->camera) || (flag & DRAW_MARKERS_LINES)) + if ((marker->camera) || (flag & DRAW_MARKERS_LINES)) #else - if (flag & DRAW_MARKERS_LINES) + if (flag & DRAW_MARKERS_LINES) #endif - { - float color[4]; - if (marker->flag & SELECT) { - copy_v4_fl4(color, 1.0f, 1.0f, 1.0f, 0.38f); - } - else { - copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 0.38f); - } - - draw_marker_line(color, xpos, yoffs + 1.5f * UI_DPI_ICON_SIZE, height); - } - - /* 5 px to offset icon to align properly, space / pixels corrects for zoom */ - if (flag & DRAW_MARKERS_LOCAL) { - icon_id = (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : - (marker->flag & SELECT) ? ICON_PMARKER_SEL : - ICON_PMARKER; - } + { + float color[4]; + if (marker->flag & SELECT) { + copy_v4_fl4(color, 1.0f, 1.0f, 1.0f, 0.38f); + } + else { + copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 0.38f); + } + + draw_marker_line(color, xpos, yoffs + 1.5f * UI_DPI_ICON_SIZE, height); + } + + /* 5 px to offset icon to align properly, space / pixels corrects for zoom */ + if (flag & DRAW_MARKERS_LOCAL) { + icon_id = (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : + (marker->flag & SELECT) ? ICON_PMARKER_SEL : ICON_PMARKER; + } #ifdef DURIAN_CAMERA_SWITCH - else if (marker->camera) { - icon_id = (marker->flag & SELECT) ? ICON_OUTLINER_OB_CAMERA : - ICON_CAMERA_DATA; - } + else if (marker->camera) { + icon_id = (marker->flag & SELECT) ? ICON_OUTLINER_OB_CAMERA : ICON_CAMERA_DATA; + } #endif - else { - icon_id = (marker->flag & SELECT) ? ICON_MARKER_HLT : - ICON_MARKER; - } + else { + icon_id = (marker->flag & SELECT) ? ICON_MARKER_HLT : ICON_MARKER; + } - UI_icon_draw(xpos - 0.55f * UI_DPI_ICON_SIZE, yoffs + UI_DPI_ICON_SIZE, icon_id); + UI_icon_draw(xpos - 0.55f * UI_DPI_ICON_SIZE, yoffs + UI_DPI_ICON_SIZE, icon_id); - GPU_blend(false); + GPU_blend(false); - /* and the marker name too, shifted slightly to the top-right */ + /* and the marker name too, shifted slightly to the top-right */ #ifdef DURIAN_CAMERA_SWITCH - if (marker->camera) { - draw_marker_name(fstyle, marker, marker->camera->id.name + 2, cfra, xpos, ypixels); - } - else if (marker->name[0]) { - draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels); - } + if (marker->camera) { + draw_marker_name(fstyle, marker, marker->camera->id.name + 2, cfra, xpos, ypixels); + } + else if (marker->name[0]) { + draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels); + } #else - if (marker->name[0]) { - draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels); - - } + if (marker->name[0]) { + draw_marker_name(fstyle, marker, marker->name, cfra, xpos, ypixels); + } #endif } /* Draw Scene-Markers in time window */ void ED_markers_draw(const bContext *C, int flag) { - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - ListBase *markers = ED_context_get_markers(C); - View2D *v2d; - TimeMarker *marker; - Scene *scene; - int select_pass; - int v2d_clip_range_x[2]; - float font_width_max; - - /* cache values */ - float ypixels, xscale, yscale; - - if (markers == NULL || BLI_listbase_is_empty(markers)) { - return; - } - - scene = CTX_data_scene(C); - v2d = UI_view2d_fromcontext(C); - int height = v2d->mask.ymax - v2d->mask.ymin; - - if (flag & DRAW_MARKERS_MARGIN) { - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - const unsigned char shade[4] = {0, 0, 0, 16}; - immUniformColor4ubv(shade); - - GPU_blend(true); - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - immRectf(pos, v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y); - - GPU_blend(false); - - immUnbindProgram(); - } - - /* no time correction for framelen! space is drawn with old values */ - ypixels = BLI_rcti_size_y(&v2d->mask); - UI_view2d_scale_get(v2d, &xscale, &yscale); - GPU_matrix_push(); - GPU_matrix_scale_2f(1.0f / xscale, 1.0f); - - /* x-bounds with offset for text (adjust for long string, avoid checking string width) */ - font_width_max = (10 * UI_DPI_FAC) / xscale; - v2d_clip_range_x[0] = v2d->cur.xmin - (sizeof(marker->name) * font_width_max); - v2d_clip_range_x[1] = v2d->cur.xmax + font_width_max; - - /* loop [unselected, selected] */ - for (select_pass = 0; select_pass <= SELECT; select_pass += SELECT) { - /* unselected markers are drawn at the first time */ - for (marker = markers->first; marker; marker = marker->next) { - if ((marker->flag & SELECT) == select_pass) { - /* bounds check */ - if ((marker->frame >= v2d_clip_range_x[0]) && - (marker->frame <= v2d_clip_range_x[1])) - { - draw_marker(fstyle, marker, scene->r.cfra, flag, - ypixels, xscale, height); - } - } - } - } - - GPU_matrix_pop(); + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + ListBase *markers = ED_context_get_markers(C); + View2D *v2d; + TimeMarker *marker; + Scene *scene; + int select_pass; + int v2d_clip_range_x[2]; + float font_width_max; + + /* cache values */ + float ypixels, xscale, yscale; + + if (markers == NULL || BLI_listbase_is_empty(markers)) { + return; + } + + scene = CTX_data_scene(C); + v2d = UI_view2d_fromcontext(C); + int height = v2d->mask.ymax - v2d->mask.ymin; + + if (flag & DRAW_MARKERS_MARGIN) { + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + const unsigned char shade[4] = {0, 0, 0, 16}; + immUniformColor4ubv(shade); + + GPU_blend(true); + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + immRectf(pos, v2d->cur.xmin, 0, v2d->cur.xmax, UI_MARKER_MARGIN_Y); + + GPU_blend(false); + + immUnbindProgram(); + } + + /* no time correction for framelen! space is drawn with old values */ + ypixels = BLI_rcti_size_y(&v2d->mask); + UI_view2d_scale_get(v2d, &xscale, &yscale); + GPU_matrix_push(); + GPU_matrix_scale_2f(1.0f / xscale, 1.0f); + + /* x-bounds with offset for text (adjust for long string, avoid checking string width) */ + font_width_max = (10 * UI_DPI_FAC) / xscale; + v2d_clip_range_x[0] = v2d->cur.xmin - (sizeof(marker->name) * font_width_max); + v2d_clip_range_x[1] = v2d->cur.xmax + font_width_max; + + /* loop [unselected, selected] */ + for (select_pass = 0; select_pass <= SELECT; select_pass += SELECT) { + /* unselected markers are drawn at the first time */ + for (marker = markers->first; marker; marker = marker->next) { + if ((marker->flag & SELECT) == select_pass) { + /* bounds check */ + if ((marker->frame >= v2d_clip_range_x[0]) && (marker->frame <= v2d_clip_range_x[1])) { + draw_marker(fstyle, marker, scene->r.cfra, flag, ypixels, xscale, height); + } + } + } + } + + GPU_matrix_pop(); } /* ************************ Marker Wrappers API ********************* */ @@ -567,48 +566,47 @@ void ED_markers_draw(const bContext *C, int flag) /* special poll() which checks if there are selected markers first */ static bool ed_markers_poll_selected_markers(bContext *C) { - ListBase *markers = ED_context_get_markers(C); + ListBase *markers = ED_context_get_markers(C); - /* first things first: markers can only exist in timeline views */ - if (ED_operator_animview_active(C) == 0) - return 0; + /* first things first: markers can only exist in timeline views */ + if (ED_operator_animview_active(C) == 0) + return 0; - /* check if some marker is selected */ - return ED_markers_get_first_selected(markers) != NULL; + /* check if some marker is selected */ + return ED_markers_get_first_selected(markers) != NULL; } static bool ed_markers_poll_selected_no_locked_markers(bContext *C) { - ListBase *markers = ED_context_get_markers(C); - ToolSettings *ts = CTX_data_tool_settings(C); + ListBase *markers = ED_context_get_markers(C); + ToolSettings *ts = CTX_data_tool_settings(C); - if (ts->lock_markers) - return 0; + if (ts->lock_markers) + return 0; - /* first things first: markers can only exist in timeline views */ - if (ED_operator_animview_active(C) == 0) - return 0; + /* first things first: markers can only exist in timeline views */ + if (ED_operator_animview_active(C) == 0) + return 0; - /* check if some marker is selected */ - return ED_markers_get_first_selected(markers) != NULL; + /* check if some marker is selected */ + return ED_markers_get_first_selected(markers) != NULL; } - /* special poll() which checks if there are any markers at all first */ static bool ed_markers_poll_markers_exist(bContext *C) { - ListBase *markers = ED_context_get_markers(C); - ToolSettings *ts = CTX_data_tool_settings(C); + ListBase *markers = ED_context_get_markers(C); + ToolSettings *ts = CTX_data_tool_settings(C); - if (ts->lock_markers) - return 0; + if (ts->lock_markers) + return 0; - /* first things first: markers can only exist in timeline views */ - if (ED_operator_animview_active(C) == 0) - return 0; + /* first things first: markers can only exist in timeline views */ + if (ED_operator_animview_active(C) == 0) + return 0; - /* list of markers must exist, as well as some markers in it! */ - return (markers && markers->first); + /* list of markers must exist, as well as some markers in it! */ + return (markers && markers->first); } /* ------------------------ */ @@ -622,29 +620,34 @@ static bool ed_markers_poll_markers_exist(bContext *C) * If NULL, the operator's standard exec() * callback will be called instead in the appropriate places. */ -static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wmEvent *event, - int (*invoke_func)(bContext *, wmOperator *, const wmEvent *)) +static int ed_markers_opwrap_invoke_custom(bContext *C, + wmOperator *op, + const wmEvent *event, + int (*invoke_func)(bContext *, + wmOperator *, + const wmEvent *)) { - int retval = OPERATOR_PASS_THROUGH; - - /* removed check for Y coord of event, keymap has bounbox now */ - - /* allow operator to run now */ - if (invoke_func) - retval = invoke_func(C, op, event); - else if (op->type->exec) - retval = op->type->exec(C, op); - else - BKE_report(op->reports, RPT_ERROR, "Programming error: operator does not actually have code to do anything!"); - - - /* unless successful, must add "pass-through" - * to let normal operator's have a chance at tackling this event */ - if ((retval & (OPERATOR_FINISHED | OPERATOR_INTERFACE)) == 0) { - retval |= OPERATOR_PASS_THROUGH; - } - - return retval; + int retval = OPERATOR_PASS_THROUGH; + + /* removed check for Y coord of event, keymap has bounbox now */ + + /* allow operator to run now */ + if (invoke_func) + retval = invoke_func(C, op, event); + else if (op->type->exec) + retval = op->type->exec(C, op); + else + BKE_report(op->reports, + RPT_ERROR, + "Programming error: operator does not actually have code to do anything!"); + + /* unless successful, must add "pass-through" + * to let normal operator's have a chance at tackling this event */ + if ((retval & (OPERATOR_FINISHED | OPERATOR_INTERFACE)) == 0) { + retval |= OPERATOR_PASS_THROUGH; + } + + return retval; } /* standard wrapper - first-tier invoke() callback to be directly assigned to operator typedata @@ -654,7 +657,7 @@ static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wm */ static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, event, NULL); + return ed_markers_opwrap_invoke_custom(C, op, event, NULL); } /* ************************** add markers *************************** */ @@ -662,50 +665,50 @@ static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, const wmEvent * /* add TimeMarker at current frame */ static int ed_marker_add_exec(bContext *C, wmOperator *UNUSED(op)) { - ListBase *markers = ED_context_get_markers(C); - TimeMarker *marker; - int frame = CTX_data_scene(C)->r.cfra; - - if (markers == NULL) - return OPERATOR_CANCELLED; - - /* prefer not having 2 markers at the same place, - * though the user can move them to overlap once added */ - for (marker = markers->first; marker; marker = marker->next) { - if (marker->frame == frame) - return OPERATOR_CANCELLED; - } - - /* deselect all */ - for (marker = markers->first; marker; marker = marker->next) - marker->flag &= ~SELECT; - - marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); - marker->flag = SELECT; - marker->frame = frame; - 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); - WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - - return OPERATOR_FINISHED; + ListBase *markers = ED_context_get_markers(C); + TimeMarker *marker; + int frame = CTX_data_scene(C)->r.cfra; + + if (markers == NULL) + return OPERATOR_CANCELLED; + + /* prefer not having 2 markers at the same place, + * though the user can move them to overlap once added */ + for (marker = markers->first; marker; marker = marker->next) { + if (marker->frame == frame) + return OPERATOR_CANCELLED; + } + + /* deselect all */ + for (marker = markers->first; marker; marker = marker->next) + marker->flag &= ~SELECT; + + marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); + marker->flag = SELECT; + marker->frame = frame; + 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); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); + + return OPERATOR_FINISHED; } static void MARKER_OT_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Time Marker"; - ot->description = "Add a new time marker"; - ot->idname = "MARKER_OT_add"; - - /* api callbacks */ - ot->exec = ed_marker_add_exec; - ot->invoke = ed_markers_opwrap_invoke; - ot->poll = ED_operator_animview_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Add Time Marker"; + ot->description = "Add a new time marker"; + ot->idname = "MARKER_OT_add"; + + /* api callbacks */ + ot->exec = ed_marker_add_exec; + ot->invoke = ed_markers_opwrap_invoke; + ot->poll = ED_operator_animview_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************** transform markers *************************** */ @@ -733,315 +736,323 @@ static void MARKER_OT_add(wmOperatorType *ot) */ typedef struct MarkerMove { - SpaceLink *slink; - ListBase *markers; - int event_type; /* store invoke-event, to verify */ - int *oldframe, evtx, firstx; - NumInput num; + SpaceLink *slink; + ListBase *markers; + int event_type; /* store invoke-event, to verify */ + int *oldframe, evtx, firstx; + NumInput num; } MarkerMove; static bool ed_marker_move_use_time(MarkerMove *mm) { - if (((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) || - ((mm->slink->spacetype == SPACE_ACTION) && (((SpaceAction *)mm->slink)->flag & SACTION_DRAWTIME)) || - ((mm->slink->spacetype == SPACE_GRAPH) && !(((SpaceGraph *)mm->slink)->flag & SIPO_DRAWTIME)) || - ((mm->slink->spacetype == SPACE_NLA) && !(((SpaceNla *)mm->slink)->flag & SNLA_DRAWTIME))) - { - return true; - } - - return false; + if (((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) || + ((mm->slink->spacetype == SPACE_ACTION) && + (((SpaceAction *)mm->slink)->flag & SACTION_DRAWTIME)) || + ((mm->slink->spacetype == SPACE_GRAPH) && + !(((SpaceGraph *)mm->slink)->flag & SIPO_DRAWTIME)) || + ((mm->slink->spacetype == SPACE_NLA) && !(((SpaceNla *)mm->slink)->flag & SNLA_DRAWTIME))) { + return true; + } + + return false; } static void ed_marker_move_update_header(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - MarkerMove *mm = op->customdata; - TimeMarker *marker, *selmarker = NULL; - const int offs = RNA_int_get(op->ptr, "frames"); - char str[UI_MAX_DRAW_STR]; - char str_offs[NUM_STR_REP_LEN]; - int totmark; - const bool use_time = ed_marker_move_use_time(mm); - - for (totmark = 0, marker = mm->markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) { - selmarker = marker; - totmark++; - } - } - - if (hasNumInput(&mm->num)) { - outputNumInput(&mm->num, str_offs, &scene->unit); - } - else if (use_time) { - BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs)); - } - else { - BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs); - } - - if (totmark == 1 && selmarker) { - /* we print current marker value */ - if (use_time) { - BLI_snprintf(str, sizeof(str), IFACE_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs); - } - else { - BLI_snprintf(str, sizeof(str), IFACE_("Marker %d offset %s"), selmarker->frame, str_offs); - } - } - else { - BLI_snprintf(str, sizeof(str), IFACE_("Marker offset %s"), str_offs); - } - - ED_area_status_text(CTX_wm_area(C), str); + Scene *scene = CTX_data_scene(C); + MarkerMove *mm = op->customdata; + TimeMarker *marker, *selmarker = NULL; + const int offs = RNA_int_get(op->ptr, "frames"); + char str[UI_MAX_DRAW_STR]; + char str_offs[NUM_STR_REP_LEN]; + int totmark; + const bool use_time = ed_marker_move_use_time(mm); + + for (totmark = 0, marker = mm->markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + selmarker = marker; + totmark++; + } + } + + if (hasNumInput(&mm->num)) { + outputNumInput(&mm->num, str_offs, &scene->unit); + } + else if (use_time) { + BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs)); + } + else { + BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs); + } + + if (totmark == 1 && selmarker) { + /* we print current marker value */ + if (use_time) { + BLI_snprintf( + str, sizeof(str), IFACE_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs); + } + else { + BLI_snprintf(str, sizeof(str), IFACE_("Marker %d offset %s"), selmarker->frame, str_offs); + } + } + else { + BLI_snprintf(str, sizeof(str), IFACE_("Marker offset %s"), str_offs); + } + + ED_area_status_text(CTX_wm_area(C), str); } /* copy selection to temp buffer */ /* return 0 if not OK */ static bool ed_marker_move_init(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ListBase *markers = ED_context_get_markers(C); - MarkerMove *mm; - TimeMarker *marker; - int a, totmark; - - if (markers == NULL) { - return false; - } - - for (totmark = 0, marker = markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) { - totmark++; - } - } - - if (totmark == 0) { - return false; - } - - op->customdata = mm = MEM_callocN(sizeof(MarkerMove), "Markermove"); - mm->slink = CTX_wm_space_data(C); - mm->markers = markers; - mm->oldframe = MEM_callocN(totmark * sizeof(int), "MarkerMove oldframe"); - - initNumInput(&mm->num); - mm->num.idx_max = 0; /* one axis */ - mm->num.val_flag[0] |= NUM_NO_FRACTION; - mm->num.unit_sys = scene->unit.system; - /* No time unit supporting frames currently... */ - mm->num.unit_type[0] = ed_marker_move_use_time(mm) ? B_UNIT_TIME : B_UNIT_NONE; - - for (a = 0, marker = markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) { - mm->oldframe[a] = marker->frame; - a++; - } - } - - return true; + Scene *scene = CTX_data_scene(C); + ListBase *markers = ED_context_get_markers(C); + MarkerMove *mm; + TimeMarker *marker; + int a, totmark; + + if (markers == NULL) { + return false; + } + + for (totmark = 0, marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + totmark++; + } + } + + if (totmark == 0) { + return false; + } + + op->customdata = mm = MEM_callocN(sizeof(MarkerMove), "Markermove"); + mm->slink = CTX_wm_space_data(C); + mm->markers = markers; + mm->oldframe = MEM_callocN(totmark * sizeof(int), "MarkerMove oldframe"); + + initNumInput(&mm->num); + mm->num.idx_max = 0; /* one axis */ + mm->num.val_flag[0] |= NUM_NO_FRACTION; + mm->num.unit_sys = scene->unit.system; + /* No time unit supporting frames currently... */ + mm->num.unit_type[0] = ed_marker_move_use_time(mm) ? B_UNIT_TIME : B_UNIT_NONE; + + for (a = 0, marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + mm->oldframe[a] = marker->frame; + a++; + } + } + + return true; } /* free stuff */ static void ed_marker_move_exit(bContext *C, wmOperator *op) { - MarkerMove *mm = op->customdata; + MarkerMove *mm = op->customdata; - /* free data */ - MEM_freeN(mm->oldframe); - MEM_freeN(op->customdata); - op->customdata = NULL; + /* free data */ + MEM_freeN(mm->oldframe); + MEM_freeN(op->customdata); + op->customdata = NULL; - /* clear custom header prints */ - ED_area_status_text(CTX_wm_area(C), NULL); + /* clear custom header prints */ + ED_area_status_text(CTX_wm_area(C), NULL); } static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (ed_marker_move_init(C, op)) { - MarkerMove *mm = op->customdata; + if (ed_marker_move_init(C, op)) { + MarkerMove *mm = op->customdata; - mm->evtx = event->x; - mm->firstx = event->x; - mm->event_type = event->type; + mm->evtx = event->x; + mm->firstx = event->x; + mm->event_type = event->type; - /* add temp handler */ - WM_event_add_modal_handler(C, op); + /* add temp handler */ + WM_event_add_modal_handler(C, op); - /* reset frs delta */ - RNA_int_set(op->ptr, "frames", 0); + /* reset frs delta */ + RNA_int_set(op->ptr, "frames", 0); - ed_marker_move_update_header(C, op); + ed_marker_move_update_header(C, op); - return OPERATOR_RUNNING_MODAL; - } + return OPERATOR_RUNNING_MODAL; + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_move_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_move_invoke); } /* note, init has to be called successfully */ static void ed_marker_move_apply(bContext *C, wmOperator *op) { #ifdef DURIAN_CAMERA_SWITCH - bScreen *sc = CTX_wm_screen(C); - Scene *scene = CTX_data_scene(C); - Object *camera = scene->camera; + bScreen *sc = CTX_wm_screen(C); + Scene *scene = CTX_data_scene(C); + Object *camera = scene->camera; #endif - MarkerMove *mm = op->customdata; - TimeMarker *marker; - int a, offs; + MarkerMove *mm = op->customdata; + TimeMarker *marker; + int a, offs; - offs = RNA_int_get(op->ptr, "frames"); - for (a = 0, marker = mm->markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) { - marker->frame = mm->oldframe[a] + offs; - a++; - } - } + offs = RNA_int_get(op->ptr, "frames"); + for (a = 0, marker = mm->markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + marker->frame = mm->oldframe[a] + offs; + a++; + } + } - 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 | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); #ifdef DURIAN_CAMERA_SWITCH - /* so we get view3d redraws */ - BKE_scene_camera_switch_update(scene); + /* so we get view3d redraws */ + BKE_scene_camera_switch_update(scene); - if (camera != scene->camera) { - BKE_screen_view3d_scene_sync(sc, scene); - WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); - } + if (camera != scene->camera) { + BKE_screen_view3d_scene_sync(sc, scene); + WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); + } #endif } /* only for modal */ static void ed_marker_move_cancel(bContext *C, wmOperator *op) { - RNA_int_set(op->ptr, "frames", 0); - ed_marker_move_apply(C, op); - ed_marker_move_exit(C, op); + RNA_int_set(op->ptr, "frames", 0); + ed_marker_move_apply(C, op); + ed_marker_move_exit(C, op); } static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *event) { - Scene *scene = CTX_data_scene(C); - MarkerMove *mm = op->customdata; - View2D *v2d = UI_view2d_fromcontext(C); - const bool has_numinput = hasNumInput(&mm->num); - const bool use_time = ed_marker_move_use_time(mm); - - /* Modal numinput active, try to handle numeric inputs first... */ - if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &mm->num, event)) { - float value = (float)RNA_int_get(op->ptr, "frames"); - - applyNumInput(&mm->num, &value); - if (use_time) { - value = TIME2FRA(value); - } - - RNA_int_set(op->ptr, "frames", (int)value); - ed_marker_move_apply(C, op); - ed_marker_move_update_header(C, op); - } - else { - bool handled = false; - switch (event->type) { - case ESCKEY: - ed_marker_move_cancel(C, op); - return OPERATOR_CANCELLED; - case RIGHTMOUSE: - /* press = user manually demands transform to be canceled */ - if (event->val == KM_PRESS) { - ed_marker_move_cancel(C, op); - return OPERATOR_CANCELLED; - } - /* else continue; <--- see if release event should be caught for tweak-end */ - ATTR_FALLTHROUGH; - - case RETKEY: - case PADENTER: - case LEFTMOUSE: - case MIDDLEMOUSE: - if (WM_event_is_modal_tweak_exit(event, 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 (!has_numinput) { - float dx; - - dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); - - if (event->x != mm->evtx) { /* XXX maybe init for first time */ - float fac; - - mm->evtx = event->x; - fac = ((float)(event->x - mm->firstx) * dx); - - apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/); - - RNA_int_set(op->ptr, "frames", (int)fac); - ed_marker_move_apply(C, op); - ed_marker_move_update_header(C, op); - } - } - break; - } - - if (!handled && event->val == KM_PRESS && handleNumInput(C, &mm->num, event)) { - float value = (float)RNA_int_get(op->ptr, "frames"); - - applyNumInput(&mm->num, &value); - if (use_time) { - value = TIME2FRA(value); - } - - RNA_int_set(op->ptr, "frames", (int)value); - ed_marker_move_apply(C, op); - ed_marker_move_update_header(C, op); - } - } - - return OPERATOR_RUNNING_MODAL; + Scene *scene = CTX_data_scene(C); + MarkerMove *mm = op->customdata; + View2D *v2d = UI_view2d_fromcontext(C); + const bool has_numinput = hasNumInput(&mm->num); + const bool use_time = ed_marker_move_use_time(mm); + + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &mm->num, event)) { + float value = (float)RNA_int_get(op->ptr, "frames"); + + applyNumInput(&mm->num, &value); + if (use_time) { + value = TIME2FRA(value); + } + + RNA_int_set(op->ptr, "frames", (int)value); + ed_marker_move_apply(C, op); + ed_marker_move_update_header(C, op); + } + else { + bool handled = false; + switch (event->type) { + case ESCKEY: + ed_marker_move_cancel(C, op); + return OPERATOR_CANCELLED; + case RIGHTMOUSE: + /* press = user manually demands transform to be canceled */ + if (event->val == KM_PRESS) { + ed_marker_move_cancel(C, op); + return OPERATOR_CANCELLED; + } + /* else continue; <--- see if release event should be caught for tweak-end */ + ATTR_FALLTHROUGH; + + case RETKEY: + case PADENTER: + case LEFTMOUSE: + case MIDDLEMOUSE: + if (WM_event_is_modal_tweak_exit(event, 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 (!has_numinput) { + float dx; + + dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); + + if (event->x != mm->evtx) { /* XXX maybe init for first time */ + float fac; + + mm->evtx = event->x; + fac = ((float)(event->x - mm->firstx) * dx); + + apply_keyb_grid(event->shift, + event->ctrl, + &fac, + 0.0, + 1.0, + 0.1, + 0 /*was: U.flag & USER_AUTOGRABGRID*/); + + RNA_int_set(op->ptr, "frames", (int)fac); + ed_marker_move_apply(C, op); + ed_marker_move_update_header(C, op); + } + } + break; + } + + if (!handled && event->val == KM_PRESS && handleNumInput(C, &mm->num, event)) { + float value = (float)RNA_int_get(op->ptr, "frames"); + + applyNumInput(&mm->num, &value); + if (use_time) { + value = TIME2FRA(value); + } + + RNA_int_set(op->ptr, "frames", (int)value); + ed_marker_move_apply(C, op); + ed_marker_move_update_header(C, op); + } + } + + return OPERATOR_RUNNING_MODAL; } static int ed_marker_move_exec(bContext *C, wmOperator *op) { - if (ed_marker_move_init(C, op)) { - ed_marker_move_apply(C, op); - ed_marker_move_exit(C, op); - return OPERATOR_FINISHED; - } - return OPERATOR_PASS_THROUGH; + if (ed_marker_move_init(C, op)) { + ed_marker_move_apply(C, op); + ed_marker_move_exit(C, op); + return OPERATOR_FINISHED; + } + return OPERATOR_PASS_THROUGH; } static void MARKER_OT_move(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Move Time Marker"; - ot->description = "Move selected time marker(s)"; - ot->idname = "MARKER_OT_move"; - - /* api callbacks */ - ot->exec = ed_marker_move_exec; - ot->invoke = ed_marker_move_invoke_wrapper; - ot->modal = ed_marker_move_modal; - ot->poll = ed_markers_poll_selected_no_locked_markers; - ot->cancel = ed_marker_move_cancel; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; - - /* rna storage */ - RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX); + /* identifiers */ + ot->name = "Move Time Marker"; + ot->description = "Move selected time marker(s)"; + ot->idname = "MARKER_OT_move"; + + /* api callbacks */ + ot->exec = ed_marker_move_exec; + ot->invoke = ed_marker_move_invoke_wrapper; + ot->modal = ed_marker_move_modal; + ot->poll = ed_markers_poll_selected_no_locked_markers; + ot->cancel = ed_marker_move_cancel; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + + /* rna storage */ + RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX); } /* ************************** duplicate markers *************************** */ @@ -1065,76 +1076,75 @@ static void MARKER_OT_move(wmOperatorType *ot) /* duplicate selected TimeMarkers */ static void ed_marker_duplicate_apply(bContext *C) { - ListBase *markers = ED_context_get_markers(C); - TimeMarker *marker, *newmarker; - - if (markers == NULL) - return; - - /* go through the list of markers, duplicate selected markers and add duplicated copies - * to the beginning of the list (unselect original markers) - */ - for (marker = markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) { - /* unselect selected marker */ - marker->flag &= ~SELECT; - - /* create and set up new marker */ - newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); - newmarker->flag = SELECT; - newmarker->frame = marker->frame; - BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name)); + ListBase *markers = ED_context_get_markers(C); + TimeMarker *marker, *newmarker; + + if (markers == NULL) + return; + + /* go through the list of markers, duplicate selected markers and add duplicated copies + * to the beginning of the list (unselect original markers) + */ + for (marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + /* unselect selected marker */ + marker->flag &= ~SELECT; + + /* create and set up new marker */ + newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); + newmarker->flag = SELECT; + newmarker->frame = marker->frame; + BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name)); #ifdef DURIAN_CAMERA_SWITCH - newmarker->camera = marker->camera; + newmarker->camera = marker->camera; #endif - /* new marker is added to the beginning of list */ - // FIXME: bad ordering! - BLI_addhead(markers, newmarker); - } - } + /* new marker is added to the beginning of list */ + // FIXME: bad ordering! + BLI_addhead(markers, newmarker); + } + } } static int ed_marker_duplicate_exec(bContext *C, wmOperator *op) { - ed_marker_duplicate_apply(C); - ed_marker_move_exec(C, op); /* assumes frs delta set */ - - return OPERATOR_FINISHED; + ed_marker_duplicate_apply(C); + ed_marker_move_exec(C, op); /* assumes frs delta set */ + return OPERATOR_FINISHED; } static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ed_marker_duplicate_apply(C); - return ed_marker_move_invoke(C, op, event); + ed_marker_duplicate_apply(C); + return ed_marker_move_invoke(C, op, event); } static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_duplicate_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_duplicate_invoke); } static void MARKER_OT_duplicate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Duplicate Time Marker"; - ot->description = "Duplicate selected time marker(s)"; - ot->idname = "MARKER_OT_duplicate"; - - /* api callbacks */ - ot->exec = ed_marker_duplicate_exec; - ot->invoke = ed_marker_duplicate_invoke_wrapper; - ot->modal = ed_marker_move_modal; - ot->poll = ed_markers_poll_selected_no_locked_markers; - ot->cancel = ed_marker_move_cancel; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* rna storage */ - RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX); + /* identifiers */ + ot->name = "Duplicate Time Marker"; + ot->description = "Duplicate selected time marker(s)"; + ot->idname = "MARKER_OT_duplicate"; + + /* api callbacks */ + ot->exec = ed_marker_duplicate_exec; + ot->invoke = ed_marker_duplicate_invoke_wrapper; + ot->modal = ed_marker_move_modal; + ot->poll = ed_markers_poll_selected_no_locked_markers; + ot->cancel = ed_marker_move_cancel; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* rna storage */ + RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX); } /* ************************** selection ************************************/ @@ -1142,137 +1152,136 @@ static void MARKER_OT_duplicate(wmOperatorType *ot) /* select/deselect TimeMarker at current frame */ static void select_timeline_marker_frame(ListBase *markers, int frame, bool extend) { - TimeMarker *marker, *marker_first = NULL; - - /* support for selection cycling */ - for (marker = markers->first; marker; marker = marker->next) { - if (marker->frame == frame) { - if (marker->flag & SELECT) { - marker_first = marker->next; - break; - } - } - } - - /* if extend is not set, then deselect markers */ - if (extend == false) { - for (marker = markers->first; marker; marker = marker->next) { - marker->flag &= ~SELECT; - } - } - - LISTBASE_CIRCULAR_FORWARD_BEGIN(markers, marker, marker_first) - { - /* this way a not-extend select will always give 1 selected marker */ - if (marker->frame == frame) { - marker->flag ^= SELECT; - break; - } - } - LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_first); + TimeMarker *marker, *marker_first = NULL; + + /* support for selection cycling */ + for (marker = markers->first; marker; marker = marker->next) { + if (marker->frame == frame) { + if (marker->flag & SELECT) { + marker_first = marker->next; + break; + } + } + } + + /* if extend is not set, then deselect markers */ + if (extend == false) { + for (marker = markers->first; marker; marker = marker->next) { + marker->flag &= ~SELECT; + } + } + + LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { + /* this way a not-extend select will always give 1 selected marker */ + if (marker->frame == frame) { + marker->flag ^= SELECT; + break; + } + } + LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_first); } static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera) { - ListBase *markers = ED_context_get_markers(C); - ARegion *ar = CTX_wm_region(C); - View2D *v2d = UI_view2d_fromcontext(C); - float viewx; - int x, cfra; + ListBase *markers = ED_context_get_markers(C); + ARegion *ar = CTX_wm_region(C); + View2D *v2d = UI_view2d_fromcontext(C); + float viewx; + int x, cfra; - if (markers == NULL) - return OPERATOR_PASS_THROUGH; + if (markers == NULL) + return OPERATOR_PASS_THROUGH; - x = event->x - ar->winrct.xmin; + x = event->x - ar->winrct.xmin; - viewx = UI_view2d_region_to_view_x(v2d, x); + viewx = UI_view2d_region_to_view_x(v2d, x); - cfra = ED_markers_find_nearest_marker_time(markers, viewx); + cfra = ED_markers_find_nearest_marker_time(markers, viewx); - select_timeline_marker_frame(markers, cfra, extend); + select_timeline_marker_frame(markers, cfra, extend); #ifdef DURIAN_CAMERA_SWITCH - if (camera) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base; - TimeMarker *marker; - int sel = 0; - - if (!extend) - BKE_view_layer_base_deselect_all(view_layer); - - for (marker = markers->first; marker; marker = marker->next) { - if (marker->frame == cfra) { - sel = (marker->flag & SELECT); - break; - } - } - - for (marker = markers->first; marker; marker = marker->next) { - if (marker->camera) { - if (marker->frame == cfra) { - base = BKE_view_layer_base_find(view_layer, marker->camera); - if (base) { - ED_object_base_select(base, sel); - if (sel) - ED_object_base_activate(C, base); - } - } - } - } - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } + if (camera) { + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *base; + TimeMarker *marker; + int sel = 0; + + if (!extend) + BKE_view_layer_base_deselect_all(view_layer); + + for (marker = markers->first; marker; marker = marker->next) { + if (marker->frame == cfra) { + sel = (marker->flag & SELECT); + break; + } + } + + for (marker = markers->first; marker; marker = marker->next) { + if (marker->camera) { + if (marker->frame == cfra) { + base = BKE_view_layer_base_find(view_layer, marker->camera); + if (base) { + ED_object_base_select(base, sel); + if (sel) + ED_object_base_activate(C, base); + } + } + } + } + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } #else - (void)camera; + (void)camera; #endif - 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 | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */ - return OPERATOR_FINISHED | 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, const wmEvent *event) { - const bool extend = RNA_boolean_get(op->ptr, "extend"); - bool camera = false; + const bool extend = RNA_boolean_get(op->ptr, "extend"); + bool camera = false; #ifdef DURIAN_CAMERA_SWITCH - camera = RNA_boolean_get(op->ptr, "camera"); + camera = RNA_boolean_get(op->ptr, "camera"); #endif - return ed_marker_select(C, event, extend, camera); + return ed_marker_select(C, event, extend, camera); } static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_select_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, ed_marker_select_invoke); } static void MARKER_OT_select(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Select Time Marker"; - ot->description = "Select time marker(s)"; - ot->idname = "MARKER_OT_select"; + /* identifiers */ + ot->name = "Select Time Marker"; + ot->description = "Select time marker(s)"; + ot->idname = "MARKER_OT_select"; - /* api callbacks */ - ot->invoke = ed_marker_select_invoke_wrapper; - ot->poll = ed_markers_poll_markers_exist; + /* api callbacks */ + ot->invoke = ed_marker_select_invoke_wrapper; + ot->poll = ed_markers_poll_markers_exist; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); #ifdef DURIAN_CAMERA_SWITCH - prop = RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); #endif } @@ -1286,110 +1295,110 @@ static void MARKER_OT_select(wmOperatorType *ot) * * callbacks: * - * exec() has to be filled in by user + * exec() has to be filled in by user * * invoke() default WM function * adds modal handler * - * modal() default WM function + * modal() default WM function * accept modal events while doing it, calls exec(), handles ESC and border drawing * - * poll() has to be filled in by user for context + * poll() has to be filled in by user for context */ static int ed_marker_box_select_exec(bContext *C, wmOperator *op) { - View2D *v2d = UI_view2d_fromcontext(C); - ListBase *markers = ED_context_get_markers(C); - rctf rect; + View2D *v2d = UI_view2d_fromcontext(C); + ListBase *markers = ED_context_get_markers(C); + rctf rect; - WM_operator_properties_border_to_rctf(op, &rect); - UI_view2d_region_to_view_rctf(v2d, &rect, &rect); + WM_operator_properties_border_to_rctf(op, &rect); + UI_view2d_region_to_view_rctf(v2d, &rect, &rect); - if (markers == NULL) - return 0; + if (markers == NULL) + return 0; - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const bool select = (sel_op != SEL_OP_SUB); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - ED_markers_deselect_all(markers, SEL_DESELECT); - } + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const bool select = (sel_op != SEL_OP_SUB); + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + ED_markers_deselect_all(markers, SEL_DESELECT); + } - for (TimeMarker *marker = markers->first; marker; marker = marker->next) { - if (BLI_rctf_isect_x(&rect, marker->frame)) { - SET_FLAG_FROM_TEST(marker->flag, select, SELECT); - } - } + for (TimeMarker *marker = markers->first; marker; marker = marker->next) { + if (BLI_rctf_isect_x(&rect, marker->frame)) { + SET_FLAG_FROM_TEST(marker->flag, select, SELECT); + } + } - 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 | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - return 1; + return 1; } static int ed_marker_select_box_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, event, WM_gesture_box_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, WM_gesture_box_invoke); } static void MARKER_OT_select_box(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Marker Box Select"; - ot->description = "Select all time markers using box selection"; - ot->idname = "MARKER_OT_select_box"; + /* identifiers */ + ot->name = "Marker Box Select"; + ot->description = "Select all time markers using box selection"; + ot->idname = "MARKER_OT_select_box"; - /* api callbacks */ - ot->exec = ed_marker_box_select_exec; - ot->invoke = ed_marker_select_box_invoke_wrapper; - ot->modal = WM_gesture_box_modal; - ot->cancel = WM_gesture_box_cancel; + /* api callbacks */ + ot->exec = ed_marker_box_select_exec; + ot->invoke = ed_marker_select_box_invoke_wrapper; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; - ot->poll = ed_markers_poll_markers_exist; + ot->poll = ed_markers_poll_markers_exist; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - WM_operator_properties_gesture_box(ot); - WM_operator_properties_select_operation_simple(ot); + /* properties */ + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation_simple(ot); } /* *********************** (de)select all ***************** */ static int ed_marker_select_all_exec(bContext *C, wmOperator *op) { - ListBase *markers = ED_context_get_markers(C); - if (markers == NULL) { - return OPERATOR_CANCELLED; - } + ListBase *markers = ED_context_get_markers(C); + if (markers == NULL) { + return OPERATOR_CANCELLED; + } - int action = RNA_enum_get(op->ptr, "action"); - ED_markers_deselect_all(markers, action); + int action = RNA_enum_get(op->ptr, "action"); + ED_markers_deselect_all(markers, action); - 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 | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void MARKER_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "(De)select all Markers"; - ot->description = "Change selection of all time markers"; - ot->idname = "MARKER_OT_select_all"; + /* identifiers */ + ot->name = "(De)select all Markers"; + ot->description = "Change selection of all time markers"; + ot->idname = "MARKER_OT_select_all"; - /* api callbacks */ - ot->exec = ed_marker_select_all_exec; - ot->invoke = ed_markers_opwrap_invoke; - ot->poll = ed_markers_poll_markers_exist; + /* api callbacks */ + ot->exec = ed_marker_select_all_exec; + ot->invoke = ed_markers_opwrap_invoke; + ot->poll = ed_markers_poll_markers_exist; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* rna */ - WM_operator_properties_select_all(ot); + /* rna */ + WM_operator_properties_select_all(ot); } /* ***************** remove marker *********************** */ @@ -1397,167 +1406,172 @@ static void MARKER_OT_select_all(wmOperatorType *ot) /* remove selected TimeMarkers */ static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op)) { - ListBase *markers = ED_context_get_markers(C); - TimeMarker *marker, *nmarker; - bool changed = false; - - if (markers == NULL) - return OPERATOR_CANCELLED; - - for (marker = markers->first; marker; marker = nmarker) { - nmarker = marker->next; - if (marker->flag & SELECT) { - BLI_freelinkN(markers, marker); - changed = true; - } - } - - if (changed) { - WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - } - - return OPERATOR_FINISHED; + ListBase *markers = ED_context_get_markers(C); + TimeMarker *marker, *nmarker; + bool changed = false; + + if (markers == NULL) + return OPERATOR_CANCELLED; + + for (marker = markers->first; marker; marker = nmarker) { + nmarker = marker->next; + if (marker->flag & SELECT) { + BLI_freelinkN(markers, marker); + changed = true; + } + } + + if (changed) { + WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); + } + + return OPERATOR_FINISHED; } static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - // XXX: must we keep these confirmations? - return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_confirm); + // XXX: must we keep these confirmations? + return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_confirm); } static void MARKER_OT_delete(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Markers"; - ot->description = "Delete selected time marker(s)"; - ot->idname = "MARKER_OT_delete"; - - /* api callbacks */ - ot->invoke = ed_marker_delete_invoke_wrapper; - ot->exec = ed_marker_delete_exec; - ot->poll = ed_markers_poll_selected_no_locked_markers; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Delete Markers"; + ot->description = "Delete selected time marker(s)"; + ot->idname = "MARKER_OT_delete"; + + /* api callbacks */ + ot->invoke = ed_marker_delete_invoke_wrapper; + ot->exec = ed_marker_delete_exec; + ot->poll = ed_markers_poll_selected_no_locked_markers; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - /* **************** rename marker ***************** */ /* rename first selected TimeMarker */ static int ed_marker_rename_exec(bContext *C, wmOperator *op) { - TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C)); + TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C)); - if (marker) { - RNA_string_get(op->ptr, "name", marker->name); + if (marker) { + RNA_string_get(op->ptr, "name", marker->name); - 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 | ND_MARKERS, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL); - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) { - /* must initialize the marker name first if there is a marker selected */ - TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C)); - if (marker) - RNA_string_set(op->ptr, "name", marker->name); + /* must initialize the marker name first if there is a marker selected */ + TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C)); + if (marker) + RNA_string_set(op->ptr, "name", marker->name); - /* now see if the operator is usable */ - return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_props_popup_confirm); + /* now see if the operator is usable */ + return ed_markers_opwrap_invoke_custom(C, op, event, WM_operator_props_popup_confirm); } static void MARKER_OT_rename(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Rename Marker"; - ot->description = "Rename first selected time marker"; - ot->idname = "MARKER_OT_rename"; - - /* api callbacks */ - ot->invoke = ed_marker_rename_invoke_wrapper; - ot->exec = ed_marker_rename_exec; - ot->poll = ed_markers_poll_selected_no_locked_markers; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker"); - //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers"); + /* identifiers */ + ot->name = "Rename Marker"; + ot->description = "Rename first selected time marker"; + ot->idname = "MARKER_OT_rename"; + + /* api callbacks */ + ot->invoke = ed_marker_rename_invoke_wrapper; + ot->exec = ed_marker_rename_exec; + ot->poll = ed_markers_poll_selected_no_locked_markers; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_string(ot->srna, + "name", + "RenamedMarker", + sizeof(((TimeMarker *)NULL)->name), + "Name", + "New name for marker"); + //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers"); } /* **************** make links to scene ***************** */ static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op) { - ListBase *markers = ED_context_get_markers(C); - Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scenes, RNA_enum_get(op->ptr, "scene")); - TimeMarker *marker, *marker_new; - - if (scene_to == NULL) { - BKE_report(op->reports, RPT_ERROR, "Scene not found"); - return OPERATOR_CANCELLED; - } - - if (scene_to == CTX_data_scene(C)) { - BKE_report(op->reports, RPT_ERROR, "Cannot re-link markers into the same scene"); - return OPERATOR_CANCELLED; - } - - if (scene_to->toolsettings->lock_markers) { - BKE_report(op->reports, RPT_ERROR, "Target scene has locked markers"); - return OPERATOR_CANCELLED; - } - - /* copy markers */ - for (marker = markers->first; marker; marker = marker->next) { - if (marker->flag & SELECT) { - marker_new = MEM_dupallocN(marker); - marker_new->prev = marker_new->next = NULL; - - BLI_addtail(&scene_to->markers, marker_new); - } - } - - return OPERATOR_FINISHED; + ListBase *markers = ED_context_get_markers(C); + Scene *scene_to = BLI_findlink(&CTX_data_main(C)->scenes, RNA_enum_get(op->ptr, "scene")); + TimeMarker *marker, *marker_new; + + if (scene_to == NULL) { + BKE_report(op->reports, RPT_ERROR, "Scene not found"); + return OPERATOR_CANCELLED; + } + + if (scene_to == CTX_data_scene(C)) { + BKE_report(op->reports, RPT_ERROR, "Cannot re-link markers into the same scene"); + return OPERATOR_CANCELLED; + } + + if (scene_to->toolsettings->lock_markers) { + BKE_report(op->reports, RPT_ERROR, "Target scene has locked markers"); + return OPERATOR_CANCELLED; + } + + /* copy markers */ + for (marker = markers->first; marker; marker = marker->next) { + if (marker->flag & SELECT) { + marker_new = MEM_dupallocN(marker); + marker_new->prev = marker_new->next = NULL; + + BLI_addtail(&scene_to->markers, marker_new); + } + } + + return OPERATOR_FINISHED; } -static int ed_marker_make_links_scene_invoke_wrapper(bContext *C, wmOperator *op, const wmEvent *event) +static int ed_marker_make_links_scene_invoke_wrapper(bContext *C, + wmOperator *op, + const wmEvent *event) { - return ed_markers_opwrap_invoke_custom(C, op, event, WM_menu_invoke); + return ed_markers_opwrap_invoke_custom(C, op, event, WM_menu_invoke); } static void MARKER_OT_make_links_scene(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Make Links to Scene"; - ot->description = "Copy selected markers to another scene"; - ot->idname = "MARKER_OT_make_links_scene"; - - /* api callbacks */ - ot->exec = ed_marker_make_links_scene_exec; - ot->invoke = ed_marker_make_links_scene_invoke_wrapper; - ot->poll = ed_markers_poll_selected_markers; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - prop = RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", ""); - RNA_def_enum_funcs(prop, RNA_scene_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; - + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Make Links to Scene"; + ot->description = "Copy selected markers to another scene"; + ot->idname = "MARKER_OT_make_links_scene"; + + /* api callbacks */ + ot->exec = ed_marker_make_links_scene_exec; + ot->invoke = ed_marker_make_links_scene_invoke_wrapper; + ot->poll = ed_markers_poll_selected_markers; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", ""); + RNA_def_enum_funcs(prop, RNA_scene_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } #ifdef DURIAN_CAMERA_SWITCH @@ -1565,65 +1579,65 @@ static void MARKER_OT_make_links_scene(wmOperatorType *ot) static int ed_marker_camera_bind_exec(bContext *C, wmOperator *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; - - /* Don't do anything if we don't have a camera selected */ - if (ob == NULL) { - BKE_report(op->reports, RPT_ERROR, "Select a camera to bind to a marker on this frame"); - return OPERATOR_CANCELLED; - } - - /* add new marker, unless we already have one on this frame, in which case, replace it */ - if (markers == NULL) - return OPERATOR_CANCELLED; - - marker = ED_markers_find_nearest_marker(markers, CFRA); - if ((marker == NULL) || (marker->frame != CFRA)) { - marker = MEM_callocN(sizeof(TimeMarker), "Camera TimeMarker"); - marker->flag = SELECT; - marker->frame = CFRA; - BLI_addtail(markers, marker); - - /* deselect all others, so that the user can then move it without problems */ - for (TimeMarker *m = markers->first; m; m = m->next) { - if (m != marker) { - m->flag &= ~SELECT; - } - } - } - - /* bind to the nominated camera (as set in operator props) */ - marker->camera = ob; - - /* camera may have changes */ - BKE_scene_camera_switch_update(scene); - BKE_screen_view3d_scene_sync(sc, scene); - - 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; + 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; + + /* Don't do anything if we don't have a camera selected */ + if (ob == NULL) { + BKE_report(op->reports, RPT_ERROR, "Select a camera to bind to a marker on this frame"); + return OPERATOR_CANCELLED; + } + + /* add new marker, unless we already have one on this frame, in which case, replace it */ + if (markers == NULL) + return OPERATOR_CANCELLED; + + marker = ED_markers_find_nearest_marker(markers, CFRA); + if ((marker == NULL) || (marker->frame != CFRA)) { + marker = MEM_callocN(sizeof(TimeMarker), "Camera TimeMarker"); + marker->flag = SELECT; + marker->frame = CFRA; + BLI_addtail(markers, marker); + + /* deselect all others, so that the user can then move it without problems */ + for (TimeMarker *m = markers->first; m; m = m->next) { + if (m != marker) { + m->flag &= ~SELECT; + } + } + } + + /* bind to the nominated camera (as set in operator props) */ + marker->camera = ob; + + /* camera may have changes */ + BKE_scene_camera_switch_update(scene); + BKE_screen_view3d_scene_sync(sc, scene); + + 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; } static void MARKER_OT_camera_bind(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Bind Camera to Markers"; - ot->description = "Bind the selected camera to a marker on the current frame"; - ot->idname = "MARKER_OT_camera_bind"; - - /* api callbacks */ - ot->exec = ed_marker_camera_bind_exec; - ot->invoke = ed_markers_opwrap_invoke; - ot->poll = ED_operator_animview_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* identifiers */ + ot->name = "Bind Camera to Markers"; + ot->description = "Bind the selected camera to a marker on the current frame"; + ot->idname = "MARKER_OT_camera_bind"; + + /* api callbacks */ + ot->exec = ed_marker_camera_bind_exec; + ot->invoke = ed_markers_opwrap_invoke; + ot->poll = ED_operator_animview_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } #endif @@ -1632,22 +1646,22 @@ static void MARKER_OT_camera_bind(wmOperatorType *ot) /* called in screen_ops.c:ED_operatortypes_screen() */ void ED_operatortypes_marker(void) { - WM_operatortype_append(MARKER_OT_add); - WM_operatortype_append(MARKER_OT_move); - WM_operatortype_append(MARKER_OT_duplicate); - WM_operatortype_append(MARKER_OT_select); - WM_operatortype_append(MARKER_OT_select_box); - WM_operatortype_append(MARKER_OT_select_all); - WM_operatortype_append(MARKER_OT_delete); - WM_operatortype_append(MARKER_OT_rename); - WM_operatortype_append(MARKER_OT_make_links_scene); + WM_operatortype_append(MARKER_OT_add); + WM_operatortype_append(MARKER_OT_move); + WM_operatortype_append(MARKER_OT_duplicate); + WM_operatortype_append(MARKER_OT_select); + WM_operatortype_append(MARKER_OT_select_box); + WM_operatortype_append(MARKER_OT_select_all); + WM_operatortype_append(MARKER_OT_delete); + WM_operatortype_append(MARKER_OT_rename); + WM_operatortype_append(MARKER_OT_make_links_scene); #ifdef DURIAN_CAMERA_SWITCH - WM_operatortype_append(MARKER_OT_camera_bind); + WM_operatortype_append(MARKER_OT_camera_bind); #endif } /* called in screen_ops.c:ED_keymap_screen() */ void ED_keymap_marker(wmKeyConfig *keyconf) { - WM_keymap_ensure(keyconf, "Markers", 0, 0); + WM_keymap_ensure(keyconf, "Markers", 0, 0); } diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index 7023a138c96..b1183167945 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -48,23 +48,22 @@ static CLG_LogRef LOG = {"ed.anim.motion_paths"}; - /* Motion path needing to be baked (mpt) */ typedef struct MPathTarget { - struct MPathTarget *next, *prev; + struct MPathTarget *next, *prev; - bMotionPath *mpath; /* motion path in question */ + bMotionPath *mpath; /* motion path in question */ - DLRBT_Tree keys; /* temp, to know where the keyframes are */ + DLRBT_Tree keys; /* temp, to know where the keyframes are */ - /* Original (Source Objects) */ - Object *ob; /* source object */ - bPoseChannel *pchan; /* source posechannel (if applicable) */ + /* Original (Source Objects) */ + Object *ob; /* source object */ + bPoseChannel *pchan; /* source posechannel (if applicable) */ - /* "Evaluated" Copies (these come from the background COW copie - * that provide all the coordinates we want to save off) - */ - Object *ob_eval; /* evaluated object */ + /* "Evaluated" Copies (these come from the background COW copie + * that provide all the coordinates we want to save off) + */ + Object *ob_eval; /* evaluated object */ } MPathTarget; /* ........ */ @@ -75,54 +74,53 @@ typedef struct MPathTarget { /* TODO: it would be nice in future to be able to update objects dependent on these bones too? */ void animviz_get_object_motionpaths(Object *ob, ListBase *targets) { - MPathTarget *mpt; - - /* object itself first */ - if ((ob->avs.recalc & ANIMVIZ_RECALC_PATHS) && (ob->mpath)) { - /* new target for object */ - mpt = MEM_callocN(sizeof(MPathTarget), "MPathTarget Ob"); - BLI_addtail(targets, mpt); - - mpt->mpath = ob->mpath; - mpt->ob = ob; - } - - /* bones */ - if ((ob->pose) && (ob->pose->avs.recalc & ANIMVIZ_RECALC_PATHS)) { - bArmature *arm = ob->data; - bPoseChannel *pchan; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone) && (arm->layer & pchan->bone->layer) && (pchan->mpath)) { - /* new target for bone */ - mpt = MEM_callocN(sizeof(MPathTarget), "MPathTarget PoseBone"); - BLI_addtail(targets, mpt); - - mpt->mpath = pchan->mpath; - mpt->ob = ob; - mpt->pchan = pchan; - } - } - } + MPathTarget *mpt; + + /* object itself first */ + if ((ob->avs.recalc & ANIMVIZ_RECALC_PATHS) && (ob->mpath)) { + /* new target for object */ + mpt = MEM_callocN(sizeof(MPathTarget), "MPathTarget Ob"); + BLI_addtail(targets, mpt); + + mpt->mpath = ob->mpath; + mpt->ob = ob; + } + + /* bones */ + if ((ob->pose) && (ob->pose->avs.recalc & ANIMVIZ_RECALC_PATHS)) { + bArmature *arm = ob->data; + bPoseChannel *pchan; + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if ((pchan->bone) && (arm->layer & pchan->bone->layer) && (pchan->mpath)) { + /* new target for bone */ + mpt = MEM_callocN(sizeof(MPathTarget), "MPathTarget PoseBone"); + BLI_addtail(targets, mpt); + + mpt->mpath = pchan->mpath; + mpt->ob = ob; + mpt->pchan = pchan; + } + } + } } /* ........ */ /* update scene for current frame */ -static void motionpaths_calc_update_scene(Main *bmain, - struct Depsgraph *depsgraph) +static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph) { - /* Do all updates - * - if this is too slow, resort to using a more efficient way - * that doesn't force complete update, but for now, this is the - * most accurate way! - * - * TODO(segey): Bring back partial updates, which became impossible - * with the new depsgraph due to unsorted nature of bases. - * - * TODO(sergey): Use evaluation context dedicated to motion paths. - */ - BKE_scene_graph_update_for_newframe(depsgraph, bmain); + /* Do all updates + * - if this is too slow, resort to using a more efficient way + * that doesn't force complete update, but for now, this is the + * most accurate way! + * + * TODO(segey): Bring back partial updates, which became impossible + * with the new depsgraph due to unsorted nature of bases. + * + * TODO(sergey): Use evaluation context dedicated to motion paths. + */ + BKE_scene_graph_update_for_newframe(depsgraph, bmain); } /* ........ */ @@ -130,78 +128,78 @@ static void motionpaths_calc_update_scene(Main *bmain, /* perform baking for the targets on the current frame */ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) { - MPathTarget *mpt; - - /* for each target, check if it can be baked on the current frame */ - for (mpt = targets->first; mpt; mpt = mpt->next) { - bMotionPath *mpath = mpt->mpath; - - /* current frame must be within the range the cache works for - * - is inclusive of the first frame, but not the last otherwise we get buffer overruns - */ - if ((cframe < mpath->start_frame) || (cframe >= mpath->end_frame)) { - continue; - } - - /* get the relevant cache vert to write to */ - bMotionPathVert *mpv = mpath->points + (cframe - mpath->start_frame); - - Object *ob_eval = mpt->ob_eval; - - /* Lookup evaluated pose channel, here because the depsgraph - * evaluation can change them so they are not cached in mpt. */ - bPoseChannel *pchan_eval = NULL; - if (mpt->pchan) { - pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name); - } - - /* pose-channel or object path baking? */ - if (pchan_eval) { - /* heads or tails */ - if (mpath->flag & MOTIONPATH_FLAG_BHEAD) { - copy_v3_v3(mpv->co, pchan_eval->pose_head); - } - else { - copy_v3_v3(mpv->co, pchan_eval->pose_tail); - } - - /* result must be in worldspace */ - mul_m4_v3(ob_eval->obmat, mpv->co); - } - else { - /* worldspace object location */ - copy_v3_v3(mpv->co, ob_eval->obmat[3]); - } - - float mframe = (float)(cframe); - - /* Tag if it's a keyframe */ - if (BLI_dlrbTree_search_exact(&mpt->keys, compare_ak_cfraPtr, &mframe)) { - mpv->flag |= MOTIONPATH_VERT_KEY; - } - else { - mpv->flag &= ~MOTIONPATH_VERT_KEY; - } - - /* Incremental update on evaluated object if possible, for fast updating - * while dragging in transform. */ - bMotionPath *mpath_eval = NULL; - if (mpt->pchan) { - mpath_eval = (pchan_eval) ? pchan_eval->mpath : NULL; - } - else { - mpath_eval = ob_eval->mpath; - } - - if (mpath_eval && mpath_eval->length == mpath->length) { - bMotionPathVert *mpv_eval = mpath_eval->points + (cframe - mpath_eval->start_frame); - *mpv_eval = *mpv; - - GPU_VERTBUF_DISCARD_SAFE(mpath_eval->points_vbo); - GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_line); - GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_points); - } - } + MPathTarget *mpt; + + /* for each target, check if it can be baked on the current frame */ + for (mpt = targets->first; mpt; mpt = mpt->next) { + bMotionPath *mpath = mpt->mpath; + + /* current frame must be within the range the cache works for + * - is inclusive of the first frame, but not the last otherwise we get buffer overruns + */ + if ((cframe < mpath->start_frame) || (cframe >= mpath->end_frame)) { + continue; + } + + /* get the relevant cache vert to write to */ + bMotionPathVert *mpv = mpath->points + (cframe - mpath->start_frame); + + Object *ob_eval = mpt->ob_eval; + + /* Lookup evaluated pose channel, here because the depsgraph + * evaluation can change them so they are not cached in mpt. */ + bPoseChannel *pchan_eval = NULL; + if (mpt->pchan) { + pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name); + } + + /* pose-channel or object path baking? */ + if (pchan_eval) { + /* heads or tails */ + if (mpath->flag & MOTIONPATH_FLAG_BHEAD) { + copy_v3_v3(mpv->co, pchan_eval->pose_head); + } + else { + copy_v3_v3(mpv->co, pchan_eval->pose_tail); + } + + /* result must be in worldspace */ + mul_m4_v3(ob_eval->obmat, mpv->co); + } + else { + /* worldspace object location */ + copy_v3_v3(mpv->co, ob_eval->obmat[3]); + } + + float mframe = (float)(cframe); + + /* Tag if it's a keyframe */ + if (BLI_dlrbTree_search_exact(&mpt->keys, compare_ak_cfraPtr, &mframe)) { + mpv->flag |= MOTIONPATH_VERT_KEY; + } + else { + mpv->flag &= ~MOTIONPATH_VERT_KEY; + } + + /* Incremental update on evaluated object if possible, for fast updating + * while dragging in transform. */ + bMotionPath *mpath_eval = NULL; + if (mpt->pchan) { + mpath_eval = (pchan_eval) ? pchan_eval->mpath : NULL; + } + else { + mpath_eval = ob_eval->mpath; + } + + if (mpath_eval && mpath_eval->length == mpath->length) { + bMotionPathVert *mpv_eval = mpath_eval->points + (cframe - mpath_eval->start_frame); + *mpv_eval = *mpv; + + GPU_VERTBUF_DISCARD_SAFE(mpath_eval->points_vbo); + GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_line); + GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_points); + } + } } /* Perform baking of the given object's and/or its bones' transforms to motion paths @@ -217,119 +215,124 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, bool restore, bool current_frame_only) { - /* sanity check */ - if (ELEM(NULL, targets, targets->first)) - return; - - /* Compute frame range to bake within. - * TODO: this method could be improved... - * 1) max range for standard baking - * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */ - int sfra = INT_MAX; - int efra = INT_MIN; - - for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { - /* try to increase area to do (only as much as needed) */ - sfra = MIN2(sfra, mpt->mpath->start_frame); - efra = MAX2(efra, mpt->mpath->end_frame); - } - - if (efra <= sfra) { - return; - } - - /* Limit frame range if we are updating just the current frame. */ - /* set frame values */ - int cfra = CFRA; - if (current_frame_only) { - if (cfra < sfra || cfra > efra) { - return; - } - sfra = efra = cfra; - } - - /* get copies of objects/bones to get the calculated results from - * (for copy-on-write evaluation), so that we actually get some results - */ - // TODO: Create a copy of background depsgraph that only contain these entities, and only evaluates them.. - for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { - mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob); - - AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id); - - /* build list of all keyframes in active action for object or pchan */ - BLI_dlrbTree_init(&mpt->keys); - - if (adt) { - bAnimVizSettings *avs; - - /* get pointer to animviz settings for each target */ - if (mpt->pchan) - avs = &mpt->ob->pose->avs; - else - avs = &mpt->ob->avs; - - /* it is assumed that keyframes for bones are all grouped in a single group - * unless an option is set to always use the whole action - */ - if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) { - bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name); - - if (agrp) { - agroup_to_keylist(adt, agrp, &mpt->keys, 0); - } - } - else { - action_to_keylist(adt, adt->action, &mpt->keys, 0); - } - } - } - - /* calculate path over requested range */ - CLOG_INFO(&LOG, 1, "Calculating MotionPaths between frames %d - %d (%d frames)", sfra, efra, efra - sfra + 1); - for (CFRA = sfra; CFRA <= efra; CFRA++) { - if (current_frame_only) { - /* For current frame, only update tagged. */ - BKE_scene_graph_update_tagged(depsgraph, bmain); - } - else { - /* Update relevant data for new frame. */ - motionpaths_calc_update_scene(bmain, depsgraph); - } - - /* perform baking for targets */ - motionpaths_calc_bake_targets(targets, CFRA); - } - - /* reset original environment */ - /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph - * may be a temporary one that works on a subset of the data. We always have - * to resoture the current frame though. */ - CFRA = cfra; - if (!current_frame_only && restore) { - motionpaths_calc_update_scene(bmain, depsgraph); - } - - /* clear recalc flags from targets */ - for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { - bAnimVizSettings *avs; - bMotionPath *mpath = mpt->mpath; - - /* get pointer to animviz settings for each target */ - if (mpt->pchan) - avs = &mpt->ob->pose->avs; - else - avs = &mpt->ob->avs; - - /* clear the flag requesting recalculation of targets */ - avs->recalc &= ~ANIMVIZ_RECALC_PATHS; - - /* Clean temp data */ - BLI_dlrbTree_free(&mpt->keys); - - /* Free previous batches to force update. */ - GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo); - GPU_BATCH_DISCARD_SAFE(mpath->batch_line); - GPU_BATCH_DISCARD_SAFE(mpath->batch_points); - } + /* sanity check */ + if (ELEM(NULL, targets, targets->first)) + return; + + /* Compute frame range to bake within. + * TODO: this method could be improved... + * 1) max range for standard baking + * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */ + int sfra = INT_MAX; + int efra = INT_MIN; + + for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { + /* try to increase area to do (only as much as needed) */ + sfra = MIN2(sfra, mpt->mpath->start_frame); + efra = MAX2(efra, mpt->mpath->end_frame); + } + + if (efra <= sfra) { + return; + } + + /* Limit frame range if we are updating just the current frame. */ + /* set frame values */ + int cfra = CFRA; + if (current_frame_only) { + if (cfra < sfra || cfra > efra) { + return; + } + sfra = efra = cfra; + } + + /* get copies of objects/bones to get the calculated results from + * (for copy-on-write evaluation), so that we actually get some results + */ + // TODO: Create a copy of background depsgraph that only contain these entities, and only evaluates them.. + for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { + mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob); + + AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id); + + /* build list of all keyframes in active action for object or pchan */ + BLI_dlrbTree_init(&mpt->keys); + + if (adt) { + bAnimVizSettings *avs; + + /* get pointer to animviz settings for each target */ + if (mpt->pchan) + avs = &mpt->ob->pose->avs; + else + avs = &mpt->ob->avs; + + /* it is assumed that keyframes for bones are all grouped in a single group + * unless an option is set to always use the whole action + */ + if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) { + bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name); + + if (agrp) { + agroup_to_keylist(adt, agrp, &mpt->keys, 0); + } + } + else { + action_to_keylist(adt, adt->action, &mpt->keys, 0); + } + } + } + + /* calculate path over requested range */ + CLOG_INFO(&LOG, + 1, + "Calculating MotionPaths between frames %d - %d (%d frames)", + sfra, + efra, + efra - sfra + 1); + for (CFRA = sfra; CFRA <= efra; CFRA++) { + if (current_frame_only) { + /* For current frame, only update tagged. */ + BKE_scene_graph_update_tagged(depsgraph, bmain); + } + else { + /* Update relevant data for new frame. */ + motionpaths_calc_update_scene(bmain, depsgraph); + } + + /* perform baking for targets */ + motionpaths_calc_bake_targets(targets, CFRA); + } + + /* reset original environment */ + /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph + * may be a temporary one that works on a subset of the data. We always have + * to resoture the current frame though. */ + CFRA = cfra; + if (!current_frame_only && restore) { + motionpaths_calc_update_scene(bmain, depsgraph); + } + + /* clear recalc flags from targets */ + for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) { + bAnimVizSettings *avs; + bMotionPath *mpath = mpt->mpath; + + /* get pointer to animviz settings for each target */ + if (mpt->pchan) + avs = &mpt->ob->pose->avs; + else + avs = &mpt->ob->avs; + + /* clear the flag requesting recalculation of targets */ + avs->recalc &= ~ANIMVIZ_RECALC_PATHS; + + /* Clean temp data */ + BLI_dlrbTree_free(&mpt->keys); + + /* Free previous batches to force update. */ + GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo); + GPU_BATCH_DISCARD_SAFE(mpath->batch_line); + GPU_BATCH_DISCARD_SAFE(mpath->batch_points); + } } diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 2287f2e0347..91cbc2ff3e0 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include @@ -60,61 +59,62 @@ /* Check if the operator can be run from the current context */ static bool change_frame_poll(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - - /* XXX temp? prevent changes during render */ - if (G.is_rendering) return false; - - /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION, - * this shouldn't show up in 3D editor (or others without 2D timeline view) via search - */ - if (sa) { - if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { - return true; - } - else if (sa->spacetype == SPACE_GRAPH) { - /* NOTE: Graph Editor has special version which does some extra stuff. - * No need to show the generic error message for that case though! - */ - return false; - } - } - - CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active"); - return false; + ScrArea *sa = CTX_wm_area(C); + + /* XXX temp? prevent changes during render */ + if (G.is_rendering) + return false; + + /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION, + * this shouldn't show up in 3D editor (or others without 2D timeline view) via search + */ + if (sa) { + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { + return true; + } + else if (sa->spacetype == SPACE_GRAPH) { + /* NOTE: Graph Editor has special version which does some extra stuff. + * No need to show the generic error message for that case though! + */ + return false; + } + } + + CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active"); + return false; } /* Set the new frame number */ static void change_frame_apply(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - float frame = RNA_float_get(op->ptr, "frame"); - bool do_snap = RNA_boolean_get(op->ptr, "snap"); - - if (do_snap) { - if (CTX_wm_space_seq(C)) { - frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); - } - else { - frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame); - } - } - - /* set the new frame number */ - if (scene->r.flag & SCER_SHOW_SUBFRAME) { - CFRA = (int)frame; - SUBFRA = frame - (int)frame; - } - else { - CFRA = round_fl_to_int(frame); - SUBFRA = 0.0f; - } - FRAMENUMBER_MIN_CLAMP(CFRA); - - /* do updates */ - BKE_sound_seek_scene(bmain, scene); - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + float frame = RNA_float_get(op->ptr, "frame"); + bool do_snap = RNA_boolean_get(op->ptr, "snap"); + + if (do_snap) { + if (CTX_wm_space_seq(C)) { + frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); + } + else { + frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame); + } + } + + /* set the new frame number */ + if (scene->r.flag & SCER_SHOW_SUBFRAME) { + CFRA = (int)frame; + SUBFRA = frame - (int)frame; + } + else { + CFRA = round_fl_to_int(frame); + SUBFRA = 0.0f; + } + FRAMENUMBER_MIN_CLAMP(CFRA); + + /* do updates */ + BKE_sound_seek_scene(bmain, scene); + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); } /* ---- */ @@ -122,9 +122,9 @@ static void change_frame_apply(bContext *C, wmOperator *op) /* Non-modal callback for running operator without user input */ static int change_frame_exec(bContext *C, wmOperator *op) { - change_frame_apply(C, op); + change_frame_apply(C, op); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } /* ---- */ @@ -132,402 +132,401 @@ static int change_frame_exec(bContext *C, wmOperator *op) /* Get frame from mouse coordinates */ static float frame_from_event(bContext *C, const wmEvent *event) { - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - float frame; + ARegion *region = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + float frame; - /* convert from region coordinates to View2D 'tot' space */ - frame = UI_view2d_region_to_view_x(®ion->v2d, event->mval[0]); + /* convert from region coordinates to View2D 'tot' space */ + frame = UI_view2d_region_to_view_x(®ion->v2d, event->mval[0]); - /* respect preview range restrictions (if only allowed to move around within that range) */ - if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) { - CLAMP(frame, PSFRA, PEFRA); - } + /* respect preview range restrictions (if only allowed to move around within that range) */ + if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) { + CLAMP(frame, PSFRA, PEFRA); + } - return frame; + return frame; } static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event) { - ScrArea *sa = CTX_wm_area(C); - bScreen *screen = CTX_wm_screen(C); - if (sa && sa->spacetype == SPACE_SEQ) { - SpaceSeq *sseq = sa->spacedata.first; - if (ED_space_sequencer_check_show_strip(sseq)) { - ED_sequencer_special_preview_set(C, event->mval); - } - } - if (screen) - screen->scrubbing = true; + ScrArea *sa = CTX_wm_area(C); + bScreen *screen = CTX_wm_screen(C); + if (sa && sa->spacetype == SPACE_SEQ) { + SpaceSeq *sseq = sa->spacedata.first; + if (ED_space_sequencer_check_show_strip(sseq)) { + ED_sequencer_special_preview_set(C, event->mval); + } + } + if (screen) + screen->scrubbing = true; } static void change_frame_seq_preview_end(bContext *C) { - bScreen *screen = CTX_wm_screen(C); - bool notify = false; - - if (screen->scrubbing) { - screen->scrubbing = false; - notify = true; - } - - if (ED_sequencer_special_preview_get() != NULL) { - ED_sequencer_special_preview_clear(); - notify = true; - } - - if (notify) { - Scene *scene = CTX_data_scene(C); - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); - } + bScreen *screen = CTX_wm_screen(C); + bool notify = false; + + if (screen->scrubbing) { + screen->scrubbing = false; + notify = true; + } + + if (ED_sequencer_special_preview_get() != NULL) { + ED_sequencer_special_preview_clear(); + notify = true; + } + + if (notify) { + Scene *scene = CTX_data_scene(C); + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); + } } /* Modal Operator init */ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - /* Change to frame that mouse is over before adding modal handler, - * as user could click on a single frame (jump to frame) as well as - * click-dragging over a range (modal scrubbing). - */ - RNA_float_set(op->ptr, "frame", frame_from_event(C, event)); + /* Change to frame that mouse is over before adding modal handler, + * as user could click on a single frame (jump to frame) as well as + * click-dragging over a range (modal scrubbing). + */ + RNA_float_set(op->ptr, "frame", frame_from_event(C, event)); - change_frame_seq_preview_begin(C, event); + change_frame_seq_preview_begin(C, event); - change_frame_apply(C, op); + change_frame_apply(C, op); - /* add temp handler */ - WM_event_add_modal_handler(C, op); + /* add temp handler */ + WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } static void change_frame_cancel(bContext *C, wmOperator *UNUSED(op)) { - change_frame_seq_preview_end(C); + change_frame_seq_preview_end(C); } /* Modal event handling of frame changing */ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event) { - int ret = OPERATOR_RUNNING_MODAL; - /* execute the events */ - switch (event->type) { - case ESCKEY: - ret = OPERATOR_FINISHED; - break; - - case MOUSEMOVE: - RNA_float_set(op->ptr, "frame", frame_from_event(C, event)); - change_frame_apply(C, op); - break; - - case LEFTMOUSE: - case RIGHTMOUSE: - case MIDDLEMOUSE: - /* We check for either mouse-button to end, to work with all user keymaps. */ - if (event->val == KM_RELEASE) - ret = OPERATOR_FINISHED; - break; - - case LEFTCTRLKEY: - case RIGHTCTRLKEY: - if (event->val == KM_RELEASE) { - RNA_boolean_set(op->ptr, "snap", false); - } - else if (event->val == KM_PRESS) { - RNA_boolean_set(op->ptr, "snap", true); - } - break; - } - - if (ret != OPERATOR_RUNNING_MODAL) { - change_frame_seq_preview_end(C); - } - - return ret; + int ret = OPERATOR_RUNNING_MODAL; + /* execute the events */ + switch (event->type) { + case ESCKEY: + ret = OPERATOR_FINISHED; + break; + + case MOUSEMOVE: + RNA_float_set(op->ptr, "frame", frame_from_event(C, event)); + change_frame_apply(C, op); + break; + + case LEFTMOUSE: + case RIGHTMOUSE: + case MIDDLEMOUSE: + /* We check for either mouse-button to end, to work with all user keymaps. */ + if (event->val == KM_RELEASE) + ret = OPERATOR_FINISHED; + break; + + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + if (event->val == KM_RELEASE) { + RNA_boolean_set(op->ptr, "snap", false); + } + else if (event->val == KM_PRESS) { + RNA_boolean_set(op->ptr, "snap", true); + } + break; + } + + if (ret != OPERATOR_RUNNING_MODAL) { + change_frame_seq_preview_end(C); + } + + return ret; } static void ANIM_OT_change_frame(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Change Frame"; - ot->idname = "ANIM_OT_change_frame"; - ot->description = "Interactively change the current frame number"; - - /* api callbacks */ - ot->exec = change_frame_exec; - ot->invoke = change_frame_invoke; - ot->cancel = change_frame_cancel; - ot->modal = change_frame_modal; - ot->poll = change_frame_poll; - - /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED; - ot->undo_group = "Frame Change"; - - /* rna */ - ot->prop = RNA_def_float(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); - prop = RNA_def_boolean(ot->srna, "snap", false, "Snap", ""); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Change Frame"; + ot->idname = "ANIM_OT_change_frame"; + ot->description = "Interactively change the current frame number"; + + /* api callbacks */ + ot->exec = change_frame_exec; + ot->invoke = change_frame_invoke; + ot->cancel = change_frame_cancel; + ot->modal = change_frame_modal; + ot->poll = change_frame_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED; + ot->undo_group = "Frame Change"; + + /* rna */ + ot->prop = RNA_def_float( + ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); + prop = RNA_def_boolean(ot->srna, "snap", false, "Snap", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } - /* ****************** Start/End Frame Operators *******************************/ static bool anim_set_end_frames_poll(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - - /* XXX temp? prevent changes during render */ - if (G.is_rendering) return false; - - /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION, - * this shouldn't show up in 3D editor (or others without 2D timeline view) via search - */ - if (sa) { - if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { - return true; - } - } - - CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active"); - return false; + ScrArea *sa = CTX_wm_area(C); + + /* XXX temp? prevent changes during render */ + if (G.is_rendering) + return false; + + /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION, + * this shouldn't show up in 3D editor (or others without 2D timeline view) via search + */ + if (sa) { + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { + return true; + } + } + + CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active"); + return false; } static int anim_set_sfra_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - int frame; + Scene *scene = CTX_data_scene(C); + int frame; - if (scene == NULL) - return OPERATOR_CANCELLED; + if (scene == NULL) + return OPERATOR_CANCELLED; - frame = CFRA; + frame = CFRA; - /* if Preview Range is defined, set the 'start' frame for that */ - if (PRVRANGEON) - scene->r.psfra = frame; - else - scene->r.sfra = frame; + /* if Preview Range is defined, set the 'start' frame for that */ + if (PRVRANGEON) + scene->r.psfra = frame; + else + scene->r.sfra = frame; - if (PEFRA < frame) { - if (PRVRANGEON) - scene->r.pefra = frame; - else - scene->r.efra = frame; - } + if (PEFRA < frame) { + if (PRVRANGEON) + scene->r.pefra = frame; + else + scene->r.efra = frame; + } - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_start_frame_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Start Frame"; - ot->idname = "ANIM_OT_start_frame_set"; - ot->description = "Set the current frame as the preview or scene start frame"; + /* identifiers */ + ot->name = "Set Start Frame"; + ot->idname = "ANIM_OT_start_frame_set"; + ot->description = "Set the current frame as the preview or scene start frame"; - /* api callbacks */ - ot->exec = anim_set_sfra_exec; - ot->poll = anim_set_end_frames_poll; + /* api callbacks */ + ot->exec = anim_set_sfra_exec; + ot->poll = anim_set_end_frames_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - static int anim_set_efra_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - int frame; + Scene *scene = CTX_data_scene(C); + int frame; - if (scene == NULL) - return OPERATOR_CANCELLED; + if (scene == NULL) + return OPERATOR_CANCELLED; - frame = CFRA; + frame = CFRA; - /* if Preview Range is defined, set the 'end' frame for that */ - if (PRVRANGEON) - scene->r.pefra = frame; - else - scene->r.efra = frame; + /* if Preview Range is defined, set the 'end' frame for that */ + if (PRVRANGEON) + scene->r.pefra = frame; + else + scene->r.efra = frame; - if (PSFRA > frame) { - if (PRVRANGEON) - scene->r.psfra = frame; - else - scene->r.sfra = frame; - } + if (PSFRA > frame) { + if (PRVRANGEON) + scene->r.psfra = frame; + else + scene->r.sfra = frame; + } - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_end_frame_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set End Frame"; - ot->idname = "ANIM_OT_end_frame_set"; - ot->description = "Set the current frame as the preview or scene end frame"; + /* identifiers */ + ot->name = "Set End Frame"; + ot->idname = "ANIM_OT_end_frame_set"; + ot->description = "Set the current frame as the preview or scene end frame"; - /* api callbacks */ - ot->exec = anim_set_efra_exec; - ot->poll = anim_set_end_frames_poll; + /* api callbacks */ + ot->exec = anim_set_efra_exec; + ot->poll = anim_set_end_frames_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ****************** set preview range operator ****************************/ static int previewrange_define_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - float sfra, efra; - rcti rect; - - /* get min/max values from box select rect (already in region coordinates, not screen) */ - WM_operator_properties_border_to_rcti(op, &rect); - - /* convert min/max values to frames (i.e. region to 'tot' rect) */ - sfra = UI_view2d_region_to_view_x(&ar->v2d, rect.xmin); - efra = UI_view2d_region_to_view_x(&ar->v2d, rect.xmax); - - /* set start/end frames for preview-range - * - must clamp within allowable limits - * - end must not be before start (though this won't occur most of the time) - */ - FRAMENUMBER_MIN_CLAMP(sfra); - FRAMENUMBER_MIN_CLAMP(efra); - if (efra < sfra) efra = sfra; - - scene->r.flag |= SCER_PRV_RANGE; - scene->r.psfra = round_fl_to_int(sfra); - scene->r.pefra = round_fl_to_int(efra); - - /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ARegion *ar = CTX_wm_region(C); + float sfra, efra; + rcti rect; + + /* get min/max values from box select rect (already in region coordinates, not screen) */ + WM_operator_properties_border_to_rcti(op, &rect); + + /* convert min/max values to frames (i.e. region to 'tot' rect) */ + sfra = UI_view2d_region_to_view_x(&ar->v2d, rect.xmin); + efra = UI_view2d_region_to_view_x(&ar->v2d, rect.xmax); + + /* set start/end frames for preview-range + * - must clamp within allowable limits + * - end must not be before start (though this won't occur most of the time) + */ + FRAMENUMBER_MIN_CLAMP(sfra); + FRAMENUMBER_MIN_CLAMP(efra); + if (efra < sfra) + efra = sfra; + + scene->r.flag |= SCER_PRV_RANGE; + scene->r.psfra = round_fl_to_int(sfra); + scene->r.pefra = round_fl_to_int(efra); + + /* send notifiers */ + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); + + return OPERATOR_FINISHED; } static void ANIM_OT_previewrange_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Preview Range"; - ot->idname = "ANIM_OT_previewrange_set"; - ot->description = "Interactively define frame range used for playback"; - - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = previewrange_define_exec; - ot->modal = WM_gesture_box_modal; - ot->cancel = WM_gesture_box_cancel; - - ot->poll = ED_operator_animview_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* rna */ - /* used to define frame range. - * - * note: border Y values are not used, - * but are needed by box_select gesture operator stuff */ - WM_operator_properties_border(ot); + /* identifiers */ + ot->name = "Set Preview Range"; + ot->idname = "ANIM_OT_previewrange_set"; + ot->description = "Interactively define frame range used for playback"; + + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = previewrange_define_exec; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; + + ot->poll = ED_operator_animview_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* rna */ + /* used to define frame range. + * + * note: border Y values are not used, + * but are needed by box_select gesture operator stuff */ + WM_operator_properties_border(ot); } /* ****************** clear preview range operator ****************************/ static int previewrange_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - ScrArea *curarea = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + ScrArea *curarea = CTX_wm_area(C); - /* sanity checks */ - if (ELEM(NULL, scene, curarea)) - return OPERATOR_CANCELLED; + /* sanity checks */ + if (ELEM(NULL, scene, curarea)) + return OPERATOR_CANCELLED; - /* simply clear values */ - scene->r.flag &= ~SCER_PRV_RANGE; - scene->r.psfra = 0; - scene->r.pefra = 0; + /* simply clear values */ + scene->r.flag &= ~SCER_PRV_RANGE; + scene->r.psfra = 0; + scene->r.pefra = 0; - ED_area_tag_redraw(curarea); + ED_area_tag_redraw(curarea); - /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); + /* send notifiers */ + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void ANIM_OT_previewrange_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Preview Range"; - ot->idname = "ANIM_OT_previewrange_clear"; - ot->description = "Clear Preview Range"; + /* identifiers */ + ot->name = "Clear Preview Range"; + ot->idname = "ANIM_OT_previewrange_clear"; + ot->description = "Clear Preview Range"; - /* api callbacks */ - ot->exec = previewrange_clear_exec; + /* api callbacks */ + ot->exec = previewrange_clear_exec; - ot->poll = ED_operator_animview_active; + ot->poll = ED_operator_animview_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************** registration **********************************/ void ED_operatortypes_anim(void) { - /* Animation Editors only -------------------------- */ - WM_operatortype_append(ANIM_OT_change_frame); - - WM_operatortype_append(ANIM_OT_start_frame_set); - WM_operatortype_append(ANIM_OT_end_frame_set); - - WM_operatortype_append(ANIM_OT_previewrange_set); - WM_operatortype_append(ANIM_OT_previewrange_clear); - - /* Entire UI --------------------------------------- */ - WM_operatortype_append(ANIM_OT_keyframe_insert); - WM_operatortype_append(ANIM_OT_keyframe_delete); - WM_operatortype_append(ANIM_OT_keyframe_insert_menu); - WM_operatortype_append(ANIM_OT_keyframe_delete_v3d); - WM_operatortype_append(ANIM_OT_keyframe_clear_v3d); - WM_operatortype_append(ANIM_OT_keyframe_insert_button); - WM_operatortype_append(ANIM_OT_keyframe_delete_button); - WM_operatortype_append(ANIM_OT_keyframe_clear_button); - WM_operatortype_append(ANIM_OT_keyframe_insert_by_name); - WM_operatortype_append(ANIM_OT_keyframe_delete_by_name); - - - WM_operatortype_append(ANIM_OT_driver_button_add); - WM_operatortype_append(ANIM_OT_driver_button_remove); - WM_operatortype_append(ANIM_OT_driver_button_edit); - WM_operatortype_append(ANIM_OT_copy_driver_button); - WM_operatortype_append(ANIM_OT_paste_driver_button); - - - WM_operatortype_append(ANIM_OT_keyingset_button_add); - WM_operatortype_append(ANIM_OT_keyingset_button_remove); - - WM_operatortype_append(ANIM_OT_keying_set_add); - WM_operatortype_append(ANIM_OT_keying_set_remove); - WM_operatortype_append(ANIM_OT_keying_set_path_add); - WM_operatortype_append(ANIM_OT_keying_set_path_remove); - - WM_operatortype_append(ANIM_OT_keying_set_active_set); + /* Animation Editors only -------------------------- */ + WM_operatortype_append(ANIM_OT_change_frame); + + WM_operatortype_append(ANIM_OT_start_frame_set); + WM_operatortype_append(ANIM_OT_end_frame_set); + + WM_operatortype_append(ANIM_OT_previewrange_set); + WM_operatortype_append(ANIM_OT_previewrange_clear); + + /* Entire UI --------------------------------------- */ + WM_operatortype_append(ANIM_OT_keyframe_insert); + WM_operatortype_append(ANIM_OT_keyframe_delete); + WM_operatortype_append(ANIM_OT_keyframe_insert_menu); + WM_operatortype_append(ANIM_OT_keyframe_delete_v3d); + WM_operatortype_append(ANIM_OT_keyframe_clear_v3d); + WM_operatortype_append(ANIM_OT_keyframe_insert_button); + WM_operatortype_append(ANIM_OT_keyframe_delete_button); + WM_operatortype_append(ANIM_OT_keyframe_clear_button); + WM_operatortype_append(ANIM_OT_keyframe_insert_by_name); + WM_operatortype_append(ANIM_OT_keyframe_delete_by_name); + + WM_operatortype_append(ANIM_OT_driver_button_add); + WM_operatortype_append(ANIM_OT_driver_button_remove); + WM_operatortype_append(ANIM_OT_driver_button_edit); + WM_operatortype_append(ANIM_OT_copy_driver_button); + WM_operatortype_append(ANIM_OT_paste_driver_button); + + WM_operatortype_append(ANIM_OT_keyingset_button_add); + WM_operatortype_append(ANIM_OT_keyingset_button_remove); + + WM_operatortype_append(ANIM_OT_keying_set_add); + WM_operatortype_append(ANIM_OT_keying_set_remove); + WM_operatortype_append(ANIM_OT_keying_set_path_add); + WM_operatortype_append(ANIM_OT_keying_set_path_remove); + + WM_operatortype_append(ANIM_OT_keying_set_active_set); } void ED_keymap_anim(wmKeyConfig *keyconf) { - WM_keymap_ensure(keyconf, "Animation", 0, 0); + WM_keymap_ensure(keyconf, "Animation", 0, 0); } diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index d726c25816b..d6564be9574 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include @@ -70,212 +69,216 @@ */ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add) { - AnimData *adt; - FCurve *fcu; - - /* sanity checks */ - if (ELEM(NULL, id, rna_path)) - return NULL; - - /* init animdata if none available yet */ - adt = BKE_animdata_from_id(id); - if ((adt == NULL) && (add)) - adt = BKE_animdata_add_id(id); - if (adt == NULL) { - /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ - return NULL; - } - - /* try to find f-curve matching for this setting - * - add if not found and allowed to add one - * TODO: add auto-grouping support? how this works will need to be resolved - */ - fcu = list_find_fcurve(&adt->drivers, rna_path, array_index); - - if ((fcu == NULL) && (add)) { - /* use default settings to make a F-Curve */ - fcu = MEM_callocN(sizeof(FCurve), "FCurve"); - - fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; - - /* store path - make copy, and store that */ - fcu->rna_path = BLI_strdup(rna_path); - fcu->array_index = array_index; - - /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */ - if (add > 0) { - BezTriple *bezt; - size_t i; - - /* add some new driver data */ - fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); - - /* F-Modifier or Keyframes? */ - // FIXME: replace these magic numbers with defines - if (add == 2) { - /* Python API Backwards compatibility hack: - * Create FModifier so that old scripts won't break - * for now before 2.7 series -- (September 4, 2013) - */ - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); - } - else { - /* add 2 keyframes so that user has something to work with - * - These are configured to 0,0 and 1,1 to give a 1-1 mapping - * which can be easily tweaked from there. - */ - insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); - insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); - - /* configure this curve to extrapolate */ - for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) { - bezt->h1 = bezt->h2 = HD_VECT; - } - - fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; - calchandles_fcurve(fcu); - } - } - - /* just add F-Curve to end of driver list */ - BLI_addtail(&adt->drivers, fcu); - } - - /* return the F-Curve */ - return fcu; + AnimData *adt; + FCurve *fcu; + + /* sanity checks */ + if (ELEM(NULL, id, rna_path)) + return NULL; + + /* init animdata if none available yet */ + adt = BKE_animdata_from_id(id); + if ((adt == NULL) && (add)) + adt = BKE_animdata_add_id(id); + if (adt == NULL) { + /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ + return NULL; + } + + /* try to find f-curve matching for this setting + * - add if not found and allowed to add one + * TODO: add auto-grouping support? how this works will need to be resolved + */ + fcu = list_find_fcurve(&adt->drivers, rna_path, array_index); + + if ((fcu == NULL) && (add)) { + /* use default settings to make a F-Curve */ + fcu = MEM_callocN(sizeof(FCurve), "FCurve"); + + fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); + fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + + /* store path - make copy, and store that */ + fcu->rna_path = BLI_strdup(rna_path); + fcu->array_index = array_index; + + /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */ + if (add > 0) { + BezTriple *bezt; + size_t i; + + /* add some new driver data */ + fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); + + /* F-Modifier or Keyframes? */ + // FIXME: replace these magic numbers with defines + if (add == 2) { + /* Python API Backwards compatibility hack: + * Create FModifier so that old scripts won't break + * for now before 2.7 series -- (September 4, 2013) + */ + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu); + } + else { + /* add 2 keyframes so that user has something to work with + * - These are configured to 0,0 and 1,1 to give a 1-1 mapping + * which can be easily tweaked from there. + */ + insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); + insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST); + + /* configure this curve to extrapolate */ + for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) { + bezt->h1 = bezt->h2 = HD_VECT; + } + + fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; + calchandles_fcurve(fcu); + } + } + + /* just add F-Curve to end of driver list */ + BLI_addtail(&adt->drivers, fcu); + } + + /* return the F-Curve */ + return fcu; } /* ************************************************** */ /* Driver Management API */ /* Helper for ANIM_add_driver_with_target - Adds the actual driver */ -static int add_driver_with_target( - ReportList *UNUSED(reports), - ID *dst_id, const char dst_path[], int dst_index, - ID *src_id, const char src_path[], int src_index, - PointerRNA *dst_ptr, PropertyRNA *dst_prop, - PointerRNA *src_ptr, PropertyRNA *src_prop, - short flag, int driver_type) +static int add_driver_with_target(ReportList *UNUSED(reports), + ID *dst_id, + const char dst_path[], + int dst_index, + ID *src_id, + const char src_path[], + int src_index, + PointerRNA *dst_ptr, + PropertyRNA *dst_prop, + PointerRNA *src_ptr, + PropertyRNA *src_prop, + short flag, + int driver_type) { - FCurve *fcu; - short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; - const char *prop_name = RNA_property_identifier(src_prop); - - /* Create F-Curve with Driver */ - fcu = verify_driver_fcurve(dst_id, dst_path, dst_index, add_mode); - - if (fcu && fcu->driver) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - - /* Set the type of the driver */ - driver->type = driver_type; - - /* Set driver expression, so that the driver works out of the box - * - * The following checks define a bit of "autodetection magic" we use - * to ensure that the drivers will behave as expected out of the box - * when faced with properties with different units. - */ - /* XXX: if we have N-1 mapping, should we include all those in the expression? */ - if ((RNA_property_unit(dst_prop) == PROP_UNIT_ROTATION) && - (RNA_property_unit(src_prop) != PROP_UNIT_ROTATION)) - { - /* Rotation Destination: normal -> radians, so convert src to radians - * (However, if both input and output is a rotation, don't apply such corrections) - */ - BLI_strncpy(driver->expression, "radians(var)", sizeof(driver->expression)); - } - else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) && - (RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) - { - /* Rotation Source: radians -> normal, so convert src to degrees - * (However, if both input and output is a rotation, don't apply such corrections) - */ - BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression)); - } - else { - /* Just a normal property without any unit problems */ - BLI_strncpy(driver->expression, "var", sizeof(driver->expression)); - } - - /* Create a driver variable for the target - * - For transform properties, we want to automatically use "transform channel" instead - * (The only issue is with quat rotations vs euler channels...) - * - To avoid problems with transform properties depending on the final transform that they - * control (thus creating pseudo-cycles - see T48734), we don't use transform channels - * when both the source and destinations are in same places. - */ - dvar = driver_add_new_variable(driver); - - if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) && - (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) && - (src_ptr->data != dst_ptr->data)) - { - /* Transform Channel */ - DriverTarget *dtar; - - driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN); - dtar = &dvar->targets[0]; - - /* Bone or Object target? */ - dtar->id = src_id; - dtar->idtype = GS(src_id->name); - - if (src_ptr->type == &RNA_PoseBone) { - RNA_string_get(src_ptr, "name", dtar->pchan_name); - } - - /* Transform channel depends on type */ - if (STREQ(prop_name, "location")) { - if (src_index == 2) - dtar->transChan = DTAR_TRANSCHAN_LOCZ; - else if (src_index == 1) - dtar->transChan = DTAR_TRANSCHAN_LOCY; - else - dtar->transChan = DTAR_TRANSCHAN_LOCX; - } - else if (STREQ(prop_name, "scale")) { - if (src_index == 2) - dtar->transChan = DTAR_TRANSCHAN_SCALEZ; - else if (src_index == 1) - dtar->transChan = DTAR_TRANSCHAN_SCALEY; - else - dtar->transChan = DTAR_TRANSCHAN_SCALEX; - } - else { - /* XXX: With quaternions and axis-angle, this mapping might not be correct... - * But since those have 4 elements instead, there's not much we can do - */ - if (src_index == 2) - dtar->transChan = DTAR_TRANSCHAN_ROTZ; - else if (src_index == 1) - dtar->transChan = DTAR_TRANSCHAN_ROTY; - else - dtar->transChan = DTAR_TRANSCHAN_ROTX; - } - } - else { - /* Single RNA Property */ - DriverTarget *dtar = &dvar->targets[0]; - - /* ID is as-is */ - dtar->id = src_id; - dtar->idtype = GS(src_id->name); - - /* Need to make a copy of the path (or build one with array index built in) */ - if (RNA_property_array_check(src_prop)) { - dtar->rna_path = BLI_sprintfN("%s[%d]", src_path, src_index); - } - else { - dtar->rna_path = BLI_strdup(src_path); - } - } - } - - /* set the done status */ - return (fcu != NULL); + FCurve *fcu; + short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; + const char *prop_name = RNA_property_identifier(src_prop); + + /* Create F-Curve with Driver */ + fcu = verify_driver_fcurve(dst_id, dst_path, dst_index, add_mode); + + if (fcu && fcu->driver) { + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + + /* Set the type of the driver */ + driver->type = driver_type; + + /* Set driver expression, so that the driver works out of the box + * + * The following checks define a bit of "autodetection magic" we use + * to ensure that the drivers will behave as expected out of the box + * when faced with properties with different units. + */ + /* XXX: if we have N-1 mapping, should we include all those in the expression? */ + if ((RNA_property_unit(dst_prop) == PROP_UNIT_ROTATION) && + (RNA_property_unit(src_prop) != PROP_UNIT_ROTATION)) { + /* Rotation Destination: normal -> radians, so convert src to radians + * (However, if both input and output is a rotation, don't apply such corrections) + */ + BLI_strncpy(driver->expression, "radians(var)", sizeof(driver->expression)); + } + else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) && + (RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) { + /* Rotation Source: radians -> normal, so convert src to degrees + * (However, if both input and output is a rotation, don't apply such corrections) + */ + BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression)); + } + else { + /* Just a normal property without any unit problems */ + BLI_strncpy(driver->expression, "var", sizeof(driver->expression)); + } + + /* Create a driver variable for the target + * - For transform properties, we want to automatically use "transform channel" instead + * (The only issue is with quat rotations vs euler channels...) + * - To avoid problems with transform properties depending on the final transform that they + * control (thus creating pseudo-cycles - see T48734), we don't use transform channels + * when both the source and destinations are in same places. + */ + dvar = driver_add_new_variable(driver); + + if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) && + (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || + STRPREFIX(prop_name, "rotation_")) && + (src_ptr->data != dst_ptr->data)) { + /* Transform Channel */ + DriverTarget *dtar; + + driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN); + dtar = &dvar->targets[0]; + + /* Bone or Object target? */ + dtar->id = src_id; + dtar->idtype = GS(src_id->name); + + if (src_ptr->type == &RNA_PoseBone) { + RNA_string_get(src_ptr, "name", dtar->pchan_name); + } + + /* Transform channel depends on type */ + if (STREQ(prop_name, "location")) { + if (src_index == 2) + dtar->transChan = DTAR_TRANSCHAN_LOCZ; + else if (src_index == 1) + dtar->transChan = DTAR_TRANSCHAN_LOCY; + else + dtar->transChan = DTAR_TRANSCHAN_LOCX; + } + else if (STREQ(prop_name, "scale")) { + if (src_index == 2) + dtar->transChan = DTAR_TRANSCHAN_SCALEZ; + else if (src_index == 1) + dtar->transChan = DTAR_TRANSCHAN_SCALEY; + else + dtar->transChan = DTAR_TRANSCHAN_SCALEX; + } + else { + /* XXX: With quaternions and axis-angle, this mapping might not be correct... + * But since those have 4 elements instead, there's not much we can do + */ + if (src_index == 2) + dtar->transChan = DTAR_TRANSCHAN_ROTZ; + else if (src_index == 1) + dtar->transChan = DTAR_TRANSCHAN_ROTY; + else + dtar->transChan = DTAR_TRANSCHAN_ROTX; + } + } + else { + /* Single RNA Property */ + DriverTarget *dtar = &dvar->targets[0]; + + /* ID is as-is */ + dtar->id = src_id; + dtar->idtype = GS(src_id->name); + + /* Need to make a copy of the path (or build one with array index built in) */ + if (RNA_property_array_check(src_prop)) { + dtar->rna_path = BLI_sprintfN("%s[%d]", src_path, src_index); + } + else { + dtar->rna_path = BLI_strdup(src_path); + } + } + } + + /* set the done status */ + return (fcu != NULL); } /* Main Driver Management API calls: @@ -289,75 +292,118 @@ static int add_driver_with_target( * - driver_type: eDriver_Types * - mapping_type: eCreateDriver_MappingTypes */ -int ANIM_add_driver_with_target( - ReportList *reports, - ID *dst_id, const char dst_path[], int dst_index, - ID *src_id, const char src_path[], int src_index, - short flag, int driver_type, short mapping_type) +int ANIM_add_driver_with_target(ReportList *reports, + ID *dst_id, + const char dst_path[], + int dst_index, + ID *src_id, + const char src_path[], + int src_index, + short flag, + int driver_type, + short mapping_type) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - - PointerRNA id_ptr2, ptr2; - PropertyRNA *prop2; - int done_tot = 0; - - /* validate pointers first - exit if failure */ - RNA_id_pointer_create(dst_id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, dst_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)", - dst_id->name, dst_path); - return 0; - } - - RNA_id_pointer_create(src_id, &id_ptr2); - if ((RNA_path_resolve_property(&id_ptr2, src_path, &ptr2, &prop2) == false) || - (mapping_type == CREATEDRIVER_MAPPING_NONE)) - { - /* No target - So, fall back to default method for adding a "simple" driver normally */ - return ANIM_add_driver(reports, dst_id, dst_path, dst_index, flag | CREATEDRIVER_WITH_DEFAULT_DVAR, driver_type); - } - - /* handle curve-property mappings based on mapping_type */ - switch (mapping_type) { - case CREATEDRIVER_MAPPING_N_N: /* N-N - Try to match as much as possible, - * then use the first one */ - { - /* Use the shorter of the two (to avoid out of bounds access) */ - int dst_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1; - int src_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr2, prop2) : 1; - - int len = MIN2(dst_len, src_len); - int i; - - for (i = 0; i < len; i++) { - done_tot += add_driver_with_target(reports, dst_id, dst_path, i, src_id, src_path, i, &ptr, prop, &ptr2, prop2, flag, driver_type); - } - break; - } - - case CREATEDRIVER_MAPPING_1_N: /* 1-N - Specified target index for all */ - default: - { - int len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1; - int i; - - for (i = 0; i < len; i++) { - done_tot += add_driver_with_target(reports, dst_id, dst_path, i, src_id, src_path, src_index, &ptr, prop, &ptr2, prop2, flag, driver_type); - } - break; - } - - case CREATEDRIVER_MAPPING_1_1: /* 1-1 - Use the specified index (unless -1) */ - { - done_tot = add_driver_with_target(reports, dst_id, dst_path, dst_index, src_id, src_path, src_index, &ptr, prop, &ptr2, prop2, flag, driver_type); - break; - } - } - - /* done */ - return done_tot; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + + PointerRNA id_ptr2, ptr2; + PropertyRNA *prop2; + int done_tot = 0; + + /* validate pointers first - exit if failure */ + RNA_id_pointer_create(dst_id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, dst_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)", + dst_id->name, + dst_path); + return 0; + } + + RNA_id_pointer_create(src_id, &id_ptr2); + if ((RNA_path_resolve_property(&id_ptr2, src_path, &ptr2, &prop2) == false) || + (mapping_type == CREATEDRIVER_MAPPING_NONE)) { + /* No target - So, fall back to default method for adding a "simple" driver normally */ + return ANIM_add_driver( + reports, dst_id, dst_path, dst_index, flag | CREATEDRIVER_WITH_DEFAULT_DVAR, driver_type); + } + + /* handle curve-property mappings based on mapping_type */ + switch (mapping_type) { + case CREATEDRIVER_MAPPING_N_N: /* N-N - Try to match as much as possible, + * then use the first one */ + { + /* Use the shorter of the two (to avoid out of bounds access) */ + int dst_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1; + int src_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr2, prop2) : 1; + + int len = MIN2(dst_len, src_len); + int i; + + for (i = 0; i < len; i++) { + done_tot += add_driver_with_target(reports, + dst_id, + dst_path, + i, + src_id, + src_path, + i, + &ptr, + prop, + &ptr2, + prop2, + flag, + driver_type); + } + break; + } + + case CREATEDRIVER_MAPPING_1_N: /* 1-N - Specified target index for all */ + default: { + int len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1; + int i; + + for (i = 0; i < len; i++) { + done_tot += add_driver_with_target(reports, + dst_id, + dst_path, + i, + src_id, + src_path, + src_index, + &ptr, + prop, + &ptr2, + prop2, + flag, + driver_type); + } + break; + } + + case CREATEDRIVER_MAPPING_1_1: /* 1-1 - Use the specified index (unless -1) */ + { + done_tot = add_driver_with_target(reports, + dst_id, + dst_path, + dst_index, + src_id, + src_path, + src_index, + &ptr, + prop, + &ptr2, + prop2, + flag, + driver_type); + break; + } + } + + /* done */ + return done_tot; } /* --------------------------------- */ @@ -365,155 +411,169 @@ int ANIM_add_driver_with_target( /* Main Driver Management API calls: * Add a new driver for the specified property on the given ID block */ -int ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type) +int ANIM_add_driver( + ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - FCurve *fcu; - int array_index_max; - int done_tot = 0; - - /* validate pointer first - exit if failure */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - - /* key entire array convenience method */ - if (array_index == -1) { - array_index_max = RNA_property_array_length(&ptr, prop); - array_index = 0; - } - else - array_index_max = array_index; - - /* maximum index should be greater than the start index */ - if (array_index == array_index_max) - array_index_max += 1; - - /* will only loop once unless the array index was -1 */ - for (; array_index < array_index_max; array_index++) { - short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; - - /* create F-Curve with Driver */ - fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode); - - if (fcu && fcu->driver) { - ChannelDriver *driver = fcu->driver; - - /* set the type of the driver */ - driver->type = type; - - /* Creating drivers for buttons will create the driver(s) with type - * "scripted expression" so that their values won't be lost immediately, - * so here we copy those values over to the driver's expression - * - * If the "default dvar" option (for easier UI setup of drivers) is provided, - * include "var" in the expressions too, so that the user doesn't have to edit - * it to get something to happen. It should be fine to just add it to the default - * value, so that we get both in the expression, even if it's a bit more confusing - * that way... - */ - if (type == DRIVER_TYPE_PYTHON) { - PropertyType proptype = RNA_property_type(prop); - int array = RNA_property_array_length(&ptr, prop); - const char *dvar_prefix = (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) ? "var + " : ""; - char *expression = driver->expression; - int val, maxlen = sizeof(driver->expression); - float fval; - - if (proptype == PROP_BOOLEAN) { - if (!array) val = RNA_property_boolean_get(&ptr, prop); - else val = RNA_property_boolean_get_index(&ptr, prop, array_index); - - BLI_snprintf(expression, maxlen, "%s%s", dvar_prefix, (val) ? "True" : "False"); - } - else if (proptype == PROP_INT) { - if (!array) val = RNA_property_int_get(&ptr, prop); - else val = RNA_property_int_get_index(&ptr, prop, array_index); - - BLI_snprintf(expression, maxlen, "%s%d", dvar_prefix, val); - } - else if (proptype == PROP_FLOAT) { - if (!array) fval = RNA_property_float_get(&ptr, prop); - else fval = RNA_property_float_get_index(&ptr, prop, array_index); - - BLI_snprintf(expression, maxlen, "%s%.3f", dvar_prefix, fval); - BLI_str_rstrip_float_zero(expression, '\0'); - } - else if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) { - BLI_strncpy(expression, "var", maxlen); - } - } - - /* for easier setup of drivers from UI, a driver variable should be - * added if flag is set (UI calls only) - */ - if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) { - /* assume that users will mostly want this to be of type "Transform Channel" too, - * since this allows the easiest setting up of common rig components - */ - DriverVar *dvar = driver_add_new_variable(driver); - driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN); - } - } - - /* set the done status */ - done_tot += (fcu != NULL); - } - - /* done */ - return done_tot; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + FCurve *fcu; + int array_index_max; + int done_tot = 0; + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)", + id->name, + rna_path); + return 0; + } + + /* key entire array convenience method */ + if (array_index == -1) { + array_index_max = RNA_property_array_length(&ptr, prop); + array_index = 0; + } + else + array_index_max = array_index; + + /* maximum index should be greater than the start index */ + if (array_index == array_index_max) + array_index_max += 1; + + /* will only loop once unless the array index was -1 */ + for (; array_index < array_index_max; array_index++) { + short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; + + /* create F-Curve with Driver */ + fcu = verify_driver_fcurve(id, rna_path, array_index, add_mode); + + if (fcu && fcu->driver) { + ChannelDriver *driver = fcu->driver; + + /* set the type of the driver */ + driver->type = type; + + /* Creating drivers for buttons will create the driver(s) with type + * "scripted expression" so that their values won't be lost immediately, + * so here we copy those values over to the driver's expression + * + * If the "default dvar" option (for easier UI setup of drivers) is provided, + * include "var" in the expressions too, so that the user doesn't have to edit + * it to get something to happen. It should be fine to just add it to the default + * value, so that we get both in the expression, even if it's a bit more confusing + * that way... + */ + if (type == DRIVER_TYPE_PYTHON) { + PropertyType proptype = RNA_property_type(prop); + int array = RNA_property_array_length(&ptr, prop); + const char *dvar_prefix = (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) ? "var + " : ""; + char *expression = driver->expression; + int val, maxlen = sizeof(driver->expression); + float fval; + + if (proptype == PROP_BOOLEAN) { + if (!array) + val = RNA_property_boolean_get(&ptr, prop); + else + val = RNA_property_boolean_get_index(&ptr, prop, array_index); + + BLI_snprintf(expression, maxlen, "%s%s", dvar_prefix, (val) ? "True" : "False"); + } + else if (proptype == PROP_INT) { + if (!array) + val = RNA_property_int_get(&ptr, prop); + else + val = RNA_property_int_get_index(&ptr, prop, array_index); + + BLI_snprintf(expression, maxlen, "%s%d", dvar_prefix, val); + } + else if (proptype == PROP_FLOAT) { + if (!array) + fval = RNA_property_float_get(&ptr, prop); + else + fval = RNA_property_float_get_index(&ptr, prop, array_index); + + BLI_snprintf(expression, maxlen, "%s%.3f", dvar_prefix, fval); + BLI_str_rstrip_float_zero(expression, '\0'); + } + else if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) { + BLI_strncpy(expression, "var", maxlen); + } + } + + /* for easier setup of drivers from UI, a driver variable should be + * added if flag is set (UI calls only) + */ + if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) { + /* assume that users will mostly want this to be of type "Transform Channel" too, + * since this allows the easiest setting up of common rig components + */ + DriverVar *dvar = driver_add_new_variable(driver); + driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN); + } + } + + /* set the done status */ + done_tot += (fcu != NULL); + } + + /* done */ + return done_tot; } /* Main Driver Management API calls: * Remove the driver for the specified property on the given ID block (if available) */ -bool ANIM_remove_driver(ReportList *UNUSED(reports), ID *id, const char rna_path[], int array_index, short UNUSED(flag)) +bool ANIM_remove_driver(ReportList *UNUSED(reports), + ID *id, + const char rna_path[], + int array_index, + short UNUSED(flag)) { - AnimData *adt; - FCurve *fcu; - bool success = false; - - /* we don't check the validity of the path here yet, but it should be ok... */ - adt = BKE_animdata_from_id(id); - - if (adt) { - if (array_index == -1) { - /* step through all drivers, removing all of those with the same base path */ - FCurve *fcu_iter = adt->drivers.first; - - while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) { - /* store the next fcurve for looping */ - fcu_iter = fcu->next; - - /* remove F-Curve from driver stack, then free it */ - BLI_remlink(&adt->drivers, fcu); - free_fcurve(fcu); - - /* done successfully */ - success = true; - } - } - else { - /* find the matching driver and remove it only - * Note: here is one of the places where we don't want new F-Curve + Driver added! - * so 'add' var must be 0 - */ - fcu = verify_driver_fcurve(id, rna_path, array_index, 0); - if (fcu) { - BLI_remlink(&adt->drivers, fcu); - free_fcurve(fcu); - - success = true; - } - } - } - - return success; + AnimData *adt; + FCurve *fcu; + bool success = false; + + /* we don't check the validity of the path here yet, but it should be ok... */ + adt = BKE_animdata_from_id(id); + + if (adt) { + if (array_index == -1) { + /* step through all drivers, removing all of those with the same base path */ + FCurve *fcu_iter = adt->drivers.first; + + while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) { + /* store the next fcurve for looping */ + fcu_iter = fcu->next; + + /* remove F-Curve from driver stack, then free it */ + BLI_remlink(&adt->drivers, fcu); + free_fcurve(fcu); + + /* done successfully */ + success = true; + } + } + else { + /* find the matching driver and remove it only + * Note: here is one of the places where we don't want new F-Curve + Driver added! + * so 'add' var must be 0 + */ + fcu = verify_driver_fcurve(id, rna_path, array_index, 0); + if (fcu) { + BLI_remlink(&adt->drivers, fcu); + free_fcurve(fcu); + + success = true; + } + } + } + + return success; } /* ************************************************** */ @@ -525,16 +585,16 @@ static FCurve *channeldriver_copypaste_buf = NULL; /* This function frees any MEM_calloc'ed copy/paste buffer data */ void ANIM_drivers_copybuf_free(void) { - /* free the buffer F-Curve if it exists, as if it were just another F-Curve */ - if (channeldriver_copypaste_buf) - free_fcurve(channeldriver_copypaste_buf); - channeldriver_copypaste_buf = NULL; + /* free the buffer F-Curve if it exists, as if it were just another F-Curve */ + if (channeldriver_copypaste_buf) + free_fcurve(channeldriver_copypaste_buf); + channeldriver_copypaste_buf = NULL; } /* Checks if there is a driver in the copy/paste buffer */ bool ANIM_driver_can_paste(void) { - return (channeldriver_copypaste_buf != NULL); + return (channeldriver_copypaste_buf != NULL); } /* ------------------- */ @@ -542,98 +602,106 @@ bool ANIM_driver_can_paste(void) /* Main Driver Management API calls: * Make a copy of the driver for the specified property on the given ID block */ -bool ANIM_copy_driver(ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag)) +bool ANIM_copy_driver( + ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag)) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - FCurve *fcu; - - /* validate pointer first - exit if failure */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not find driver to copy, as RNA path is invalid for the given ID (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - - /* try to get F-Curve with Driver */ - fcu = verify_driver_fcurve(id, rna_path, array_index, 0); - - /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */ - ANIM_drivers_copybuf_free(); - - /* copy this to the copy/paste buf if it exists */ - if (fcu && fcu->driver) { - /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily - * so that we don't end up wasting memory storing the path which won't get used ever... - */ - char *tmp_path = fcu->rna_path; - fcu->rna_path = NULL; - - /* make a copy of the F-Curve with */ - channeldriver_copypaste_buf = copy_fcurve(fcu); - - /* restore the path */ - fcu->rna_path = tmp_path; - - /* copied... */ - return 1; - } - - /* done */ - return 0; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + FCurve *fcu; + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf(reports, + RPT_ERROR, + "Could not find driver to copy, as RNA path is invalid for the given ID (ID = %s, " + "path = %s)", + id->name, + rna_path); + return 0; + } + + /* try to get F-Curve with Driver */ + fcu = verify_driver_fcurve(id, rna_path, array_index, 0); + + /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */ + ANIM_drivers_copybuf_free(); + + /* copy this to the copy/paste buf if it exists */ + if (fcu && fcu->driver) { + /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily + * so that we don't end up wasting memory storing the path which won't get used ever... + */ + char *tmp_path = fcu->rna_path; + fcu->rna_path = NULL; + + /* make a copy of the F-Curve with */ + channeldriver_copypaste_buf = copy_fcurve(fcu); + + /* restore the path */ + fcu->rna_path = tmp_path; + + /* copied... */ + return 1; + } + + /* done */ + return 0; } /* Main Driver Management API calls: * Add a new driver for the specified property on the given ID block or replace an existing one * with the driver + driver-curve data from the buffer */ -bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag)) +bool ANIM_paste_driver( + ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag)) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - FCurve *fcu; - - /* validate pointer first - exit if failure */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not paste driver, as RNA path is invalid for the given ID (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - - /* if the buffer is empty, cannot paste... */ - if (channeldriver_copypaste_buf == NULL) { - BKE_report(reports, RPT_ERROR, "Paste driver: no driver to paste"); - return 0; - } - - /* create Driver F-Curve, but without data which will be copied across... */ - fcu = verify_driver_fcurve(id, rna_path, array_index, -1); - - if (fcu) { - /* copy across the curve data from the buffer curve - * NOTE: this step needs care to not miss new settings - */ - /* keyframes/samples */ - fcu->bezt = MEM_dupallocN(channeldriver_copypaste_buf->bezt); - fcu->fpt = MEM_dupallocN(channeldriver_copypaste_buf->fpt); - fcu->totvert = channeldriver_copypaste_buf->totvert; - - /* modifiers */ - copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers); - - /* extrapolation mode */ - fcu->extend = channeldriver_copypaste_buf->extend; - - /* the 'juicy' stuff - the driver */ - fcu->driver = fcurve_copy_driver(channeldriver_copypaste_buf->driver); - } - - /* done */ - return (fcu != NULL); + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + FCurve *fcu; + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not paste driver, as RNA path is invalid for the given ID (ID = %s, path = %s)", + id->name, + rna_path); + return 0; + } + + /* if the buffer is empty, cannot paste... */ + if (channeldriver_copypaste_buf == NULL) { + BKE_report(reports, RPT_ERROR, "Paste driver: no driver to paste"); + return 0; + } + + /* create Driver F-Curve, but without data which will be copied across... */ + fcu = verify_driver_fcurve(id, rna_path, array_index, -1); + + if (fcu) { + /* copy across the curve data from the buffer curve + * NOTE: this step needs care to not miss new settings + */ + /* keyframes/samples */ + fcu->bezt = MEM_dupallocN(channeldriver_copypaste_buf->bezt); + fcu->fpt = MEM_dupallocN(channeldriver_copypaste_buf->fpt); + fcu->totvert = channeldriver_copypaste_buf->totvert; + + /* modifiers */ + copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers); + + /* extrapolation mode */ + fcu->extend = channeldriver_copypaste_buf->extend; + + /* the 'juicy' stuff - the driver */ + fcu->driver = fcurve_copy_driver(channeldriver_copypaste_buf->driver); + } + + /* done */ + return (fcu != NULL); } /* ************************************************** */ @@ -645,24 +713,24 @@ static ListBase driver_vars_copybuf = {NULL, NULL}; /* This function frees any MEM_calloc'ed copy/paste buffer data */ void ANIM_driver_vars_copybuf_free(void) { - /* Free the driver variables kept in the buffer */ - if (driver_vars_copybuf.first) { - DriverVar *dvar, *dvarn; - - /* Free variables (and any data they use) */ - for (dvar = driver_vars_copybuf.first; dvar; dvar = dvarn) { - dvarn = dvar->next; - driver_free_variable(&driver_vars_copybuf, dvar); - } - } - - BLI_listbase_clear(&driver_vars_copybuf); + /* Free the driver variables kept in the buffer */ + if (driver_vars_copybuf.first) { + DriverVar *dvar, *dvarn; + + /* Free variables (and any data they use) */ + for (dvar = driver_vars_copybuf.first; dvar; dvar = dvarn) { + dvarn = dvar->next; + driver_free_variable(&driver_vars_copybuf, dvar); + } + } + + BLI_listbase_clear(&driver_vars_copybuf); } /* Checks if there are driver variables in the copy/paste buffer */ bool ANIM_driver_vars_can_paste(void) { - return (BLI_listbase_is_empty(&driver_vars_copybuf) == false); + return (BLI_listbase_is_empty(&driver_vars_copybuf) == false); } /* -------------------------------------------------- */ @@ -670,78 +738,78 @@ bool ANIM_driver_vars_can_paste(void) /* Copy the given driver's variables to the buffer */ bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu) { - /* sanity checks */ - if (ELEM(NULL, fcu, fcu->driver)) { - BKE_report(reports, RPT_ERROR, "No driver to copy variables from"); - return false; - } + /* sanity checks */ + if (ELEM(NULL, fcu, fcu->driver)) { + BKE_report(reports, RPT_ERROR, "No driver to copy variables from"); + return false; + } - if (BLI_listbase_is_empty(&fcu->driver->variables)) { - BKE_report(reports, RPT_ERROR, "Driver has no variables to copy"); - return false; - } + if (BLI_listbase_is_empty(&fcu->driver->variables)) { + BKE_report(reports, RPT_ERROR, "Driver has no variables to copy"); + return false; + } - /* clear buffer */ - ANIM_driver_vars_copybuf_free(); + /* clear buffer */ + ANIM_driver_vars_copybuf_free(); - /* copy over the variables */ - driver_variables_copy(&driver_vars_copybuf, &fcu->driver->variables); + /* copy over the variables */ + driver_variables_copy(&driver_vars_copybuf, &fcu->driver->variables); - return (BLI_listbase_is_empty(&driver_vars_copybuf) == false); + return (BLI_listbase_is_empty(&driver_vars_copybuf) == false); } /* Paste the variables in the buffer to the given FCurve */ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace) { - ChannelDriver *driver = (fcu) ? fcu->driver : NULL; - ListBase tmp_list = {NULL, NULL}; - - /* sanity checks */ - if (BLI_listbase_is_empty(&driver_vars_copybuf)) { - BKE_report(reports, RPT_ERROR, "No driver variables in clipboard to paste"); - return false; - } - - if (ELEM(NULL, fcu, fcu->driver)) { - BKE_report(reports, RPT_ERROR, "Cannot paste driver variables without a driver"); - return false; - } - - /* 1) Make a new copy of the variables in the buffer - these will get pasted later... */ - driver_variables_copy(&tmp_list, &driver_vars_copybuf); - - /* 2) Prepare destination array */ - if (replace) { - DriverVar *dvar, *dvarn; - - /* Free all existing vars first - We aren't retaining anything */ - for (dvar = driver->variables.first; dvar; dvar = dvarn) { - dvarn = dvar->next; - driver_free_variable_ex(driver, dvar); - } - - BLI_listbase_clear(&driver->variables); - } - - /* 3) Add new vars */ - if (driver->variables.last) { - DriverVar *last = driver->variables.last; - DriverVar *first = tmp_list.first; - - last->next = first; - first->prev = last; - - driver->variables.last = tmp_list.last; - } - else { - driver->variables.first = tmp_list.first; - driver->variables.last = tmp_list.last; - } - - /* since driver variables are cached, the expression needs re-compiling too */ - BKE_driver_invalidate_expression(driver, false, true); - - return true; + ChannelDriver *driver = (fcu) ? fcu->driver : NULL; + ListBase tmp_list = {NULL, NULL}; + + /* sanity checks */ + if (BLI_listbase_is_empty(&driver_vars_copybuf)) { + BKE_report(reports, RPT_ERROR, "No driver variables in clipboard to paste"); + return false; + } + + if (ELEM(NULL, fcu, fcu->driver)) { + BKE_report(reports, RPT_ERROR, "Cannot paste driver variables without a driver"); + return false; + } + + /* 1) Make a new copy of the variables in the buffer - these will get pasted later... */ + driver_variables_copy(&tmp_list, &driver_vars_copybuf); + + /* 2) Prepare destination array */ + if (replace) { + DriverVar *dvar, *dvarn; + + /* Free all existing vars first - We aren't retaining anything */ + for (dvar = driver->variables.first; dvar; dvar = dvarn) { + dvarn = dvar->next; + driver_free_variable_ex(driver, dvar); + } + + BLI_listbase_clear(&driver->variables); + } + + /* 3) Add new vars */ + if (driver->variables.last) { + DriverVar *last = driver->variables.last; + DriverVar *first = tmp_list.first; + + last->next = first; + first->prev = last; + + driver->variables.last = tmp_list.last; + } + else { + driver->variables.first = tmp_list.first; + driver->variables.last = tmp_list.last; + } + + /* since driver variables are cached, the expression needs re-compiling too */ + BKE_driver_invalidate_expression(driver, false, true); + + return true; } /* ************************************************** */ @@ -753,397 +821,421 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace) /* NOTE: Used by ANIM_OT_driver_button_add and UI_OT_eyedropper_driver */ // XXX: These names need reviewing EnumPropertyItem prop_driver_create_mapping_types[] = { - {CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", 0, "All from Target", - "Drive all components of this property using the target picked"}, - {CREATEDRIVER_MAPPING_1_1, "DIRECT", 0, "Single from Target", - "Drive this component of this property using the target picked"}, - - {CREATEDRIVER_MAPPING_N_N, "MATCH", ICON_COLOR, "Match Indices", - "Create drivers for each pair of corresponding elements"}, - - {CREATEDRIVER_MAPPING_NONE_ALL, "NONE_ALL", ICON_HAND, "Manually Create Later", - "Create drivers for all properties without assigning any targets yet"}, - {CREATEDRIVER_MAPPING_NONE, "NONE_SINGLE", 0, "Manually Create Later (Single)", - "Create driver for this property only and without assigning any targets yet"}, - {0, NULL, 0, NULL, NULL}, + {CREATEDRIVER_MAPPING_1_N, + "SINGLE_MANY", + 0, + "All from Target", + "Drive all components of this property using the target picked"}, + {CREATEDRIVER_MAPPING_1_1, + "DIRECT", + 0, + "Single from Target", + "Drive this component of this property using the target picked"}, + + {CREATEDRIVER_MAPPING_N_N, + "MATCH", + ICON_COLOR, + "Match Indices", + "Create drivers for each pair of corresponding elements"}, + + {CREATEDRIVER_MAPPING_NONE_ALL, + "NONE_ALL", + ICON_HAND, + "Manually Create Later", + "Create drivers for all properties without assigning any targets yet"}, + {CREATEDRIVER_MAPPING_NONE, + "NONE_SINGLE", + 0, + "Manually Create Later (Single)", + "Create driver for this property only and without assigning any targets yet"}, + {0, NULL, 0, NULL, NULL}, }; /* Filtering callback for driver mapping types enum */ -static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, PointerRNA *UNUSED(owner_ptr), PropertyRNA *UNUSED(owner_prop), bool *r_free) +static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, + PointerRNA *UNUSED(owner_ptr), + PropertyRNA *UNUSED(owner_prop), + bool *r_free) { - EnumPropertyItem *input = prop_driver_create_mapping_types; - EnumPropertyItem *item = NULL; + EnumPropertyItem *input = prop_driver_create_mapping_types; + EnumPropertyItem *item = NULL; - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - int index; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + int index; - int totitem = 0; + int totitem = 0; - if (!C) /* needed for docs */ - return prop_driver_create_mapping_types; + if (!C) /* needed for docs */ + return prop_driver_create_mapping_types; - UI_context_active_but_prop_get(C, &ptr, &prop, &index); + UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - const bool is_array = RNA_property_array_check(prop); + if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { + const bool is_array = RNA_property_array_check(prop); - while (input->identifier) { - if (ELEM(input->value, CREATEDRIVER_MAPPING_1_1, CREATEDRIVER_MAPPING_NONE) || (is_array)) { - RNA_enum_item_add(&item, &totitem, input); - } - input++; - } - } - else { - /* We need at least this one! */ - RNA_enum_items_add_value(&item, &totitem, input, CREATEDRIVER_MAPPING_NONE); - } + while (input->identifier) { + if (ELEM(input->value, CREATEDRIVER_MAPPING_1_1, CREATEDRIVER_MAPPING_NONE) || (is_array)) { + RNA_enum_item_add(&item, &totitem, input); + } + input++; + } + } + else { + /* We need at least this one! */ + RNA_enum_items_add_value(&item, &totitem, input, CREATEDRIVER_MAPPING_NONE); + } - RNA_enum_item_end(&item, &totitem); + RNA_enum_item_end(&item, &totitem); - *r_free = true; - return item; + *r_free = true; + return item; } - /* Add Driver (With Menu) Button Operator ------------------------ */ static bool add_driver_button_poll(bContext *C) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - int index; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + int index; - /* this operator can only run if there's a property button active, and it can be animated */ - UI_context_active_but_prop_get(C, &ptr, &prop, &index); - return (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)); + /* this operator can only run if there's a property button active, and it can be animated */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + return (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)); } /* Wrapper for creating a driver without knowing what the targets will be yet (i.e. "manual/add later") */ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_type) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - int index; - int success = 0; - - UI_context_active_but_prop_get(C, &ptr, &prop, &index); - - if (mapping_type == CREATEDRIVER_MAPPING_NONE_ALL) - index = -1; - - if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); - short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; - - if (path) { - success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON); - MEM_freeN(path); - } - } - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX - - return OPERATOR_FINISHED; - } - else { - return OPERATOR_CANCELLED; - } + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + int index; + int success = 0; + + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + if (mapping_type == CREATEDRIVER_MAPPING_NONE_ALL) + index = -1; + + if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { + char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; + + if (path) { + success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON); + MEM_freeN(path); + } + } + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } } static int add_driver_button_menu_exec(bContext *C, wmOperator *op) { - short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); - if (ELEM(mapping_type, CREATEDRIVER_MAPPING_NONE, CREATEDRIVER_MAPPING_NONE_ALL)) { - /* Just create driver with no targets */ - return add_driver_button_none(C, op, mapping_type); - } - else { - /* Create Driver using Eyedropper */ - wmOperatorType *ot = WM_operatortype_find("UI_OT_eyedropper_driver", true); - - /* XXX: We assume that it's fine to use the same set of properties, since they're actually the same... */ - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, op->ptr); - - return OPERATOR_FINISHED; - } + short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); + if (ELEM(mapping_type, CREATEDRIVER_MAPPING_NONE, CREATEDRIVER_MAPPING_NONE_ALL)) { + /* Just create driver with no targets */ + return add_driver_button_none(C, op, mapping_type); + } + else { + /* Create Driver using Eyedropper */ + wmOperatorType *ot = WM_operatortype_find("UI_OT_eyedropper_driver", true); + + /* XXX: We assume that it's fine to use the same set of properties, since they're actually the same... */ + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, op->ptr); + + return OPERATOR_FINISHED; + } } /* Show menu or create drivers */ static int add_driver_button_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - PropertyRNA *prop; - - if ((prop = RNA_struct_find_property(op->ptr, "mapping_type")) && RNA_property_is_set(op->ptr, prop)) { - /* Mapping Type is Set - Directly go into creating drivers */ - return add_driver_button_menu_exec(C, op); - } - else { - /* Show menu */ - // TODO: This should get filtered by the enum filter - /* important to execute in the region we're currently in */ - return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT); - } + PropertyRNA *prop; + + if ((prop = RNA_struct_find_property(op->ptr, "mapping_type")) && + RNA_property_is_set(op->ptr, prop)) { + /* Mapping Type is Set - Directly go into creating drivers */ + return add_driver_button_menu_exec(C, op); + } + else { + /* Show menu */ + // TODO: This should get filtered by the enum filter + /* important to execute in the region we're currently in */ + return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT); + } } static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Driver Menu"; - ot->idname = "ANIM_OT_driver_button_add_menu"; - ot->description = "Add driver(s) for the property(s) represented by the highlighted button"; - - /* callbacks */ - ot->invoke = add_driver_button_menu_invoke; - ot->exec = add_driver_button_menu_exec; - ot->poll = add_driver_button_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0, - "Mapping Type", "Method used to match target and driven properties"); - RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf); + /* identifiers */ + ot->name = "Add Driver Menu"; + ot->idname = "ANIM_OT_driver_button_add_menu"; + ot->description = "Add driver(s) for the property(s) represented by the highlighted button"; + + /* callbacks */ + ot->invoke = add_driver_button_menu_invoke; + ot->exec = add_driver_button_menu_exec; + ot->poll = add_driver_button_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, + "mapping_type", + prop_driver_create_mapping_types, + 0, + "Mapping Type", + "Method used to match target and driven properties"); + RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf); } /* Add Driver Button Operator ------------------------ */ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - int index; - - /* try to find driver using property retrieved from UI */ - UI_context_active_but_prop_get(C, &ptr, &prop, &index); - - if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - /* 1) Create a new "empty" driver for this property */ - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); - short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; - short success = 0; - - if (path) { - success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON); - MEM_freeN(path); - } - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - DEG_id_tag_update(ptr.id.data, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); - } - - /* 2) Show editing panel for setting up this driver */ - /* TODO: Use a different one from the editing popever, so we can have the single/all toggle? */ - UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports); - } - - return OPERATOR_INTERFACE; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + int index; + + /* try to find driver using property retrieved from UI */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { + /* 1) Create a new "empty" driver for this property */ + char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; + short success = 0; + + if (path) { + success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON); + MEM_freeN(path); + } + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + DEG_id_tag_update(ptr.id.data, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); + } + + /* 2) Show editing panel for setting up this driver */ + /* TODO: Use a different one from the editing popever, so we can have the single/all toggle? */ + UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports); + } + + return OPERATOR_INTERFACE; } void ANIM_OT_driver_button_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Driver"; - ot->idname = "ANIM_OT_driver_button_add"; - ot->description = "Add driver for the property under the cursor"; - - /* callbacks */ - /* NOTE: No exec, as we need all these to use the current context info */ - ot->invoke = add_driver_button_invoke; - ot->poll = add_driver_button_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* identifiers */ + ot->name = "Add Driver"; + ot->idname = "ANIM_OT_driver_button_add"; + ot->description = "Add driver for the property under the cursor"; + + /* callbacks */ + /* NOTE: No exec, as we need all these to use the current context info */ + ot->invoke = add_driver_button_invoke; + ot->poll = add_driver_button_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; } /* Remove Driver Button Operator ------------------------ */ static int remove_driver_button_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - short success = 0; - int index; - const bool all = RNA_boolean_get(op->ptr, "all"); + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + short success = 0; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); - /* try to find driver using property retrieved from UI */ - UI_context_active_but_prop_get(C, &ptr, &prop, &index); + /* try to find driver using property retrieved from UI */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (all) - index = -1; + if (all) + index = -1; - if (ptr.id.data && ptr.data && prop) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + if (ptr.id.data && ptr.data && prop) { + char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); - if (path) { - success = ANIM_remove_driver(op->reports, ptr.id.data, path, index, 0); + if (path) { + success = ANIM_remove_driver(op->reports, ptr.id.data, path, index, 0); - MEM_freeN(path); - } - } + MEM_freeN(path); + } + } - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - DEG_relations_tag_update(CTX_data_main(C)); - WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX - } + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + DEG_relations_tag_update(CTX_data_main(C)); + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX + } - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_driver_button_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Driver"; - ot->idname = "ANIM_OT_driver_button_remove"; - ot->description = "Remove the driver(s) for the property(s) connected represented by the highlighted button"; + /* identifiers */ + ot->name = "Remove Driver"; + ot->idname = "ANIM_OT_driver_button_remove"; + ot->description = + "Remove the driver(s) for the property(s) connected represented by the highlighted button"; - /* callbacks */ - ot->exec = remove_driver_button_exec; - //op->poll = ??? // TODO: need to have some driver to be able to do this... + /* callbacks */ + ot->exec = remove_driver_button_exec; + //op->poll = ??? // TODO: need to have some driver to be able to do this... - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array"); } /* Edit Driver Button Operator ------------------------ */ static int edit_driver_button_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - int index; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + int index; - /* try to find driver using property retrieved from UI */ - UI_context_active_but_prop_get(C, &ptr, &prop, &index); + /* try to find driver using property retrieved from UI */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (ptr.id.data && ptr.data && prop) { - UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports); - } + if (ptr.id.data && ptr.data && prop) { + UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports); + } - return OPERATOR_INTERFACE; + return OPERATOR_INTERFACE; } void ANIM_OT_driver_button_edit(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Edit Driver"; - ot->idname = "ANIM_OT_driver_button_edit"; - ot->description = "Edit the drivers for the property connected represented by the highlighted button"; - - /* callbacks */ - ot->exec = edit_driver_button_exec; - //op->poll = ??? // TODO: need to have some driver to be able to do this... - - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* identifiers */ + ot->name = "Edit Driver"; + ot->idname = "ANIM_OT_driver_button_edit"; + ot->description = + "Edit the drivers for the property connected represented by the highlighted button"; + + /* callbacks */ + ot->exec = edit_driver_button_exec; + //op->poll = ??? // TODO: need to have some driver to be able to do this... + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; } /* Copy Driver Button Operator ------------------------ */ static int copy_driver_button_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - short success = 0; - int index; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + short success = 0; + int index; - /* try to create driver using property retrieved from UI */ - UI_context_active_but_prop_get(C, &ptr, &prop, &index); + /* try to create driver using property retrieved from UI */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { + char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); - if (path) { - /* only copy the driver for the button that this was involved for */ - success = ANIM_copy_driver(op->reports, ptr.id.data, path, index, 0); + if (path) { + /* only copy the driver for the button that this was involved for */ + success = ANIM_copy_driver(op->reports, ptr.id.data, path, index, 0); - UI_context_update_anim_flag(C); + UI_context_update_anim_flag(C); - MEM_freeN(path); - } - } + MEM_freeN(path); + } + } - /* since we're just copying, we don't really need to do anything else...*/ - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + /* since we're just copying, we don't really need to do anything else...*/ + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_copy_driver_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Copy Driver"; - ot->idname = "ANIM_OT_copy_driver_button"; - ot->description = "Copy the driver for the highlighted button"; + /* identifiers */ + ot->name = "Copy Driver"; + ot->idname = "ANIM_OT_copy_driver_button"; + ot->description = "Copy the driver for the highlighted button"; - /* callbacks */ - ot->exec = copy_driver_button_exec; - //op->poll = ??? // TODO: need to have some driver to be able to do this... + /* callbacks */ + ot->exec = copy_driver_button_exec; + //op->poll = ??? // TODO: need to have some driver to be able to do this... - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; } /* Paste Driver Button Operator ------------------------ */ static int paste_driver_button_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - short success = 0; - int index; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + short success = 0; + int index; - /* try to create driver using property retrieved from UI */ - UI_context_active_but_prop_get(C, &ptr, &prop, &index); + /* try to create driver using property retrieved from UI */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); - if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { + char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); - if (path) { - /* only copy the driver for the button that this was involved for */ - success = ANIM_paste_driver(op->reports, ptr.id.data, path, index, 0); + if (path) { + /* only copy the driver for the button that this was involved for */ + success = ANIM_paste_driver(op->reports, ptr.id.data, path, index, 0); - UI_context_update_anim_flag(C); + UI_context_update_anim_flag(C); - DEG_relations_tag_update(CTX_data_main(C)); - DEG_id_tag_update(ptr.id.data, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + DEG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(ptr.id.data, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL); // XXX - MEM_freeN(path); - } - } + MEM_freeN(path); + } + } - /* since we're just copying, we don't really need to do anything else...*/ - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + /* since we're just copying, we don't really need to do anything else...*/ + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_paste_driver_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Paste Driver"; - ot->idname = "ANIM_OT_paste_driver_button"; - ot->description = "Paste the driver in the copy/paste buffer for the highlighted button"; + /* identifiers */ + ot->name = "Paste Driver"; + ot->idname = "ANIM_OT_paste_driver_button"; + ot->description = "Paste the driver in the copy/paste buffer for the highlighted button"; - /* callbacks */ - ot->exec = paste_driver_button_exec; - //op->poll = ??? // TODO: need to have some driver to be able to do this... + /* callbacks */ + ot->exec = paste_driver_button_exec; + //op->poll = ??? // TODO: need to have some driver to be able to do this... - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; } /* ************************************************** */ diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 8edad506a33..919090cdee9 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -21,7 +21,6 @@ * \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, @@ -65,635 +64,939 @@ // XXX! -------------------------------- /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */ -#define UI_FLT_MAX 10000.0f +#define UI_FLT_MAX 10000.0f -#define B_REDR 1 -#define B_FMODIFIER_REDRAW 20 +#define B_REDR 1 +#define B_FMODIFIER_REDRAW 20 /* callback to verify modifier data */ static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg)) { - FModifier *fcm = (FModifier *)fcm_v; - const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + FModifier *fcm = (FModifier *)fcm_v; + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); - /* call the verify callback on the modifier if applicable */ - if (fmi && fmi->verify_data) - fmi->verify_data(fcm); + /* call the verify callback on the modifier if applicable */ + if (fmi && fmi->verify_data) + fmi->verify_data(fcm); } /* callback to remove the given modifier */ typedef struct FModifierDeleteContext { - ID *fcurve_owner_id; - ListBase *modifiers; + ID *fcurve_owner_id; + ListBase *modifiers; } FModifierDeleteContext; static void delete_fmodifier_cb(bContext *C, void *ctx_v, void *fcm_v) { - FModifierDeleteContext *ctx = (FModifierDeleteContext *)ctx_v; - ListBase *modifiers = ctx->modifiers; - FModifier *fcm = (FModifier *)fcm_v; + FModifierDeleteContext *ctx = (FModifierDeleteContext *)ctx_v; + ListBase *modifiers = ctx->modifiers; + FModifier *fcm = (FModifier *)fcm_v; - /* remove the given F-Modifier from the active modifier-stack */ - remove_fmodifier(modifiers, fcm); + /* remove the given F-Modifier from the active modifier-stack */ + remove_fmodifier(modifiers, fcm); - ED_undo_push(C, "Delete F-Curve Modifier"); + 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 - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - DEG_id_tag_update(ctx->fcurve_owner_id, ID_RECALC_ANIMATION); + /* 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 + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + DEG_id_tag_update(ctx->fcurve_owner_id, ID_RECALC_ANIMATION); } /* --------------- */ /* draw settings for generator modifier */ -static void draw_modifier__generator(uiLayout *layout, ID *fcurve_owner_id, FModifier *fcm, short width) +static void draw_modifier__generator(uiLayout *layout, + ID *fcurve_owner_id, + FModifier *fcm, + short width) { - FMod_Generator *data = (FMod_Generator *)fcm->data; - uiLayout /* *col, */ /* UNUSED */ *row; - uiBlock *block; - uiBut *but; - PointerRNA ptr; - short bwidth = width - 1.5 * UI_UNIT_X; /* max button width */ - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr); - - /* basic settings (backdrop + mode selector + some padding) */ - /* col = uiLayoutColumn(layout, true); */ /* UNUSED */ - block = uiLayoutGetBlock(layout); - UI_block_align_begin(block); - but = uiDefButR(block, UI_BTYPE_MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL); - UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); - - uiDefButR(block, UI_BTYPE_TOGGLE, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "use_additive", -1, 0, 0, -1, -1, NULL); - UI_block_align_end(block); - - /* now add settings for individual modes */ - switch (data->mode) { - case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */ - { - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - float *cp = NULL; - char xval[32]; - unsigned int i; - int maxXWidth; - - /* draw polynomial order selector */ - row = uiLayoutRow(layout, false); - block = uiLayoutGetBlock(row); - but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0.5f * UI_UNIT_X, 0, bwidth, UI_UNIT_Y, - &data->poly_order, 1, 100, 0, 0, - TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)")); - UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); - - - /* calculate maximum width of label for "x^n" labels */ - if (data->arraysize > 2) { - BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize); - /* XXX: UI_fontstyle_string_width is not accurate */ - maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X; - } - else { - /* basic size (just "x") */ - maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X; - } - - /* draw controls for each coefficient and a + sign at end of row */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - - cp = data->coefficients; - for (i = 0; (i < data->arraysize) && (cp); i++, cp++) { - /* To align with first line... */ - if (i) - uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - else - uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - /* coefficient */ - uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, bwidth / 2, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX, - 10, 3, TIP_("Coefficient for polynomial")); - - /* 'x' param (and '+' if necessary) */ - if (i == 0) - BLI_strncpy(xval, "", sizeof(xval)); - else if (i == 1) - BLI_strncpy(xval, "x", sizeof(xval)); - else - BLI_snprintf(xval, sizeof(xval), "x^%u", i); - uiDefBut(block, UI_BTYPE_LABEL, 1, xval, 0, 0, maxXWidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, TIP_("Power of x")); - - if ( (i != (data->arraysize - 1)) || ((i == 0) && data->arraysize == 2) ) { - uiDefBut(block, UI_BTYPE_LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - /* next coefficient on a new row */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - } - else { - /* For alignment in UI! */ - uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - } - } - break; - } - - case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */ - { - float *cp = NULL; - unsigned int i; - - /* draw polynomial order selector */ - row = uiLayoutRow(layout, false); - block = uiLayoutGetBlock(row); - but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0, 0, width - 1.5 * UI_UNIT_X, UI_UNIT_Y, - &data->poly_order, 1, 100, 0, 0, - TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)")); - UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); - - - /* draw controls for each pair of coefficients */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - - cp = data->coefficients; - for (i = 0; (i < data->poly_order) && (cp); i++, cp += 2) { - /* To align with first line */ - if (i) - uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - else - uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - /* opening bracket */ - uiDefBut(block, UI_BTYPE_LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - /* coefficients */ - uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX, - 10, 3, TIP_("Coefficient of x")); - - uiDefBut(block, UI_BTYPE_LABEL, 1, "x +", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp + 1, -UI_FLT_MAX, UI_FLT_MAX, - 10, 3, TIP_("Second coefficient")); - - /* closing bracket and multiplication sign */ - if ( (i != (data->poly_order - 1)) || ((i == 0) && data->poly_order == 2) ) { - uiDefBut(block, UI_BTYPE_LABEL, 1, ") \xc3\x97", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - /* set up new row for the next pair of coefficients */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - } - else - uiDefBut(block, UI_BTYPE_LABEL, 1, ") ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - } - break; - } - } + FMod_Generator *data = (FMod_Generator *)fcm->data; + uiLayout /* *col, */ /* UNUSED */ *row; + uiBlock *block; + uiBut *but; + PointerRNA ptr; + short bwidth = width - 1.5 * UI_UNIT_X; /* max button width */ + + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr); + + /* basic settings (backdrop + mode selector + some padding) */ + /* col = uiLayoutColumn(layout, true); */ /* UNUSED */ + block = uiLayoutGetBlock(layout); + UI_block_align_begin(block); + but = uiDefButR(block, + UI_BTYPE_MENU, + B_FMODIFIER_REDRAW, + NULL, + 0, + 0, + bwidth, + UI_UNIT_Y, + &ptr, + "mode", + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); + + uiDefButR(block, + UI_BTYPE_TOGGLE, + B_FMODIFIER_REDRAW, + NULL, + 0, + 0, + bwidth, + UI_UNIT_Y, + &ptr, + "use_additive", + -1, + 0, + 0, + -1, + -1, + NULL); + UI_block_align_end(block); + + /* now add settings for individual modes */ + switch (data->mode) { + case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */ + { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + float *cp = NULL; + char xval[32]; + unsigned int i; + int maxXWidth; + + /* draw polynomial order selector */ + row = uiLayoutRow(layout, false); + block = uiLayoutGetBlock(row); + but = uiDefButI( + block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + IFACE_("Poly Order:"), + 0.5f * UI_UNIT_X, + 0, + bwidth, + UI_UNIT_Y, + &data->poly_order, + 1, + 100, + 0, + 0, + TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)")); + UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); + + /* calculate maximum width of label for "x^n" labels */ + if (data->arraysize > 2) { + BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize); + /* XXX: UI_fontstyle_string_width is not accurate */ + maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X; + } + else { + /* basic size (just "x") */ + maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X; + } + + /* draw controls for each coefficient and a + sign at end of row */ + row = uiLayoutRow(layout, true); + block = uiLayoutGetBlock(row); + + cp = data->coefficients; + for (i = 0; (i < data->arraysize) && (cp); i++, cp++) { + /* To align with first line... */ + if (i) + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + " ", + 0, + 0, + 2 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + else + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + "y =", + 0, + 0, + 2 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + + /* coefficient */ + uiDefButF(block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + "", + 0, + 0, + bwidth / 2, + UI_UNIT_Y, + cp, + -UI_FLT_MAX, + UI_FLT_MAX, + 10, + 3, + TIP_("Coefficient for polynomial")); + + /* 'x' param (and '+' if necessary) */ + if (i == 0) + BLI_strncpy(xval, "", sizeof(xval)); + else if (i == 1) + BLI_strncpy(xval, "x", sizeof(xval)); + else + BLI_snprintf(xval, sizeof(xval), "x^%u", i); + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + xval, + 0, + 0, + maxXWidth, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + TIP_("Power of x")); + + if ((i != (data->arraysize - 1)) || ((i == 0) && data->arraysize == 2)) { + uiDefBut( + block, UI_BTYPE_LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + + /* next coefficient on a new row */ + row = uiLayoutRow(layout, true); + block = uiLayoutGetBlock(row); + } + else { + /* For alignment in UI! */ + uiDefBut( + block, UI_BTYPE_LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + } + } + break; + } + + case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */ + { + float *cp = NULL; + unsigned int i; + + /* draw polynomial order selector */ + row = uiLayoutRow(layout, false); + block = uiLayoutGetBlock(row); + but = uiDefButI( + block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + IFACE_("Poly Order:"), + 0, + 0, + width - 1.5 * UI_UNIT_X, + UI_UNIT_Y, + &data->poly_order, + 1, + 100, + 0, + 0, + TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)")); + UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); + + /* draw controls for each pair of coefficients */ + row = uiLayoutRow(layout, true); + block = uiLayoutGetBlock(row); + + cp = data->coefficients; + for (i = 0; (i < data->poly_order) && (cp); i++, cp += 2) { + /* To align with first line */ + if (i) + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + " ", + 0, + 0, + 2.5 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + else + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + "y =", + 0, + 0, + 2.5 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + /* opening bracket */ + uiDefBut( + block, UI_BTYPE_LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + + /* coefficients */ + uiDefButF(block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + "", + 0, + 0, + 5 * UI_UNIT_X, + UI_UNIT_Y, + cp, + -UI_FLT_MAX, + UI_FLT_MAX, + 10, + 3, + TIP_("Coefficient of x")); + + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + "x +", + 0, + 0, + 2 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + + uiDefButF(block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + "", + 0, + 0, + 5 * UI_UNIT_X, + UI_UNIT_Y, + cp + 1, + -UI_FLT_MAX, + UI_FLT_MAX, + 10, + 3, + TIP_("Second coefficient")); + + /* closing bracket and multiplication sign */ + if ((i != (data->poly_order - 1)) || ((i == 0) && data->poly_order == 2)) { + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + ") \xc3\x97", + 0, + 0, + 2 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + + /* set up new row for the next pair of coefficients */ + row = uiLayoutRow(layout, true); + block = uiLayoutGetBlock(row); + } + else + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + ") ", + 0, + 0, + 2 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + } + break; + } + } } /* --------------- */ /* draw settings for generator modifier */ -static void draw_modifier__fn_generator(uiLayout *layout, ID *fcurve_owner_id, FModifier *fcm, short UNUSED(width)) +static void draw_modifier__fn_generator(uiLayout *layout, + ID *fcurve_owner_id, + FModifier *fcm, + short UNUSED(width)) { - uiLayout *col; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr); - - /* add the settings */ - col = uiLayoutColumn(layout, true); - uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE); - uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); - - col = uiLayoutColumn(layout, false); // no grouping for now - 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); + uiLayout *col; + PointerRNA ptr; + + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifierFunctionGenerator, fcm, &ptr); + + /* add the settings */ + col = uiLayoutColumn(layout, true); + uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE); + uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + + col = uiLayoutColumn(layout, false); // no grouping for now + 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); } /* --------------- */ /* draw settings for cycles modifier */ -static void draw_modifier__cycles(uiLayout *layout, ID *fcurve_owner_id, FModifier *fcm, short UNUSED(width)) +static void draw_modifier__cycles(uiLayout *layout, + ID *fcurve_owner_id, + FModifier *fcm, + short UNUSED(width)) { - uiLayout *split, *col; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierCycles, fcm, &ptr); - - /* split into 2 columns - * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room - */ - split = uiLayoutSplit(layout, 0.5f, false); - - /* before range */ - col = uiLayoutColumn(split, true); - uiItemL(col, IFACE_("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, true); - uiItemL(col, IFACE_("After:"), ICON_NONE); - uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE); - uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE); + uiLayout *split, *col; + PointerRNA ptr; + + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifierCycles, fcm, &ptr); + + /* split into 2 columns + * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room + */ + split = uiLayoutSplit(layout, 0.5f, false); + + /* before range */ + col = uiLayoutColumn(split, true); + uiItemL(col, IFACE_("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, true); + uiItemL(col, IFACE_("After:"), ICON_NONE); + uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE); + uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE); } /* --------------- */ /* draw settings for noise modifier */ -static void draw_modifier__noise(uiLayout *layout, ID *fcurve_owner_id, FModifier *fcm, short UNUSED(width)) +static void draw_modifier__noise(uiLayout *layout, + ID *fcurve_owner_id, + FModifier *fcm, + short UNUSED(width)) { - uiLayout *split, *col; - PointerRNA ptr; + uiLayout *split, *col; + PointerRNA ptr; - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierNoise, fcm, &ptr); + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifierNoise, fcm, &ptr); - /* blending mode */ - uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE); + /* blending mode */ + uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE); - /* split into 2 columns */ - split = uiLayoutSplit(layout, 0.5f, false); + /* split into 2 columns */ + split = uiLayoutSplit(layout, 0.5f, false); - /* col 1 */ - col = uiLayoutColumn(split, false); - uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "offset", 0, NULL, ICON_NONE); + /* col 1 */ + col = uiLayoutColumn(split, false); + uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "offset", 0, NULL, ICON_NONE); - /* col 2 */ - col = uiLayoutColumn(split, false); - uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE); + /* col 2 */ + col = uiLayoutColumn(split, false); + uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE); } /* callback to add new envelope data point */ static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(arg)) { - Scene *scene = CTX_data_scene(C); - FMod_Envelope *env = (FMod_Envelope *)fcm_dv; - FCM_EnvelopeData *fedn; - FCM_EnvelopeData fed; - - /* init template data */ - fed.min = -1.0f; - fed.max = 1.0f; - fed.time = (float)scene->r.cfra; // XXX make this int for ease of use? - fed.f1 = fed.f2 = 0; - - /* check that no data exists for the current frame... */ - if (env->data) { - bool exists; - int i = BKE_fcm_envelope_find_index(env->data, (float)(scene->r.cfra), env->totvert, &exists); - - /* binarysearch_...() will set exists by default to 0, - * so if it is non-zero, that means that the point exists already */ - if (exists) { - return; - } - - /* add new */ - fedn = MEM_callocN((env->totvert + 1) * sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"); - - /* add the points that should occur before the point to be pasted */ - if (i > 0) - memcpy(fedn, env->data, i * sizeof(FCM_EnvelopeData)); - - /* add point to paste at index i */ - *(fedn + i) = fed; - - /* add the points that occur after the point to be pasted */ - if (i < env->totvert) - memcpy(fedn + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData)); - - /* replace (+ free) old with new */ - MEM_freeN(env->data); - env->data = fedn; - - env->totvert++; - } - else { - env->data = MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"); - *(env->data) = fed; - - env->totvert = 1; - } + Scene *scene = CTX_data_scene(C); + FMod_Envelope *env = (FMod_Envelope *)fcm_dv; + FCM_EnvelopeData *fedn; + FCM_EnvelopeData fed; + + /* init template data */ + fed.min = -1.0f; + fed.max = 1.0f; + fed.time = (float)scene->r.cfra; // XXX make this int for ease of use? + fed.f1 = fed.f2 = 0; + + /* check that no data exists for the current frame... */ + if (env->data) { + bool exists; + int i = BKE_fcm_envelope_find_index(env->data, (float)(scene->r.cfra), env->totvert, &exists); + + /* binarysearch_...() will set exists by default to 0, + * so if it is non-zero, that means that the point exists already */ + if (exists) { + return; + } + + /* add new */ + fedn = MEM_callocN((env->totvert + 1) * sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"); + + /* add the points that should occur before the point to be pasted */ + if (i > 0) + memcpy(fedn, env->data, i * sizeof(FCM_EnvelopeData)); + + /* add point to paste at index i */ + *(fedn + i) = fed; + + /* add the points that occur after the point to be pasted */ + if (i < env->totvert) + memcpy(fedn + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData)); + + /* replace (+ free) old with new */ + MEM_freeN(env->data); + env->data = fedn; + + env->totvert++; + } + else { + env->data = MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"); + *(env->data) = fed; + + env->totvert = 1; + } } /* callback to remove envelope data point */ // TODO: should we have a separate file for things like this? static void fmod_envelope_deletepoint_cb(bContext *UNUSED(C), void *fcm_dv, void *ind_v) { - FMod_Envelope *env = (FMod_Envelope *)fcm_dv; - FCM_EnvelopeData *fedn; - int index = POINTER_AS_INT(ind_v); - - /* check that no data exists for the current frame... */ - 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)); - - /* free old array, and set the new */ - MEM_freeN(env->data); - env->data = fedn; - env->totvert--; - } - else { - /* just free array, since the only vert was deleted */ - if (env->data) { - MEM_freeN(env->data); - env->data = NULL; - } - env->totvert = 0; - } + FMod_Envelope *env = (FMod_Envelope *)fcm_dv; + FCM_EnvelopeData *fedn; + int index = POINTER_AS_INT(ind_v); + + /* check that no data exists for the current frame... */ + 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)); + + /* free old array, and set the new */ + MEM_freeN(env->data); + env->data = fedn; + env->totvert--; + } + else { + /* just free array, since the only vert was deleted */ + if (env->data) { + MEM_freeN(env->data); + env->data = NULL; + } + env->totvert = 0; + } } /* draw settings for envelope modifier */ -static void draw_modifier__envelope(uiLayout *layout, ID *fcurve_owner_id, FModifier *fcm, short UNUSED(width)) +static void draw_modifier__envelope(uiLayout *layout, + ID *fcurve_owner_id, + FModifier *fcm, + short UNUSED(width)) { - FMod_Envelope *env = (FMod_Envelope *)fcm->data; - FCM_EnvelopeData *fed; - uiLayout *col, *row; - uiBlock *block; - uiBut *but; - PointerRNA ptr; - int i; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierEnvelope, fcm, &ptr); - - /* general settings */ - col = uiLayoutColumn(layout, true); - uiItemL(col, IFACE_("Envelope:"), ICON_NONE); - uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE); - - row = uiLayoutRow(col, true); - uiItemR(row, &ptr, "default_min", 0, IFACE_("Min"), ICON_NONE); - uiItemR(row, &ptr, "default_max", 0, IFACE_("Max"), ICON_NONE); - - /* control points header */ - /* TODO: move this control-point control stuff to using the new special widgets for lists - * the current way is far too cramped */ - row = uiLayoutRow(layout, false); - block = uiLayoutGetBlock(row); - - uiDefBut(block, UI_BTYPE_LABEL, 1, IFACE_("Control Points:"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - but = uiDefBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, IFACE_("Add Point"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, TIP_("Add a new control-point to the envelope on the current frame")); - UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL); - - /* control points list */ - for (i = 0, fed = env->data; i < env->totvert; i++, fed++) { - /* get a new row to operate on */ - row = uiLayoutRow(layout, true); - block = uiLayoutGetBlock(row); - - UI_block_align_begin(block); - but = uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Fra:"), 0, 0, 4.5 * UI_UNIT_X, UI_UNIT_Y, - &fed->time, -MAXFRAMEF, MAXFRAMEF, 10, 1, TIP_("Frame that envelope point occurs")); - UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); - - uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Min:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, - &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Minimum bound of envelope at this point")); - uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Max:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, - &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Maximum bound of envelope at this point")); - - but = uiDefIconBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 0.9 * UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete envelope control point")); - UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, POINTER_FROM_INT(i)); - UI_block_align_begin(block); - } + FMod_Envelope *env = (FMod_Envelope *)fcm->data; + FCM_EnvelopeData *fed; + uiLayout *col, *row; + uiBlock *block; + uiBut *but; + PointerRNA ptr; + int i; + + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifierEnvelope, fcm, &ptr); + + /* general settings */ + col = uiLayoutColumn(layout, true); + uiItemL(col, IFACE_("Envelope:"), ICON_NONE); + uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE); + + row = uiLayoutRow(col, true); + uiItemR(row, &ptr, "default_min", 0, IFACE_("Min"), ICON_NONE); + uiItemR(row, &ptr, "default_max", 0, IFACE_("Max"), ICON_NONE); + + /* control points header */ + /* TODO: move this control-point control stuff to using the new special widgets for lists + * the current way is far too cramped */ + row = uiLayoutRow(layout, false); + block = uiLayoutGetBlock(row); + + uiDefBut(block, + UI_BTYPE_LABEL, + 1, + IFACE_("Control Points:"), + 0, + 0, + 7.5 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + + but = uiDefBut(block, + UI_BTYPE_BUT, + B_FMODIFIER_REDRAW, + IFACE_("Add Point"), + 0, + 0, + 7.5 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Add a new control-point to the envelope on the current frame")); + UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL); + + /* control points list */ + for (i = 0, fed = env->data; i < env->totvert; i++, fed++) { + /* get a new row to operate on */ + row = uiLayoutRow(layout, true); + block = uiLayoutGetBlock(row); + + UI_block_align_begin(block); + but = uiDefButF(block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + IFACE_("Fra:"), + 0, + 0, + 4.5 * UI_UNIT_X, + UI_UNIT_Y, + &fed->time, + -MAXFRAMEF, + MAXFRAMEF, + 10, + 1, + TIP_("Frame that envelope point occurs")); + UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL); + + uiDefButF(block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + IFACE_("Min:"), + 0, + 0, + 5 * UI_UNIT_X, + UI_UNIT_Y, + &fed->min, + -UI_FLT_MAX, + UI_FLT_MAX, + 10, + 2, + TIP_("Minimum bound of envelope at this point")); + uiDefButF(block, + UI_BTYPE_NUM, + B_FMODIFIER_REDRAW, + IFACE_("Max:"), + 0, + 0, + 5 * UI_UNIT_X, + UI_UNIT_Y, + &fed->max, + -UI_FLT_MAX, + UI_FLT_MAX, + 10, + 2, + TIP_("Maximum bound of envelope at this point")); + + but = uiDefIconBut(block, + UI_BTYPE_BUT, + B_FMODIFIER_REDRAW, + ICON_X, + 0, + 0, + 0.9 * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Delete envelope control point")); + UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, POINTER_FROM_INT(i)); + UI_block_align_begin(block); + } } /* --------------- */ /* draw settings for limits modifier */ -static void draw_modifier__limits(uiLayout *layout, ID *fcurve_owner_id, FModifier *fcm, short UNUSED(width)) +static void draw_modifier__limits(uiLayout *layout, + ID *fcurve_owner_id, + FModifier *fcm, + short UNUSED(width)) { - uiLayout *split, *col /* , *row */ /* UNUSED */; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierLimits, fcm, &ptr); - - /* row 1: minimum */ - { - /* row = uiLayoutRow(layout, false); */ /* UNUSED */ - - /* split into 2 columns */ - split = uiLayoutSplit(layout, 0.5f, false); - - /* x-minimum */ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE); - - /* y-minimum*/ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE); - } - - /* row 2: maximum */ - { - /* row = uiLayoutRow(layout, false); */ /* UNUSED */ - - /* split into 2 columns */ - split = uiLayoutSplit(layout, 0.5f, false); - - /* x-minimum */ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE); - - /* y-minimum*/ - col = uiLayoutColumn(split, true); - uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE); - } + uiLayout *split, *col /* , *row */ /* UNUSED */; + PointerRNA ptr; + + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifierLimits, fcm, &ptr); + + /* row 1: minimum */ + { + /* row = uiLayoutRow(layout, false); */ /* UNUSED */ + + /* split into 2 columns */ + split = uiLayoutSplit(layout, 0.5f, false); + + /* x-minimum */ + col = uiLayoutColumn(split, true); + uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE); + + /* y-minimum*/ + col = uiLayoutColumn(split, true); + uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE); + } + + /* row 2: maximum */ + { + /* row = uiLayoutRow(layout, false); */ /* UNUSED */ + + /* split into 2 columns */ + split = uiLayoutSplit(layout, 0.5f, false); + + /* x-minimum */ + col = uiLayoutColumn(split, true); + uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE); + + /* y-minimum*/ + col = uiLayoutColumn(split, true); + uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE); + } } /* --------------- */ /* draw settings for stepped interpolation modifier */ -static void draw_modifier__stepped(uiLayout *layout, ID *fcurve_owner_id, FModifier *fcm, short UNUSED(width)) +static void draw_modifier__stepped(uiLayout *layout, + ID *fcurve_owner_id, + FModifier *fcm, + short UNUSED(width)) { - uiLayout *col, *sub; - PointerRNA ptr; + uiLayout *col, *sub; + PointerRNA ptr; - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifierStepped, fcm, &ptr); + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifierStepped, fcm, &ptr); - /* block 1: "stepping" settings */ - col = uiLayoutColumn(layout, false); - uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE); + /* block 1: "stepping" settings */ + col = uiLayoutColumn(layout, false); + 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, true); - uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE); + /* block 2: start range settings */ + col = uiLayoutColumn(layout, true); + uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE); - sub = uiLayoutColumn(col, true); - uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_start")); - uiItemR(sub, &ptr, "frame_start", 0, NULL, ICON_NONE); + sub = uiLayoutColumn(col, true); + uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_start")); + uiItemR(sub, &ptr, "frame_start", 0, NULL, ICON_NONE); - /* block 3: end range settings */ - col = uiLayoutColumn(layout, true); - uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE); + /* block 3: end range settings */ + col = uiLayoutColumn(layout, true); + uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE); - sub = uiLayoutColumn(col, true); - uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_end")); - uiItemR(sub, &ptr, "frame_end", 0, NULL, ICON_NONE); + sub = uiLayoutColumn(col, true); + uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_end")); + uiItemR(sub, &ptr, "frame_end", 0, NULL, ICON_NONE); } /* --------------- */ -void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *fcurve_owner_id, - ListBase *modifiers, FModifier *fcm) +void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, + ID *fcurve_owner_id, + ListBase *modifiers, + FModifier *fcm) { - const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); - uiLayout *box, *row, *sub, *col; - uiBlock *block; - uiBut *but; - short width = 314; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(fcurve_owner_id, &RNA_FModifier, fcm, &ptr); - - /* draw header */ - { - /* get layout-row + UI-block for this */ - box = uiLayoutBox(layout); - - row = uiLayoutRow(box, false); - block = uiLayoutGetBlock(row); // err... - - /* left-align -------------------------------------------- */ - sub = uiLayoutRow(row, true); - uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - - /* expand */ - uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - - /* checkbox for 'active' status (for now) */ - uiItemR(sub, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - - /* name */ - if (fmi) - uiItemL(sub, IFACE_(fmi->name), ICON_NONE); - else - uiItemL(sub, IFACE_(""), ICON_NONE); - - /* right-align ------------------------------------------- */ - sub = uiLayoutRow(row, true); - uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); - - - /* 'mute' button */ - uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - - UI_block_emboss_set(block, UI_EMBOSS_NONE); - - /* delete button */ - but = uiDefIconBut(block, UI_BTYPE_BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete F-Curve Modifier")); - FModifierDeleteContext *ctx = MEM_mallocN(sizeof(FModifierDeleteContext), "fmodifier ctx"); - ctx->fcurve_owner_id = fcurve_owner_id; - ctx->modifiers = modifiers; - UI_but_funcN_set(but, delete_fmodifier_cb, ctx, fcm); - - UI_block_emboss_set(block, UI_EMBOSS); - } - - /* when modifier is expanded, draw settings */ - if (fcm->flag & FMODIFIER_FLAG_EXPANDED) { - /* set up the flexible-box layout which acts as the backdrop for the modifier settings */ - box = uiLayoutBox(layout); - - /* draw settings for individual modifiers */ - switch (fcm->type) { - case FMODIFIER_TYPE_GENERATOR: /* Generator */ - draw_modifier__generator(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */ - draw_modifier__fn_generator(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_CYCLES: /* Cycles */ - draw_modifier__cycles(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_ENVELOPE: /* Envelope */ - draw_modifier__envelope(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_LIMITS: /* Limits */ - draw_modifier__limits(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_NOISE: /* Noise */ - draw_modifier__noise(box, fcurve_owner_id, fcm, width); - break; - - case FMODIFIER_TYPE_STEPPED: /* Stepped */ - draw_modifier__stepped(box, fcurve_owner_id, fcm, width); - break; - - 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, true); - - /* top row: use restricted range */ - row = uiLayoutRow(col, true); - uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE); - - if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { - /* second row: settings */ - row = uiLayoutRow(col, true); - - uiItemR(row, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); - uiItemR(row, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); - - /* third row: blending influence */ - row = uiLayoutRow(col, true); - - uiItemR(row, &ptr, "blend_in", 0, IFACE_("In"), ICON_NONE); - uiItemR(row, &ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE); - } - - /* influence -------------------------------------------------------------- */ - col = uiLayoutColumn(box, true); - - /* 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); - } - } - } + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + uiLayout *box, *row, *sub, *col; + uiBlock *block; + uiBut *but; + short width = 314; + PointerRNA ptr; + + /* init the RNA-pointer */ + RNA_pointer_create(fcurve_owner_id, &RNA_FModifier, fcm, &ptr); + + /* draw header */ + { + /* get layout-row + UI-block for this */ + box = uiLayoutBox(layout); + + row = uiLayoutRow(box, false); + block = uiLayoutGetBlock(row); // err... + + /* left-align -------------------------------------------- */ + sub = uiLayoutRow(row, true); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + /* expand */ + uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + + /* checkbox for 'active' status (for now) */ + uiItemR(sub, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + + /* name */ + if (fmi) + uiItemL(sub, IFACE_(fmi->name), ICON_NONE); + else + uiItemL(sub, IFACE_(""), ICON_NONE); + + /* right-align ------------------------------------------- */ + sub = uiLayoutRow(row, true); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); + + /* 'mute' button */ + uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + /* delete button */ + but = uiDefIconBut(block, + UI_BTYPE_BUT, + B_REDR, + ICON_X, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Delete F-Curve Modifier")); + FModifierDeleteContext *ctx = MEM_mallocN(sizeof(FModifierDeleteContext), "fmodifier ctx"); + ctx->fcurve_owner_id = fcurve_owner_id; + ctx->modifiers = modifiers; + UI_but_funcN_set(but, delete_fmodifier_cb, ctx, fcm); + + UI_block_emboss_set(block, UI_EMBOSS); + } + + /* when modifier is expanded, draw settings */ + if (fcm->flag & FMODIFIER_FLAG_EXPANDED) { + /* set up the flexible-box layout which acts as the backdrop for the modifier settings */ + box = uiLayoutBox(layout); + + /* draw settings for individual modifiers */ + switch (fcm->type) { + case FMODIFIER_TYPE_GENERATOR: /* Generator */ + draw_modifier__generator(box, fcurve_owner_id, fcm, width); + break; + + case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */ + draw_modifier__fn_generator(box, fcurve_owner_id, fcm, width); + break; + + case FMODIFIER_TYPE_CYCLES: /* Cycles */ + draw_modifier__cycles(box, fcurve_owner_id, fcm, width); + break; + + case FMODIFIER_TYPE_ENVELOPE: /* Envelope */ + draw_modifier__envelope(box, fcurve_owner_id, fcm, width); + break; + + case FMODIFIER_TYPE_LIMITS: /* Limits */ + draw_modifier__limits(box, fcurve_owner_id, fcm, width); + break; + + case FMODIFIER_TYPE_NOISE: /* Noise */ + draw_modifier__noise(box, fcurve_owner_id, fcm, width); + break; + + case FMODIFIER_TYPE_STEPPED: /* Stepped */ + draw_modifier__stepped(box, fcurve_owner_id, fcm, width); + break; + + 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, true); + + /* top row: use restricted range */ + row = uiLayoutRow(col, true); + uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE); + + if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { + /* second row: settings */ + row = uiLayoutRow(col, true); + + uiItemR(row, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); + uiItemR(row, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); + + /* third row: blending influence */ + row = uiLayoutRow(col, true); + + uiItemR(row, &ptr, "blend_in", 0, IFACE_("In"), ICON_NONE); + uiItemR(row, &ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE); + } + + /* influence -------------------------------------------------------------- */ + col = uiLayoutColumn(box, true); + + /* 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); + } + } + } } /* ********************************************** */ @@ -707,8 +1010,8 @@ static ListBase fmodifier_copypaste_buf = {NULL, NULL}; /* free the copy/paste buffer */ void ANIM_fmodifiers_copybuf_free(void) { - /* just free the whole buffer */ - free_fmodifiers(&fmodifier_copypaste_buf); + /* just free the whole buffer */ + free_fmodifiers(&fmodifier_copypaste_buf); } /* copy the given F-Modifiers to the buffer, returning whether anything was copied or not @@ -717,28 +1020,28 @@ void ANIM_fmodifiers_copybuf_free(void) */ bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active) { - bool ok = true; - - /* sanity checks */ - if (ELEM(NULL, modifiers, modifiers->first)) - return 0; - - /* copy the whole list, or just the active one? */ - if (active) { - FModifier *fcm = find_active_fmodifier(modifiers); - - if (fcm) { - FModifier *fcmN = copy_fmodifier(fcm); - BLI_addtail(&fmodifier_copypaste_buf, fcmN); - } - else - ok = 0; - } - else - copy_fmodifiers(&fmodifier_copypaste_buf, modifiers); - - /* did we succeed? */ - return ok; + bool ok = true; + + /* sanity checks */ + if (ELEM(NULL, modifiers, modifiers->first)) + return 0; + + /* copy the whole list, or just the active one? */ + if (active) { + FModifier *fcm = find_active_fmodifier(modifiers); + + if (fcm) { + FModifier *fcmN = copy_fmodifier(fcm); + BLI_addtail(&fmodifier_copypaste_buf, fcmN); + } + else + ok = 0; + } + else + copy_fmodifiers(&fmodifier_copypaste_buf, modifiers); + + /* did we succeed? */ + return ok; } /* 'Paste' the F-Modifier(s) from the buffer to the specified list @@ -746,40 +1049,40 @@ bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active) */ bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve) { - FModifier *fcm; - bool ok = false; + FModifier *fcm; + bool ok = false; - /* sanity checks */ - if (modifiers == NULL) - return 0; + /* sanity checks */ + if (modifiers == NULL) + return 0; - bool was_cyclic = curve && BKE_fcurve_is_cyclic(curve); + bool was_cyclic = curve && BKE_fcurve_is_cyclic(curve); - /* if replacing the list, free the existing modifiers */ - if (replace) - free_fmodifiers(modifiers); + /* if replacing the list, free the existing modifiers */ + if (replace) + free_fmodifiers(modifiers); - /* now copy over all the modifiers in the buffer to the end of the list */ - for (fcm = fmodifier_copypaste_buf.first; fcm; fcm = fcm->next) { - /* make a copy of it */ - FModifier *fcmN = copy_fmodifier(fcm); + /* now copy over all the modifiers in the buffer to the end of the list */ + for (fcm = fmodifier_copypaste_buf.first; fcm; fcm = fcm->next) { + /* make a copy of it */ + FModifier *fcmN = copy_fmodifier(fcm); - fcmN->curve = curve; + fcmN->curve = curve; - /* make sure the new one isn't active, otherwise the list may get several actives */ - fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE; + /* make sure the new one isn't active, otherwise the list may get several actives */ + fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE; - /* now add it to the end of the list */ - BLI_addtail(modifiers, fcmN); - ok = 1; - } + /* now add it to the end of the list */ + BLI_addtail(modifiers, fcmN); + ok = 1; + } - /* adding or removing the Cycles modifier requires an update to handles */ - if (curve && BKE_fcurve_is_cyclic(curve) != was_cyclic) - calchandles_fcurve(curve); + /* adding or removing the Cycles modifier requires an update to handles */ + if (curve && BKE_fcurve_is_cyclic(curve) != was_cyclic) + calchandles_fcurve(curve); - /* did we succeed? */ - return ok; + /* did we succeed? */ + return ok; } /* ********************************************** */ diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 19ac0ea18a0..e8c17e10b17 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - /* System includes ----------------------------------------------------- */ #include @@ -62,60 +61,60 @@ BLI_INLINE bool is_cfra_eq(float a, float b) { - return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH); + return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH); } BLI_INLINE bool is_cfra_lt(float a, float b) { - return (b - a) > BEZT_BINARYSEARCH_THRESH; + return (b - a) > BEZT_BINARYSEARCH_THRESH; } /* Comparator callback used for ActKeyColumns and cframe float-value pointer */ /* 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; - const float *cframe = data; - float val = *cframe; + ActKeyColumn *ak = (ActKeyColumn *)node; + const float *cframe = data; + float val = *cframe; - if (is_cfra_eq(val, ak->cfra)) - return 0; + if (is_cfra_eq(val, ak->cfra)) + return 0; - if (val < ak->cfra) - return -1; - else - return 1; + if (val < ak->cfra) + return -1; + else + return 1; } /* --------------- */ /* Set of references to three logically adjacent keys. */ typedef struct BezTripleChain { - /* Current keyframe. */ - BezTriple *cur; + /* Current keyframe. */ + BezTriple *cur; - /* Logical neighbors. May be NULL. */ - BezTriple *prev, *next; + /* Logical neighbors. May be NULL. */ + BezTriple *prev, *next; } BezTripleChain; /* Categorize the interpolation & handle type of the keyframe. */ static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt) { - if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) { - return KEYFRAME_HANDLE_AUTO_CLAMP; - } - else if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) { - return KEYFRAME_HANDLE_AUTO; - } - else if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) { - return KEYFRAME_HANDLE_VECTOR; - } - else if (ELEM(HD_FREE, bezt->h1, bezt->h2)) { - return KEYFRAME_HANDLE_FREE; - } - else { - return KEYFRAME_HANDLE_ALIGNED; - } + if (bezt->h1 == HD_AUTO_ANIM && bezt->h2 == HD_AUTO_ANIM) { + return KEYFRAME_HANDLE_AUTO_CLAMP; + } + else if (ELEM(bezt->h1, HD_AUTO_ANIM, HD_AUTO) && ELEM(bezt->h2, HD_AUTO_ANIM, HD_AUTO)) { + return KEYFRAME_HANDLE_AUTO; + } + else if (bezt->h1 == HD_VECT && bezt->h2 == HD_VECT) { + return KEYFRAME_HANDLE_VECTOR; + } + else if (ELEM(HD_FREE, bezt->h1, bezt->h2)) { + return KEYFRAME_HANDLE_FREE; + } + else { + return KEYFRAME_HANDLE_ALIGNED; + } } /* Determine if the keyframe is an extreme by comparing with neighbors. @@ -123,113 +122,114 @@ static eKeyframeHandleDrawOpts bezt_handle_type(BezTriple *bezt) */ static eKeyframeExtremeDrawOpts bezt_extreme_type(BezTripleChain *chain) { - if (chain->prev == NULL && chain->next == NULL) { - return KEYFRAME_EXTREME_NONE; - } - - /* Keyframe values for the current one and neighbors. */ - float cur_y = chain->cur->vec[1][1]; - float prev_y = cur_y, next_y = cur_y; - - if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) { - prev_y = chain->prev->vec[1][1]; - } - if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) { - next_y = chain->next->vec[1][1]; - } - - /* Static hold. */ - if (prev_y == cur_y && next_y == cur_y) { - return KEYFRAME_EXTREME_FLAT; - } - - /* Middle of an incline. */ - if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) { - return KEYFRAME_EXTREME_NONE; - } - - /* Bezier handle values for the overshoot check. */ - bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ; - bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ; - float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y; - float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y; - - /* Detect extremes. One of the neighbors is allowed to be equal to current. */ - if (prev_y < cur_y || next_y < cur_y) { - bool is_overshoot = (handle_l > cur_y || handle_r > cur_y); - - return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); - } - - if (prev_y > cur_y || next_y > cur_y) { - bool is_overshoot = (handle_l < cur_y || handle_r < cur_y); - - return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); - } - - return KEYFRAME_EXTREME_NONE; + if (chain->prev == NULL && chain->next == NULL) { + return KEYFRAME_EXTREME_NONE; + } + + /* Keyframe values for the current one and neighbors. */ + float cur_y = chain->cur->vec[1][1]; + float prev_y = cur_y, next_y = cur_y; + + if (chain->prev && !IS_EQF(cur_y, chain->prev->vec[1][1])) { + prev_y = chain->prev->vec[1][1]; + } + if (chain->next && !IS_EQF(cur_y, chain->next->vec[1][1])) { + next_y = chain->next->vec[1][1]; + } + + /* Static hold. */ + if (prev_y == cur_y && next_y == cur_y) { + return KEYFRAME_EXTREME_FLAT; + } + + /* Middle of an incline. */ + if ((prev_y < cur_y && next_y > cur_y) || (prev_y > cur_y && next_y < cur_y)) { + return KEYFRAME_EXTREME_NONE; + } + + /* Bezier handle values for the overshoot check. */ + bool l_bezier = chain->prev && chain->prev->ipo == BEZT_IPO_BEZ; + bool r_bezier = chain->next && chain->cur->ipo == BEZT_IPO_BEZ; + float handle_l = l_bezier ? chain->cur->vec[0][1] : cur_y; + float handle_r = r_bezier ? chain->cur->vec[2][1] : cur_y; + + /* Detect extremes. One of the neighbors is allowed to be equal to current. */ + if (prev_y < cur_y || next_y < cur_y) { + bool is_overshoot = (handle_l > cur_y || handle_r > cur_y); + + return KEYFRAME_EXTREME_MAX | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); + } + + if (prev_y > cur_y || next_y > cur_y) { + bool is_overshoot = (handle_l < cur_y || handle_r < cur_y); + + return KEYFRAME_EXTREME_MIN | (is_overshoot ? KEYFRAME_EXTREME_MIXED : 0); + } + + return KEYFRAME_EXTREME_NONE; } /* Comparator callback used for ActKeyColumns and BezTripleChain */ static short compare_ak_bezt(void *node, void *data) { - BezTripleChain *chain = data; + BezTripleChain *chain = data; - return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]); + return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]); } /* New node callback used for building ActKeyColumns from BezTripleChain */ static DLRBT_Node *nalloc_ak_bezt(void *data) { - ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"); - BezTripleChain *chain = data; - BezTriple *bezt = chain->cur; + ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"); + BezTripleChain *chain = data; + BezTriple *bezt = chain->cur; - /* store settings based on state of BezTriple */ - ak->cfra = bezt->vec[1][0]; - ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0; - ak->key_type = BEZKEYTYPE(bezt); - ak->handle_type = bezt_handle_type(bezt); - ak->extreme_type = bezt_extreme_type(chain); + /* store settings based on state of BezTriple */ + ak->cfra = bezt->vec[1][0]; + ak->sel = BEZT_ISSEL_ANY(bezt) ? SELECT : 0; + ak->key_type = BEZKEYTYPE(bezt); + ak->handle_type = bezt_handle_type(bezt); + ak->extreme_type = bezt_extreme_type(chain); - /* count keyframes in this column */ - ak->totkey = 1; + /* count keyframes in this column */ + ak->totkey = 1; - return (DLRBT_Node *)ak; + return (DLRBT_Node *)ak; } /* Node updater callback used for building ActKeyColumns from BezTripleChain */ static void nupdate_ak_bezt(void *node, void *data) { - ActKeyColumn *ak = node; - BezTripleChain *chain = data; - BezTriple *bezt = chain->cur; - - /* set selection status and 'touched' status */ - if (BEZT_ISSEL_ANY(bezt)) ak->sel = SELECT; - - /* count keyframes in this column */ - ak->totkey++; - - /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */ - if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) - ak->key_type = BEZT_KEYTYPE_KEYFRAME; - - /* For interpolation type, select the highest value (enum is sorted). */ - ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt)); - - /* For extremes, detect when combining different states. */ - char new_extreme = bezt_extreme_type(chain); - - if (new_extreme != ak->extreme_type) { - /* Replace the flat status without adding mixed. */ - if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) { - ak->extreme_type = new_extreme; - } - else if (new_extreme != KEYFRAME_EXTREME_FLAT) { - ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED); - } - } + ActKeyColumn *ak = node; + BezTripleChain *chain = data; + BezTriple *bezt = chain->cur; + + /* set selection status and 'touched' status */ + if (BEZT_ISSEL_ANY(bezt)) + ak->sel = SELECT; + + /* count keyframes in this column */ + ak->totkey++; + + /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */ + if (BEZKEYTYPE(bezt) == BEZT_KEYTYPE_KEYFRAME) + ak->key_type = BEZT_KEYTYPE_KEYFRAME; + + /* For interpolation type, select the highest value (enum is sorted). */ + ak->handle_type = MAX2(ak->handle_type, bezt_handle_type(bezt)); + + /* For extremes, detect when combining different states. */ + char new_extreme = bezt_extreme_type(chain); + + if (new_extreme != ak->extreme_type) { + /* Replace the flat status without adding mixed. */ + if (ak->extreme_type == KEYFRAME_EXTREME_FLAT) { + ak->extreme_type = new_extreme; + } + else if (new_extreme != KEYFRAME_EXTREME_FLAT) { + ak->extreme_type |= (new_extreme | KEYFRAME_EXTREME_MIXED); + } + } } /* ......... */ @@ -237,44 +237,45 @@ static void nupdate_ak_bezt(void *node, void *data) /* Comparator callback used for ActKeyColumns and GPencil frame */ static short compare_ak_gpframe(void *node, void *data) { - bGPDframe *gpf = (bGPDframe *)data; + bGPDframe *gpf = (bGPDframe *)data; - float frame = gpf->framenum; - return compare_ak_cfraPtr(node, &frame); + float frame = gpf->framenum; + return compare_ak_cfraPtr(node, &frame); } /* New node callback used for building ActKeyColumns from GPencil frames */ static DLRBT_Node *nalloc_ak_gpframe(void *data) { - ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); - bGPDframe *gpf = (bGPDframe *)data; + ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); + bGPDframe *gpf = (bGPDframe *)data; - /* store settings based on state of BezTriple */ - ak->cfra = gpf->framenum; - ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0; - ak->key_type = gpf->key_type; + /* store settings based on state of BezTriple */ + ak->cfra = gpf->framenum; + ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0; + ak->key_type = gpf->key_type; - /* count keyframes in this column */ - ak->totkey = 1; + /* count keyframes in this column */ + ak->totkey = 1; - return (DLRBT_Node *)ak; + return (DLRBT_Node *)ak; } /* Node updater callback used for building ActKeyColumns from GPencil frames */ static void nupdate_ak_gpframe(void *node, void *data) { - ActKeyColumn *ak = (ActKeyColumn *)node; - bGPDframe *gpf = (bGPDframe *)data; + ActKeyColumn *ak = (ActKeyColumn *)node; + bGPDframe *gpf = (bGPDframe *)data; - /* set selection status and 'touched' status */ - if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT; + /* set selection status and 'touched' status */ + if (gpf->flag & GP_FRAME_SELECT) + ak->sel = SELECT; - /* count keyframes in this column */ - ak->totkey++; + /* count keyframes in this column */ + ak->totkey++; - /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */ - if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) - ak->key_type = BEZT_KEYTYPE_KEYFRAME; + /* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */ + if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME) + ak->key_type = BEZT_KEYTYPE_KEYFRAME; } /* ......... */ @@ -282,193 +283,198 @@ static void nupdate_ak_gpframe(void *node, void *data) /* Comparator callback used for ActKeyColumns and GPencil frame */ static short compare_ak_masklayshape(void *node, void *data) { - MaskLayerShape *masklay_shape = (MaskLayerShape *)data; + MaskLayerShape *masklay_shape = (MaskLayerShape *)data; - float frame = masklay_shape->frame; - return compare_ak_cfraPtr(node, &frame); + float frame = masklay_shape->frame; + return compare_ak_cfraPtr(node, &frame); } /* New node callback used for building ActKeyColumns from GPencil frames */ static DLRBT_Node *nalloc_ak_masklayshape(void *data) { - ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); - MaskLayerShape *masklay_shape = (MaskLayerShape *)data; + ActKeyColumn *ak = MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"); + MaskLayerShape *masklay_shape = (MaskLayerShape *)data; - /* store settings based on state of BezTriple */ - ak->cfra = masklay_shape->frame; - ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0; + /* store settings based on state of BezTriple */ + ak->cfra = masklay_shape->frame; + ak->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? SELECT : 0; - /* count keyframes in this column */ - ak->totkey = 1; + /* count keyframes in this column */ + ak->totkey = 1; - return (DLRBT_Node *)ak; + return (DLRBT_Node *)ak; } /* Node updater callback used for building ActKeyColumns from GPencil frames */ static void nupdate_ak_masklayshape(void *node, void *data) { - ActKeyColumn *ak = (ActKeyColumn *)node; - MaskLayerShape *masklay_shape = (MaskLayerShape *)data; + ActKeyColumn *ak = (ActKeyColumn *)node; + MaskLayerShape *masklay_shape = (MaskLayerShape *)data; - /* set selection status and 'touched' status */ - if (masklay_shape->flag & MASK_SHAPE_SELECT) ak->sel = SELECT; + /* set selection status and 'touched' status */ + if (masklay_shape->flag & MASK_SHAPE_SELECT) + ak->sel = SELECT; - /* count keyframes in this column */ - ak->totkey++; + /* count keyframes in this column */ + ak->totkey++; } - /* --------------- */ /* Add the given BezTriple to the given 'list' of Keyframes */ static void add_bezt_to_keycolumns_list(DLRBT_Tree *keys, BezTripleChain *bezt) { - if (ELEM(NULL, keys, bezt)) - return; - else - BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt); + if (ELEM(NULL, keys, bezt)) + return; + else + BLI_dlrbTree_add(keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt); } /* Add the given GPencil Frame to the given 'list' of Keyframes */ static void add_gpframe_to_keycolumns_list(DLRBT_Tree *keys, bGPDframe *gpf) { - if (ELEM(NULL, keys, gpf)) - return; - else - BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf); + if (ELEM(NULL, keys, gpf)) + return; + else + BLI_dlrbTree_add(keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf); } /* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */ static void add_masklay_to_keycolumns_list(DLRBT_Tree *keys, MaskLayerShape *masklay_shape) { - if (ELEM(NULL, keys, masklay_shape)) - return; - else - BLI_dlrbTree_add(keys, compare_ak_masklayshape, nalloc_ak_masklayshape, nupdate_ak_masklayshape, masklay_shape); + if (ELEM(NULL, keys, masklay_shape)) + return; + else + BLI_dlrbTree_add(keys, + compare_ak_masklayshape, + nalloc_ak_masklayshape, + nupdate_ak_masklayshape, + masklay_shape); } /* ActKeyBlocks (Long Keyframes) ------------------------------------------ */ -static const ActKeyBlockInfo dummy_keyblock = { 0 }; +static const ActKeyBlockInfo dummy_keyblock = {0}; static void compute_keyblock_data(ActKeyBlockInfo *info, BezTriple *prev, BezTriple *beztn) { - memset(info, 0, sizeof(ActKeyBlockInfo)); - - if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) { - /* Animator tagged a "moving hold" - * - Previous key must also be tagged as a moving hold, otherwise - * we're just dealing with the first of a pair, and we don't - * want to be creating any phantom holds... - */ - if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) { - info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; - } - } - - /* Check for same values... - * - Handles must have same central value as each other - * - Handles which control that section of the curve must be constant - */ - if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) { - bool hold; - - /* Only check handles in case of actual bezier interpolation. */ - if (prev->ipo == BEZT_IPO_BEZ) { - hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) && IS_EQF(prev->vec[1][1], prev->vec[2][1]); - } - /* This interpolation type induces movement even between identical keys. */ - else { - hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC); - } - - if (hold) { - info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; - } - } - - /* Remember non-bezier interpolation info. */ - if (prev->ipo != BEZT_IPO_BEZ) { - info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER; - } - - info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn); + memset(info, 0, sizeof(ActKeyBlockInfo)); + + if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) { + /* Animator tagged a "moving hold" + * - Previous key must also be tagged as a moving hold, otherwise + * we're just dealing with the first of a pair, and we don't + * want to be creating any phantom holds... + */ + if (BEZKEYTYPE(prev) == BEZT_KEYTYPE_MOVEHOLD) { + info->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; + } + } + + /* Check for same values... + * - Handles must have same central value as each other + * - Handles which control that section of the curve must be constant + */ + if (IS_EQF(beztn->vec[1][1], prev->vec[1][1])) { + bool hold; + + /* Only check handles in case of actual bezier interpolation. */ + if (prev->ipo == BEZT_IPO_BEZ) { + hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) && + IS_EQF(prev->vec[1][1], prev->vec[2][1]); + } + /* This interpolation type induces movement even between identical keys. */ + else { + hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC); + } + + if (hold) { + info->flag |= ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD; + } + } + + /* Remember non-bezier interpolation info. */ + if (prev->ipo != BEZT_IPO_BEZ) { + info->flag |= ACTKEYBLOCK_FLAG_NON_BEZIER; + } + + info->sel = BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn); } static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block) { - /* New curve and block. */ - if (col->totcurve <= 1 && col->totblock == 0) { - memcpy(&col->block, block, sizeof(ActKeyBlockInfo)); - } - /* Existing curve. */ - else { - col->block.conflict |= (col->block.flag ^ block->flag); - col->block.flag |= block->flag; - col->block.sel |= block->sel; - } - - if (block->flag) { - col->totblock++; - } + /* New curve and block. */ + if (col->totcurve <= 1 && col->totblock == 0) { + memcpy(&col->block, block, sizeof(ActKeyBlockInfo)); + } + /* Existing curve. */ + else { + col->block.conflict |= (col->block.flag ^ block->flag); + col->block.flag |= block->flag; + col->block.sel |= block->sel; + } + + if (block->flag) { + col->totblock++; + } } static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len) { - ActKeyColumn *col = keys->first; - - if (bezt && bezt_len >= 2) { - ActKeyBlockInfo block; - - /* Find the first key column while inserting dummy blocks. */ - for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) { - add_keyblock_info(col, &dummy_keyblock); - } - - BLI_assert(col != NULL); - - /* Insert real blocks. */ - for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) { - /* Wrong order of bezier keys: resync position. */ - if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) { - /* Backtrack to find the right location. */ - if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) { - ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact( - keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]); - - if (newcol != NULL) { - col = newcol; - - /* The previous keyblock is garbage too. */ - if (col->prev != NULL) { - add_keyblock_info(col->prev, &dummy_keyblock); - } - } - else { - BLI_assert(false); - } - } - - continue; - } - - /* Normal sequence */ - BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0])); - - compute_keyblock_data(&block, bezt, bezt + 1); - - for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) { - add_keyblock_info(col, &block); - } - - BLI_assert(col != NULL); - } - } - - /* Insert dummy blocks at the end. */ - for (; col != NULL; col = col->next) { - add_keyblock_info(col, &dummy_keyblock); - } + ActKeyColumn *col = keys->first; + + if (bezt && bezt_len >= 2) { + ActKeyBlockInfo block; + + /* Find the first key column while inserting dummy blocks. */ + for (; col != NULL && is_cfra_lt(col->cfra, bezt[0].vec[1][0]); col = col->next) { + add_keyblock_info(col, &dummy_keyblock); + } + + BLI_assert(col != NULL); + + /* Insert real blocks. */ + for (int v = 1; col != NULL && v < bezt_len; v++, bezt++) { + /* Wrong order of bezier keys: resync position. */ + if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) { + /* Backtrack to find the right location. */ + if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) { + ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact( + keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]); + + if (newcol != NULL) { + col = newcol; + + /* The previous keyblock is garbage too. */ + if (col->prev != NULL) { + add_keyblock_info(col->prev, &dummy_keyblock); + } + } + else { + BLI_assert(false); + } + } + + continue; + } + + /* Normal sequence */ + BLI_assert(is_cfra_eq(col->cfra, bezt[0].vec[1][0])); + + compute_keyblock_data(&block, bezt, bezt + 1); + + for (; col != NULL && is_cfra_lt(col->cfra, bezt[1].vec[1][0]); col = col->next) { + add_keyblock_info(col, &block); + } + + BLI_assert(col != NULL); + } + } + + /* Insert dummy blocks at the end. */ + for (; col != NULL; col = col->next) { + add_keyblock_info(col, &dummy_keyblock); + } } /* Walk through columns and propagate blocks and totcurve. @@ -478,689 +484,756 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *keys, BezTriple *bezt, int be */ static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len) { - /* Recompute the prev/next linked list. */ - BLI_dlrbTree_linkedlist_sync(keys); - - /* Find the curve count */ - int max_curve = 0; - - for (ActKeyColumn *col = keys->first; col; col = col->next) { - max_curve = MAX2(max_curve, col->totcurve); - } - - /* Propagate blocks to inserted keys */ - ActKeyColumn *prev_ready = NULL; - - for (ActKeyColumn *col = keys->first; col; col = col->next) { - /* Pre-existing column. */ - if (col->totcurve > 0) { - prev_ready = col; - } - /* Newly inserted column, so copy block data from previous. */ - else if (prev_ready != NULL) { - col->totblock = prev_ready->totblock; - memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo)); - } - - col->totcurve = max_curve + 1; - } - - /* Add blocks on top */ - add_bezt_to_keyblocks_list(keys, bezt, bezt_len); + /* Recompute the prev/next linked list. */ + BLI_dlrbTree_linkedlist_sync(keys); + + /* Find the curve count */ + int max_curve = 0; + + for (ActKeyColumn *col = keys->first; col; col = col->next) { + max_curve = MAX2(max_curve, col->totcurve); + } + + /* Propagate blocks to inserted keys */ + ActKeyColumn *prev_ready = NULL; + + for (ActKeyColumn *col = keys->first; col; col = col->next) { + /* Pre-existing column. */ + if (col->totcurve > 0) { + prev_ready = col; + } + /* Newly inserted column, so copy block data from previous. */ + else if (prev_ready != NULL) { + col->totblock = prev_ready->totblock; + memcpy(&col->block, &prev_ready->block, sizeof(ActKeyBlockInfo)); + } + + col->totcurve = max_curve + 1; + } + + /* Add blocks on top */ + add_bezt_to_keyblocks_list(keys, bezt, bezt_len); } /* --------- */ bool actkeyblock_is_valid(ActKeyColumn *ac) { - return ac != NULL && ac->next != NULL && ac->totblock > 0; + return ac != NULL && ac->next != NULL && ac->totblock > 0; } /* Checks if ActKeyBlock should exist... */ int actkeyblock_get_valid_hold(ActKeyColumn *ac) { - /* check that block is valid */ - if (!actkeyblock_is_valid(ac)) - return 0; + /* check that block is valid */ + if (!actkeyblock_is_valid(ac)) + return 0; - const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | ACTKEYBLOCK_FLAG_ANY_HOLD); - return (ac->block.flag & ~ac->block.conflict) & hold_mask; + const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD | + ACTKEYBLOCK_FLAG_ANY_HOLD); + return (ac->block.flag & ~ac->block.conflict) & hold_mask; } /* *************************** Keyframe Drawing *************************** */ -void draw_keyframe_shape(float x, float y, float size, bool sel, short key_type, short mode, float alpha, - unsigned int pos_id, unsigned int size_id, unsigned int color_id, unsigned int outline_color_id, - unsigned int flags_id, short handle_type, short extreme_type) +void draw_keyframe_shape(float x, + float y, + float size, + bool sel, + short key_type, + short mode, + float alpha, + unsigned int pos_id, + unsigned int size_id, + unsigned int color_id, + unsigned int outline_color_id, + unsigned int flags_id, + short handle_type, + short extreme_type) { - bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH); - bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH); - - BLI_assert(draw_fill || draw_outline); - - /* tweak size of keyframe shape according to type of keyframe - * - 'proper' keyframes have key_type = 0, so get drawn at full size - */ - switch (key_type) { - case BEZT_KEYTYPE_KEYFRAME: /* must be full size */ - break; - - case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */ - size *= 0.85f; - break; - - case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes - * (but by less than for breakdowns) */ - size *= 0.925f; - break; - - case BEZT_KEYTYPE_EXTREME: /* slightly larger */ - size *= 1.2f; - break; - - default: - size -= 0.8f * key_type; - } - - unsigned char fill_col[4]; - unsigned char outline_col[4]; - unsigned int flags = 0; - - /* draw! */ - if (draw_fill) { - /* get interior colors from theme (for selected and unselected only) */ - switch (key_type) { - case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */ - UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_BREAKDOWN_SELECT : TH_KEYTYPE_BREAKDOWN, fill_col); - break; - case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */ - UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_EXTREME_SELECT : TH_KEYTYPE_EXTREME, fill_col); - break; - case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */ - UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_JITTER_SELECT : TH_KEYTYPE_JITTER, fill_col); - break; - case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */ - UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_MOVEHOLD_SELECT : TH_KEYTYPE_MOVEHOLD, fill_col); - break; - case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */ - default: - UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_KEYFRAME_SELECT : TH_KEYTYPE_KEYFRAME, fill_col); - } - - /* NOTE: we don't use the straight alpha from the theme, or else effects such as - * graying out protected/muted channels doesn't work correctly! - */ - fill_col[3] *= alpha; - - if (!draw_outline) { - /* force outline color to match */ - outline_col[0] = fill_col[0]; - outline_col[1] = fill_col[1]; - outline_col[2] = fill_col[2]; - outline_col[3] = fill_col[3]; - } - } - - if (draw_outline) { - /* exterior - black frame */ - UI_GetThemeColor4ubv(sel ? TH_KEYBORDER_SELECT : TH_KEYBORDER, outline_col); - outline_col[3] *= alpha; - - if (!draw_fill) { - /* fill color needs to be (outline.rgb, 0) */ - fill_col[0] = outline_col[0]; - fill_col[1] = outline_col[1]; - fill_col[2] = outline_col[2]; - fill_col[3] = 0; - } - - /* Handle type to outline shape. */ - switch (handle_type) { - case KEYFRAME_HANDLE_AUTO_CLAMP: flags = 0x2; break; /* circle */ - case KEYFRAME_HANDLE_AUTO: flags = 0x12; break; /* circle with dot */ - case KEYFRAME_HANDLE_VECTOR: flags = 0xC; break; /* square */ - case KEYFRAME_HANDLE_ALIGNED: flags = 0x5; break; /* clipped diamond */ - - case KEYFRAME_HANDLE_FREE: - default: - flags = 1; /* diamond */ - } - - /* Extreme type to arrow-like shading. */ - if (extreme_type & KEYFRAME_EXTREME_MAX) { - flags |= 0x100; - } - if (extreme_type & KEYFRAME_EXTREME_MIN) { - flags |= 0x200; - } - if (extreme_type & KEYFRAME_EXTREME_MIXED) { - flags |= 0x400; - } - } - - immAttr1f(size_id, size); - immAttr4ubv(color_id, fill_col); - immAttr4ubv(outline_color_id, outline_col); - immAttr1u(flags_id, flags); - immVertex2f(pos_id, x, y); + bool draw_fill = ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH); + bool draw_outline = ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH); + + BLI_assert(draw_fill || draw_outline); + + /* tweak size of keyframe shape according to type of keyframe + * - 'proper' keyframes have key_type = 0, so get drawn at full size + */ + switch (key_type) { + case BEZT_KEYTYPE_KEYFRAME: /* must be full size */ + break; + + case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */ + size *= 0.85f; + break; + + case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes + * (but by less than for breakdowns) */ + size *= 0.925f; + break; + + case BEZT_KEYTYPE_EXTREME: /* slightly larger */ + size *= 1.2f; + break; + + default: + size -= 0.8f * key_type; + } + + unsigned char fill_col[4]; + unsigned char outline_col[4]; + unsigned int flags = 0; + + /* draw! */ + if (draw_fill) { + /* get interior colors from theme (for selected and unselected only) */ + switch (key_type) { + case BEZT_KEYTYPE_BREAKDOWN: /* bluish frames (default theme) */ + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_BREAKDOWN_SELECT : TH_KEYTYPE_BREAKDOWN, fill_col); + break; + case BEZT_KEYTYPE_EXTREME: /* reddish frames (default theme) */ + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_EXTREME_SELECT : TH_KEYTYPE_EXTREME, fill_col); + break; + case BEZT_KEYTYPE_JITTER: /* greenish frames (default theme) */ + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_JITTER_SELECT : TH_KEYTYPE_JITTER, fill_col); + break; + case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */ + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_MOVEHOLD_SELECT : TH_KEYTYPE_MOVEHOLD, fill_col); + break; + case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */ + default: + UI_GetThemeColor4ubv(sel ? TH_KEYTYPE_KEYFRAME_SELECT : TH_KEYTYPE_KEYFRAME, fill_col); + } + + /* NOTE: we don't use the straight alpha from the theme, or else effects such as + * graying out protected/muted channels doesn't work correctly! + */ + fill_col[3] *= alpha; + + if (!draw_outline) { + /* force outline color to match */ + outline_col[0] = fill_col[0]; + outline_col[1] = fill_col[1]; + outline_col[2] = fill_col[2]; + outline_col[3] = fill_col[3]; + } + } + + if (draw_outline) { + /* exterior - black frame */ + UI_GetThemeColor4ubv(sel ? TH_KEYBORDER_SELECT : TH_KEYBORDER, outline_col); + outline_col[3] *= alpha; + + if (!draw_fill) { + /* fill color needs to be (outline.rgb, 0) */ + fill_col[0] = outline_col[0]; + fill_col[1] = outline_col[1]; + fill_col[2] = outline_col[2]; + fill_col[3] = 0; + } + + /* Handle type to outline shape. */ + switch (handle_type) { + case KEYFRAME_HANDLE_AUTO_CLAMP: + flags = 0x2; + break; /* circle */ + case KEYFRAME_HANDLE_AUTO: + flags = 0x12; + break; /* circle with dot */ + case KEYFRAME_HANDLE_VECTOR: + flags = 0xC; + break; /* square */ + case KEYFRAME_HANDLE_ALIGNED: + flags = 0x5; + break; /* clipped diamond */ + + case KEYFRAME_HANDLE_FREE: + default: + flags = 1; /* diamond */ + } + + /* Extreme type to arrow-like shading. */ + if (extreme_type & KEYFRAME_EXTREME_MAX) { + flags |= 0x100; + } + if (extreme_type & KEYFRAME_EXTREME_MIN) { + flags |= 0x200; + } + if (extreme_type & KEYFRAME_EXTREME_MIXED) { + flags |= 0x400; + } + } + + immAttr1f(size_id, size); + immAttr4ubv(color_id, fill_col); + immAttr4ubv(outline_color_id, outline_col); + immAttr1u(flags_id, flags); + immVertex2f(pos_id, x, y); } -static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, float ypos, float yscale_fac, bool channelLocked, int saction_flag) +static void draw_keylist(View2D *v2d, + DLRBT_Tree *keys, + float ypos, + float yscale_fac, + bool channelLocked, + int saction_flag) { - const float icon_sz = U.widget_unit * 0.5f * yscale_fac; - const float half_icon_sz = 0.5f * icon_sz; - const float smaller_sz = 0.35f * icon_sz; - const float ipo_sz = 0.1f * icon_sz; - - GPU_blend(true); - - /* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */ - /* TODO: allow this opacity factor to be themed? */ - float alpha = channelLocked ? 0.25f : 1.0f; - - /* Show interpolation and handle type? */ - bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0; - - /* draw keyblocks */ - if (keys) { - float sel_color[4], unsel_color[4]; - float sel_mhcol[4], unsel_mhcol[4]; - float ipo_color[4], ipo_color_mix[4]; - - /* cache colours first */ - UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color); - UI_GetThemeColor4fv(TH_STRIP, unsel_color); - UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color); - - sel_color[3] *= alpha; - unsel_color[3] *= alpha; - ipo_color[3] *= alpha; - - copy_v4_v4(sel_mhcol, sel_color); - sel_mhcol[3] *= 0.8f; - copy_v4_v4(unsel_mhcol, unsel_color); - unsel_mhcol[3] *= 0.8f; - copy_v4_v4(ipo_color_mix, ipo_color); - ipo_color_mix[3] *= 0.5f; - - uint block_len = 0; - for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) { - if (actkeyblock_get_valid_hold(ab)) { - block_len++; - } - if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) { - block_len++; - } - } - - if (block_len > 0) { - GPUVertFormat *format = immVertexFormat(); - uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - - immBegin(GPU_PRIM_TRIS, 6 * block_len); - for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) { - int valid_hold = actkeyblock_get_valid_hold(ab); - if (valid_hold != 0) { - if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) { - /* draw "moving hold" long-keyframe block - slightly smaller */ - immRectf_fast_with_color(pos_id, color_id, - ab->cfra, ypos - smaller_sz, ab->next->cfra, ypos + smaller_sz, - (ab->block.sel) ? sel_mhcol : unsel_mhcol); - } - else { - /* draw standard long-keyframe block */ - immRectf_fast_with_color(pos_id, color_id, - ab->cfra, ypos - half_icon_sz, ab->next->cfra, ypos + half_icon_sz, - (ab->block.sel) ? sel_color : unsel_color); - } - } - if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) { - /* draw an interpolation line */ - immRectf_fast_with_color(pos_id, color_id, - ab->cfra, ypos - ipo_sz, ab->next->cfra, ypos + ipo_sz, - (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color); - } - } - immEnd(); - immUnbindProgram(); - } - } - - if (keys) { - /* count keys */ - uint key_len = 0; - for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) { - /* optimization: if keyframe doesn't appear within 5 units (screenspace) in visible area, don't draw - * - this might give some improvements, since we current have to flip between view/region matrices - */ - if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) - key_len++; - } - - if (key_len > 0) { - /* draw keys */ - GPUVertFormat *format = immVertexFormat(); - uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - uint outline_color_id = GPU_vertformat_attr_add(format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); - immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); - GPU_enable_program_point_size(); - immUniform2f("ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1); - immBegin(GPU_PRIM_POINTS, key_len); - - short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE; - - for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) { - if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) { - if (show_ipo) { - handle_type = ak->handle_type; - } - if (saction_flag & SACTION_SHOW_EXTREMES) { - extreme_type = ak->extreme_type; - } - - draw_keyframe_shape(ak->cfra, ypos, icon_sz, (ak->sel & SELECT), ak->key_type, KEYFRAME_SHAPE_BOTH, alpha, - pos_id, size_id, color_id, outline_color_id, flags_id, handle_type, extreme_type); - } - } - - immEnd(); - GPU_disable_program_point_size(); - immUnbindProgram(); - } - } - - GPU_blend(false); + const float icon_sz = U.widget_unit * 0.5f * yscale_fac; + const float half_icon_sz = 0.5f * icon_sz; + const float smaller_sz = 0.35f * icon_sz; + const float ipo_sz = 0.1f * icon_sz; + + GPU_blend(true); + + /* locked channels are less strongly shown, as feedback for locked channels in DopeSheet */ + /* TODO: allow this opacity factor to be themed? */ + float alpha = channelLocked ? 0.25f : 1.0f; + + /* Show interpolation and handle type? */ + bool show_ipo = (saction_flag & SACTION_SHOW_INTERPOLATION) != 0; + + /* draw keyblocks */ + if (keys) { + float sel_color[4], unsel_color[4]; + float sel_mhcol[4], unsel_mhcol[4]; + float ipo_color[4], ipo_color_mix[4]; + + /* cache colours first */ + UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color); + UI_GetThemeColor4fv(TH_STRIP, unsel_color); + UI_GetThemeColor4fv(TH_DOPESHEET_IPOLINE, ipo_color); + + sel_color[3] *= alpha; + unsel_color[3] *= alpha; + ipo_color[3] *= alpha; + + copy_v4_v4(sel_mhcol, sel_color); + sel_mhcol[3] *= 0.8f; + copy_v4_v4(unsel_mhcol, unsel_color); + unsel_mhcol[3] *= 0.8f; + copy_v4_v4(ipo_color_mix, ipo_color); + ipo_color_mix[3] *= 0.5f; + + uint block_len = 0; + for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) { + if (actkeyblock_get_valid_hold(ab)) { + block_len++; + } + if (show_ipo && actkeyblock_is_valid(ab) && (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) { + block_len++; + } + } + + if (block_len > 0) { + GPUVertFormat *format = immVertexFormat(); + uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + immBegin(GPU_PRIM_TRIS, 6 * block_len); + for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) { + int valid_hold = actkeyblock_get_valid_hold(ab); + if (valid_hold != 0) { + if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) { + /* draw "moving hold" long-keyframe block - slightly smaller */ + immRectf_fast_with_color(pos_id, + color_id, + ab->cfra, + ypos - smaller_sz, + ab->next->cfra, + ypos + smaller_sz, + (ab->block.sel) ? sel_mhcol : unsel_mhcol); + } + else { + /* draw standard long-keyframe block */ + immRectf_fast_with_color(pos_id, + color_id, + ab->cfra, + ypos - half_icon_sz, + ab->next->cfra, + ypos + half_icon_sz, + (ab->block.sel) ? sel_color : unsel_color); + } + } + if (show_ipo && actkeyblock_is_valid(ab) && + (ab->block.flag & ACTKEYBLOCK_FLAG_NON_BEZIER)) { + /* draw an interpolation line */ + immRectf_fast_with_color( + pos_id, + color_id, + ab->cfra, + ypos - ipo_sz, + ab->next->cfra, + ypos + ipo_sz, + (ab->block.conflict & ACTKEYBLOCK_FLAG_NON_BEZIER) ? ipo_color_mix : ipo_color); + } + } + immEnd(); + immUnbindProgram(); + } + } + + if (keys) { + /* count keys */ + uint key_len = 0; + for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) { + /* optimization: if keyframe doesn't appear within 5 units (screenspace) in visible area, don't draw + * - this might give some improvements, since we current have to flip between view/region matrices + */ + if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) + key_len++; + } + + if (key_len > 0) { + /* draw keys */ + GPUVertFormat *format = immVertexFormat(); + uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uint color_id = GPU_vertformat_attr_add( + format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + uint outline_color_id = GPU_vertformat_attr_add( + format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); + immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); + GPU_enable_program_point_size(); + immUniform2f( + "ViewportSize", BLI_rcti_size_x(&v2d->mask) + 1, BLI_rcti_size_y(&v2d->mask) + 1); + immBegin(GPU_PRIM_POINTS, key_len); + + short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE; + + for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) { + if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) { + if (show_ipo) { + handle_type = ak->handle_type; + } + if (saction_flag & SACTION_SHOW_EXTREMES) { + extreme_type = ak->extreme_type; + } + + draw_keyframe_shape(ak->cfra, + ypos, + icon_sz, + (ak->sel & SELECT), + ak->key_type, + KEYFRAME_SHAPE_BOTH, + alpha, + pos_id, + size_id, + color_id, + outline_color_id, + flags_id, + handle_type, + extreme_type); + } + } + + immEnd(); + GPU_disable_program_point_size(); + immUnbindProgram(); + } + } + + GPU_blend(false); } /* *************************** Channel Drawing Funcs *************************** */ -void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac, int saction_flag) +void draw_summary_channel( + View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - saction_flag &= ~SACTION_SHOW_EXTREMES; + saction_flag &= ~SACTION_SHOW_EXTREMES; - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - summary_to_keylist(ac, &keys, saction_flag); + summary_to_keylist(ac, &keys, saction_flag); - draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac, int saction_flag) +void draw_scene_channel( + View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - saction_flag &= ~SACTION_SHOW_EXTREMES; + saction_flag &= ~SACTION_SHOW_EXTREMES; - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - scene_to_keylist(ads, sce, &keys, saction_flag); + scene_to_keylist(ads, sce, &keys, saction_flag); - draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac, int saction_flag) +void draw_object_channel( + View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - saction_flag &= ~SACTION_SHOW_EXTREMES; + saction_flag &= ~SACTION_SHOW_EXTREMES; - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - ob_to_keylist(ads, ob, &keys, saction_flag); + ob_to_keylist(ads, ob, &keys, saction_flag); - draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac, int saction_flag) +void draw_fcurve_channel( + View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - bool locked = (fcu->flag & FCURVE_PROTECTED) || - ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || - ((adt && adt->action) && ID_IS_LINKED(adt->action)); + bool locked = (fcu->flag & FCURVE_PROTECTED) || + ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || + ((adt && adt->action) && ID_IS_LINKED(adt->action)); - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - fcurve_to_keylist(adt, fcu, &keys, saction_flag); + fcurve_to_keylist(adt, fcu, &keys, saction_flag); - draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag) +void draw_agroup_channel( + View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - bool locked = (agrp->flag & AGRP_PROTECTED) || - ((adt && adt->action) && ID_IS_LINKED(adt->action)); + bool locked = (agrp->flag & AGRP_PROTECTED) || + ((adt && adt->action) && ID_IS_LINKED(adt->action)); - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - agroup_to_keylist(adt, agrp, &keys, saction_flag); + agroup_to_keylist(adt, agrp, &keys, saction_flag); - draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac, int saction_flag) +void draw_action_channel( + View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - bool locked = (act && ID_IS_LINKED(act)); + bool locked = (act && ID_IS_LINKED(act)); - saction_flag &= ~SACTION_SHOW_EXTREMES; + saction_flag &= ~SACTION_SHOW_EXTREMES; - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - action_to_keylist(adt, act, &keys, saction_flag); + action_to_keylist(adt, act, &keys, saction_flag); - draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac, int saction_flag) +void draw_gpencil_channel( + View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - saction_flag &= ~SACTION_SHOW_EXTREMES; + saction_flag &= ~SACTION_SHOW_EXTREMES; - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - gpencil_to_keylist(ads, gpd, &keys, false); + gpencil_to_keylist(ads, gpd, &keys, false); - draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, false, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag) +void draw_gpl_channel( + View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac, int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0; + bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0; - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - gpl_to_keylist(ads, gpl, &keys); + gpl_to_keylist(ads, gpl, &keys); - draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } -void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac, int saction_flag) +void draw_masklay_channel(View2D *v2d, + bDopeSheet *ads, + MaskLayer *masklay, + float ypos, + float yscale_fac, + int saction_flag) { - DLRBT_Tree keys; + DLRBT_Tree keys; - bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0; + bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0; - BLI_dlrbTree_init(&keys); + BLI_dlrbTree_init(&keys); - mask_to_keylist(ads, masklay, &keys); + mask_to_keylist(ads, masklay, &keys); - draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); + draw_keylist(v2d, &keys, ypos, yscale_fac, locked, saction_flag); - BLI_dlrbTree_free(&keys); + BLI_dlrbTree_free(&keys); } /* *************************** Keyframe List Conversions *************************** */ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, int saction_flag) { - if (ac) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* get F-Curves to take keyframes from */ - filter = ANIMFILTER_DATA_VISIBLE; - 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) { - /* Why not use all #eAnim_KeyType here? - * All of the other key types are actually "summaries" themselves, - * and will just end up duplicating stuff that comes up through - * standard filtering of just F-Curves. Given the way that these work, - * there isn't really any benefit at all from including them. - Aligorith */ - - switch (ale->datatype) { - case ALE_FCURVE: - fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); - break; - case ALE_MASKLAY: - mask_to_keylist(ac->ads, ale->data, keys); - break; - case ALE_GPFRAME: - gpl_to_keylist(ac->ads, ale->data, keys); - break; - default: - // printf("%s: datatype %d unhandled\n", __func__, ale->datatype); - break; - } - } - - ANIM_animdata_freelist(&anim_data); - } + if (ac) { + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get F-Curves to take keyframes from */ + filter = ANIMFILTER_DATA_VISIBLE; + 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) { + /* Why not use all #eAnim_KeyType here? + * All of the other key types are actually "summaries" themselves, + * and will just end up duplicating stuff that comes up through + * standard filtering of just F-Curves. Given the way that these work, + * there isn't really any benefit at all from including them. - Aligorith */ + + switch (ale->datatype) { + case ALE_FCURVE: + fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); + break; + case ALE_MASKLAY: + mask_to_keylist(ac->ads, ale->data, keys); + break; + case ALE_GPFRAME: + gpl_to_keylist(ac->ads, ale->data, keys); + break; + default: + // printf("%s: datatype %d unhandled\n", __func__, ale->datatype); + break; + } + } + + ANIM_animdata_freelist(&anim_data); + } } void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, int saction_flag) { - bAnimContext ac = {NULL}; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - bAnimListElem dummychan = {NULL}; + bAnimListElem dummychan = {NULL}; - if (sce == NULL) - return; + 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; + /* 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; + 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); + /* 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, saction_flag); + /* 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, saction_flag); - ANIM_animdata_freelist(&anim_data); + ANIM_animdata_freelist(&anim_data); } void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, int saction_flag) { - bAnimContext ac = {NULL}; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - bAnimListElem dummychan = {NULL}; - Base dummybase = {NULL}; + bAnimListElem dummychan = {NULL}; + Base dummybase = {NULL}; - if (ob == NULL) - return; + if (ob == NULL) + return; - /* create a dummy wrapper data to work with */ - dummybase.object = ob; + /* create a dummy wrapper data to work with */ + dummybase.object = ob; - dummychan.type = ANIMTYPE_OBJECT; - dummychan.data = &dummybase; - dummychan.id = &ob->id; - dummychan.adt = ob->adt; + dummychan.type = ANIMTYPE_OBJECT; + dummychan.data = &dummybase; + dummychan.id = &ob->id; + dummychan.adt = ob->adt; - ac.ads = ads; - ac.data = &dummychan; - ac.datatype = ANIMCONT_CHANNEL; + 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); + /* 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, saction_flag); + /* 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, saction_flag); - ANIM_animdata_freelist(&anim_data); + ANIM_animdata_freelist(&anim_data); } -void cachefile_to_keylist(bDopeSheet *ads, CacheFile *cache_file, DLRBT_Tree *keys, int saction_flag) +void cachefile_to_keylist(bDopeSheet *ads, + CacheFile *cache_file, + DLRBT_Tree *keys, + int saction_flag) { - if (cache_file == NULL) { - return; - } - - /* create a dummy wrapper data to work with */ - bAnimListElem dummychan = {NULL}; - dummychan.type = ANIMTYPE_DSCACHEFILE; - dummychan.data = cache_file; - dummychan.id = &cache_file->id; - dummychan.adt = cache_file->adt; - - bAnimContext ac = {NULL}; - ac.ads = ads; - ac.data = &dummychan; - ac.datatype = ANIMCONT_CHANNEL; - - /* get F-Curves to take keyframes from */ - ListBase anim_data = { NULL, NULL }; - int 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 (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) { - fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); - } - - ANIM_animdata_freelist(&anim_data); + if (cache_file == NULL) { + return; + } + + /* create a dummy wrapper data to work with */ + bAnimListElem dummychan = {NULL}; + dummychan.type = ANIMTYPE_DSCACHEFILE; + dummychan.data = cache_file; + dummychan.id = &cache_file->id; + dummychan.adt = cache_file->adt; + + bAnimContext ac = {NULL}; + ac.ads = ads; + ac.data = &dummychan; + ac.datatype = ANIMCONT_CHANNEL; + + /* get F-Curves to take keyframes from */ + ListBase anim_data = {NULL, NULL}; + int 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 (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) { + fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag); + } + + ANIM_animdata_freelist(&anim_data); } void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, int saction_flag) { - if (fcu && fcu->totvert && fcu->bezt) { - /* apply NLA-mapping (if applicable) */ - if (adt) - ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0); + if (fcu && fcu->totvert && fcu->bezt) { + /* apply NLA-mapping (if applicable) */ + if (adt) + ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0); - /* Check if the curve is cyclic. */ - bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2); - bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0; + /* Check if the curve is cyclic. */ + bool is_cyclic = BKE_fcurve_is_cyclic(fcu) && (fcu->totvert >= 2); + bool do_extremes = (saction_flag & SACTION_SHOW_EXTREMES) != 0; - /* loop through beztriples, making ActKeysColumns */ - BezTripleChain chain = { 0 }; + /* loop through beztriples, making ActKeysColumns */ + BezTripleChain chain = {0}; - for (int v = 0; v < fcu->totvert; v++) { - chain.cur = &fcu->bezt[v]; + for (int v = 0; v < fcu->totvert; v++) { + chain.cur = &fcu->bezt[v]; - /* Neighbor keys, accounting for being cyclic. */ - if (do_extremes) { - chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL; - chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL; - } + /* Neighbor keys, accounting for being cyclic. */ + if (do_extremes) { + chain.prev = (v > 0) ? &fcu->bezt[v - 1] : is_cyclic ? &fcu->bezt[fcu->totvert - 2] : NULL; + chain.next = (v + 1 < fcu->totvert) ? &fcu->bezt[v + 1] : is_cyclic ? &fcu->bezt[1] : NULL; + } - add_bezt_to_keycolumns_list(keys, &chain); - } + add_bezt_to_keycolumns_list(keys, &chain); + } - /* Update keyblocks. */ - update_keyblocks(keys, fcu->bezt, fcu->totvert); + /* Update keyblocks. */ + update_keyblocks(keys, fcu->bezt, fcu->totvert); - /* unapply NLA-mapping if applicable */ - if (adt) - ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0); - } + /* unapply NLA-mapping if applicable */ + if (adt) + ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0); + } } void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, DLRBT_Tree *keys, int saction_flag) { - FCurve *fcu; - - if (agrp) { - /* loop through F-Curves */ - for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) { - fcurve_to_keylist(adt, fcu, keys, saction_flag); - } - } + FCurve *fcu; + + if (agrp) { + /* loop through F-Curves */ + for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) { + fcurve_to_keylist(adt, fcu, keys, saction_flag); + } + } } void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, int saction_flag) { - FCurve *fcu; - - if (act) { - /* loop through F-Curves */ - for (fcu = act->curves.first; fcu; fcu = fcu->next) { - fcurve_to_keylist(adt, fcu, keys, saction_flag); - } - } + FCurve *fcu; + + if (act) { + /* loop through F-Curves */ + for (fcu = act->curves.first; fcu; fcu = fcu->next) { + fcurve_to_keylist(adt, fcu, keys, saction_flag); + } + } } - void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active) { - bGPDlayer *gpl; - - if (gpd && keys) { - /* for now, just aggregate out all the frames, but only for visible layers */ - for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { - if ((gpl->flag & GP_LAYER_HIDE) == 0) { - if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) { - gpl_to_keylist(ads, gpl, keys); - } - } - } - } + bGPDlayer *gpl; + + if (gpd && keys) { + /* for now, just aggregate out all the frames, but only for visible layers */ + for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { + if ((gpl->flag & GP_LAYER_HIDE) == 0) { + if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) { + gpl_to_keylist(ads, gpl, keys); + } + } + } + } } void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys) { - bGPDframe *gpf; + bGPDframe *gpf; - if (gpl && keys) { - /* although the frames should already be in an ordered list, they are not suitable for displaying yet */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) - add_gpframe_to_keycolumns_list(keys, gpf); + if (gpl && keys) { + /* although the frames should already be in an ordered list, they are not suitable for displaying yet */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) + add_gpframe_to_keycolumns_list(keys, gpf); - update_keyblocks(keys, NULL, 0); - } + update_keyblocks(keys, NULL, 0); + } } void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, DLRBT_Tree *keys) { - MaskLayerShape *masklay_shape; - - if (masklay && keys) { - for (masklay_shape = masklay->splines_shapes.first; - masklay_shape; - masklay_shape = masklay_shape->next) - { - add_masklay_to_keycolumns_list(keys, masklay_shape); - } - - update_keyblocks(keys, NULL, 0); - } + MaskLayerShape *masklay_shape; + + if (masklay && keys) { + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; + masklay_shape = masklay_shape->next) { + add_masklay_to_keycolumns_list(keys, masklay_shape); + } + + update_keyblocks(keys, NULL, 0); + } } diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 837a25946da..bb0ab112af4 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -20,7 +20,6 @@ * \ingroup edanimation */ - #include #include #include @@ -71,329 +70,369 @@ * operation on them, and optionally applies an F-Curve validation function afterwards. */ // TODO: make this function work on samples too... -short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) -{ - BezTriple *bezt; - short ok = 0; - unsigned int i; - - /* sanity check */ - if (ELEM(NULL, fcu, fcu->bezt)) - return 0; - - /* set the F-Curve into the editdata so that it can be accessed */ - if (ked) { - ked->fcu = fcu; - ked->curIndex = 0; - ked->curflags = ok; - } - - /* if function to apply to bezier curves is set, then loop through executing it on beztriples */ - if (key_cb) { - /* if there's a validation func, include that check in the loop - * (this is should be more efficient than checking for it in every loop) - */ - if (key_ok) { - for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { - if (ked) { - /* advance the index, and reset the ok flags (to not influence the result) */ - ked->curIndex = i; - ked->curflags = 0; - } - - /* Only operate on this BezTriple if it fulfills the criteria of the validation func */ - if ((ok = key_ok(ked, bezt))) { - if (ked) ked->curflags = ok; - - /* Exit with return-code '1' if function returns positive - * This is useful if finding if some BezTriple satisfies a condition. - */ - if (key_cb(ked, bezt)) return 1; - } - } - } - else { - for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { - if (ked) ked->curIndex = i; - - /* Exit with return-code '1' if function returns positive - * This is useful if finding if some BezTriple satisfies a condition. - */ - if (key_cb(ked, bezt)) return 1; - } - } - } - - /* unset the F-Curve from the editdata now that it's done */ - if (ked) { - ked->fcu = NULL; - ked->curIndex = 0; - ked->curflags = 0; - } - - /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */ - if (fcu_cb) - fcu_cb(fcu); - - /* done */ - return 0; +short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, + FCurve *fcu, + KeyframeEditFunc key_ok, + KeyframeEditFunc key_cb, + FcuEditFunc fcu_cb) +{ + BezTriple *bezt; + short ok = 0; + unsigned int i; + + /* sanity check */ + if (ELEM(NULL, fcu, fcu->bezt)) + return 0; + + /* set the F-Curve into the editdata so that it can be accessed */ + if (ked) { + ked->fcu = fcu; + ked->curIndex = 0; + ked->curflags = ok; + } + + /* if function to apply to bezier curves is set, then loop through executing it on beztriples */ + if (key_cb) { + /* if there's a validation func, include that check in the loop + * (this is should be more efficient than checking for it in every loop) + */ + if (key_ok) { + for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { + if (ked) { + /* advance the index, and reset the ok flags (to not influence the result) */ + ked->curIndex = i; + ked->curflags = 0; + } + + /* Only operate on this BezTriple if it fulfills the criteria of the validation func */ + if ((ok = key_ok(ked, bezt))) { + if (ked) + ked->curflags = ok; + + /* Exit with return-code '1' if function returns positive + * This is useful if finding if some BezTriple satisfies a condition. + */ + if (key_cb(ked, bezt)) + return 1; + } + } + } + else { + for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { + if (ked) + ked->curIndex = i; + + /* Exit with return-code '1' if function returns positive + * This is useful if finding if some BezTriple satisfies a condition. + */ + if (key_cb(ked, bezt)) + return 1; + } + } + } + + /* unset the F-Curve from the editdata now that it's done */ + if (ked) { + ked->fcu = NULL; + ked->curIndex = 0; + ked->curflags = 0; + } + + /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */ + if (fcu_cb) + fcu_cb(fcu); + + /* done */ + return 0; } /* -------------------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */ /* This function is used to loop over the keyframe data in an Action Group */ -static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) +static short agrp_keyframes_loop(KeyframeEditData *ked, + bActionGroup *agrp, + KeyframeEditFunc key_ok, + KeyframeEditFunc key_cb, + FcuEditFunc fcu_cb) { - FCurve *fcu; + FCurve *fcu; - /* sanity check */ - if (agrp == NULL) - return 0; + /* sanity check */ + if (agrp == NULL) + return 0; - /* only iterate over the F-Curves that are in this group */ - for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) { - if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) - return 1; - } + /* only iterate over the F-Curves that are in this group */ + for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) { + if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) + return 1; + } - return 0; + return 0; } /* This function is used to loop over the keyframe data in an Action */ -static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) +static short act_keyframes_loop(KeyframeEditData *ked, + bAction *act, + KeyframeEditFunc key_ok, + KeyframeEditFunc key_cb, + FcuEditFunc fcu_cb) { - FCurve *fcu; + FCurve *fcu; - /* sanity check */ - if (act == NULL) - return 0; + /* sanity check */ + if (act == NULL) + return 0; - /* just loop through all F-Curves */ - for (fcu = act->curves.first; fcu; fcu = fcu->next) { - if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) - return 1; - } + /* just loop through all F-Curves */ + for (fcu = act->curves.first; fcu; fcu = fcu->next) { + if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) + return 1; + } - return 0; + return 0; } /* This function is used to loop over the keyframe data in an Object */ -static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) +static short ob_keyframes_loop(KeyframeEditData *ked, + bDopeSheet *ads, + Object *ob, + KeyframeEditFunc key_ok, + KeyframeEditFunc key_cb, + FcuEditFunc fcu_cb) { - bAnimContext ac = {NULL}; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - int ret = 0; + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + int ret = 0; - bAnimListElem dummychan = {NULL}; - Base dummybase = {NULL}; + bAnimListElem dummychan = {NULL}; + Base dummybase = {NULL}; - if (ob == NULL) - return 0; + if (ob == NULL) + return 0; - /* create a dummy wrapper data to work with */ - dummybase.object = ob; + /* create a dummy wrapper data to work with */ + dummybase.object = ob; - dummychan.type = ANIMTYPE_OBJECT; - dummychan.data = &dummybase; - dummychan.id = &ob->id; - dummychan.adt = ob->adt; + dummychan.type = ANIMTYPE_OBJECT; + dummychan.data = &dummybase; + dummychan.id = &ob->id; + dummychan.adt = ob->adt; - ac.ads = ads; - ac.data = &dummychan; - ac.datatype = ANIMCONT_CHANNEL; + 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); + /* 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; - } - } + /* 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; + } + } - ANIM_animdata_freelist(&anim_data); + ANIM_animdata_freelist(&anim_data); - /* return return code - defaults to zero if nothing happened */ - return ret; + /* 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, bDopeSheet *ads, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) +static short scene_keyframes_loop(KeyframeEditData *ked, + bDopeSheet *ads, + Scene *sce, + KeyframeEditFunc key_ok, + KeyframeEditFunc key_cb, + FcuEditFunc fcu_cb) { - bAnimContext ac = {NULL}; - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - int ret = 0; + bAnimContext ac = {NULL}; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + int ret = 0; - bAnimListElem dummychan = {NULL}; + bAnimListElem dummychan = {NULL}; - if (sce == NULL) - return 0; + if (sce == NULL) + return 0; - /* create a dummy wrapper data to work with */ - dummychan.type = ANIMTYPE_SCENE; - dummychan.data = sce; - dummychan.id = &sce->id; - dummychan.adt = sce->adt; + /* 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; + 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); + /* 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; - } - } + /* 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; + } + } - ANIM_animdata_freelist(&anim_data); + ANIM_animdata_freelist(&anim_data); - /* return return code - defaults to zero if nothing happened */ - return ret; + /* 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) -{ - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter, ret_code = 0; - - /* sanity check */ - if (ac == NULL) - return 0; - - /* get F-Curves to take keyframes from */ - filter = ANIMFILTER_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 */ - for (ale = anim_data.first; ale; ale = ale->next) { - switch (ale->datatype) { - case ALE_MASKLAY: - case ALE_GPFRAME: - break; - - case ALE_FCURVE: - default: - { - if (ked && ked->iterflags) { - /* make backups of the current values, so that a localised fix - * (e.g. NLA time remapping) can be applied to these values - */ - float f1 = ked->f1; - float f2 = ked->f2; - - if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - - if (ked->iterflags & KED_F1_NLA_UNMAP) - ked->f1 = BKE_nla_tweakedit_remap(adt, f1, NLATIME_CONVERT_UNMAP); - if (ked->iterflags & KED_F2_NLA_UNMAP) - ked->f2 = BKE_nla_tweakedit_remap(adt, f2, NLATIME_CONVERT_UNMAP); - } - - /* now operate on the channel as per normal */ - ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb); - - /* reset */ - ked->f1 = f1; - ked->f2 = f2; - } - else { - /* no special handling required... */ - ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb); - } - break; - } - } - - if (ret_code) - break; - } - - ANIM_animdata_freelist(&anim_data); - - return ret_code; +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; + int filter, ret_code = 0; + + /* sanity check */ + if (ac == NULL) + return 0; + + /* get F-Curves to take keyframes from */ + 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 */ + for (ale = anim_data.first; ale; ale = ale->next) { + switch (ale->datatype) { + case ALE_MASKLAY: + case ALE_GPFRAME: + break; + + case ALE_FCURVE: + default: { + if (ked && ked->iterflags) { + /* make backups of the current values, so that a localised fix + * (e.g. NLA time remapping) can be applied to these values + */ + float f1 = ked->f1; + float f2 = ked->f2; + + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + if (ked->iterflags & KED_F1_NLA_UNMAP) + ked->f1 = BKE_nla_tweakedit_remap(adt, f1, NLATIME_CONVERT_UNMAP); + if (ked->iterflags & KED_F2_NLA_UNMAP) + ked->f2 = BKE_nla_tweakedit_remap(adt, f2, NLATIME_CONVERT_UNMAP); + } + + /* now operate on the channel as per normal */ + ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb); + + /* reset */ + ked->f1 = f1; + ked->f2 = f2; + } + else { + /* no special handling required... */ + ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb); + } + break; + } + } + + if (ret_code) + break; + } + + ANIM_animdata_freelist(&anim_data); + + return ret_code; } /* --- */ /* This function is used to apply operation to all keyframes, regardless of the type */ -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) - return 0; - - /* method to use depends on the type of keyframe data */ - switch (ale->datatype) { - /* direct keyframe data (these loops are exposed) */ - case ALE_FCURVE: /* F-Curve */ - return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb); - - /* indirect 'summaries' (these are not exposed directly) - * NOTE: must keep this code in sync with the drawing code and also the filtering code! - */ - case ALE_GROUP: /* action group */ - return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb); - case ALE_ACT: /* action */ - return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb); - - case ALE_OB: /* object */ - 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, 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); - } - - return 0; +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) + return 0; + + /* method to use depends on the type of keyframe data */ + switch (ale->datatype) { + /* direct keyframe data (these loops are exposed) */ + case ALE_FCURVE: /* F-Curve */ + return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb); + + /* indirect 'summaries' (these are not exposed directly) + * NOTE: must keep this code in sync with the drawing code and also the filtering code! + */ + case ALE_GROUP: /* action group */ + return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb); + case ALE_ACT: /* action */ + return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb); + + case ALE_OB: /* object */ + 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, 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); + } + + 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, bDopeSheet *ads, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) -{ - /* sanity checks */ - if (data == NULL) - return 0; - - /* method to use depends on the type of keyframe data */ - switch (keytype) { - /* direct keyframe data (these loops are exposed) */ - case ALE_FCURVE: /* F-Curve */ - return ANIM_fcurve_keyframes_loop(ked, data, key_ok, key_cb, fcu_cb); - - /* indirect 'summaries' (these are not exposed directly) - * NOTE: must keep this code in sync with the drawing code and also the filtering code! - */ - case ALE_GROUP: /* action group */ - return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb); - case ALE_ACT: /* action */ - return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb); - - case ALE_OB: /* object */ - return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb); - case ALE_SCE: /* scene */ - 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); - } - - return 0; +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) + return 0; + + /* method to use depends on the type of keyframe data */ + switch (keytype) { + /* direct keyframe data (these loops are exposed) */ + case ALE_FCURVE: /* F-Curve */ + return ANIM_fcurve_keyframes_loop(ked, data, key_ok, key_cb, fcu_cb); + + /* indirect 'summaries' (these are not exposed directly) + * NOTE: must keep this code in sync with the drawing code and also the filtering code! + */ + case ALE_GROUP: /* action group */ + return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb); + case ALE_ACT: /* action */ + return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb); + + case ALE_OB: /* object */ + return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb); + case ALE_SCE: /* scene */ + 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); + } + + return 0; } /* ************************************************************************** */ @@ -403,23 +442,23 @@ short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads // used to be recalc_*_ipos() where * was object or action void ANIM_editkeyframes_refresh(bAnimContext *ac) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; - /* filter animation data */ - filter = ANIMFILTER_DATA_VISIBLE; - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + /* filter animation data */ + 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 tag them to - * ensure the keyframes are in order and handles are in a valid position. */ - for (ale = anim_data.first; ale; ale = ale->next) { - ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER; - } + /* Loop over F-Curves that are likely to have been edited, and tag them to + * ensure the keyframes are in order and handles are in a valid position. */ + for (ale = anim_data.first; ale; ale = ale->next) { + ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER; + } - /* free temp data */ - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); + /* free temp data */ + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); } /* ************************************************************************** */ @@ -433,271 +472,267 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac) * - requires that a var, of type short, is named 'ok', and has been initialized to 0 */ #define KEYFRAME_OK_CHECKS(check) \ - { \ - CHECK_TYPE(ok, short); \ - if (check(1)) \ - ok |= KEYFRAME_OK_KEY; \ - \ - if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \ - if (check(0)) \ - ok |= KEYFRAME_OK_H1; \ - if (check(2)) \ - ok |= KEYFRAME_OK_H2; \ - } \ - } (void)0 + { \ + CHECK_TYPE(ok, short); \ + if (check(1)) \ + ok |= KEYFRAME_OK_KEY; \ +\ + if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \ + if (check(0)) \ + ok |= KEYFRAME_OK_H1; \ + if (check(2)) \ + ok |= KEYFRAME_OK_H2; \ + } \ + } \ + (void)0 /* ------------------------ */ static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt) { - short ok = 0; + short ok = 0; - /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */ + /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */ #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1) - KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK - /* return ok flags */ - return ok; + /* return ok flags */ + return ok; } static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt) { - short ok = 0; + short ok = 0; - /* frame range is stored in float properties */ + /* frame range is stored in float properties */ #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2)) - KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK - /* return ok flags */ - return ok; + /* return ok flags */ + return ok; } static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - /* this macro checks all beztriple handles for selection... - * only one of the verts has to be selected for this to be ok... - */ - if (BEZT_ISSEL_ANY(bezt)) - return KEYFRAME_OK_ALL; - else - return 0; + /* this macro checks all beztriple handles for selection... + * only one of the verts has to be selected for this to be ok... + */ + if (BEZT_ISSEL_ANY(bezt)) + return KEYFRAME_OK_ALL; + else + return 0; } static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt) { - short ok = 0; + short ok = 0; - /* value is stored in f1 property - * - 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? - */ + /* value is stored in f1 property + * - 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_EQF(bezt->vec[_index][1], ked->f1) - KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK - /* return ok flags */ - return ok; + /* return ok flags */ + return ok; } static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt) { - short ok = 0; + short ok = 0; - /* value range is stored in float properties */ + /* value range is stored in float properties */ #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2)) - KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK - /* return ok flags */ - return ok; + /* return ok flags */ + return ok; } static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) { - /* rect is stored in data property (it's of type rectf, but may not be set) */ - if (ked->data) { - short ok = 0; + /* rect is stored in data property (it's of type rectf, but may not be set) */ + if (ked->data) { + short ok = 0; #define KEY_CHECK_OK(_index) BLI_rctf_isect_pt_v(ked->data, bezt->vec[_index]) - KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK - /* return ok flags */ - return ok; - } - else - return 0; + /* return ok flags */ + return ok; + } + else + return 0; } /** * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso */ -bool keyframe_region_lasso_test( - const KeyframeEdit_LassoData *data_lasso, - const float xy[2]) +bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2]) { - if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) { - float xy_view[2]; + if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) { + float xy_view[2]; - BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy); + BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy); - if (BLI_lasso_is_point_inside(data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) { - return true; - } - } + if (BLI_lasso_is_point_inside( + data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) { + return true; + } + } - return false; + return false; } static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) { - /* check for lasso customdata (KeyframeEdit_LassoData) */ - if (ked->data) { - short ok = 0; + /* check for lasso customdata (KeyframeEdit_LassoData) */ + if (ked->data) { + short ok = 0; #define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index]) - KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK - /* return ok flags */ - return ok; - } - else - return 0; + /* return ok flags */ + return ok; + } + else + return 0; } static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt) { - /* check for lasso customdata (KeyframeEdit_LassoData) */ - if (ked->data) { - KeyframeEdit_LassoData *data = ked->data; - float pt[2]; + /* check for lasso customdata (KeyframeEdit_LassoData) */ + if (ked->data) { + KeyframeEdit_LassoData *data = ked->data; + float pt[2]; - /* late-binding remap of the x values (for summary channels) */ - /* XXX: Ideally we reset, but it should be fine just leaving it as-is - * as the next channel will reset it properly, while the next summary-channel - * curve will also reset by itself... - */ - if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { - data->rectf_scaled->xmin = ked->f1; - data->rectf_scaled->xmax = ked->f2; - } + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } - /* only use the x-coordinate of the point; the y is the channel range... */ - pt[0] = bezt->vec[1][0]; - pt[1] = ked->channel_y; + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; - if (keyframe_region_lasso_test(data, pt)) - return KEYFRAME_OK_KEY; - } - return 0; + if (keyframe_region_lasso_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; } /** * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle */ -bool keyframe_region_circle_test( - const KeyframeEdit_CircleData *data_circle, - const float xy[2]) +bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2]) { - if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) { - float xy_view[2]; + if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) { + float xy_view[2]; - BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy); + BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy); - xy_view[0] = xy_view[0] - data_circle->mval[0]; - xy_view[1] = xy_view[1] - data_circle->mval[1]; - return len_squared_v2(xy_view) < data_circle->radius_squared; - } + xy_view[0] = xy_view[0] - data_circle->mval[0]; + xy_view[1] = xy_view[1] - data_circle->mval[1]; + return len_squared_v2(xy_view) < data_circle->radius_squared; + } - return false; + return false; } - static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) { - /* check for circle select customdata (KeyframeEdit_CircleData) */ - if (ked->data) { - short ok = 0; + /* check for circle select customdata (KeyframeEdit_CircleData) */ + if (ked->data) { + short ok = 0; #define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index]) - KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK - /* return ok flags */ - return ok; - } - else - return 0; + /* return ok flags */ + return ok; + } + else + return 0; } static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt) { - /* check for circle select customdata (KeyframeEdit_CircleData) */ - if (ked->data) { - KeyframeEdit_CircleData *data = ked->data; - float pt[2]; + /* check for circle select customdata (KeyframeEdit_CircleData) */ + if (ked->data) { + KeyframeEdit_CircleData *data = ked->data; + float pt[2]; - /* late-binding remap of the x values (for summary channels) */ - /* XXX: Ideally we reset, but it should be fine just leaving it as-is - * as the next channel will reset it properly, while the next summary-channel - * curve will also reset by itself... - */ - if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { - data->rectf_scaled->xmin = ked->f1; - data->rectf_scaled->xmax = ked->f2; - } + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } - /* only use the x-coordinate of the point; the y is the channel range... */ - pt[0] = bezt->vec[1][0]; - pt[1] = ked->channel_y; + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; - if (keyframe_region_circle_test(data, pt)) - return KEYFRAME_OK_KEY; - } - return 0; + if (keyframe_region_circle_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; } - KeyframeEditFunc ANIM_editkeyframes_ok(short mode) { - /* eEditKeyframes_Validate */ - switch (mode) { - case BEZT_OK_FRAME: - /* only if bezt falls on the right frame (float) */ - return ok_bezier_frame; - case BEZT_OK_FRAMERANGE: - /* only if bezt falls within the specified frame range (floats) */ - return ok_bezier_framerange; - case BEZT_OK_SELECTED: - /* only if bezt is selected (self) */ - return ok_bezier_selected; - case BEZT_OK_VALUE: - /* only if bezt value matches (float) */ - return ok_bezier_value; - case BEZT_OK_VALUERANGE: - /* only if bezier falls within the specified value range (floats) */ - return ok_bezier_valuerange; - case BEZT_OK_REGION: - /* only if bezier falls within the specified rect (data -> rectf) */ - return ok_bezier_region; - case BEZT_OK_REGION_LASSO: - /* only if the point falls within KeyframeEdit_LassoData defined data */ - return ok_bezier_region_lasso; - case BEZT_OK_REGION_CIRCLE: - /* only if the point falls within KeyframeEdit_CircleData defined data */ - return ok_bezier_region_circle; - case BEZT_OK_CHANNEL_LASSO: - /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */ - return ok_bezier_channel_lasso; - case BEZT_OK_CHANNEL_CIRCLE: - /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */ - return ok_bezier_channel_circle; - default: /* nothing was ok */ - return NULL; - } + /* eEditKeyframes_Validate */ + switch (mode) { + case BEZT_OK_FRAME: + /* only if bezt falls on the right frame (float) */ + return ok_bezier_frame; + case BEZT_OK_FRAMERANGE: + /* only if bezt falls within the specified frame range (floats) */ + return ok_bezier_framerange; + case BEZT_OK_SELECTED: + /* only if bezt is selected (self) */ + return ok_bezier_selected; + case BEZT_OK_VALUE: + /* only if bezt value matches (float) */ + return ok_bezier_value; + case BEZT_OK_VALUERANGE: + /* only if bezier falls within the specified value range (floats) */ + return ok_bezier_valuerange; + case BEZT_OK_REGION: + /* only if bezier falls within the specified rect (data -> rectf) */ + return ok_bezier_region; + case BEZT_OK_REGION_LASSO: + /* only if the point falls within KeyframeEdit_LassoData defined data */ + return ok_bezier_region_lasso; + case BEZT_OK_REGION_CIRCLE: + /* only if the point falls within KeyframeEdit_CircleData defined data */ + return ok_bezier_region_circle; + case BEZT_OK_CHANNEL_LASSO: + /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */ + return ok_bezier_channel_lasso; + case BEZT_OK_CHANNEL_CIRCLE: + /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */ + return ok_bezier_channel_circle; + default: /* nothing was ok */ + return NULL; + } } /* ******************************************* */ @@ -709,36 +744,36 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode) */ short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt) { - /* only if selected */ - if (bezt->f2 & SELECT) { - /* store average time in float 1 (only do rounding at last step) */ - ked->f1 += bezt->vec[1][0]; + /* only if selected */ + if (bezt->f2 & SELECT) { + /* store average time in float 1 (only do rounding at last step) */ + ked->f1 += bezt->vec[1][0]; - /* store average value in float 2 (only do rounding at last step) - * - this isn't always needed, but some operators may also require this - */ - ked->f2 += bezt->vec[1][1]; + /* store average value in float 2 (only do rounding at last step) + * - this isn't always needed, but some operators may also require this + */ + ked->f2 += bezt->vec[1][1]; - /* increment number of items */ - ked->i1++; - } + /* increment number of items */ + ked->i1++; + } - return 0; + return 0; } /* helper callback for columnselect__keys() -> populate * list CfraElems with frame numbers from selected beztriples */ short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt) { - /* only if selected */ - if (bezt->f2 & SELECT) { - CfraElem *ce = MEM_callocN(sizeof(CfraElem), "cfraElem"); - BLI_addtail(&ked->list, ce); + /* only if selected */ + if (bezt->f2 & SELECT) { + CfraElem *ce = MEM_callocN(sizeof(CfraElem), "cfraElem"); + BLI_addtail(&ked->list, ce); - ce->cfra = bezt->vec[1][0]; - } + ce->cfra = bezt->vec[1][0]; + } - return 0; + return 0; } /* used to remap times from one range to another @@ -746,15 +781,15 @@ short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt) */ void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt) { - KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data; - const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin); + KeyframeEditCD_Remap *rmap = (KeyframeEditCD_Remap *)ked->data; + const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin); - /* perform transform on all three handles unless indicated otherwise */ - // TODO: need to include some checks for that + /* perform transform on all three handles unless indicated otherwise */ + // TODO: need to include some checks for that - bezt->vec[0][0] = scale * (bezt->vec[0][0] - rmap->oldMin) + rmap->newMin; - bezt->vec[1][0] = scale * (bezt->vec[1][0] - rmap->oldMin) + rmap->newMin; - bezt->vec[2][0] = scale * (bezt->vec[2][0] - rmap->oldMin) + rmap->newMin; + bezt->vec[0][0] = scale * (bezt->vec[0][0] - rmap->oldMin) + rmap->newMin; + bezt->vec[1][0] = scale * (bezt->vec[1][0] - rmap->oldMin) + rmap->newMin; + bezt->vec[2][0] = scale * (bezt->vec[2][0] - rmap->oldMin) + rmap->newMin; } /* ******************************************* */ @@ -763,199 +798,201 @@ void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt) /* snaps the keyframe to the nearest frame */ static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->vec[1][0] = (float)(floorf(bezt->vec[1][0] + 0.5f)); - return 0; + if (bezt->f2 & SELECT) + bezt->vec[1][0] = (float)(floorf(bezt->vec[1][0] + 0.5f)); + return 0; } /* snaps the keyframe to the nearest second */ static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt) { - const Scene *scene = ked->scene; - const float secf = (float)FPS; + const Scene *scene = ked->scene; + const float secf = (float)FPS; - if (bezt->f2 & SELECT) - bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf); - return 0; + if (bezt->f2 & SELECT) + bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf); + return 0; } /* snaps the keyframe to the current frame */ static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt) { - const Scene *scene = ked->scene; - if (bezt->f2 & SELECT) - bezt->vec[1][0] = (float)CFRA; - return 0; + const Scene *scene = ked->scene; + if (bezt->f2 & SELECT) + bezt->vec[1][0] = (float)CFRA; + return 0; } /* snaps the keyframe time to the nearest marker's frame */ static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->vec[1][0] = (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]); - return 0; + if (bezt->f2 & SELECT) + bezt->vec[1][0] = (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]); + return 0; } /* make the handles have the same value as the key */ static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) { - bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1]; + if (bezt->f2 & SELECT) { + bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1]; - if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN; - if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN; - } - return 0; + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) + bezt->h1 = HD_ALIGN; + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) + bezt->h2 = HD_ALIGN; + } + return 0; } /* frame to snap to is stored in the custom data -> first float value slot */ static short snap_bezier_time(KeyframeEditData *ked, BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->vec[1][0] = ked->f1; - return 0; + if (bezt->f2 & SELECT) + bezt->vec[1][0] = ked->f1; + return 0; } /* value to snap to is stored in the custom data -> first float value slot */ static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->vec[1][1] = ked->f1; - return 0; + if (bezt->f2 & SELECT) + bezt->vec[1][1] = ked->f1; + return 0; } KeyframeEditFunc ANIM_editkeyframes_snap(short type) { - /* eEditKeyframes_Snap */ - switch (type) { - case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */ - return snap_bezier_nearest; - case SNAP_KEYS_CURFRAME: /* snap to current frame */ - return snap_bezier_cframe; - case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */ - return snap_bezier_nearmarker; - case SNAP_KEYS_NEARSEC: /* snap to nearest second */ - return snap_bezier_nearestsec; - case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */ - return snap_bezier_horizontal; - case SNAP_KEYS_TIME: /* snap to given frame/time */ - return snap_bezier_time; - case SNAP_KEYS_VALUE: /* snap to given value */ - return snap_bezier_value; - default: /* just in case */ - return snap_bezier_nearest; - } + /* eEditKeyframes_Snap */ + switch (type) { + case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */ + return snap_bezier_nearest; + case SNAP_KEYS_CURFRAME: /* snap to current frame */ + return snap_bezier_cframe; + case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */ + return snap_bezier_nearmarker; + case SNAP_KEYS_NEARSEC: /* snap to nearest second */ + return snap_bezier_nearestsec; + case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */ + return snap_bezier_horizontal; + case SNAP_KEYS_TIME: /* snap to given frame/time */ + return snap_bezier_time; + case SNAP_KEYS_VALUE: /* snap to given value */ + return snap_bezier_value; + default: /* just in case */ + return snap_bezier_nearest; + } } /* --------- */ static void mirror_bezier_xaxis_ex(BezTriple *bezt, const float center) { - float diff; - int i; + float diff; + int i; - for (i = 0; i < 3; i++) { - diff = (center - bezt->vec[i][0]); - bezt->vec[i][0] = (center + diff); - } - swap_v3_v3(bezt->vec[0], bezt->vec[2]); + for (i = 0; i < 3; i++) { + diff = (center - bezt->vec[i][0]); + bezt->vec[i][0] = (center + diff); + } + swap_v3_v3(bezt->vec[0], bezt->vec[2]); - SWAP(char, bezt->h1, bezt->h2); - SWAP(char, bezt->f1, bezt->f3); + SWAP(char, bezt->h1, bezt->h2); + SWAP(char, bezt->f1, bezt->f3); } static void mirror_bezier_yaxis_ex(BezTriple *bezt, const float center) { - float diff; - int i; + float diff; + int i; - for (i = 0; i < 3; i++) { - diff = (center - bezt->vec[i][1]); - bezt->vec[i][1] = (center + diff); - } + for (i = 0; i < 3; i++) { + diff = (center - bezt->vec[i][1]); + bezt->vec[i][1] = (center + diff); + } } static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt) { - const Scene *scene = ked->scene; + const Scene *scene = ked->scene; - if (bezt->f2 & SELECT) { - mirror_bezier_xaxis_ex(bezt, CFRA); - } + if (bezt->f2 & SELECT) { + mirror_bezier_xaxis_ex(bezt, CFRA); + } - return 0; + return 0; } static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) { - /* Yes, names are inverted, we are mirroring across y axis, hence along x axis... */ - mirror_bezier_xaxis_ex(bezt, 0.0f); - } + if (bezt->f2 & SELECT) { + /* Yes, names are inverted, we are mirroring across y axis, hence along x axis... */ + mirror_bezier_xaxis_ex(bezt, 0.0f); + } - return 0; + return 0; } static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) { - /* Yes, names are inverted, we are mirroring across x axis, hence along y axis... */ - mirror_bezier_yaxis_ex(bezt, 0.0f); - } + if (bezt->f2 & SELECT) { + /* Yes, names are inverted, we are mirroring across x axis, hence along y axis... */ + mirror_bezier_yaxis_ex(bezt, 0.0f); + } - return 0; + return 0; } static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt) { - /* mirroring time stored in f1 */ - if (bezt->f2 & SELECT) { - mirror_bezier_xaxis_ex(bezt, ked->f1); - } + /* mirroring time stored in f1 */ + if (bezt->f2 & SELECT) { + mirror_bezier_xaxis_ex(bezt, ked->f1); + } - return 0; + return 0; } static short mirror_bezier_time(KeyframeEditData *ked, BezTriple *bezt) { - /* value to mirror over is stored in f1 */ - if (bezt->f2 & SELECT) { - mirror_bezier_xaxis_ex(bezt, ked->f1); - } + /* value to mirror over is stored in f1 */ + if (bezt->f2 & SELECT) { + mirror_bezier_xaxis_ex(bezt, ked->f1); + } - return 0; + return 0; } static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt) { - /* value to mirror over is stored in the custom data -> first float value slot */ - if (bezt->f2 & SELECT) { - mirror_bezier_yaxis_ex(bezt, ked->f1); - } + /* value to mirror over is stored in the custom data -> first float value slot */ + if (bezt->f2 & SELECT) { + mirror_bezier_yaxis_ex(bezt, ked->f1); + } - return 0; + return 0; } /* Note: for markers and 'value', the values to use must be supplied as the first float value */ // calchandles_fcurve KeyframeEditFunc ANIM_editkeyframes_mirror(short type) { - switch (type) { - case MIRROR_KEYS_CURFRAME: /* mirror over current frame */ - return mirror_bezier_cframe; - case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */ - return mirror_bezier_yaxis; - case MIRROR_KEYS_XAXIS: /* mirror over value 0 */ - return mirror_bezier_xaxis; - case MIRROR_KEYS_MARKER: /* mirror over marker */ - return mirror_bezier_marker; - case MIRROR_KEYS_TIME: /* mirror over frame/time */ - return mirror_bezier_time; - case MIRROR_KEYS_VALUE: /* mirror over given value */ - return mirror_bezier_value; - default: /* just in case */ - return mirror_bezier_yaxis; - } + switch (type) { + case MIRROR_KEYS_CURFRAME: /* mirror over current frame */ + return mirror_bezier_cframe; + case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */ + return mirror_bezier_yaxis; + case MIRROR_KEYS_XAXIS: /* mirror over value 0 */ + return mirror_bezier_xaxis; + case MIRROR_KEYS_MARKER: /* mirror over marker */ + return mirror_bezier_marker; + case MIRROR_KEYS_TIME: /* mirror over frame/time */ + return mirror_bezier_time; + case MIRROR_KEYS_VALUE: /* mirror over given value */ + return mirror_bezier_value; + default: /* just in case */ + return mirror_bezier_yaxis; + } } /* ******************************************* */ @@ -964,24 +1001,27 @@ KeyframeEditFunc ANIM_editkeyframes_mirror(short type) /* standard validation step for a few of these (implemented as macro for inlining without fn-call overhead): * "if the handles are not of the same type, set them to type free" */ -#define ENSURE_HANDLES_MATCH(bezt) \ - if (bezt->h1 != bezt->h2) { \ - if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ - bezt->h1 = HD_FREE; \ - if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ - bezt->h2 = HD_FREE; \ - } (void)0 +#define ENSURE_HANDLES_MATCH(bezt) \ + if (bezt->h1 != bezt->h2) { \ + if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ + bezt->h1 = HD_FREE; \ + if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ + bezt->h2 = HD_FREE; \ + } \ + (void)0 /* Sets the selected bezier handles to type 'auto' */ static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { - if (bezt->f1 & SELECT) bezt->h1 = HD_AUTO; - if (bezt->f3 & SELECT) bezt->h2 = HD_AUTO; + if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { + if (bezt->f1 & SELECT) + bezt->h1 = HD_AUTO; + if (bezt->f3 & SELECT) + bezt->h2 = HD_AUTO; - ENSURE_HANDLES_MATCH(bezt); - } - return 0; + ENSURE_HANDLES_MATCH(bezt); + } + return 0; } /* Sets the selected bezier handles to type 'auto-clamped' @@ -989,307 +1029,317 @@ static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt) */ static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { - if (bezt->f1 & SELECT) bezt->h1 = HD_AUTO_ANIM; - if (bezt->f3 & SELECT) bezt->h2 = HD_AUTO_ANIM; + if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { + if (bezt->f1 & SELECT) + bezt->h1 = HD_AUTO_ANIM; + if (bezt->f3 & SELECT) + bezt->h2 = HD_AUTO_ANIM; - ENSURE_HANDLES_MATCH(bezt); - } - return 0; + ENSURE_HANDLES_MATCH(bezt); + } + return 0; } /* Sets the selected bezier handles to type 'vector' */ static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f1 & SELECT) bezt->h1 = HD_VECT; - if (bezt->f3 & SELECT) bezt->h2 = HD_VECT; - return 0; + if (bezt->f1 & SELECT) + bezt->h1 = HD_VECT; + if (bezt->f3 & SELECT) + bezt->h2 = HD_VECT; + return 0; } /* Queries if the handle should be set to 'free' or 'align' */ // NOTE: this was used for the 'toggle free/align' option -// currently this isn't used, but may be restored later +// currently this isn't used, but may be restored later static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if ((bezt->f1 & SELECT) && (bezt->h1)) return 1; - if ((bezt->f3 & SELECT) && (bezt->h2)) return 1; - return 0; + if ((bezt->f1 & SELECT) && (bezt->h1)) + return 1; + if ((bezt->f3 & SELECT) && (bezt->h2)) + return 1; + return 0; } /* Sets selected bezier handles to type 'align' */ static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f1 & SELECT) bezt->h1 = HD_ALIGN; - if (bezt->f3 & SELECT) bezt->h2 = HD_ALIGN; - return 0; + if (bezt->f1 & SELECT) + bezt->h1 = HD_ALIGN; + if (bezt->f3 & SELECT) + bezt->h2 = HD_ALIGN; + return 0; } /* Sets selected bezier handles to type 'free' */ static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f1 & SELECT) bezt->h1 = HD_FREE; - if (bezt->f3 & SELECT) bezt->h2 = HD_FREE; - return 0; + if (bezt->f1 & SELECT) + bezt->h1 = HD_FREE; + if (bezt->f3 & SELECT) + bezt->h2 = HD_FREE; + return 0; } /* Set all selected Bezier Handles to a single type */ // calchandles_fcurve KeyframeEditFunc ANIM_editkeyframes_handles(short code) { - switch (code) { - case HD_AUTO: /* auto */ - return set_bezier_auto; - case HD_AUTO_ANIM: /* auto clamped */ - return set_bezier_auto_clamped; + switch (code) { + case HD_AUTO: /* auto */ + return set_bezier_auto; + case HD_AUTO_ANIM: /* auto clamped */ + return set_bezier_auto_clamped; - case HD_VECT: /* vector */ - return set_bezier_vector; - case HD_FREE: /* free */ - return set_bezier_free; - case HD_ALIGN: /* align */ - return set_bezier_align; + case HD_VECT: /* vector */ + return set_bezier_vector; + case HD_FREE: /* free */ + return set_bezier_free; + case HD_ALIGN: /* align */ + return set_bezier_align; - default: /* check for toggle free or align? */ - return bezier_isfree; - } + default: /* check for toggle free or align? */ + return bezier_isfree; + } } /* ------- */ static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_CONST; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_CONST; + return 0; } static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_LIN; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_LIN; + return 0; } static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_BEZ; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_BEZ; + return 0; } static short set_bezt_back(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_BACK; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_BACK; + return 0; } static short set_bezt_bounce(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_BOUNCE; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_BOUNCE; + return 0; } static short set_bezt_circle(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_CIRC; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_CIRC; + return 0; } static short set_bezt_cubic(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_CUBIC; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_CUBIC; + return 0; } static short set_bezt_elastic(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_ELASTIC; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_ELASTIC; + return 0; } static short set_bezt_expo(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_EXPO; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_EXPO; + return 0; } static short set_bezt_quad(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_QUAD; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_QUAD; + return 0; } static short set_bezt_quart(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_QUART; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_QUART; + return 0; } static short set_bezt_quint(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_QUINT; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_QUINT; + return 0; } static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->ipo = BEZT_IPO_SINE; - return 0; + if (bezt->f2 & SELECT) + bezt->ipo = BEZT_IPO_SINE; + return 0; } /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */ // ANIM_editkeyframes_ipocurve_ipotype() ! KeyframeEditFunc ANIM_editkeyframes_ipo(short code) { - switch (code) { - /* interpolation */ - case BEZT_IPO_CONST: /* constant */ - return set_bezt_constant; - case BEZT_IPO_LIN: /* linear */ - return set_bezt_linear; - - /* easing */ - case BEZT_IPO_BACK: - return set_bezt_back; - case BEZT_IPO_BOUNCE: - return set_bezt_bounce; - case BEZT_IPO_CIRC: - return set_bezt_circle; - case BEZT_IPO_CUBIC: - return set_bezt_cubic; - case BEZT_IPO_ELASTIC: - return set_bezt_elastic; - case BEZT_IPO_EXPO: - return set_bezt_expo; - case BEZT_IPO_QUAD: - return set_bezt_quad; - case BEZT_IPO_QUART: - return set_bezt_quart; - case BEZT_IPO_QUINT: - return set_bezt_quint; - case BEZT_IPO_SINE: - return set_bezt_sine; - - default: /* bezier */ - return set_bezt_bezier; - } + switch (code) { + /* interpolation */ + case BEZT_IPO_CONST: /* constant */ + return set_bezt_constant; + case BEZT_IPO_LIN: /* linear */ + return set_bezt_linear; + + /* easing */ + case BEZT_IPO_BACK: + return set_bezt_back; + case BEZT_IPO_BOUNCE: + return set_bezt_bounce; + case BEZT_IPO_CIRC: + return set_bezt_circle; + case BEZT_IPO_CUBIC: + return set_bezt_cubic; + case BEZT_IPO_ELASTIC: + return set_bezt_elastic; + case BEZT_IPO_EXPO: + return set_bezt_expo; + case BEZT_IPO_QUAD: + return set_bezt_quad; + case BEZT_IPO_QUART: + return set_bezt_quart; + case BEZT_IPO_QUINT: + return set_bezt_quint; + case BEZT_IPO_SINE: + return set_bezt_sine; + + default: /* bezier */ + return set_bezt_bezier; + } } /* ------- */ static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - BEZKEYTYPE(bezt) = BEZT_KEYTYPE_KEYFRAME; - return 0; + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt) = BEZT_KEYTYPE_KEYFRAME; + return 0; } static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - BEZKEYTYPE(bezt) = BEZT_KEYTYPE_BREAKDOWN; - return 0; + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt) = BEZT_KEYTYPE_BREAKDOWN; + return 0; } static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - BEZKEYTYPE(bezt) = BEZT_KEYTYPE_EXTREME; - return 0; + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt) = BEZT_KEYTYPE_EXTREME; + return 0; } static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - BEZKEYTYPE(bezt) = BEZT_KEYTYPE_JITTER; - return 0; + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt) = BEZT_KEYTYPE_JITTER; + return 0; } static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD; - return 0; + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD; + return 0; } /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */ KeyframeEditFunc ANIM_editkeyframes_keytype(short code) { - switch (code) { - case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */ - return set_keytype_breakdown; + switch (code) { + case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */ + return set_keytype_breakdown; - case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */ - return set_keytype_extreme; + case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */ + return set_keytype_extreme; - case BEZT_KEYTYPE_JITTER: /* jitter keyframe */ - return set_keytype_jitter; + case BEZT_KEYTYPE_JITTER: /* jitter keyframe */ + return set_keytype_jitter; - case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */ - return set_keytype_moving_hold; + case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */ + return set_keytype_moving_hold; - case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */ - default: - return set_keytype_keyframe; - } + case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */ + default: + return set_keytype_keyframe; + } } /* ------- */ static short set_easingtype_easein(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->easing = BEZT_IPO_EASE_IN; - return 0; + if (bezt->f2 & SELECT) + bezt->easing = BEZT_IPO_EASE_IN; + return 0; } static short set_easingtype_easeout(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->easing = BEZT_IPO_EASE_OUT; - return 0; + if (bezt->f2 & SELECT) + bezt->easing = BEZT_IPO_EASE_OUT; + return 0; } static short set_easingtype_easeinout(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->easing = BEZT_IPO_EASE_IN_OUT; - return 0; + if (bezt->f2 & SELECT) + bezt->easing = BEZT_IPO_EASE_IN_OUT; + return 0; } static short set_easingtype_easeauto(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - if (bezt->f2 & SELECT) - bezt->easing = BEZT_IPO_EASE_AUTO; - return 0; + if (bezt->f2 & SELECT) + bezt->easing = BEZT_IPO_EASE_AUTO; + return 0; } /* Set the easing type of the selected BezTriples in each F-Curve to the specified one */ KeyframeEditFunc ANIM_editkeyframes_easing(short mode) { - switch (mode) { - case BEZT_IPO_EASE_IN: /* ease in */ - return set_easingtype_easein; + switch (mode) { + case BEZT_IPO_EASE_IN: /* ease in */ + return set_easingtype_easein; - case BEZT_IPO_EASE_OUT: /* ease out */ - return set_easingtype_easeout; + case BEZT_IPO_EASE_OUT: /* ease out */ + return set_easingtype_easeout; - case BEZT_IPO_EASE_IN_OUT: /* both */ - return set_easingtype_easeinout; + case BEZT_IPO_EASE_IN_OUT: /* both */ + return set_easingtype_easeinout; - default: /* auto */ - return set_easingtype_easeauto; - } + default: /* auto */ + return set_easingtype_easeauto; + } } /* ******************************************* */ @@ -1297,67 +1347,67 @@ KeyframeEditFunc ANIM_editkeyframes_easing(short mode) static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt) { - /* if we've got info on what to select, use it, otherwise select all */ - if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { - if (ked->curflags & KEYFRAME_OK_KEY) - bezt->f2 |= SELECT; - if (ked->curflags & KEYFRAME_OK_H1) - bezt->f1 |= SELECT; - if (ked->curflags & KEYFRAME_OK_H2) - bezt->f3 |= SELECT; - } - else { - BEZT_SEL_ALL(bezt); - } + /* if we've got info on what to select, use it, otherwise select all */ + if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { + if (ked->curflags & KEYFRAME_OK_KEY) + bezt->f2 |= SELECT; + if (ked->curflags & KEYFRAME_OK_H1) + bezt->f1 |= SELECT; + if (ked->curflags & KEYFRAME_OK_H2) + bezt->f3 |= SELECT; + } + else { + BEZT_SEL_ALL(bezt); + } - return 0; + return 0; } static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt) { - /* if we've got info on what to deselect, use it, otherwise deselect all */ - if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { - if (ked->curflags & KEYFRAME_OK_KEY) - bezt->f2 &= ~SELECT; - if (ked->curflags & KEYFRAME_OK_H1) - bezt->f1 &= ~SELECT; - if (ked->curflags & KEYFRAME_OK_H2) - bezt->f3 &= ~SELECT; - } - else { - BEZT_DESEL_ALL(bezt); - } + /* if we've got info on what to deselect, use it, otherwise deselect all */ + if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { + if (ked->curflags & KEYFRAME_OK_KEY) + bezt->f2 &= ~SELECT; + if (ked->curflags & KEYFRAME_OK_H1) + bezt->f1 &= ~SELECT; + if (ked->curflags & KEYFRAME_OK_H2) + bezt->f3 &= ~SELECT; + } + else { + BEZT_DESEL_ALL(bezt); + } - return 0; + return 0; } static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt) { - /* Invert the selection for the whole bezier triple */ - bezt->f2 ^= SELECT; - if (bezt->f2 & SELECT) { - bezt->f1 |= SELECT; - bezt->f3 |= SELECT; - } - else { - bezt->f1 &= ~SELECT; - bezt->f3 &= ~SELECT; - } - return 0; + /* Invert the selection for the whole bezier triple */ + bezt->f2 ^= SELECT; + if (bezt->f2 & SELECT) { + bezt->f1 |= SELECT; + bezt->f3 |= SELECT; + } + else { + bezt->f1 &= ~SELECT; + bezt->f3 &= ~SELECT; + } + return 0; } KeyframeEditFunc ANIM_editkeyframes_select(short selectmode) { - switch (selectmode) { - case SELECT_ADD: /* add */ - return select_bezier_add; - case SELECT_SUBTRACT: /* subtract */ - return select_bezier_subtract; - case SELECT_INVERT: /* invert */ - return select_bezier_invert; - default: /* replace (need to clear all, then add) */ - return select_bezier_add; - } + switch (selectmode) { + case SELECT_ADD: /* add */ + return select_bezier_add; + case SELECT_SUBTRACT: /* subtract */ + return select_bezier_subtract; + case SELECT_INVERT: /* invert */ + return select_bezier_invert; + default: /* replace (need to clear all, then add) */ + return select_bezier_add; + } } /* ******************************************* */ @@ -1373,91 +1423,91 @@ KeyframeEditFunc ANIM_editkeyframes_select(short selectmode) static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt) { - FCurve *fcu = ked->fcu; - char *map = ked->data; - int i = ked->curIndex; + FCurve *fcu = ked->fcu; + char *map = ked->data; + int i = ked->curIndex; - /* if current is selected, just make sure it stays this way */ - if (BEZT_ISSEL_ANY(bezt)) { - map[i] = 1; - return 0; - } + /* if current is selected, just make sure it stays this way */ + if (BEZT_ISSEL_ANY(bezt)) { + map[i] = 1; + return 0; + } - /* if previous is selected, that means that selection should extend across */ - if (i > 0) { - BezTriple *prev = bezt - 1; + /* if previous is selected, that means that selection should extend across */ + if (i > 0) { + BezTriple *prev = bezt - 1; - if (BEZT_ISSEL_ANY(prev)) { - map[i] = 1; - return 0; - } - } + if (BEZT_ISSEL_ANY(prev)) { + map[i] = 1; + return 0; + } + } - /* if next is selected, that means that selection should extend across */ - if (i < (fcu->totvert - 1)) { - BezTriple *next = bezt + 1; + /* if next is selected, that means that selection should extend across */ + if (i < (fcu->totvert - 1)) { + BezTriple *next = bezt + 1; - if (BEZT_ISSEL_ANY(next)) { - map[i] = 1; - return 0; - } - } + if (BEZT_ISSEL_ANY(next)) { + map[i] = 1; + return 0; + } + } - return 0; + return 0; } static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt) { - FCurve *fcu = ked->fcu; - char *map = ked->data; - int i = ked->curIndex; - - /* if current is selected, check the left/right keyframes - * since it might need to be deselected (but otherwise no) - */ - if (BEZT_ISSEL_ANY(bezt)) { - /* if previous is not selected, we're on the tip of an iceberg */ - if (i > 0) { - BezTriple *prev = bezt - 1; - - if (BEZT_ISSEL_ANY(prev) == 0) - return 0; - } - else if (i == 0) { - /* current keyframe is selected at an endpoint, so should get deselected */ - return 0; - } - - /* if next is not selected, we're on the tip of an iceberg */ - if (i < (fcu->totvert - 1)) { - BezTriple *next = bezt + 1; - - if (BEZT_ISSEL_ANY(next) == 0) - return 0; - } - else if (i == (fcu->totvert - 1)) { - /* current keyframe is selected at an endpoint, so should get deselected */ - return 0; - } - - /* if we're still here, that means that keyframe should remain untouched */ - map[i] = 1; - } - - return 0; + FCurve *fcu = ked->fcu; + char *map = ked->data; + int i = ked->curIndex; + + /* if current is selected, check the left/right keyframes + * since it might need to be deselected (but otherwise no) + */ + if (BEZT_ISSEL_ANY(bezt)) { + /* if previous is not selected, we're on the tip of an iceberg */ + if (i > 0) { + BezTriple *prev = bezt - 1; + + if (BEZT_ISSEL_ANY(prev) == 0) + return 0; + } + else if (i == 0) { + /* current keyframe is selected at an endpoint, so should get deselected */ + return 0; + } + + /* if next is not selected, we're on the tip of an iceberg */ + if (i < (fcu->totvert - 1)) { + BezTriple *next = bezt + 1; + + if (BEZT_ISSEL_ANY(next) == 0) + return 0; + } + else if (i == (fcu->totvert - 1)) { + /* current keyframe is selected at an endpoint, so should get deselected */ + return 0; + } + + /* if we're still here, that means that keyframe should remain untouched */ + map[i] = 1; + } + + return 0; } /* Get callback for building selection map */ KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode) { - switch (mode) { - case SELMAP_LESS: /* less */ - return selmap_build_bezier_less; + switch (mode) { + case SELMAP_LESS: /* less */ + return selmap_build_bezier_less; - case SELMAP_MORE: /* more */ - default: - return selmap_build_bezier_more; - } + case SELMAP_MORE: /* more */ + default: + return selmap_build_bezier_more; + } } /* ----------- */ @@ -1465,16 +1515,16 @@ KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode) /* flush selection map values to the given beztriple */ short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt) { - const char *map = ked->data; - short on = map[ked->curIndex]; + const char *map = ked->data; + short on = map[ked->curIndex]; - /* select or deselect based on whether the map allows it or not */ - if (on) { - BEZT_SEL_ALL(bezt); - } - else { - BEZT_DESEL_ALL(bezt); - } + /* select or deselect based on whether the map allows it or not */ + if (on) { + BEZT_SEL_ALL(bezt); + } + else { + BEZT_DESEL_ALL(bezt); + } - return 0; + return 0; } diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index c9e672a111d..945327ed78b 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include #include @@ -37,7 +36,6 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" - #include "BKE_action.h" #include "BKE_fcurve.h" #include "BKE_report.h" @@ -71,68 +69,68 @@ */ void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc) { - /* sanity check */ - if (fcu == NULL) - return; - - /* verify the index: - * 1) cannot be greater than the number of available keyframes - * 2) negative indices are for specifying a value from the end of the array - */ - if (abs(index) >= fcu->totvert) - return; - else if (index < 0) - index += fcu->totvert; - - /* Delete this keyframe */ - memmove(&fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1)); - fcu->totvert--; - - if (fcu->totvert == 0) { - if (fcu->bezt) - MEM_freeN(fcu->bezt); - fcu->bezt = NULL; - } - - /* recalc handles - only if it won't cause problems */ - if (do_recalc) - calchandles_fcurve(fcu); + /* sanity check */ + if (fcu == NULL) + return; + + /* verify the index: + * 1) cannot be greater than the number of available keyframes + * 2) negative indices are for specifying a value from the end of the array + */ + if (abs(index) >= fcu->totvert) + return; + else if (index < 0) + index += fcu->totvert; + + /* Delete this keyframe */ + memmove( + &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1)); + fcu->totvert--; + + if (fcu->totvert == 0) { + if (fcu->bezt) + MEM_freeN(fcu->bezt); + fcu->bezt = NULL; + } + + /* recalc handles - only if it won't cause problems */ + if (do_recalc) + calchandles_fcurve(fcu); } /* Delete selected keyframes in given F-Curve */ bool delete_fcurve_keys(FCurve *fcu) { - int i; - bool changed = false; - - if (fcu->bezt == NULL) /* ignore baked curves */ - return false; - - /* Delete selected BezTriples */ - for (i = 0; i < fcu->totvert; i++) { - if (fcu->bezt[i].f2 & SELECT) { - memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1)); - fcu->totvert--; - i--; - changed = true; - } - } - - /* Free the array of BezTriples if there are not keyframes */ - if (fcu->totvert == 0) - clear_fcurve_keys(fcu); - - return changed; + int i; + bool changed = false; + + if (fcu->bezt == NULL) /* ignore baked curves */ + return false; + + /* Delete selected BezTriples */ + for (i = 0; i < fcu->totvert; i++) { + if (fcu->bezt[i].f2 & SELECT) { + memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1)); + fcu->totvert--; + i--; + changed = true; + } + } + + /* Free the array of BezTriples if there are not keyframes */ + if (fcu->totvert == 0) + clear_fcurve_keys(fcu); + + return changed; } - void clear_fcurve_keys(FCurve *fcu) { - if (fcu->bezt) - MEM_freeN(fcu->bezt); - fcu->bezt = NULL; + if (fcu->bezt) + MEM_freeN(fcu->bezt); + fcu->bezt = NULL; - fcu->totvert = 0; + fcu->totvert = 0; } /* ---------------- */ @@ -140,36 +138,36 @@ void clear_fcurve_keys(FCurve *fcu) /* duplicate selected keyframes for the given F-Curve */ void duplicate_fcurve_keys(FCurve *fcu) { - BezTriple *newbezt; - int i; - - /* this can only work when there is an F-Curve, and also when there are some BezTriples */ - if (ELEM(NULL, fcu, fcu->bezt)) - return; - - for (i = 0; i < fcu->totvert; i++) { - /* If a key is selected */ - if (fcu->bezt[i].f2 & SELECT) { - /* Expand the list */ - newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert + 1), "beztriple"); - - memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i + 1)); - memcpy(newbezt + i + 1, fcu->bezt + i, sizeof(BezTriple)); - memcpy(newbezt + i + 2, fcu->bezt + i + 1, sizeof(BezTriple) * (fcu->totvert - (i + 1))); - fcu->totvert++; - - /* reassign pointers... (free old, and add new) */ - MEM_freeN(fcu->bezt); - fcu->bezt = newbezt; - - /* Unselect the current key */ - BEZT_DESEL_ALL(&fcu->bezt[i]); - i++; - - /* Select the copied key */ - BEZT_SEL_ALL(&fcu->bezt[i]); - } - } + BezTriple *newbezt; + int i; + + /* this can only work when there is an F-Curve, and also when there are some BezTriples */ + if (ELEM(NULL, fcu, fcu->bezt)) + return; + + for (i = 0; i < fcu->totvert; i++) { + /* If a key is selected */ + if (fcu->bezt[i].f2 & SELECT) { + /* Expand the list */ + newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert + 1), "beztriple"); + + memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i + 1)); + memcpy(newbezt + i + 1, fcu->bezt + i, sizeof(BezTriple)); + memcpy(newbezt + i + 2, fcu->bezt + i + 1, sizeof(BezTriple) * (fcu->totvert - (i + 1))); + fcu->totvert++; + + /* reassign pointers... (free old, and add new) */ + MEM_freeN(fcu->bezt); + fcu->bezt = newbezt; + + /* Unselect the current key */ + BEZT_DESEL_ALL(&fcu->bezt[i]); + i++; + + /* Select the copied key */ + BEZT_SEL_ALL(&fcu->bezt[i]); + } + } } /* **************************************************** */ @@ -180,327 +178,325 @@ void duplicate_fcurve_keys(FCurve *fcu) */ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault) { - FCurve *fcu = (FCurve *)ale->key_data; - BezTriple *old_bezts, *bezt, *beztn; - BezTriple *lastb; - int totCount, i; - - /* check if any points */ - if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) || - (!cleardefault && fcu->totvert == 1)) - { - return; - } - - /* make a copy of the old BezTriples, and clear F-Curve */ - old_bezts = fcu->bezt; - totCount = fcu->totvert; - fcu->bezt = NULL; - fcu->totvert = 0; - - /* now insert first keyframe, as it should be ok */ - bezt = old_bezts; - insert_bezt_fcurve(fcu, bezt, 0); - if (!(bezt->f2 & SELECT)) { - lastb = fcu->bezt; - lastb->f1 = lastb->f2 = lastb->f3 = 0; - } - - /* Loop through BezTriples, comparing them. Skip any that do - * not fit the criteria for "ok" points. - */ - for (i = 1; i < totCount; i++) { - float prev[2], cur[2], next[2]; - - /* get BezTriples and their values */ - if (i < (totCount - 1)) { - beztn = (old_bezts + (i + 1)); - next[0] = beztn->vec[1][0]; next[1] = beztn->vec[1][1]; - } - else { - beztn = NULL; - next[0] = next[1] = 0.0f; - } - lastb = (fcu->bezt + (fcu->totvert - 1)); - bezt = (old_bezts + i); - - /* get references for quicker access */ - prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1]; - cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1]; - - if (!(bezt->f2 & SELECT)) { - insert_bezt_fcurve(fcu, bezt, 0); - lastb = (fcu->bezt + (fcu->totvert - 1)); - lastb->f1 = lastb->f2 = lastb->f3 = 0; - continue; - } - - /* check if current bezt occurs at same time as last ok */ - if (IS_EQT(cur[0], prev[0], thresh)) { - /* If there is a next beztriple, and if occurs at the same time, only insert - * if there is a considerable distance between the points, and also if the - * current is further away than the next one is to the previous. - */ - if (beztn && (IS_EQT(cur[0], next[0], thresh)) && - (IS_EQT(next[1], prev[1], thresh) == 0)) - { - /* only add if current is further away from previous */ - if (cur[1] > next[1]) { - if (IS_EQT(cur[1], prev[1], thresh) == 0) { - /* add new keyframe */ - insert_bezt_fcurve(fcu, bezt, 0); - } - } - } - else { - /* only add if values are a considerable distance apart */ - if (IS_EQT(cur[1], prev[1], thresh) == 0) { - /* add new keyframe */ - insert_bezt_fcurve(fcu, bezt, 0); - } - } - } - else { - /* checks required are dependent on whether this is last keyframe or not */ - if (beztn) { - /* does current have same value as previous and next? */ - if (IS_EQT(cur[1], prev[1], thresh) == 0) { - /* add new keyframe */ - insert_bezt_fcurve(fcu, bezt, 0); - } - else if (IS_EQT(cur[1], next[1], thresh) == 0) { - /* add new keyframe */ - insert_bezt_fcurve(fcu, bezt, 0); - } - } - else { - /* add if value doesn't equal that of previous */ - if (IS_EQT(cur[1], prev[1], thresh) == 0) { - /* add new keyframe */ - insert_bezt_fcurve(fcu, bezt, 0); - } - } - } - } - - /* now free the memory used by the old BezTriples */ - if (old_bezts) - MEM_freeN(old_bezts); - - /* final step, if there is just one key in fcurve, check if it's - * the default value and if is, remove fcurve completely. */ - if (cleardefault && fcu->totvert == 1) { - float default_value = 0.0f; - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - RNA_id_pointer_create(ale->id, &id_ptr); - - /* get property to read from, and get value as appropriate */ - if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { - if (RNA_property_type(prop) == PROP_FLOAT) - default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index); - } - - if (fcu->bezt->vec[1][1] == default_value) { - clear_fcurve_keys(fcu); - - /* check if curve is really unused and if it is, return signal for deletion */ - if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && - (fcu->driver == NULL)) - { - AnimData *adt = ale->adt; - ANIM_fcurve_delete_from_animdata(ac, adt, fcu); - ale->key_data = NULL; - } - } - } + FCurve *fcu = (FCurve *)ale->key_data; + BezTriple *old_bezts, *bezt, *beztn; + BezTriple *lastb; + int totCount, i; + + /* check if any points */ + if ((fcu == NULL) || (fcu->bezt == NULL) || (fcu->totvert == 0) || + (!cleardefault && fcu->totvert == 1)) { + return; + } + + /* make a copy of the old BezTriples, and clear F-Curve */ + old_bezts = fcu->bezt; + totCount = fcu->totvert; + fcu->bezt = NULL; + fcu->totvert = 0; + + /* now insert first keyframe, as it should be ok */ + bezt = old_bezts; + insert_bezt_fcurve(fcu, bezt, 0); + if (!(bezt->f2 & SELECT)) { + lastb = fcu->bezt; + lastb->f1 = lastb->f2 = lastb->f3 = 0; + } + + /* Loop through BezTriples, comparing them. Skip any that do + * not fit the criteria for "ok" points. + */ + for (i = 1; i < totCount; i++) { + float prev[2], cur[2], next[2]; + + /* get BezTriples and their values */ + if (i < (totCount - 1)) { + beztn = (old_bezts + (i + 1)); + next[0] = beztn->vec[1][0]; + next[1] = beztn->vec[1][1]; + } + else { + beztn = NULL; + next[0] = next[1] = 0.0f; + } + lastb = (fcu->bezt + (fcu->totvert - 1)); + bezt = (old_bezts + i); + + /* get references for quicker access */ + prev[0] = lastb->vec[1][0]; + prev[1] = lastb->vec[1][1]; + cur[0] = bezt->vec[1][0]; + cur[1] = bezt->vec[1][1]; + + if (!(bezt->f2 & SELECT)) { + insert_bezt_fcurve(fcu, bezt, 0); + lastb = (fcu->bezt + (fcu->totvert - 1)); + lastb->f1 = lastb->f2 = lastb->f3 = 0; + continue; + } + + /* check if current bezt occurs at same time as last ok */ + if (IS_EQT(cur[0], prev[0], thresh)) { + /* If there is a next beztriple, and if occurs at the same time, only insert + * if there is a considerable distance between the points, and also if the + * current is further away than the next one is to the previous. + */ + if (beztn && (IS_EQT(cur[0], next[0], thresh)) && (IS_EQT(next[1], prev[1], thresh) == 0)) { + /* only add if current is further away from previous */ + if (cur[1] > next[1]) { + if (IS_EQT(cur[1], prev[1], thresh) == 0) { + /* add new keyframe */ + insert_bezt_fcurve(fcu, bezt, 0); + } + } + } + else { + /* only add if values are a considerable distance apart */ + if (IS_EQT(cur[1], prev[1], thresh) == 0) { + /* add new keyframe */ + insert_bezt_fcurve(fcu, bezt, 0); + } + } + } + else { + /* checks required are dependent on whether this is last keyframe or not */ + if (beztn) { + /* does current have same value as previous and next? */ + if (IS_EQT(cur[1], prev[1], thresh) == 0) { + /* add new keyframe */ + insert_bezt_fcurve(fcu, bezt, 0); + } + else if (IS_EQT(cur[1], next[1], thresh) == 0) { + /* add new keyframe */ + insert_bezt_fcurve(fcu, bezt, 0); + } + } + else { + /* add if value doesn't equal that of previous */ + if (IS_EQT(cur[1], prev[1], thresh) == 0) { + /* add new keyframe */ + insert_bezt_fcurve(fcu, bezt, 0); + } + } + } + } + + /* now free the memory used by the old BezTriples */ + if (old_bezts) + MEM_freeN(old_bezts); + + /* final step, if there is just one key in fcurve, check if it's + * the default value and if is, remove fcurve completely. */ + if (cleardefault && fcu->totvert == 1) { + float default_value = 0.0f; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + RNA_id_pointer_create(ale->id, &id_ptr); + + /* get property to read from, and get value as appropriate */ + if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { + if (RNA_property_type(prop) == PROP_FLOAT) + default_value = RNA_property_float_get_default_index(&ptr, prop, fcu->array_index); + } + + if (fcu->bezt->vec[1][1] == default_value) { + clear_fcurve_keys(fcu); + + /* check if curve is really unused and if it is, return signal for deletion */ + if ((list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) && + (fcu->driver == NULL)) { + AnimData *adt = ale->adt; + ANIM_fcurve_delete_from_animdata(ac, adt, fcu); + ale->key_data = NULL; + } + } + } } /* ---------------- */ /* 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 */ + 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; - - if (fcu->bezt == NULL) { - return; - } - - /* first loop through - count how many verts are selected */ - bezt = fcu->bezt; - for (i = 0; i < fcu->totvert; i++, bezt++) { - if (BEZT_ISSEL_ANY(bezt)) - totSel++; - } - - /* if any points were selected, allocate tSmooth_Bezt points to work on */ - if (totSel >= 3) { - tSmooth_Bezt *tarray, *tsb; - - /* allocate memory in one go */ - tsb = tarray = MEM_callocN(totSel * sizeof(tSmooth_Bezt), "tSmooth_Bezt Array"); - - /* populate tarray with data of selected points */ - bezt = fcu->bezt; - for (i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) { - if (BEZT_ISSEL_ANY(bezt)) { - /* tsb simply needs pointer to vec, and index */ - tsb->h1 = &bezt->vec[0][1]; - tsb->h2 = &bezt->vec[1][1]; - tsb->h3 = &bezt->vec[2][1]; - - /* advance to the next tsb to populate */ - if (x < totSel - 1) - tsb++; - else - break; - } - } - - /* calculate the new smoothed F-Curve's with weighted averages: - * - 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 smoothing deltas and new values */ - tsb = tarray; - for (i = 0; i < totSel; i++, tsb++) { - /* 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); - const tSmooth_Bezt *tN1 = tsb + 1; - const tSmooth_Bezt *tN2 = (i + 2 < totSel) ? (tsb + 2) : (NULL); - - const float p1 = *tP1->h2; - const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2); - const float c1 = *tsb->h2; - const float n1 = *tN1->h2; - const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2); - - /* 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: apply new values */ - tsb = tarray; - for (i = 0; i < totSel; i++, tsb++) { - /* don't touch end points, as their values weren'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 */ - MEM_freeN(tarray); - } - - /* recalculate handles */ - calchandles_fcurve(fcu); + BezTriple *bezt; + int i, x, totSel = 0; + + if (fcu->bezt == NULL) { + return; + } + + /* first loop through - count how many verts are selected */ + bezt = fcu->bezt; + for (i = 0; i < fcu->totvert; i++, bezt++) { + if (BEZT_ISSEL_ANY(bezt)) + totSel++; + } + + /* if any points were selected, allocate tSmooth_Bezt points to work on */ + if (totSel >= 3) { + tSmooth_Bezt *tarray, *tsb; + + /* allocate memory in one go */ + tsb = tarray = MEM_callocN(totSel * sizeof(tSmooth_Bezt), "tSmooth_Bezt Array"); + + /* populate tarray with data of selected points */ + bezt = fcu->bezt; + for (i = 0, x = 0; (i < fcu->totvert) && (x < totSel); i++, bezt++) { + if (BEZT_ISSEL_ANY(bezt)) { + /* tsb simply needs pointer to vec, and index */ + tsb->h1 = &bezt->vec[0][1]; + tsb->h2 = &bezt->vec[1][1]; + tsb->h3 = &bezt->vec[2][1]; + + /* advance to the next tsb to populate */ + if (x < totSel - 1) + tsb++; + else + break; + } + } + + /* calculate the new smoothed F-Curve's with weighted averages: + * - 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 smoothing deltas and new values */ + tsb = tarray; + for (i = 0; i < totSel; i++, tsb++) { + /* 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); + const tSmooth_Bezt *tN1 = tsb + 1; + const tSmooth_Bezt *tN2 = (i + 2 < totSel) ? (tsb + 2) : (NULL); + + const float p1 = *tP1->h2; + const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2); + const float c1 = *tsb->h2; + const float n1 = *tN1->h2; + const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2); + + /* 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: apply new values */ + tsb = tarray; + for (i = 0; i < totSel; i++, tsb++) { + /* don't touch end points, as their values weren'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 */ + MEM_freeN(tarray); + } + + /* recalculate handles */ + calchandles_fcurve(fcu); } /* ---------------- */ /* little cache for values... */ typedef struct TempFrameValCache { - float frame, val; + float frame, val; } TempFrameValCache; - /* Evaluates the curves between each selected keyframe on each frame, and keys the value */ void sample_fcurve(FCurve *fcu) { - BezTriple *bezt, *start = NULL, *end = NULL; - TempFrameValCache *value_cache, *fp; - int sfra, range; - int i, n; - - if (fcu->bezt == NULL) /* ignore baked */ - return; - - /* find selected keyframes... once pair has been found, add keyframes */ - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - /* check if selected, and which end this is */ - if (BEZT_ISSEL_ANY(bezt)) { - if (start) { - /* If next bezt is also selected, don't start sampling yet, - * but instead wait for that one to reconsider, to avoid - * changing the curve when sampling consecutive segments - * (T53229) - */ - if (i < fcu->totvert - 1) { - BezTriple *next = &fcu->bezt[i + 1]; - if (BEZT_ISSEL_ANY(next)) { - continue; - } - } - - /* set end */ - end = bezt; - - /* cache values then add keyframes using these values, as adding - * keyframes while sampling will affect the outcome... - * - only start sampling+adding from index=1, so that we don't overwrite original keyframe - */ - range = (int)(ceil(end->vec[1][0] - start->vec[1][0])); - sfra = (int)(floor(start->vec[1][0])); - - if (range) { - value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache"); - - /* sample values */ - for (n = 1, fp = value_cache; n < range && fp; n++, fp++) { - fp->frame = (float)(sfra + n); - fp->val = evaluate_fcurve(fcu, fp->frame); - } - - /* add keyframes with these, tagging as 'breakdowns' */ - for (n = 1, fp = value_cache; n < range && fp; n++, fp++) { - insert_vert_fcurve(fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, 1); - } - - /* free temp cache */ - MEM_freeN(value_cache); - - /* as we added keyframes, we need to compensate so that bezt is at the right place */ - bezt = fcu->bezt + i + range - 1; - i += (range - 1); - } - - /* the current selection island has ended, so start again from scratch */ - start = NULL; - end = NULL; - } - else { - /* just set start keyframe */ - start = bezt; - end = NULL; - } - } - } - - /* recalculate channel's handles? */ - calchandles_fcurve(fcu); + BezTriple *bezt, *start = NULL, *end = NULL; + TempFrameValCache *value_cache, *fp; + int sfra, range; + int i, n; + + if (fcu->bezt == NULL) /* ignore baked */ + return; + + /* find selected keyframes... once pair has been found, add keyframes */ + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + /* check if selected, and which end this is */ + if (BEZT_ISSEL_ANY(bezt)) { + if (start) { + /* If next bezt is also selected, don't start sampling yet, + * but instead wait for that one to reconsider, to avoid + * changing the curve when sampling consecutive segments + * (T53229) + */ + if (i < fcu->totvert - 1) { + BezTriple *next = &fcu->bezt[i + 1]; + if (BEZT_ISSEL_ANY(next)) { + continue; + } + } + + /* set end */ + end = bezt; + + /* cache values then add keyframes using these values, as adding + * keyframes while sampling will affect the outcome... + * - only start sampling+adding from index=1, so that we don't overwrite original keyframe + */ + range = (int)(ceil(end->vec[1][0] - start->vec[1][0])); + sfra = (int)(floor(start->vec[1][0])); + + if (range) { + value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache"); + + /* sample values */ + for (n = 1, fp = value_cache; n < range && fp; n++, fp++) { + fp->frame = (float)(sfra + n); + fp->val = evaluate_fcurve(fcu, fp->frame); + } + + /* add keyframes with these, tagging as 'breakdowns' */ + for (n = 1, fp = value_cache; n < range && fp; n++, fp++) { + insert_vert_fcurve(fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, 1); + } + + /* free temp cache */ + MEM_freeN(value_cache); + + /* as we added keyframes, we need to compensate so that bezt is at the right place */ + bezt = fcu->bezt + i + range - 1; + i += (range - 1); + } + + /* the current selection island has ended, so start again from scratch */ + start = NULL; + end = NULL; + } + else { + /* just set start keyframe */ + start = bezt; + end = NULL; + } + } + } + + /* recalculate channel's handles? */ + calchandles_fcurve(fcu); } /* **************************************************** */ @@ -520,46 +516,45 @@ static float animcopy_cfra = 0.0; /* datatype for use in copy/paste buffer */ typedef struct tAnimCopybufItem { - struct tAnimCopybufItem *next, *prev; + struct tAnimCopybufItem *next, *prev; - ID *id; /* ID which owns the curve */ - bActionGroup *grp; /* Action Group */ - char *rna_path; /* RNA-Path */ - int array_index; /* array index */ + ID *id; /* ID which owns the curve */ + bActionGroup *grp; /* Action Group */ + char *rna_path; /* RNA-Path */ + int array_index; /* array index */ - int totvert; /* number of keyframes stored for this channel */ - BezTriple *bezt; /* keyframes in buffer */ + int totvert; /* number of keyframes stored for this channel */ + BezTriple *bezt; /* keyframes in buffer */ - short id_type; /* Result of GS(id->name)*/ - bool is_bone; /* special flag for armature bones */ + short id_type; /* Result of GS(id->name)*/ + bool is_bone; /* special flag for armature bones */ } tAnimCopybufItem; - /* This function frees any MEM_calloc'ed copy/paste buffer data */ void ANIM_fcurves_copybuf_free(void) { - tAnimCopybufItem *aci, *acn; + tAnimCopybufItem *aci, *acn; - /* free each buffer element */ - for (aci = animcopybuf.first; aci; aci = acn) { - acn = aci->next; + /* free each buffer element */ + for (aci = animcopybuf.first; aci; aci = acn) { + acn = aci->next; - /* free keyframes */ - if (aci->bezt) - MEM_freeN(aci->bezt); + /* free keyframes */ + if (aci->bezt) + MEM_freeN(aci->bezt); - /* free RNA-path */ - if (aci->rna_path) - MEM_freeN(aci->rna_path); + /* free RNA-path */ + if (aci->rna_path) + MEM_freeN(aci->rna_path); - /* free ourself */ - BLI_freelinkN(&animcopybuf, aci); - } + /* free ourself */ + BLI_freelinkN(&animcopybuf, aci); + } - /* restore initial state */ - BLI_listbase_clear(&animcopybuf); - animcopy_firstframe = 999999999.0f; - animcopy_lastframe = -999999999.0f; + /* restore initial state */ + BLI_listbase_clear(&animcopybuf); + animcopy_firstframe = 999999999.0f; + animcopy_lastframe = -999999999.0f; } /* ------------------- */ @@ -567,468 +562,501 @@ void ANIM_fcurves_copybuf_free(void) /* This function adds data to the keyframes copy/paste buffer, freeing existing data first */ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data) { - bAnimListElem *ale; - Scene *scene = ac->scene; - - /* clear buffer first */ - ANIM_fcurves_copybuf_free(); - - /* assume that each of these is an F-Curve */ - for (ale = anim_data->first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; - tAnimCopybufItem *aci; - BezTriple *bezt, *nbezt, *newbuf; - int i; - - /* firstly, check if F-Curve has any selected keyframes - * - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data) - * - this check should also eliminate any problems associated with using sample-data - */ - if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0) - continue; - - /* init copybuf item info */ - aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem"); - aci->id = ale->id; - aci->id_type = GS(ale->id->name); - aci->grp = fcu->grp; - aci->rna_path = MEM_dupallocN(fcu->rna_path); - aci->array_index = fcu->array_index; - - /* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo. - * storing the relevant information here helps avoiding crashes if we undo-repaste */ - if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) { - Object *ob = (Object *)aci->id; - bPoseChannel *pchan; - char *bone_name; - - bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (pchan) { - aci->is_bone = true; - } - if (bone_name) MEM_freeN(bone_name); - } - - BLI_addtail(&animcopybuf, aci); - - /* add selected keyframes to buffer */ - /* TODO: currently, we resize array every time we add a new vert - - * this works ok as long as it is assumed only a few keys are copied */ - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - if (BEZT_ISSEL_ANY(bezt)) { - /* add to buffer */ - newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple"); - - /* assume that since we are just re-sizing the array, just copy all existing data across */ - if (aci->bezt) - memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert)); - - /* copy current beztriple across too */ - nbezt = &newbuf[aci->totvert]; - *nbezt = *bezt; - - /* ensure copy buffer is selected so pasted keys are selected */ - BEZT_SEL_ALL(nbezt); - - /* free old array and set the new */ - if (aci->bezt) MEM_freeN(aci->bezt); - aci->bezt = newbuf; - aci->totvert++; - - /* check if this is the earliest frame encountered so far */ - if (bezt->vec[1][0] < animcopy_firstframe) - animcopy_firstframe = bezt->vec[1][0]; - if (bezt->vec[1][0] > animcopy_lastframe) - animcopy_lastframe = bezt->vec[1][0]; - } - } - - } - - /* check if anything ended up in the buffer */ - if (ELEM(NULL, animcopybuf.first, animcopybuf.last)) - return -1; - - /* in case 'relative' paste method is used */ - animcopy_cfra = CFRA; - - /* everything went fine */ - return 0; + bAnimListElem *ale; + Scene *scene = ac->scene; + + /* clear buffer first */ + ANIM_fcurves_copybuf_free(); + + /* assume that each of these is an F-Curve */ + for (ale = anim_data->first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + tAnimCopybufItem *aci; + BezTriple *bezt, *nbezt, *newbuf; + int i; + + /* firstly, check if F-Curve has any selected keyframes + * - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data) + * - this check should also eliminate any problems associated with using sample-data + */ + if (ANIM_fcurve_keyframes_loop( + NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0) + continue; + + /* init copybuf item info */ + aci = MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem"); + aci->id = ale->id; + aci->id_type = GS(ale->id->name); + aci->grp = fcu->grp; + aci->rna_path = MEM_dupallocN(fcu->rna_path); + aci->array_index = fcu->array_index; + + /* detect if this is a bone. We do that here rather than during pasting because ID pointers will get invalidated if we undo. + * storing the relevant information here helps avoiding crashes if we undo-repaste */ + if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) { + Object *ob = (Object *)aci->id; + bPoseChannel *pchan; + char *bone_name; + + bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones["); + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (pchan) { + aci->is_bone = true; + } + if (bone_name) + MEM_freeN(bone_name); + } + + BLI_addtail(&animcopybuf, aci); + + /* add selected keyframes to buffer */ + /* TODO: currently, we resize array every time we add a new vert - + * this works ok as long as it is assumed only a few keys are copied */ + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + if (BEZT_ISSEL_ANY(bezt)) { + /* add to buffer */ + newbuf = MEM_callocN(sizeof(BezTriple) * (aci->totvert + 1), "copybuf beztriple"); + + /* assume that since we are just re-sizing the array, just copy all existing data across */ + if (aci->bezt) + memcpy(newbuf, aci->bezt, sizeof(BezTriple) * (aci->totvert)); + + /* copy current beztriple across too */ + nbezt = &newbuf[aci->totvert]; + *nbezt = *bezt; + + /* ensure copy buffer is selected so pasted keys are selected */ + BEZT_SEL_ALL(nbezt); + + /* free old array and set the new */ + if (aci->bezt) + MEM_freeN(aci->bezt); + aci->bezt = newbuf; + aci->totvert++; + + /* check if this is the earliest frame encountered so far */ + if (bezt->vec[1][0] < animcopy_firstframe) + animcopy_firstframe = bezt->vec[1][0]; + if (bezt->vec[1][0] > animcopy_lastframe) + animcopy_lastframe = bezt->vec[1][0]; + } + } + } + + /* check if anything ended up in the buffer */ + if (ELEM(NULL, animcopybuf.first, animcopybuf.last)) + return -1; + + /* in case 'relative' paste method is used */ + animcopy_cfra = CFRA; + + /* everything went fine */ + return 0; } static void flip_names(tAnimCopybufItem *aci, char **name) { - if (aci->is_bone) { - char *str_start; - if ((str_start = strstr(aci->rna_path, "pose.bones["))) { - /* ninja coding, try to change the name */ - char bname_new[MAX_VGROUP_NAME]; - char *str_iter, *str_end; - int length, prefix_l, postfix_l; - - str_start += 12; - prefix_l = str_start - aci->rna_path; - - str_end = strchr(str_start, '\"'); - - length = str_end - str_start; - postfix_l = strlen(str_end); - - /* more ninja stuff, temporary substitute with NULL terminator */ - str_start[length] = 0; - BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new)); - str_start[length] = '\"'; - - str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path"); - - BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1); - str_iter += prefix_l; - BLI_strncpy(str_iter, bname_new, length + 1); - str_iter += length; - BLI_strncpy(str_iter, str_end, postfix_l + 1); - str_iter[postfix_l] = '\0'; - } - } + if (aci->is_bone) { + char *str_start; + if ((str_start = strstr(aci->rna_path, "pose.bones["))) { + /* ninja coding, try to change the name */ + char bname_new[MAX_VGROUP_NAME]; + char *str_iter, *str_end; + int length, prefix_l, postfix_l; + + str_start += 12; + prefix_l = str_start - aci->rna_path; + + str_end = strchr(str_start, '\"'); + + length = str_end - str_start; + postfix_l = strlen(str_end); + + /* more ninja stuff, temporary substitute with NULL terminator */ + str_start[length] = 0; + BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new)); + str_start[length] = '\"'; + + str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), + "flipped_path"); + + BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1); + str_iter += prefix_l; + BLI_strncpy(str_iter, bname_new, length + 1); + str_iter += length; + BLI_strncpy(str_iter, str_end, postfix_l + 1); + str_iter[postfix_l] = '\0'; + } + } } /* ------------------- */ /* most strict method: exact matches only */ -static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple, bool flip) +static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, + const short from_single, + const short to_simple, + bool flip) { - tAnimCopybufItem *aci; - - for (aci = animcopybuf.first; aci; aci = aci->next) { - if (to_simple || (aci->rna_path && fcu->rna_path)) { - if (!to_simple && flip && aci->is_bone && fcu->rna_path) { - if ((from_single) || (aci->array_index == fcu->array_index)) { - char *name = NULL; - flip_names(aci, &name); - if (STREQ(name, fcu->rna_path)) { - MEM_freeN(name); - break; - } - MEM_freeN(name); - } - } - else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) { - if ((from_single) || (aci->array_index == fcu->array_index)) { - break; - } - } - } - } - - return aci; + tAnimCopybufItem *aci; + + for (aci = animcopybuf.first; aci; aci = aci->next) { + if (to_simple || (aci->rna_path && fcu->rna_path)) { + if (!to_simple && flip && aci->is_bone && fcu->rna_path) { + if ((from_single) || (aci->array_index == fcu->array_index)) { + char *name = NULL; + flip_names(aci, &name); + if (STREQ(name, fcu->rna_path)) { + MEM_freeN(name); + break; + } + MEM_freeN(name); + } + } + else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) { + if ((from_single) || (aci->array_index == fcu->array_index)) { + break; + } + } + } + } + + return aci; } /* medium match strictness: path match only (i.e. ignore ID) */ -static tAnimCopybufItem *pastebuf_match_path_property( - Main *bmain, FCurve *fcu, const short from_single, const short UNUSED(to_simple)) +static tAnimCopybufItem *pastebuf_match_path_property(Main *bmain, + FCurve *fcu, + const short from_single, + const short UNUSED(to_simple)) { - tAnimCopybufItem *aci; - - for (aci = animcopybuf.first; aci; aci = aci->next) { - /* check that paths exist */ - if (aci->rna_path && fcu->rna_path) { - /* find the property of the fcurve and compare against the end of the tAnimCopybufItem - * more involved since it needs to do path lookups. - * This is not 100% reliable since the user could be editing the curves on a path that wont - * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste - * this should work out ok. - */ - if (BLI_findindex(which_libbase(bmain, aci->id_type), aci->id) == -1) { - /* pedantic but the ID could have been removed, and beats crashing! */ - printf("paste_animedit_keys: error ID has been removed!\n"); - } - else { - PointerRNA id_ptr, rptr; - PropertyRNA *prop; - - RNA_id_pointer_create(aci->id, &id_ptr); - - if (RNA_path_resolve_property(&id_ptr, aci->rna_path, &rptr, &prop)) { - const char *identifier = RNA_property_identifier(prop); - int len_id = strlen(identifier); - int len_path = strlen(fcu->rna_path); - if (len_id <= len_path) { - /* note, paths which end with "] will fail with this test - Animated ID Props */ - if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) { - if ((from_single) || (aci->array_index == fcu->array_index)) - break; - } - } - } - else { - printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path); - } - } - } - } - - return aci; + tAnimCopybufItem *aci; + + for (aci = animcopybuf.first; aci; aci = aci->next) { + /* check that paths exist */ + if (aci->rna_path && fcu->rna_path) { + /* find the property of the fcurve and compare against the end of the tAnimCopybufItem + * more involved since it needs to do path lookups. + * This is not 100% reliable since the user could be editing the curves on a path that wont + * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste + * this should work out ok. + */ + if (BLI_findindex(which_libbase(bmain, aci->id_type), aci->id) == -1) { + /* pedantic but the ID could have been removed, and beats crashing! */ + printf("paste_animedit_keys: error ID has been removed!\n"); + } + else { + PointerRNA id_ptr, rptr; + PropertyRNA *prop; + + RNA_id_pointer_create(aci->id, &id_ptr); + + if (RNA_path_resolve_property(&id_ptr, aci->rna_path, &rptr, &prop)) { + const char *identifier = RNA_property_identifier(prop); + int len_id = strlen(identifier); + int len_path = strlen(fcu->rna_path); + if (len_id <= len_path) { + /* note, paths which end with "] will fail with this test - Animated ID Props */ + if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) { + if ((from_single) || (aci->array_index == fcu->array_index)) + break; + } + } + } + else { + printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", + aci->id->name, + aci->rna_path); + } + } + } + } + + return aci; } /* least strict matching heuristic: indices only */ -static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) +static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, + const short from_single, + const short UNUSED(to_simple)) { - tAnimCopybufItem *aci; + tAnimCopybufItem *aci; - for (aci = animcopybuf.first; aci; aci = aci->next) { - /* check that paths exist */ - if ((from_single) || (aci->array_index == fcu->array_index)) { - break; - } - } + for (aci = animcopybuf.first; aci; aci = aci->next) { + /* check that paths exist */ + if ((from_single) || (aci->array_index == fcu->array_index)) { + break; + } + } - return aci; + return aci; } /* ................ */ static void do_curve_mirror_flippping(tAnimCopybufItem *aci, BezTriple *bezt) { - if (aci->is_bone) { - const size_t slength = strlen(aci->rna_path); - bool flip = false; - if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0) - flip = true; - else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) && ELEM(aci->array_index, 2, 3)) - flip = true; - else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) && ELEM(aci->array_index, 1, 2)) - flip = true; - else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) && ELEM(aci->array_index, 2, 3)) - flip = true; - - if (flip) { - bezt->vec[0][1] = -bezt->vec[0][1]; - bezt->vec[1][1] = -bezt->vec[1][1]; - bezt->vec[2][1] = -bezt->vec[2][1]; - } - } + if (aci->is_bone) { + const size_t slength = strlen(aci->rna_path); + bool flip = false; + if (BLI_strn_endswith(aci->rna_path, "location", slength) && aci->array_index == 0) + flip = true; + else if (BLI_strn_endswith(aci->rna_path, "rotation_quaternion", slength) && + ELEM(aci->array_index, 2, 3)) + flip = true; + else if (BLI_strn_endswith(aci->rna_path, "rotation_euler", slength) && + ELEM(aci->array_index, 1, 2)) + flip = true; + else if (BLI_strn_endswith(aci->rna_path, "rotation_axis_angle", slength) && + ELEM(aci->array_index, 2, 3)) + flip = true; + + if (flip) { + bezt->vec[0][1] = -bezt->vec[0][1]; + bezt->vec[1][1] = -bezt->vec[1][1]; + bezt->vec[2][1] = -bezt->vec[2][1]; + } + } } /* helper for paste_animedit_keys() - performs the actual pasting */ -static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip) +static void paste_animedit_keys_fcurve( + FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode, bool flip) { - BezTriple *bezt; - int i; - - /* First de-select existing FCurve's keyframes */ - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - BEZT_DESEL_ALL(bezt); - } - - /* mix mode with existing data */ - switch (merge_mode) { - case KEYFRAME_PASTE_MERGE_MIX: - /* do-nothing */ - break; - - case KEYFRAME_PASTE_MERGE_OVER: - /* remove all keys */ - clear_fcurve_keys(fcu); - break; - - case KEYFRAME_PASTE_MERGE_OVER_RANGE: - case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL: - { - float f_min; - float f_max; - - if (merge_mode == KEYFRAME_PASTE_MERGE_OVER_RANGE) { - f_min = aci->bezt[0].vec[1][0] + offset; - f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset; - } - else { /* Entire Range */ - f_min = animcopy_firstframe + offset; - f_max = animcopy_lastframe + offset; - } - - /* remove keys in range */ - if (f_min < f_max) { - /* select verts in range for removal */ - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) { - bezt->f2 |= SELECT; - } - } - - /* remove frames in the range */ - delete_fcurve_keys(fcu); - } - break; - } - } - - /* just start pasting, with the first keyframe on the current frame, and so on */ - for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) { - /* temporarily apply offset to src beztriple while copying */ - if (flip) - do_curve_mirror_flippping(aci, bezt); - - bezt->vec[0][0] += offset; - bezt->vec[1][0] += offset; - bezt->vec[2][0] += offset; - - /* insert the keyframe - * NOTE: we do not want to inherit handles from existing keyframes in this case! - */ - - insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL); - - /* un-apply offset from src beztriple after copying */ - bezt->vec[0][0] -= offset; - bezt->vec[1][0] -= offset; - bezt->vec[2][0] -= offset; - - if (flip) - do_curve_mirror_flippping(aci, bezt); - } - - /* recalculate F-Curve's handles? */ - calchandles_fcurve(fcu); + BezTriple *bezt; + int i; + + /* First de-select existing FCurve's keyframes */ + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + BEZT_DESEL_ALL(bezt); + } + + /* mix mode with existing data */ + switch (merge_mode) { + case KEYFRAME_PASTE_MERGE_MIX: + /* do-nothing */ + break; + + case KEYFRAME_PASTE_MERGE_OVER: + /* remove all keys */ + clear_fcurve_keys(fcu); + break; + + case KEYFRAME_PASTE_MERGE_OVER_RANGE: + case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL: { + float f_min; + float f_max; + + if (merge_mode == KEYFRAME_PASTE_MERGE_OVER_RANGE) { + f_min = aci->bezt[0].vec[1][0] + offset; + f_max = aci->bezt[aci->totvert - 1].vec[1][0] + offset; + } + else { /* Entire Range */ + f_min = animcopy_firstframe + offset; + f_max = animcopy_lastframe + offset; + } + + /* remove keys in range */ + if (f_min < f_max) { + /* select verts in range for removal */ + for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { + if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) { + bezt->f2 |= SELECT; + } + } + + /* remove frames in the range */ + delete_fcurve_keys(fcu); + } + break; + } + } + + /* just start pasting, with the first keyframe on the current frame, and so on */ + for (i = 0, bezt = aci->bezt; i < aci->totvert; i++, bezt++) { + /* temporarily apply offset to src beztriple while copying */ + if (flip) + do_curve_mirror_flippping(aci, bezt); + + bezt->vec[0][0] += offset; + bezt->vec[1][0] += offset; + bezt->vec[2][0] += offset; + + /* insert the keyframe + * NOTE: we do not want to inherit handles from existing keyframes in this case! + */ + + insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL); + + /* un-apply offset from src beztriple after copying */ + bezt->vec[0][0] -= offset; + bezt->vec[1][0] -= offset; + bezt->vec[2][0] -= offset; + + if (flip) + do_curve_mirror_flippping(aci, bezt); + } + + /* recalculate F-Curve's handles? */ + calchandles_fcurve(fcu); } /* ------------------- */ const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = { - {KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"}, - {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"}, - {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"}, - {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"}, - {0, NULL, 0, NULL, NULL}, + {KEYFRAME_PASTE_OFFSET_CFRA_START, + "START", + 0, + "Frame Start", + "Paste keys starting at current frame"}, + {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"}, + {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, + "RELATIVE", + 0, + "Frame Relative", + "Paste keys relative to the current frame when copying"}, + {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"}, + {0, NULL, 0, NULL, NULL}, }; const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = { - {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"}, - {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"}, - {KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"}, - {KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL, "OVER_RANGE_ALL", 0, "Overwrite Entire Range", "Overwrite keys in pasted range, using the range of all copied keys"}, - {0, NULL, 0, NULL, NULL}, + {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"}, + {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"}, + {KEYFRAME_PASTE_MERGE_OVER_RANGE, + "OVER_RANGE", + 0, + "Overwrite Range", + "Overwrite keys in pasted range"}, + {KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL, + "OVER_RANGE_ALL", + 0, + "Overwrite Entire Range", + "Overwrite keys in pasted range, using the range of all copied keys"}, + {0, NULL, 0, NULL, NULL}, }; - /** * This function pastes data from the keyframes copy/paste buffer * * \return Status code is whether the method FAILED to do anything */ -short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data, - const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip) +short paste_animedit_keys(bAnimContext *ac, + ListBase *anim_data, + const eKeyPasteOffset offset_mode, + const eKeyMergeMode merge_mode, + bool flip) { - bAnimListElem *ale; - - const Scene *scene = (ac->scene); - - const bool from_single = BLI_listbase_is_single(&animcopybuf); - const bool to_simple = BLI_listbase_is_single(anim_data); - - float offset = 0.0f; - int pass; - - /* check if buffer is empty */ - if (BLI_listbase_is_empty(&animcopybuf)) { - BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste"); - return -1; - } - - if (BLI_listbase_is_empty(anim_data)) { - BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into"); - return -1; - } - - /* methods of offset */ - switch (offset_mode) { - case KEYFRAME_PASTE_OFFSET_CFRA_START: - offset = (float)(CFRA - animcopy_firstframe); - break; - case KEYFRAME_PASTE_OFFSET_CFRA_END: - offset = (float)(CFRA - animcopy_lastframe); - break; - case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE: - offset = (float)(CFRA - animcopy_cfra); - break; - case KEYFRAME_PASTE_OFFSET_NONE: - offset = 0.0f; - break; - } - - if (from_single && to_simple) { - /* 1:1 match, no tricky checking, just paste */ - FCurve *fcu; - tAnimCopybufItem *aci; - - ale = anim_data->first; - fcu = (FCurve *)ale->data; /* destination F-Curve */ - aci = animcopybuf.first; - - paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false); - ale->update |= ANIM_UPDATE_DEFAULT; - } - else { - /* from selected channels - * This "passes" system aims to try to find "matching" channels to paste keyframes - * into with increasingly loose matching heuristics. The process finishes when at least - * one F-Curve has been pasted into. - */ - for (pass = 0; pass < 3; pass++) { - unsigned int totmatch = 0; - - for (ale = anim_data->first; ale; ale = ale->next) { - /* find buffer item to paste from - * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group - * - if names do matter, only check if id-type is ok for now (group check is not that important) - * - most importantly, rna-paths should match (array indices are unimportant for now) - */ - AnimData *adt = ANIM_nla_mapping_get(ac, ale); - FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */ - tAnimCopybufItem *aci = NULL; - - switch (pass) { - case 0: - /* most strict, must be exact path match data_path & index */ - aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip); - break; - - case 1: - /* less strict, just compare property names */ - aci = pastebuf_match_path_property(ac->bmain, fcu, from_single, to_simple); - break; - - case 2: - /* Comparing properties gave no results, so just do index comparisons */ - aci = pastebuf_match_index_only(fcu, from_single, to_simple); - break; - } - - /* copy the relevant data from the matching buffer curve */ - if (aci) { - totmatch++; - - if (adt) { - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); - paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip); - ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); - } - else { - paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip); - } - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - /* don't continue if some fcurves were pasted */ - if (totmatch) - break; - } - } - - ANIM_animdata_update(ac, anim_data); - - return 0; + bAnimListElem *ale; + + const Scene *scene = (ac->scene); + + const bool from_single = BLI_listbase_is_single(&animcopybuf); + const bool to_simple = BLI_listbase_is_single(anim_data); + + float offset = 0.0f; + int pass; + + /* check if buffer is empty */ + if (BLI_listbase_is_empty(&animcopybuf)) { + BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste"); + return -1; + } + + if (BLI_listbase_is_empty(anim_data)) { + BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into"); + return -1; + } + + /* methods of offset */ + switch (offset_mode) { + case KEYFRAME_PASTE_OFFSET_CFRA_START: + offset = (float)(CFRA - animcopy_firstframe); + break; + case KEYFRAME_PASTE_OFFSET_CFRA_END: + offset = (float)(CFRA - animcopy_lastframe); + break; + case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE: + offset = (float)(CFRA - animcopy_cfra); + break; + case KEYFRAME_PASTE_OFFSET_NONE: + offset = 0.0f; + break; + } + + if (from_single && to_simple) { + /* 1:1 match, no tricky checking, just paste */ + FCurve *fcu; + tAnimCopybufItem *aci; + + ale = anim_data->first; + fcu = (FCurve *)ale->data; /* destination F-Curve */ + aci = animcopybuf.first; + + paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false); + ale->update |= ANIM_UPDATE_DEFAULT; + } + else { + /* from selected channels + * This "passes" system aims to try to find "matching" channels to paste keyframes + * into with increasingly loose matching heuristics. The process finishes when at least + * one F-Curve has been pasted into. + */ + for (pass = 0; pass < 3; pass++) { + unsigned int totmatch = 0; + + for (ale = anim_data->first; ale; ale = ale->next) { + /* find buffer item to paste from + * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group + * - if names do matter, only check if id-type is ok for now (group check is not that important) + * - most importantly, rna-paths should match (array indices are unimportant for now) + */ + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */ + tAnimCopybufItem *aci = NULL; + + switch (pass) { + case 0: + /* most strict, must be exact path match data_path & index */ + aci = pastebuf_match_path_full(fcu, from_single, to_simple, flip); + break; + + case 1: + /* less strict, just compare property names */ + aci = pastebuf_match_path_property(ac->bmain, fcu, from_single, to_simple); + break; + + case 2: + /* Comparing properties gave no results, so just do index comparisons */ + aci = pastebuf_match_index_only(fcu, from_single, to_simple); + break; + } + + /* copy the relevant data from the matching buffer curve */ + if (aci) { + totmatch++; + + if (adt) { + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); + paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip); + ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); + } + else { + paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip); + } + } + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + /* don't continue if some fcurves were pasted */ + if (totmatch) + break; + } + } + + ANIM_animdata_update(ac, anim_data); + + return 0; } /* **************************************************** */ diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 793a73e6939..cc8dbbca439 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include #include @@ -80,7 +79,9 @@ #include "anim_intern.h" -static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *prop, Scene *scene); +static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, + PropertyRNA *prop, + Scene *scene); /* ************************************************** */ /* Keyframing Setting Wrangling */ @@ -88,35 +89,35 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA * /* Get the active settings for keyframing settings from context (specifically the given scene) */ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode) { - eInsertKeyFlags flag = INSERTKEY_NOFLAGS; - - /* standard flags */ - { - /* visual keying */ - if (IS_AUTOKEY_FLAG(scene, AUTOMATKEY)) - flag |= INSERTKEY_MATRIX; - - /* only needed */ - if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) - flag |= INSERTKEY_NEEDED; - - /* default F-Curve color mode - RGB from XYZ indices */ - if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) - flag |= INSERTKEY_XYZ2RGB; - } - - /* only if including settings from the autokeying mode... */ - if (incl_mode) { - /* keyframing mode - only replace existing keyframes */ - if (IS_AUTOKEY_MODE(scene, EDITKEYS)) - flag |= INSERTKEY_REPLACE; - - /* cycle-aware keyframe insertion - preserve cycle period and flow */ - if (IS_AUTOKEY_FLAG(scene, CYCLEAWARE)) - flag |= INSERTKEY_CYCLE_AWARE; - } - - return flag; + eInsertKeyFlags flag = INSERTKEY_NOFLAGS; + + /* standard flags */ + { + /* visual keying */ + if (IS_AUTOKEY_FLAG(scene, AUTOMATKEY)) + flag |= INSERTKEY_MATRIX; + + /* only needed */ + if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) + flag |= INSERTKEY_NEEDED; + + /* default F-Curve color mode - RGB from XYZ indices */ + if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) + flag |= INSERTKEY_XYZ2RGB; + } + + /* only if including settings from the autokeying mode... */ + if (incl_mode) { + /* keyframing mode - only replace existing keyframes */ + if (IS_AUTOKEY_MODE(scene, EDITKEYS)) + flag |= INSERTKEY_REPLACE; + + /* cycle-aware keyframe insertion - preserve cycle period and flow */ + if (IS_AUTOKEY_FLAG(scene, CYCLEAWARE)) + flag |= INSERTKEY_CYCLE_AWARE; + } + + return flag; } /* ******************************************* */ @@ -127,140 +128,145 @@ short ANIM_get_keyframing_flags(Scene *scene, short incl_mode) */ bAction *verify_adt_action(Main *bmain, ID *id, short add) { - AnimData *adt; - - /* init animdata if none available yet */ - adt = BKE_animdata_from_id(id); - if ((adt == NULL) && (add)) - adt = BKE_animdata_add_id(id); - if (adt == NULL) { - /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ - printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : ""); - return NULL; - } - - /* init action if none available yet */ - /* TODO: need some wizardry to handle NLA stuff correct */ - if ((adt->action == NULL) && (add)) { - /* init action name from name of ID block */ - char actname[sizeof(id->name) - 2]; - BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); - - /* create action */ - adt->action = BKE_action_add(bmain, actname); - - /* set ID-type from ID-block that this is going to be assigned to - * so that users can't accidentally break actions by assigning them - * to the wrong places - */ - adt->action->idroot = GS(id->name); - - /* Tag depsgraph to be rebuilt to include time dependency. */ - DEG_relations_tag_update(bmain); - } - - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - - /* return the action */ - return adt->action; + AnimData *adt; + + /* init animdata if none available yet */ + adt = BKE_animdata_from_id(id); + if ((adt == NULL) && (add)) + adt = BKE_animdata_add_id(id); + if (adt == NULL) { + /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */ + printf("ERROR: Couldn't add AnimData (ID = %s)\n", (id) ? (id->name) : ""); + return NULL; + } + + /* init action if none available yet */ + /* TODO: need some wizardry to handle NLA stuff correct */ + if ((adt->action == NULL) && (add)) { + /* init action name from name of ID block */ + char actname[sizeof(id->name) - 2]; + BLI_snprintf(actname, sizeof(actname), "%sAction", id->name + 2); + + /* create action */ + adt->action = BKE_action_add(bmain, actname); + + /* set ID-type from ID-block that this is going to be assigned to + * so that users can't accidentally break actions by assigning them + * to the wrong places + */ + adt->action->idroot = GS(id->name); + + /* Tag depsgraph to be rebuilt to include time dependency. */ + DEG_relations_tag_update(bmain); + } + + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + + /* return the action */ + return adt->action; } /* Get (or add relevant data to be able to do so) F-Curve from the Active Action, * for the given Animation Data block. This assumes that all the destinations are valid. */ -FCurve *verify_fcurve(Main *bmain, bAction *act, const char group[], PointerRNA *ptr, - const char rna_path[], const int array_index, short add) +FCurve *verify_fcurve(Main *bmain, + bAction *act, + const char group[], + PointerRNA *ptr, + const char rna_path[], + const int array_index, + short add) { - bActionGroup *agrp; - FCurve *fcu; - - /* sanity checks */ - if (ELEM(NULL, act, rna_path)) - return NULL; - - /* try to find f-curve matching for this setting - * - add if not found and allowed to add one - * TODO: add auto-grouping support? how this works will need to be resolved - */ - fcu = list_find_fcurve(&act->curves, rna_path, array_index); - - if ((fcu == NULL) && (add)) { - /* use default settings to make a F-Curve */ - fcu = MEM_callocN(sizeof(FCurve), "FCurve"); - - fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); - fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; - if (BLI_listbase_is_empty(&act->curves)) - fcu->flag |= FCURVE_ACTIVE; /* first one added active */ - - /* store path - make copy, and store that */ - fcu->rna_path = BLI_strdup(rna_path); - fcu->array_index = array_index; - - /* if a group name has been provided, try to add or find a group, then add F-Curve to it */ - if (group) { - /* try to find group */ - agrp = BKE_action_group_find_name(act, group); - - /* no matching groups, so add one */ - if (agrp == NULL) { - agrp = action_groups_add_new(act, group); - - /* sync bone group colors if applicable */ - if (ptr && (ptr->type == &RNA_PoseBone)) { - Object *ob = (Object *)ptr->id.data; - bPoseChannel *pchan = (bPoseChannel *)ptr->data; - bPose *pose = ob->pose; - bActionGroup *grp; - - /* find bone group (if present), and use the color from that */ - grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1)); - if (grp) { - agrp->customCol = grp->customCol; - action_group_colors_sync(agrp, grp); - } - } - } - - /* add F-Curve to group */ - action_groups_add_channel(act, agrp, fcu); - } - else { - /* just add F-Curve to end of Action's list */ - BLI_addtail(&act->curves, fcu); - } - - /* New f-curve was added, meaning it's possible that it affects - * dependency graph component which wasn't previously animated. - */ - DEG_relations_tag_update(bmain); - } - - /* return the F-Curve */ - return fcu; + bActionGroup *agrp; + FCurve *fcu; + + /* sanity checks */ + if (ELEM(NULL, act, rna_path)) + return NULL; + + /* try to find f-curve matching for this setting + * - add if not found and allowed to add one + * TODO: add auto-grouping support? how this works will need to be resolved + */ + fcu = list_find_fcurve(&act->curves, rna_path, array_index); + + if ((fcu == NULL) && (add)) { + /* use default settings to make a F-Curve */ + fcu = MEM_callocN(sizeof(FCurve), "FCurve"); + + fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED); + fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL; + if (BLI_listbase_is_empty(&act->curves)) + fcu->flag |= FCURVE_ACTIVE; /* first one added active */ + + /* store path - make copy, and store that */ + fcu->rna_path = BLI_strdup(rna_path); + fcu->array_index = array_index; + + /* if a group name has been provided, try to add or find a group, then add F-Curve to it */ + if (group) { + /* try to find group */ + agrp = BKE_action_group_find_name(act, group); + + /* no matching groups, so add one */ + if (agrp == NULL) { + agrp = action_groups_add_new(act, group); + + /* sync bone group colors if applicable */ + if (ptr && (ptr->type == &RNA_PoseBone)) { + Object *ob = (Object *)ptr->id.data; + bPoseChannel *pchan = (bPoseChannel *)ptr->data; + bPose *pose = ob->pose; + bActionGroup *grp; + + /* find bone group (if present), and use the color from that */ + grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1)); + if (grp) { + agrp->customCol = grp->customCol; + action_group_colors_sync(agrp, grp); + } + } + } + + /* add F-Curve to group */ + action_groups_add_channel(act, agrp, fcu); + } + else { + /* just add F-Curve to end of Action's list */ + BLI_addtail(&act->curves, fcu); + } + + /* New f-curve was added, meaning it's possible that it affects + * dependency graph component which wasn't previously animated. + */ + DEG_relations_tag_update(bmain); + } + + /* return the F-Curve */ + return fcu; } /* Helper for update_autoflags_fcurve() */ static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop) { - /* set additional flags for the F-Curve (i.e. only integer values) */ - fcu->flag &= ~(FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES); - switch (RNA_property_type(prop)) { - case PROP_FLOAT: - /* do nothing */ - break; - case PROP_INT: - /* do integer (only 'whole' numbers) interpolation between all points */ - fcu->flag |= FCURVE_INT_VALUES; - break; - default: - /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate - * values at all) interpolation between all points - * - however, we must also ensure that evaluated values are only integers still - */ - fcu->flag |= (FCURVE_DISCRETE_VALUES | FCURVE_INT_VALUES); - break; - } + /* set additional flags for the F-Curve (i.e. only integer values) */ + fcu->flag &= ~(FCURVE_INT_VALUES | FCURVE_DISCRETE_VALUES); + switch (RNA_property_type(prop)) { + case PROP_FLOAT: + /* do nothing */ + break; + case PROP_INT: + /* do integer (only 'whole' numbers) interpolation between all points */ + fcu->flag |= FCURVE_INT_VALUES; + break; + default: + /* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate + * values at all) interpolation between all points + * - however, we must also ensure that evaluated values are only integers still + */ + fcu->flag |= (FCURVE_DISCRETE_VALUES | FCURVE_INT_VALUES); + break; + } } /* Update integer/discrete flags of the FCurve (used when creating/inserting keyframes, @@ -268,34 +274,36 @@ static void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop) */ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, PointerRNA *ptr) { - PointerRNA tmp_ptr; - PropertyRNA *prop; - int old_flag = fcu->flag; - - if ((ptr->id.data == NULL) && (ptr->data == NULL)) { - BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for this fcurve"); - return; - } - - /* try to get property we should be affecting */ - if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { - /* property not found... */ - const char *idname = (ptr->id.data) ? ((ID *)ptr->id.data)->name : TIP_(""); - - BKE_reportf(reports, RPT_ERROR, - "Could not update flags for this fcurve, as RNA path is invalid for the given ID " - "(ID = %s, path = %s)", - idname, fcu->rna_path); - return; - } - - /* update F-Curve flags */ - update_autoflags_fcurve_direct(fcu, prop); - - if (old_flag != fcu->flag) { - /* Same as if keyframes had been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); - } + PointerRNA tmp_ptr; + PropertyRNA *prop; + int old_flag = fcu->flag; + + if ((ptr->id.data == NULL) && (ptr->data == NULL)) { + BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for this fcurve"); + return; + } + + /* try to get property we should be affecting */ + if (RNA_path_resolve_property(ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { + /* property not found... */ + const char *idname = (ptr->id.data) ? ((ID *)ptr->id.data)->name : TIP_(""); + + BKE_reportf(reports, + RPT_ERROR, + "Could not update flags for this fcurve, as RNA path is invalid for the given ID " + "(ID = %s, path = %s)", + idname, + fcu->rna_path); + return; + } + + /* update F-Curve flags */ + update_autoflags_fcurve_direct(fcu, prop); + + if (old_flag != fcu->flag) { + /* Same as if keyframes had been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + } } /* ************************************************** */ @@ -306,40 +314,40 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin */ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, float *py) { - if (fcu->totvert < 2 || !fcu->bezt) { - return FCU_CYCLE_NONE; - } + if (fcu->totvert < 2 || !fcu->bezt) { + return FCU_CYCLE_NONE; + } - eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu); + eFCU_Cycle_Type type = BKE_fcurve_get_cycle_type(fcu); - if (type == FCU_CYCLE_NONE) { - return FCU_CYCLE_NONE; - } + if (type == FCU_CYCLE_NONE) { + return FCU_CYCLE_NONE; + } - BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1]; - float start = first->vec[1][0], end = last->vec[1][0]; + BezTriple *first = &fcu->bezt[0], *last = &fcu->bezt[fcu->totvert - 1]; + float start = first->vec[1][0], end = last->vec[1][0]; - if (start >= end) { - return FCU_CYCLE_NONE; - } + if (start >= end) { + return FCU_CYCLE_NONE; + } - if (*px < start || *px > end) { - float period = end - start; - float step = floorf((*px - start) / period); - *px -= step * period; + if (*px < start || *px > end) { + float period = end - start; + float step = floorf((*px - start) / period); + *px -= step * period; - if (type == FCU_CYCLE_OFFSET) { - /* Nasty check to handle the case when the modes are different better. */ - FMod_Cycles *data = ((FModifier *)fcu->modifiers.first)->data; - short mode = (step >= 0) ? data->after_mode : data->before_mode; + if (type == FCU_CYCLE_OFFSET) { + /* Nasty check to handle the case when the modes are different better. */ + FMod_Cycles *data = ((FModifier *)fcu->modifiers.first)->data; + short mode = (step >= 0) ? data->after_mode : data->before_mode; - if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { - *py -= step * (last->vec[1][1] - first->vec[1][1]); - } - } - } + if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { + *py -= step * (last->vec[1][1] - first->vec[1][1]); + } + } + } - return type; + return type; } /* -------------- BezTriple Insertion -------------------- */ @@ -347,19 +355,19 @@ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, fl /* Change the Y position of a keyframe to match the input, adjusting handles. */ static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt) { - /* just change the values when replacing, so as to not overwrite handles */ - float dy = bezt->vec[1][1] - dst->vec[1][1]; + /* just change the values when replacing, so as to not overwrite handles */ + float dy = bezt->vec[1][1] - dst->vec[1][1]; - /* just apply delta value change to the handle values */ - dst->vec[0][1] += dy; - dst->vec[1][1] += dy; - dst->vec[2][1] += dy; + /* just apply delta value change to the handle values */ + dst->vec[0][1] += dy; + dst->vec[1][1] += dy; + dst->vec[2][1] += dy; - dst->f1 = bezt->f1; - dst->f2 = bezt->f2; - dst->f3 = bezt->f3; + dst->f1 = bezt->f1; + dst->f2 = bezt->f2; + dst->f3 = bezt->f3; - /* TODO: perform some other operations? */ + /* TODO: perform some other operations? */ } /* This function adds a given BezTriple to an F-Curve. It will allocate @@ -371,81 +379,81 @@ static void replace_bezt_keyframe_ypos(BezTriple *dst, const BezTriple *bezt) */ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag) { - int i = 0; - - /* are there already keyframes? */ - if (fcu->bezt) { - bool replace; - i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace); - - /* replace an existing keyframe? */ - if (replace) { - /* sanity check: 'i' may in rare cases exceed arraylen */ - if ((i >= 0) && (i < fcu->totvert)) { - if (flag & INSERTKEY_OVERWRITE_FULL) { - fcu->bezt[i] = *bezt; - } - else { - replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt); - } - - if (flag & INSERTKEY_CYCLE_AWARE) { - /* If replacing an end point of a cyclic curve without offset, modify the other end too. */ - if ((i == 0 || i == fcu->totvert - 1) && BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT) { - replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt); - } - } - } - } - /* keyframing modes allow to not replace keyframe */ - else if ((flag & INSERTKEY_REPLACE) == 0) { - /* insert new - if we're not restricted to replacing keyframes only */ - BezTriple *newb = MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple"); - - /* add the beztriples that should occur before the beztriple to be pasted (originally in fcu) */ - if (i > 0) - memcpy(newb, fcu->bezt, i * sizeof(BezTriple)); - - /* add beztriple to paste at index i */ - *(newb + i) = *bezt; - - /* add the beztriples that occur after the beztriple to be pasted (originally in fcu) */ - if (i < fcu->totvert) - memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple)); - - /* replace (+ free) old with new, only if necessary to do so */ - MEM_freeN(fcu->bezt); - fcu->bezt = newb; - - fcu->totvert++; - } - else { - return -1; - } - } - /* no keyframes already, but can only add if... - * 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know - * 2) there are no samples on the curve - * // NOTE: maybe we may want to allow this later when doing samples -> bezt conversions, - * // but for now, having both is asking for trouble - */ - else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == NULL)) { - /* create new keyframes array */ - fcu->bezt = MEM_callocN(sizeof(BezTriple), "beztriple"); - *(fcu->bezt) = *bezt; - fcu->totvert = 1; - } - /* cannot add anything */ - else { - /* return error code -1 to prevent any misunderstandings */ - return -1; - } - - - /* we need to return the index, so that some tools which do post-processing can - * detect where we added the BezTriple in the array - */ - return i; + int i = 0; + + /* are there already keyframes? */ + if (fcu->bezt) { + bool replace; + i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace); + + /* replace an existing keyframe? */ + if (replace) { + /* sanity check: 'i' may in rare cases exceed arraylen */ + if ((i >= 0) && (i < fcu->totvert)) { + if (flag & INSERTKEY_OVERWRITE_FULL) { + fcu->bezt[i] = *bezt; + } + else { + replace_bezt_keyframe_ypos(&fcu->bezt[i], bezt); + } + + if (flag & INSERTKEY_CYCLE_AWARE) { + /* If replacing an end point of a cyclic curve without offset, modify the other end too. */ + if ((i == 0 || i == fcu->totvert - 1) && + BKE_fcurve_get_cycle_type(fcu) == FCU_CYCLE_PERFECT) { + replace_bezt_keyframe_ypos(&fcu->bezt[i == 0 ? fcu->totvert - 1 : 0], bezt); + } + } + } + } + /* keyframing modes allow to not replace keyframe */ + else if ((flag & INSERTKEY_REPLACE) == 0) { + /* insert new - if we're not restricted to replacing keyframes only */ + BezTriple *newb = MEM_callocN((fcu->totvert + 1) * sizeof(BezTriple), "beztriple"); + + /* add the beztriples that should occur before the beztriple to be pasted (originally in fcu) */ + if (i > 0) + memcpy(newb, fcu->bezt, i * sizeof(BezTriple)); + + /* add beztriple to paste at index i */ + *(newb + i) = *bezt; + + /* add the beztriples that occur after the beztriple to be pasted (originally in fcu) */ + if (i < fcu->totvert) + memcpy(newb + i + 1, fcu->bezt + i, (fcu->totvert - i) * sizeof(BezTriple)); + + /* replace (+ free) old with new, only if necessary to do so */ + MEM_freeN(fcu->bezt); + fcu->bezt = newb; + + fcu->totvert++; + } + else { + return -1; + } + } + /* no keyframes already, but can only add if... + * 1) keyframing modes say that keyframes can only be replaced, so adding new ones won't know + * 2) there are no samples on the curve + * // NOTE: maybe we may want to allow this later when doing samples -> bezt conversions, + * // but for now, having both is asking for trouble + */ + else if ((flag & INSERTKEY_REPLACE) == 0 && (fcu->fpt == NULL)) { + /* create new keyframes array */ + fcu->bezt = MEM_callocN(sizeof(BezTriple), "beztriple"); + *(fcu->bezt) = *bezt; + fcu->totvert = 1; + } + /* cannot add anything */ + else { + /* return error code -1 to prevent any misunderstandings */ + return -1; + } + + /* we need to return the index, so that some tools which do post-processing can + * detect where we added the BezTriple in the array + */ + return i; } /** @@ -457,114 +465,116 @@ int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, eInsertKeyFlags flag) * \param flag: Optional flags (eInsertKeyFlags) for controlling how keys get added * and/or whether updates get done. */ -int insert_vert_fcurve(FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag) +int insert_vert_fcurve( + FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag) { - BezTriple beztr = {{{0}}}; - unsigned int oldTot = fcu->totvert; - int a; - - /* set all three points, for nicer start position - * NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok... - */ - beztr.vec[0][0] = x - 1.0f; - beztr.vec[0][1] = y; - beztr.vec[1][0] = x; - beztr.vec[1][1] = y; - beztr.vec[2][0] = x + 1.0f; - beztr.vec[2][1] = y; - beztr.f1 = beztr.f2 = beztr.f3 = SELECT; - - /* set default handle types and interpolation mode */ - if (flag & INSERTKEY_NO_USERPREF) { - /* for Py-API, we want scripts to have predictable behavior, - * hence the option to not depend on the userpref defaults - */ - beztr.h1 = beztr.h2 = HD_AUTO_ANIM; - beztr.ipo = BEZT_IPO_BEZ; - } - else { - /* for UI usage - defaults should come from the userprefs and/or toolsettings */ - beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */ - - /* use default interpolation mode, with exceptions for int/discrete values */ - beztr.ipo = U.ipo_new; - } - - /* interpolation type used is constrained by the type of values the curve can take */ - if (fcu->flag & FCURVE_DISCRETE_VALUES) { - beztr.ipo = BEZT_IPO_CONST; - } - else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) { - beztr.ipo = BEZT_IPO_LIN; - } - - /* set keyframe type value (supplied), which should come from the scene settings in most cases */ - BEZKEYTYPE(&beztr) = keyframe_type; - - /* set default values for "easing" interpolation mode settings - * NOTE: Even if these modes aren't currently used, if users switch - * to these later, we want these to work in a sane way out of - * the box. - */ - - /* "back" easing - this value used to be used when overshoot=0, but that - * introduced discontinuities in how the param worked. */ - beztr.back = 1.70158f; - - /* "elastic" easing - values here were hand-optimised for a default duration of - * ~10 frames (typical mograph motion length) */ - beztr.amplitude = 0.8f; - beztr.period = 4.1f; - - /* add temp beztriple to keyframes */ - a = insert_bezt_fcurve(fcu, &beztr, flag); - - /* what if 'a' is a negative index? - * for now, just exit to prevent any segfaults - */ - if (a < 0) return -1; - - /* don't recalculate handles if fast is set - * - this is a hack to make importers faster - * - we may calculate twice (due to autohandle needing to be calculated twice) - */ - if ((flag & INSERTKEY_FAST) == 0) - calchandles_fcurve(fcu); - - /* set handletype and interpolation */ - if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) { - BezTriple *bezt = (fcu->bezt + a); - - /* 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 - * - we may calculate twice (due to autohandle needing to be calculated twice) - */ - if ((flag & INSERTKEY_FAST) == 0) - calchandles_fcurve(fcu); - } - - /* return the index at which the keyframe was added */ - return a; + BezTriple beztr = {{{0}}}; + unsigned int oldTot = fcu->totvert; + int a; + + /* set all three points, for nicer start position + * NOTE: +/- 1 on vec.x for left and right handles is so that 'free' handles work ok... + */ + beztr.vec[0][0] = x - 1.0f; + beztr.vec[0][1] = y; + beztr.vec[1][0] = x; + beztr.vec[1][1] = y; + beztr.vec[2][0] = x + 1.0f; + beztr.vec[2][1] = y; + beztr.f1 = beztr.f2 = beztr.f3 = SELECT; + + /* set default handle types and interpolation mode */ + if (flag & INSERTKEY_NO_USERPREF) { + /* for Py-API, we want scripts to have predictable behavior, + * hence the option to not depend on the userpref defaults + */ + beztr.h1 = beztr.h2 = HD_AUTO_ANIM; + beztr.ipo = BEZT_IPO_BEZ; + } + else { + /* for UI usage - defaults should come from the userprefs and/or toolsettings */ + beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */ + + /* use default interpolation mode, with exceptions for int/discrete values */ + beztr.ipo = U.ipo_new; + } + + /* interpolation type used is constrained by the type of values the curve can take */ + if (fcu->flag & FCURVE_DISCRETE_VALUES) { + beztr.ipo = BEZT_IPO_CONST; + } + else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) { + beztr.ipo = BEZT_IPO_LIN; + } + + /* set keyframe type value (supplied), which should come from the scene settings in most cases */ + BEZKEYTYPE(&beztr) = keyframe_type; + + /* set default values for "easing" interpolation mode settings + * NOTE: Even if these modes aren't currently used, if users switch + * to these later, we want these to work in a sane way out of + * the box. + */ + + /* "back" easing - this value used to be used when overshoot=0, but that + * introduced discontinuities in how the param worked. */ + beztr.back = 1.70158f; + + /* "elastic" easing - values here were hand-optimised for a default duration of + * ~10 frames (typical mograph motion length) */ + beztr.amplitude = 0.8f; + beztr.period = 4.1f; + + /* add temp beztriple to keyframes */ + a = insert_bezt_fcurve(fcu, &beztr, flag); + + /* what if 'a' is a negative index? + * for now, just exit to prevent any segfaults + */ + if (a < 0) + return -1; + + /* don't recalculate handles if fast is set + * - this is a hack to make importers faster + * - we may calculate twice (due to autohandle needing to be calculated twice) + */ + if ((flag & INSERTKEY_FAST) == 0) + calchandles_fcurve(fcu); + + /* set handletype and interpolation */ + if ((fcu->totvert > 2) && (flag & INSERTKEY_REPLACE) == 0) { + BezTriple *bezt = (fcu->bezt + a); + + /* 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 + * - we may calculate twice (due to autohandle needing to be calculated twice) + */ + if ((flag & INSERTKEY_FAST) == 0) + calchandles_fcurve(fcu); + } + + /* return the index at which the keyframe was added */ + return a; } /* -------------- 'Smarter' Keyframing Functions -------------------- */ /* return codes for new_key_needed */ enum { - KEYNEEDED_DONTADD = 0, - KEYNEEDED_JUSTADD, - KEYNEEDED_DELPREV, - KEYNEEDED_DELNEXT, + KEYNEEDED_DONTADD = 0, + KEYNEEDED_JUSTADD, + KEYNEEDED_DELPREV, + KEYNEEDED_DELNEXT, } /*eKeyNeededStatus*/; /* This helper function determines whether a new keyframe is needed */ @@ -575,187 +585,195 @@ enum { */ static short new_key_needed(FCurve *fcu, float cFrame, float nValue) { - BezTriple *bezt = NULL, *prev = NULL; - int totCount, i; - float valA = 0.0f, valB = 0.0f; - - /* safety checking */ - if (fcu == NULL) return KEYNEEDED_JUSTADD; - totCount = fcu->totvert; - if (totCount == 0) return KEYNEEDED_JUSTADD; - - /* loop through checking if any are the same */ - bezt = fcu->bezt; - for (i = 0; i < totCount; i++) { - float prevPosi = 0.0f, prevVal = 0.0f; - float beztPosi = 0.0f, beztVal = 0.0f; - - /* get current time+value */ - beztPosi = bezt->vec[1][0]; - beztVal = bezt->vec[1][1]; - - if (prev) { - /* there is a keyframe before the one currently being examined */ - - /* get previous time+value */ - prevPosi = prev->vec[1][0]; - prevVal = prev->vec[1][1]; - - /* keyframe to be added at point where there are already two similar points? */ - 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_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) { - return KEYNEEDED_DONTADD; - } - else { - float realVal; - - /* get real value of curve at that point */ - realVal = evaluate_fcurve(fcu, cFrame); - - /* compare whether it's the same as proposed */ - if (IS_EQF(realVal, nValue)) - return KEYNEEDED_DONTADD; - else - return KEYNEEDED_JUSTADD; - } - } - - /* new keyframe before prev beztriple? */ - if (cFrame < prevPosi) { - /* A new keyframe will be added. However, whether the previous beztriple - * stays around or not depends on whether the values of previous/current - * beztriples and new keyframe are the same. - */ - if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) - return KEYNEEDED_DELNEXT; - else - return KEYNEEDED_JUSTADD; - } - } - else { - /* just add a keyframe if there's only one keyframe - * and the new one occurs before the existing one does. - */ - if ((cFrame < beztPosi) && (totCount == 1)) - return KEYNEEDED_JUSTADD; - } - - /* continue. frame to do not yet passed (or other conditions not met) */ - if (i < (totCount - 1)) { - prev = bezt; - bezt++; - } - else - break; - } - - /* Frame in which to add a new-keyframe occurs after all other keys - * -> If there are at least two existing keyframes, then if the values of the - * last two keyframes and the new-keyframe match, the last existing keyframe - * gets deleted as it is no longer required. - * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last - * keyframe is not equal to last keyframe. - */ - bezt = (fcu->bezt + (fcu->totvert - 1)); - valA = bezt->vec[1][1]; - - if (prev) - valB = prev->vec[1][1]; - else - valB = bezt->vec[1][1] + 1.0f; - - if (IS_EQF(valA, nValue) && IS_EQF(valA, valB)) - return KEYNEEDED_DELPREV; - else - return KEYNEEDED_JUSTADD; + BezTriple *bezt = NULL, *prev = NULL; + int totCount, i; + float valA = 0.0f, valB = 0.0f; + + /* safety checking */ + if (fcu == NULL) + return KEYNEEDED_JUSTADD; + totCount = fcu->totvert; + if (totCount == 0) + return KEYNEEDED_JUSTADD; + + /* loop through checking if any are the same */ + bezt = fcu->bezt; + for (i = 0; i < totCount; i++) { + float prevPosi = 0.0f, prevVal = 0.0f; + float beztPosi = 0.0f, beztVal = 0.0f; + + /* get current time+value */ + beztPosi = bezt->vec[1][0]; + beztVal = bezt->vec[1][1]; + + if (prev) { + /* there is a keyframe before the one currently being examined */ + + /* get previous time+value */ + prevPosi = prev->vec[1][0]; + prevVal = prev->vec[1][1]; + + /* keyframe to be added at point where there are already two similar points? */ + 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_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) { + return KEYNEEDED_DONTADD; + } + else { + float realVal; + + /* get real value of curve at that point */ + realVal = evaluate_fcurve(fcu, cFrame); + + /* compare whether it's the same as proposed */ + if (IS_EQF(realVal, nValue)) + return KEYNEEDED_DONTADD; + else + return KEYNEEDED_JUSTADD; + } + } + + /* new keyframe before prev beztriple? */ + if (cFrame < prevPosi) { + /* A new keyframe will be added. However, whether the previous beztriple + * stays around or not depends on whether the values of previous/current + * beztriples and new keyframe are the same. + */ + if (IS_EQF(prevVal, nValue) && IS_EQF(beztVal, nValue) && IS_EQF(prevVal, beztVal)) + return KEYNEEDED_DELNEXT; + else + return KEYNEEDED_JUSTADD; + } + } + else { + /* just add a keyframe if there's only one keyframe + * and the new one occurs before the existing one does. + */ + if ((cFrame < beztPosi) && (totCount == 1)) + return KEYNEEDED_JUSTADD; + } + + /* continue. frame to do not yet passed (or other conditions not met) */ + if (i < (totCount - 1)) { + prev = bezt; + bezt++; + } + else + break; + } + + /* Frame in which to add a new-keyframe occurs after all other keys + * -> If there are at least two existing keyframes, then if the values of the + * last two keyframes and the new-keyframe match, the last existing keyframe + * gets deleted as it is no longer required. + * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last + * keyframe is not equal to last keyframe. + */ + bezt = (fcu->bezt + (fcu->totvert - 1)); + valA = bezt->vec[1][1]; + + if (prev) + valB = prev->vec[1][1]; + else + valB = bezt->vec[1][1] + 1.0f; + + if (IS_EQF(valA, nValue) && IS_EQF(valA, valB)) + return KEYNEEDED_DELPREV; + else + return KEYNEEDED_JUSTADD; } /* ------------------ RNA Data-Access Functions ------------------ */ /* Try to read value using RNA-properties obtained already */ -static float *setting_get_rna_values(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, const bool get_evaluated, float *buffer, int buffer_size, int *r_count) +static float *setting_get_rna_values(Depsgraph *depsgraph, + PointerRNA *ptr, + PropertyRNA *prop, + const bool get_evaluated, + float *buffer, + int buffer_size, + int *r_count) { - BLI_assert(buffer_size >= 1); - - float *values = buffer; - PointerRNA ptr_eval; - - if (get_evaluated) { - DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval); - ptr = &ptr_eval; - } - - if (RNA_property_array_check(prop)) { - int length = *r_count = RNA_property_array_length(ptr, prop); - bool *tmp_bool; - int *tmp_int; - - if (length > buffer_size) { - values = MEM_malloc_arrayN(sizeof(float), length, __func__); - } - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__); - RNA_property_boolean_get_array(ptr, prop, tmp_bool); - for (int i = 0; i < length; i++) { - values[i] = (float)tmp_bool[i]; - } - MEM_freeN(tmp_bool); - break; - case PROP_INT: - tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__); - RNA_property_int_get_array(ptr, prop, tmp_int); - for (int i = 0; i < length; i++) { - values[i] = (float)tmp_int[i]; - } - MEM_freeN(tmp_int); - break; - case PROP_FLOAT: - RNA_property_float_get_array(ptr, prop, values); - break; - default: - memset(values, 0, sizeof(float) * length); - } - } - else { - *r_count = 1; - - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - *values = (float)RNA_property_boolean_get(ptr, prop); - break; - case PROP_INT: - *values = (float)RNA_property_int_get(ptr, prop); - break; - case PROP_FLOAT: - *values = RNA_property_float_get(ptr, prop); - break; - case PROP_ENUM: - *values = (float)RNA_property_enum_get(ptr, prop); - break; - default: - *values = 0.0f; - } - } - - return values; + BLI_assert(buffer_size >= 1); + + float *values = buffer; + PointerRNA ptr_eval; + + if (get_evaluated) { + DEG_get_evaluated_rna_pointer(depsgraph, ptr, &ptr_eval); + ptr = &ptr_eval; + } + + if (RNA_property_array_check(prop)) { + int length = *r_count = RNA_property_array_length(ptr, prop); + bool *tmp_bool; + int *tmp_int; + + if (length > buffer_size) { + values = MEM_malloc_arrayN(sizeof(float), length, __func__); + } + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + tmp_bool = MEM_malloc_arrayN(sizeof(*tmp_bool), length, __func__); + RNA_property_boolean_get_array(ptr, prop, tmp_bool); + for (int i = 0; i < length; i++) { + values[i] = (float)tmp_bool[i]; + } + MEM_freeN(tmp_bool); + break; + case PROP_INT: + tmp_int = MEM_malloc_arrayN(sizeof(*tmp_int), length, __func__); + RNA_property_int_get_array(ptr, prop, tmp_int); + for (int i = 0; i < length; i++) { + values[i] = (float)tmp_int[i]; + } + MEM_freeN(tmp_int); + break; + case PROP_FLOAT: + RNA_property_float_get_array(ptr, prop, values); + break; + default: + memset(values, 0, sizeof(float) * length); + } + } + else { + *r_count = 1; + + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + *values = (float)RNA_property_boolean_get(ptr, prop); + break; + case PROP_INT: + *values = (float)RNA_property_int_get(ptr, prop); + break; + case PROP_FLOAT: + *values = RNA_property_float_get(ptr, prop); + break; + case PROP_ENUM: + *values = (float)RNA_property_enum_get(ptr, prop); + break; + default: + *values = 0.0f; + } + } + + return values; } /* ------------------ 'Visual' Keyframing Functions ------------------ */ /* internal status codes for visualkey_can_use */ enum { - VISUALKEY_NONE = 0, - VISUALKEY_LOC, - VISUALKEY_ROT, - VISUALKEY_SCA, + VISUALKEY_NONE = 0, + VISUALKEY_LOC, + VISUALKEY_ROT, + VISUALKEY_SCA, }; /* This helper function determines if visual-keyframing should be used when @@ -766,331 +784,365 @@ enum { */ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) { - bConstraint *con = NULL; - short searchtype = VISUALKEY_NONE; - bool has_rigidbody = false; - bool has_parent = false; - const char *identifier = NULL; - - /* validate data */ - if (ELEM(NULL, ptr, ptr->data, prop)) - return false; - - /* get first constraint and determine type of keyframe constraints to check for - * - constraints can be on either Objects or PoseChannels, so we only check if the - * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for - * those structs, allowing us to identify the owner of the data - */ - if (ptr->type == &RNA_Object) { - /* Object */ - Object *ob = (Object *)ptr->data; - RigidBodyOb *rbo = ob->rigidbody_object; - - con = ob->constraints.first; - identifier = RNA_property_identifier(prop); - has_parent = (ob->parent != NULL); - - /* active rigidbody objects only, as only those are affected by sim */ - has_rigidbody = ((rbo) && (rbo->type == RBO_TYPE_ACTIVE)); - } - else if (ptr->type == &RNA_PoseBone) { - /* Pose Channel */ - bPoseChannel *pchan = (bPoseChannel *)ptr->data; - - con = pchan->constraints.first; - identifier = RNA_property_identifier(prop); - has_parent = (pchan->parent != NULL); - } - - /* check if any data to search using */ - if (ELEM(NULL, con, identifier) && (has_parent == false) && (has_rigidbody == false)) - return false; - - /* location or rotation identifiers only... */ - if (identifier == NULL) { - printf("%s failed: NULL identifier\n", __func__); - return false; - } - else if (strstr(identifier, "location")) { - searchtype = VISUALKEY_LOC; - } - else if (strstr(identifier, "rotation")) { - searchtype = VISUALKEY_ROT; - } - else if (strstr(identifier, "scale")) { - searchtype = VISUALKEY_SCA; - } - else { - printf("%s failed: identifier - '%s'\n", __func__, identifier); - return false; - } - - - /* only search if a searchtype and initial constraint are available */ - if (searchtype) { - /* parent or rigidbody are always matching */ - if (has_parent || has_rigidbody) - return true; - - /* constraints */ - for (; con; con = con->next) { - /* only consider constraint if it is not disabled, and has influence */ - if (con->flag & CONSTRAINT_DISABLE) continue; - if (con->enforce == 0.0f) continue; - - /* some constraints may alter these transforms */ - switch (con->type) { - /* multi-transform constraints */ - case CONSTRAINT_TYPE_CHILDOF: - case CONSTRAINT_TYPE_ARMATURE: - return true; - case CONSTRAINT_TYPE_TRANSFORM: - case CONSTRAINT_TYPE_TRANSLIKE: - return true; - case CONSTRAINT_TYPE_FOLLOWPATH: - return true; - case CONSTRAINT_TYPE_KINEMATIC: - return true; - - /* single-transform constraints */ - case CONSTRAINT_TYPE_TRACKTO: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_DAMPTRACK: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_ROTLIMIT: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_LOCLIMIT: - if (searchtype == VISUALKEY_LOC) return true; - break; - case CONSTRAINT_TYPE_SIZELIMIT: - if (searchtype == VISUALKEY_SCA) return true; - break; - case CONSTRAINT_TYPE_DISTLIMIT: - if (searchtype == VISUALKEY_LOC) return true; - break; - case CONSTRAINT_TYPE_ROTLIKE: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_LOCLIKE: - if (searchtype == VISUALKEY_LOC) return true; - break; - case CONSTRAINT_TYPE_SIZELIKE: - if (searchtype == VISUALKEY_SCA) return true; - break; - case CONSTRAINT_TYPE_LOCKTRACK: - if (searchtype == VISUALKEY_ROT) return true; - break; - case CONSTRAINT_TYPE_MINMAX: - if (searchtype == VISUALKEY_LOC) return true; - break; - - default: - break; - } - } - } - - /* when some condition is met, this function returns, so that means we've got nothing */ - return false; + bConstraint *con = NULL; + short searchtype = VISUALKEY_NONE; + bool has_rigidbody = false; + bool has_parent = false; + const char *identifier = NULL; + + /* validate data */ + if (ELEM(NULL, ptr, ptr->data, prop)) + return false; + + /* get first constraint and determine type of keyframe constraints to check for + * - constraints can be on either Objects or PoseChannels, so we only check if the + * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for + * those structs, allowing us to identify the owner of the data + */ + if (ptr->type == &RNA_Object) { + /* Object */ + Object *ob = (Object *)ptr->data; + RigidBodyOb *rbo = ob->rigidbody_object; + + con = ob->constraints.first; + identifier = RNA_property_identifier(prop); + has_parent = (ob->parent != NULL); + + /* active rigidbody objects only, as only those are affected by sim */ + has_rigidbody = ((rbo) && (rbo->type == RBO_TYPE_ACTIVE)); + } + else if (ptr->type == &RNA_PoseBone) { + /* Pose Channel */ + bPoseChannel *pchan = (bPoseChannel *)ptr->data; + + con = pchan->constraints.first; + identifier = RNA_property_identifier(prop); + has_parent = (pchan->parent != NULL); + } + + /* check if any data to search using */ + if (ELEM(NULL, con, identifier) && (has_parent == false) && (has_rigidbody == false)) + return false; + + /* location or rotation identifiers only... */ + if (identifier == NULL) { + printf("%s failed: NULL identifier\n", __func__); + return false; + } + else if (strstr(identifier, "location")) { + searchtype = VISUALKEY_LOC; + } + else if (strstr(identifier, "rotation")) { + searchtype = VISUALKEY_ROT; + } + else if (strstr(identifier, "scale")) { + searchtype = VISUALKEY_SCA; + } + else { + printf("%s failed: identifier - '%s'\n", __func__, identifier); + return false; + } + + /* only search if a searchtype and initial constraint are available */ + if (searchtype) { + /* parent or rigidbody are always matching */ + if (has_parent || has_rigidbody) + return true; + + /* constraints */ + for (; con; con = con->next) { + /* only consider constraint if it is not disabled, and has influence */ + if (con->flag & CONSTRAINT_DISABLE) + continue; + if (con->enforce == 0.0f) + continue; + + /* some constraints may alter these transforms */ + switch (con->type) { + /* multi-transform constraints */ + case CONSTRAINT_TYPE_CHILDOF: + case CONSTRAINT_TYPE_ARMATURE: + return true; + case CONSTRAINT_TYPE_TRANSFORM: + case CONSTRAINT_TYPE_TRANSLIKE: + return true; + case CONSTRAINT_TYPE_FOLLOWPATH: + return true; + case CONSTRAINT_TYPE_KINEMATIC: + return true; + + /* single-transform constraints */ + case CONSTRAINT_TYPE_TRACKTO: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_DAMPTRACK: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_ROTLIMIT: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_LOCLIMIT: + if (searchtype == VISUALKEY_LOC) + return true; + break; + case CONSTRAINT_TYPE_SIZELIMIT: + if (searchtype == VISUALKEY_SCA) + return true; + break; + case CONSTRAINT_TYPE_DISTLIMIT: + if (searchtype == VISUALKEY_LOC) + return true; + break; + case CONSTRAINT_TYPE_ROTLIKE: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_LOCLIKE: + if (searchtype == VISUALKEY_LOC) + return true; + break; + case CONSTRAINT_TYPE_SIZELIKE: + if (searchtype == VISUALKEY_SCA) + return true; + break; + case CONSTRAINT_TYPE_LOCKTRACK: + if (searchtype == VISUALKEY_ROT) + return true; + break; + case CONSTRAINT_TYPE_MINMAX: + if (searchtype == VISUALKEY_LOC) + return true; + break; + + default: + break; + } + } + } + + /* when some condition is met, this function returns, so that means we've got nothing */ + return false; } /* This helper function extracts the value to use for visual-keyframing * In the event that it is not possible to perform visual keying, try to fall-back * to using the default method. Assumes that all data it has been passed is valid. */ -static float *visualkey_get_values(Depsgraph *depsgraph, PointerRNA *ptr, PropertyRNA *prop, float *buffer, int buffer_size, int *r_count) +static float *visualkey_get_values(Depsgraph *depsgraph, + PointerRNA *ptr, + PropertyRNA *prop, + float *buffer, + int buffer_size, + int *r_count) { - BLI_assert(buffer_size >= 4); - - const char *identifier = RNA_property_identifier(prop); - float tmat[4][4]; - int rotmode; - - /* handle for Objects or PoseChannels only - * - only Location, Rotation or Scale keyframes are supported currently - * - constraints can be on either Objects or PoseChannels, so we only check if the - * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for - * those structs, allowing us to identify the owner of the data - * - assume that array_index will be sane - */ - if (ptr->type == &RNA_Object) { - Object *ob = (Object *)ptr->data; - const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - - /* Loc code is specific... */ - if (strstr(identifier, "location")) { - copy_v3_v3(buffer, ob_eval->obmat[3]); - *r_count = 3; - return buffer; - } - - copy_m4_m4(tmat, ob_eval->obmat); - rotmode = ob_eval->rotmode; - } - else if (ptr->type == &RNA_PoseBone) { - Object *ob = (Object *)ptr->id.data; - bPoseChannel *pchan = (bPoseChannel *)ptr->data; - - const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); - - BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, tmat); - rotmode = pchan_eval->rotmode; - - /* Loc code is specific... */ - if (strstr(identifier, "location")) { - /* only use for non-connected bones */ - if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) { - copy_v3_v3(buffer, tmat[3]); - *r_count = 3; - return buffer; - } - } - } - else { - return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); - } - - /* Rot/Scale code are common! */ - if (strstr(identifier, "rotation_euler")) { - mat4_to_eulO(buffer, rotmode, tmat); - - *r_count = 3; - return buffer; - } - else if (strstr(identifier, "rotation_quaternion")) { - float mat3[3][3]; - - copy_m3_m4(mat3, tmat); - mat3_to_quat_is_ok(buffer, mat3); - - *r_count = 4; - return buffer; - } - else if (strstr(identifier, "rotation_axis_angle")) { - /* w = 0, x,y,z = 1,2,3 */ - mat4_to_axis_angle(buffer + 1, buffer, tmat); - - *r_count = 4; - return buffer; - } - else if (strstr(identifier, "scale")) { - mat4_to_size(buffer, tmat); - - *r_count = 3; - return buffer; - } - - /* as the function hasn't returned yet, read value from system in the default way */ - return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); + BLI_assert(buffer_size >= 4); + + const char *identifier = RNA_property_identifier(prop); + float tmat[4][4]; + int rotmode; + + /* handle for Objects or PoseChannels only + * - only Location, Rotation or Scale keyframes are supported currently + * - constraints can be on either Objects or PoseChannels, so we only check if the + * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for + * those structs, allowing us to identify the owner of the data + * - assume that array_index will be sane + */ + if (ptr->type == &RNA_Object) { + Object *ob = (Object *)ptr->data; + const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + + /* Loc code is specific... */ + if (strstr(identifier, "location")) { + copy_v3_v3(buffer, ob_eval->obmat[3]); + *r_count = 3; + return buffer; + } + + copy_m4_m4(tmat, ob_eval->obmat); + rotmode = ob_eval->rotmode; + } + else if (ptr->type == &RNA_PoseBone) { + Object *ob = (Object *)ptr->id.data; + bPoseChannel *pchan = (bPoseChannel *)ptr->data; + + const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); + + BKE_armature_mat_pose_to_bone(pchan_eval, pchan_eval->pose_mat, tmat); + rotmode = pchan_eval->rotmode; + + /* Loc code is specific... */ + if (strstr(identifier, "location")) { + /* only use for non-connected bones */ + if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) { + copy_v3_v3(buffer, tmat[3]); + *r_count = 3; + return buffer; + } + } + } + else { + return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); + } + + /* Rot/Scale code are common! */ + if (strstr(identifier, "rotation_euler")) { + mat4_to_eulO(buffer, rotmode, tmat); + + *r_count = 3; + return buffer; + } + else if (strstr(identifier, "rotation_quaternion")) { + float mat3[3][3]; + + copy_m3_m4(mat3, tmat); + mat3_to_quat_is_ok(buffer, mat3); + + *r_count = 4; + return buffer; + } + else if (strstr(identifier, "rotation_axis_angle")) { + /* w = 0, x,y,z = 1,2,3 */ + mat4_to_axis_angle(buffer + 1, buffer, tmat); + + *r_count = 4; + return buffer; + } + else if (strstr(identifier, "scale")) { + mat4_to_size(buffer, tmat); + + *r_count = 3; + return buffer; + } + + /* as the function hasn't returned yet, read value from system in the default way */ + return setting_get_rna_values(depsgraph, ptr, prop, true, buffer, buffer_size, r_count); } /* ------------------------- Insert Key API ------------------------- */ /* Retrieve current property values to keyframe, possibly applying NLA correction when necessary. */ -static float *get_keyframe_values( - Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, int index, - struct NlaKeyframingContext *nla_context, eInsertKeyFlags flag, - float *buffer, int buffer_size, int *r_count, bool *r_force_all) +static float *get_keyframe_values(Depsgraph *depsgraph, + ReportList *reports, + PointerRNA ptr, + PropertyRNA *prop, + int index, + struct NlaKeyframingContext *nla_context, + eInsertKeyFlags flag, + float *buffer, + int buffer_size, + int *r_count, + bool *r_force_all) { - float *values; - - if ( (flag & INSERTKEY_MATRIX) && - (visualkey_can_use(&ptr, prop)) ) - { - /* visual-keying is only available for object and pchan datablocks, as - * it works by keyframing using a value extracted from the final matrix - * instead of using the kt system to extract a value. - */ - values = visualkey_get_values(depsgraph, &ptr, prop, buffer, buffer_size, r_count); - } - else { - /* read value from system */ - values = setting_get_rna_values(depsgraph, &ptr, prop, false, buffer, buffer_size, r_count); - } - - /* adjust the value for NLA factors */ - if (!BKE_animsys_nla_remap_keyframe_values(nla_context, &ptr, prop, values, *r_count, index, r_force_all)) { - BKE_report(reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); - - if (values != buffer) { - MEM_freeN(values); - } - return NULL; - } - - return values; + float *values; + + if ((flag & INSERTKEY_MATRIX) && (visualkey_can_use(&ptr, prop))) { + /* visual-keying is only available for object and pchan datablocks, as + * it works by keyframing using a value extracted from the final matrix + * instead of using the kt system to extract a value. + */ + values = visualkey_get_values(depsgraph, &ptr, prop, buffer, buffer_size, r_count); + } + else { + /* read value from system */ + values = setting_get_rna_values(depsgraph, &ptr, prop, false, buffer, buffer_size, r_count); + } + + /* adjust the value for NLA factors */ + if (!BKE_animsys_nla_remap_keyframe_values( + nla_context, &ptr, prop, values, *r_count, index, r_force_all)) { + BKE_report( + reports, RPT_ERROR, "Could not insert keyframe due to zero NLA influence or base value"); + + if (values != buffer) { + MEM_freeN(values); + } + return NULL; + } + + return values; } /* Insert the specified keyframe value into a single F-Curve. */ -static bool insert_keyframe_value(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, FCurve *fcu, float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +static bool insert_keyframe_value(ReportList *reports, + PointerRNA *ptr, + PropertyRNA *prop, + FCurve *fcu, + float cfra, + float curval, + eBezTriple_KeyframeType keytype, + eInsertKeyFlags flag) { - /* F-Curve not editable? */ - if (fcurve_is_keyframable(fcu) == 0) { - BKE_reportf(reports, RPT_ERROR, - "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, " - "and try removing F-Modifiers", - fcu->rna_path, fcu->array_index); - return false; - } - - /* adjust frame on which to add keyframe */ - if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) { - PathResolvedRNA anim_rna; - - if (RNA_path_resolved_create(ptr, prop, fcu->array_index, &anim_rna)) { - /* for making it easier to add corrective drivers... */ - cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, cfra); - } - else { - cfra = 0.0f; - } - } - - /* adjust coordinates for cycle aware insertion */ - if (flag & INSERTKEY_CYCLE_AWARE) { - if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) { - /* inhibit action from insert_vert_fcurve unless it's a perfect cycle */ - flag &= ~INSERTKEY_CYCLE_AWARE; - } - } - - /* only insert keyframes where they are needed */ - if (flag & INSERTKEY_NEEDED) { - short insert_mode; - - /* check whether this curve really needs a new keyframe */ - insert_mode = new_key_needed(fcu, cfra, curval); - - /* only return success if keyframe added */ - if (insert_mode == KEYNEEDED_DONTADD) { - return false; - } - - /* insert new keyframe at current frame */ - if (insert_vert_fcurve(fcu, cfra, curval, keytype, flag) < 0) { - return false; - } - - /* delete keyframe immediately before/after newly added */ - switch (insert_mode) { - case KEYNEEDED_DELPREV: - delete_fcurve_key(fcu, fcu->totvert - 2, 1); - break; - case KEYNEEDED_DELNEXT: - delete_fcurve_key(fcu, 1, 1); - break; - } - - return true; - } - else { - /* just insert keyframe */ - return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0; - } + /* F-Curve not editable? */ + if (fcurve_is_keyframable(fcu) == 0) { + BKE_reportf( + reports, + RPT_ERROR, + "F-Curve with path '%s[%d]' cannot be keyframed, ensure that it is not locked or sampled, " + "and try removing F-Modifiers", + fcu->rna_path, + fcu->array_index); + return false; + } + + /* adjust frame on which to add keyframe */ + if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) { + PathResolvedRNA anim_rna; + + if (RNA_path_resolved_create(ptr, prop, fcu->array_index, &anim_rna)) { + /* for making it easier to add corrective drivers... */ + cfra = evaluate_driver(&anim_rna, fcu->driver, fcu->driver, cfra); + } + else { + cfra = 0.0f; + } + } + + /* adjust coordinates for cycle aware insertion */ + if (flag & INSERTKEY_CYCLE_AWARE) { + if (remap_cyclic_keyframe_location(fcu, &cfra, &curval) != FCU_CYCLE_PERFECT) { + /* inhibit action from insert_vert_fcurve unless it's a perfect cycle */ + flag &= ~INSERTKEY_CYCLE_AWARE; + } + } + + /* only insert keyframes where they are needed */ + if (flag & INSERTKEY_NEEDED) { + short insert_mode; + + /* check whether this curve really needs a new keyframe */ + insert_mode = new_key_needed(fcu, cfra, curval); + + /* only return success if keyframe added */ + if (insert_mode == KEYNEEDED_DONTADD) { + return false; + } + + /* insert new keyframe at current frame */ + if (insert_vert_fcurve(fcu, cfra, curval, keytype, flag) < 0) { + return false; + } + + /* delete keyframe immediately before/after newly added */ + switch (insert_mode) { + case KEYNEEDED_DELPREV: + delete_fcurve_key(fcu, fcu->totvert - 2, 1); + break; + case KEYNEEDED_DELNEXT: + delete_fcurve_key(fcu, 1, 1); + break; + } + + return true; + } + else { + /* just insert keyframe */ + return insert_vert_fcurve(fcu, cfra, curval, keytype, flag) >= 0; + } } /* Secondary Keyframing API call: @@ -1105,104 +1157,134 @@ static bool insert_keyframe_value(ReportList *reports, PointerRNA *ptr, Property * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh, * and extra keyframe filtering. */ -bool insert_keyframe_direct(Depsgraph *depsgraph, ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, eBezTriple_KeyframeType keytype, struct NlaKeyframingContext *nla_context, eInsertKeyFlags flag) +bool insert_keyframe_direct(Depsgraph *depsgraph, + ReportList *reports, + PointerRNA ptr, + PropertyRNA *prop, + FCurve *fcu, + float cfra, + eBezTriple_KeyframeType keytype, + struct NlaKeyframingContext *nla_context, + eInsertKeyFlags flag) { - float curval = 0.0f; - - /* no F-Curve to add keyframe to? */ - if (fcu == NULL) { - BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to"); - return false; - } - - /* if no property given yet, try to validate from F-Curve info */ - if ((ptr.id.data == NULL) && (ptr.data == NULL)) { - BKE_report(reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from"); - return false; - } - if (prop == NULL) { - PointerRNA tmp_ptr; - - /* try to get property we should be affecting */ - if (RNA_path_resolve_property(&ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { - /* property not found... */ - const char *idname = (ptr.id.data) ? ((ID *)ptr.id.data)->name : TIP_(""); - - BKE_reportf(reports, RPT_ERROR, - "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - idname, fcu->rna_path); - return false; - } - else { - /* property found, so overwrite 'ptr' to make later code easier */ - ptr = tmp_ptr; - } - } - - /* update F-Curve flags to ensure proper behavior for property type */ - update_autoflags_fcurve_direct(fcu, prop); - - /* Obtain the value to insert. */ - float value_buffer[RNA_MAX_ARRAY_LENGTH]; - int value_count; - int index = fcu->array_index; - - float *values = get_keyframe_values(depsgraph, reports, ptr, prop, index, nla_context, flag, - value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, NULL); - - if (values == NULL) { - /* This happens if NLA rejects this insertion. */ - return false; - } - - if (index >= 0 && index < value_count) { - curval = values[index]; - } - - if (values != value_buffer) { - MEM_freeN(values); - } - - return insert_keyframe_value(reports, &ptr, prop, fcu, cfra, curval, keytype, flag); + float curval = 0.0f; + + /* no F-Curve to add keyframe to? */ + if (fcu == NULL) { + BKE_report(reports, RPT_ERROR, "No F-Curve to add keyframes to"); + return false; + } + + /* if no property given yet, try to validate from F-Curve info */ + if ((ptr.id.data == NULL) && (ptr.data == NULL)) { + BKE_report( + reports, RPT_ERROR, "No RNA pointer available to retrieve values for keyframing from"); + return false; + } + if (prop == NULL) { + PointerRNA tmp_ptr; + + /* try to get property we should be affecting */ + if (RNA_path_resolve_property(&ptr, fcu->rna_path, &tmp_ptr, &prop) == false) { + /* property not found... */ + const char *idname = (ptr.id.data) ? ((ID *)ptr.id.data)->name : TIP_(""); + + BKE_reportf(reports, + RPT_ERROR, + "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, " + "path = %s)", + idname, + fcu->rna_path); + return false; + } + else { + /* property found, so overwrite 'ptr' to make later code easier */ + ptr = tmp_ptr; + } + } + + /* update F-Curve flags to ensure proper behavior for property type */ + update_autoflags_fcurve_direct(fcu, prop); + + /* Obtain the value to insert. */ + float value_buffer[RNA_MAX_ARRAY_LENGTH]; + int value_count; + int index = fcu->array_index; + + float *values = get_keyframe_values(depsgraph, + reports, + ptr, + prop, + index, + nla_context, + flag, + value_buffer, + RNA_MAX_ARRAY_LENGTH, + &value_count, + NULL); + + if (values == NULL) { + /* This happens if NLA rejects this insertion. */ + return false; + } + + if (index >= 0 && index < value_count) { + curval = values[index]; + } + + if (values != value_buffer) { + MEM_freeN(values); + } + + return insert_keyframe_value(reports, &ptr, prop, fcu, cfra, curval, keytype, flag); } /* Find or create the FCurve based on the given path, and insert the specified value into it. */ -static bool insert_keyframe_fcurve_value( - Main *bmain, ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, - bAction *act, const char group[], const char rna_path[], int array_index, - float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag) +static bool insert_keyframe_fcurve_value(Main *bmain, + ReportList *reports, + PointerRNA *ptr, + PropertyRNA *prop, + bAction *act, + const char group[], + const char rna_path[], + int array_index, + float cfra, + float curval, + eBezTriple_KeyframeType keytype, + eInsertKeyFlags flag) { - /* make sure the F-Curve exists - * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet - * but still try to get the F-Curve if it exists... - */ - FCurve *fcu = verify_fcurve(bmain, act, group, ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0); - - /* we may not have a F-Curve when we're replacing only... */ - if (fcu) { - /* set color mode if the F-Curve is new (i.e. without any keyframes) */ - if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) { - /* 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 - */ - PropertySubType prop_subtype = RNA_property_subtype(prop); - if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { - fcu->color_mode = FCURVE_COLOR_AUTO_RGB; - } - else if (ELEM(prop_subtype, PROP_QUATERNION)) { - fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; - } - } - - /* update F-Curve flags to ensure proper behavior for property type */ - update_autoflags_fcurve_direct(fcu, prop); - - /* insert keyframe */ - return insert_keyframe_value(reports, ptr, prop, fcu, cfra, curval, keytype, flag); - } - else { - return false; - } + /* make sure the F-Curve exists + * - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet + * but still try to get the F-Curve if it exists... + */ + FCurve *fcu = verify_fcurve( + bmain, act, group, ptr, rna_path, array_index, (flag & INSERTKEY_REPLACE) == 0); + + /* we may not have a F-Curve when we're replacing only... */ + if (fcu) { + /* set color mode if the F-Curve is new (i.e. without any keyframes) */ + if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) { + /* 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 + */ + PropertySubType prop_subtype = RNA_property_subtype(prop); + if (ELEM(prop_subtype, PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { + fcu->color_mode = FCURVE_COLOR_AUTO_RGB; + } + else if (ELEM(prop_subtype, PROP_QUATERNION)) { + fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } + } + + /* update F-Curve flags to ensure proper behavior for property type */ + update_autoflags_fcurve_direct(fcu, prop); + + /* insert keyframe */ + return insert_keyframe_value(reports, ptr, prop, fcu, cfra, curval, keytype, flag); + } + else { + return false; + } } /* Main Keyframing API call: @@ -1214,119 +1296,188 @@ static bool insert_keyframe_fcurve_value( * * index of -1 keys all array indices */ -short insert_keyframe( - Main *bmain, Depsgraph *depsgraph, ReportList *reports, ID *id, bAction *act, - const char group[], const char rna_path[], int array_index, float cfra, eBezTriple_KeyframeType keytype, ListBase *nla_cache, eInsertKeyFlags flag) +short insert_keyframe(Main *bmain, + Depsgraph *depsgraph, + ReportList *reports, + ID *id, + bAction *act, + const char group[], + const char rna_path[], + int array_index, + float cfra, + eBezTriple_KeyframeType keytype, + ListBase *nla_cache, + eInsertKeyFlags flag) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop = NULL; - AnimData *adt; - ListBase tmp_nla_cache = {NULL, NULL}; - NlaKeyframingContext *nla_context = NULL; - int ret = 0; - - /* validate pointer first - exit if failure */ - if (id == NULL) { - BKE_reportf(reports, RPT_ERROR, "No ID block to insert keyframe in (path = %s)", rna_path); - return 0; - } - - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - (id) ? id->name : TIP_(""), rna_path); - return 0; - } - - /* if no action is provided, keyframe to the default one attached to this ID-block */ - if (act == NULL) { - /* get action to add F-Curve+keyframe to */ - act = verify_adt_action(bmain, id, 1); - - if (act == NULL) { - BKE_reportf(reports, RPT_ERROR, - "Could not insert keyframe, as this type does not support animation data (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - } - - /* apply NLA-mapping to frame to use (if applicable) */ - adt = BKE_animdata_from_id(id); - - if (adt && adt->action == act) { - /* Get NLA context for value remapping. */ - nla_context = BKE_animsys_get_nla_keyframing_context(nla_cache ? nla_cache : &tmp_nla_cache, depsgraph, &id_ptr, adt, cfra); - - /* Apply NLA-mapping to frame. */ - cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); - } - - /* Obtain values to insert. */ - float value_buffer[RNA_MAX_ARRAY_LENGTH]; - int value_count; - bool force_all; - - float *values = get_keyframe_values(depsgraph, reports, ptr, prop, array_index, nla_context, flag, - value_buffer, RNA_MAX_ARRAY_LENGTH, &value_count, &force_all); - - if (values != NULL) { - /* Key the entire array. */ - if (array_index == -1 || force_all) { - /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ - if (force_all && (flag & INSERTKEY_REPLACE) != 0) { - int exclude = -1; - - for (array_index = 0; array_index < value_count; array_index++) { - if (insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag)) { - ret++; - exclude = array_index; - break; - } - } - - if (exclude != -1) { - flag &= ~INSERTKEY_REPLACE; - - for (array_index = 0; array_index < value_count; array_index++) { - if (array_index != exclude) { - ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); - } - } - } - } - /* Simply insert all channels. */ - else { - for (array_index = 0; array_index < value_count; array_index++) { - ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); - } - } - } - /* Key a single index. */ - else { - if (array_index >= 0 && array_index < value_count) { - ret += insert_keyframe_fcurve_value(bmain, reports, &ptr, prop, act, group, rna_path, array_index, cfra, values[array_index], keytype, flag); - } - } - } - - if (values != value_buffer) { - MEM_freeN(values); - } - - BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); - - if (ret) { - if (act != NULL) { - DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - if (adt != NULL && adt->action != NULL && adt->action != act) { - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - } - - return ret; + PointerRNA id_ptr, ptr; + PropertyRNA *prop = NULL; + AnimData *adt; + ListBase tmp_nla_cache = {NULL, NULL}; + NlaKeyframingContext *nla_context = NULL; + int ret = 0; + + /* validate pointer first - exit if failure */ + if (id == NULL) { + BKE_reportf(reports, RPT_ERROR, "No ID block to insert keyframe in (path = %s)", rna_path); + return 0; + } + + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", + (id) ? id->name : TIP_(""), + rna_path); + return 0; + } + + /* if no action is provided, keyframe to the default one attached to this ID-block */ + if (act == NULL) { + /* get action to add F-Curve+keyframe to */ + act = verify_adt_action(bmain, id, 1); + + if (act == NULL) { + BKE_reportf(reports, + RPT_ERROR, + "Could not insert keyframe, as this type does not support animation data (ID = " + "%s, path = %s)", + id->name, + rna_path); + return 0; + } + } + + /* apply NLA-mapping to frame to use (if applicable) */ + adt = BKE_animdata_from_id(id); + + if (adt && adt->action == act) { + /* Get NLA context for value remapping. */ + nla_context = BKE_animsys_get_nla_keyframing_context( + nla_cache ? nla_cache : &tmp_nla_cache, depsgraph, &id_ptr, adt, cfra); + + /* Apply NLA-mapping to frame. */ + cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + } + + /* Obtain values to insert. */ + float value_buffer[RNA_MAX_ARRAY_LENGTH]; + int value_count; + bool force_all; + + float *values = get_keyframe_values(depsgraph, + reports, + ptr, + prop, + array_index, + nla_context, + flag, + value_buffer, + RNA_MAX_ARRAY_LENGTH, + &value_count, + &force_all); + + if (values != NULL) { + /* Key the entire array. */ + if (array_index == -1 || force_all) { + /* In force mode, if any of the curves succeeds, drop the replace mode and restart. */ + if (force_all && (flag & INSERTKEY_REPLACE) != 0) { + int exclude = -1; + + for (array_index = 0; array_index < value_count; array_index++) { + if (insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag)) { + ret++; + exclude = array_index; + break; + } + } + + if (exclude != -1) { + flag &= ~INSERTKEY_REPLACE; + + for (array_index = 0; array_index < value_count; array_index++) { + if (array_index != exclude) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag); + } + } + } + } + /* Simply insert all channels. */ + else { + for (array_index = 0; array_index < value_count; array_index++) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag); + } + } + } + /* Key a single index. */ + else { + if (array_index >= 0 && array_index < value_count) { + ret += insert_keyframe_fcurve_value(bmain, + reports, + &ptr, + prop, + act, + group, + rna_path, + array_index, + cfra, + values[array_index], + keytype, + flag); + } + } + } + + if (values != value_buffer) { + MEM_freeN(values); + } + + BKE_animsys_free_nla_keyframing_context_cache(&tmp_nla_cache); + + if (ret) { + if (act != NULL) { + DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + if (adt != NULL && adt->action != NULL && adt->action != act) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + } + + return ret; } /* ************************************************** */ @@ -1340,128 +1491,138 @@ short insert_keyframe( * the keyframe deletion. These include the quick refresh options. */ - - /** * \note caller needs to run #BKE_nla_tweakedit_remap to get NLA relative frame. * caller should also check #BKE_fcurve_is_protected before keying. */ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra) { - bool found; - int i; - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - - /* Only delete curve too if it won't be doing anything anymore */ - if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) - ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); - - /* return success */ - return true; - } - return false; + bool found; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + + /* Only delete curve too if it won't be doing anything anymore */ + if ((fcu->totvert == 0) && + (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + + /* return success */ + return true; + } + return false; } static void deg_tag_after_keyframe_delete(Main *bmain, ID *id, AnimData *adt) { - if (adt->action == NULL) { - /* In the case last f-curve wes removed need to inform dependency graph - * about relations update, since it needs to get rid of animation operation - * for this datablock. */ - DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION_NO_FLUSH); - DEG_relations_tag_update(bmain); - } - else { - DEG_id_tag_update_ex(bmain, &adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } + if (adt->action == NULL) { + /* In the case last f-curve wes removed need to inform dependency graph + * about relations update, since it needs to get rid of animation operation + * for this datablock. */ + DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION_NO_FLUSH); + DEG_relations_tag_update(bmain); + } + else { + DEG_id_tag_update_ex(bmain, &adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } } -short delete_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act, - const char group[], const char rna_path[], int array_index, float cfra, +short delete_keyframe(Main *bmain, + ReportList *reports, + ID *id, + bAction *act, + const char group[], + const char rna_path[], + int array_index, + float cfra, eInsertKeyFlags UNUSED(flag)) { - AnimData *adt = BKE_animdata_from_id(id); - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - int array_index_max = array_index + 1; - int ret = 0; - - /* sanity checks */ - if (ELEM(NULL, id, adt)) { - BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); - return 0; - } - - /* validate pointer first - exit if failure */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not delete keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - - /* get F-Curve - * Note: here is one of the places where we don't want new Action + F-Curve added! - * so 'add' var must be 0 - */ - if (act == NULL) { - /* if no action is provided, use the default one attached to this ID-block - * - if it doesn't exist, then we're out of options... - */ - if (adt->action) { - act = adt->action; - - /* apply NLA-mapping to frame to use (if applicable) */ - cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); - } - else { - BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); - return 0; - } - } - - /* key entire array convenience method */ - if (array_index == -1) { - array_index = 0; - array_index_max = RNA_property_array_length(&ptr, prop); - - /* for single properties, increase max_index so that the property itself gets included, - * but don't do this for standard arrays since that can cause corruption issues - * (extra unused curves) - */ - if (array_index_max == array_index) - array_index_max++; - } - - /* will only loop once unless the array index was -1 */ - for (; array_index < array_index_max; array_index++) { - FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0); - - /* check if F-Curve exists and/or whether it can be edited */ - if (fcu == NULL) - continue; - - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve '%s' for %s '%s'", - fcu->rna_path, BKE_idcode_to_name(GS(id->name)), id->name + 2); - continue; - } - - ret += delete_keyframe_fcurve(adt, fcu, cfra); - - } - if (ret) { - deg_tag_after_keyframe_delete(bmain, id, adt); - } - /* return success/failure */ - return ret; + AnimData *adt = BKE_animdata_from_id(id); + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + int array_index_max = array_index + 1; + int ret = 0; + + /* sanity checks */ + if (ELEM(NULL, id, adt)) { + BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); + return 0; + } + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not delete keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", + id->name, + rna_path); + return 0; + } + + /* get F-Curve + * Note: here is one of the places where we don't want new Action + F-Curve added! + * so 'add' var must be 0 + */ + if (act == NULL) { + /* if no action is provided, use the default one attached to this ID-block + * - if it doesn't exist, then we're out of options... + */ + if (adt->action) { + act = adt->action; + + /* apply NLA-mapping to frame to use (if applicable) */ + cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + } + else { + BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); + return 0; + } + } + + /* key entire array convenience method */ + if (array_index == -1) { + array_index = 0; + array_index_max = RNA_property_array_length(&ptr, prop); + + /* for single properties, increase max_index so that the property itself gets included, + * but don't do this for standard arrays since that can cause corruption issues + * (extra unused curves) + */ + if (array_index_max == array_index) + array_index_max++; + } + + /* will only loop once unless the array index was -1 */ + for (; array_index < array_index_max; array_index++) { + FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0); + + /* check if F-Curve exists and/or whether it can be edited */ + if (fcu == NULL) + continue; + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(reports, + RPT_WARNING, + "Not deleting keyframe for locked F-Curve '%s' for %s '%s'", + fcu->rna_path, + BKE_idcode_to_name(GS(id->name)), + id->name + 2); + continue; + } + + ret += delete_keyframe_fcurve(adt, fcu, cfra); + } + if (ret) { + deg_tag_after_keyframe_delete(bmain, id, adt); + } + /* return success/failure */ + return ret; } /* ************************************************** */ @@ -1474,86 +1635,97 @@ short delete_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act, * The flag argument is used for special settings that alter the behavior of * the keyframe deletion. These include the quick refresh options. */ -static short clear_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *act, - const char group[], const char rna_path[], int array_index, +static short clear_keyframe(Main *bmain, + ReportList *reports, + ID *id, + bAction *act, + const char group[], + const char rna_path[], + int array_index, eInsertKeyFlags UNUSED(flag)) { - AnimData *adt = BKE_animdata_from_id(id); - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - int array_index_max = array_index + 1; - int ret = 0; - - /* sanity checks */ - if (ELEM(NULL, id, adt)) { - BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); - return 0; - } - - /* validate pointer first - exit if failure */ - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { - BKE_reportf(reports, RPT_ERROR, - "Could not clear keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", - id->name, rna_path); - return 0; - } - - /* get F-Curve - * Note: here is one of the places where we don't want new Action + F-Curve added! - * so 'add' var must be 0 - */ - if (act == NULL) { - /* if no action is provided, use the default one attached to this ID-block - * - if it doesn't exist, then we're out of options... - */ - if (adt->action) { - act = adt->action; - } - else { - BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); - return 0; - } - } - - /* key entire array convenience method */ - if (array_index == -1) { - array_index = 0; - array_index_max = RNA_property_array_length(&ptr, prop); - - /* for single properties, increase max_index so that the property itself gets included, - * but don't do this for standard arrays since that can cause corruption issues - * (extra unused curves) - */ - if (array_index_max == array_index) - array_index_max++; - } - - /* will only loop once unless the array index was -1 */ - for (; array_index < array_index_max; array_index++) { - FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0); - - /* check if F-Curve exists and/or whether it can be edited */ - if (fcu == NULL) - continue; - - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(reports, RPT_WARNING, - "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'", - fcu->rna_path, BKE_idcode_to_name(GS(id->name)), id->name + 2); - continue; - } - - ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); - - /* return success */ - ret++; - } - if (ret) { - deg_tag_after_keyframe_delete(bmain, id, adt); - } - /* return success/failure */ - return ret; + AnimData *adt = BKE_animdata_from_id(id); + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + int array_index_max = array_index + 1; + int ret = 0; + + /* sanity checks */ + if (ELEM(NULL, id, adt)) { + BKE_report(reports, RPT_ERROR, "No ID block and/or AnimData to delete keyframe from"); + return 0; + } + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) { + BKE_reportf( + reports, + RPT_ERROR, + "Could not clear keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)", + id->name, + rna_path); + return 0; + } + + /* get F-Curve + * Note: here is one of the places where we don't want new Action + F-Curve added! + * so 'add' var must be 0 + */ + if (act == NULL) { + /* if no action is provided, use the default one attached to this ID-block + * - if it doesn't exist, then we're out of options... + */ + if (adt->action) { + act = adt->action; + } + else { + BKE_reportf(reports, RPT_ERROR, "No action to delete keyframes from for ID = %s", id->name); + return 0; + } + } + + /* key entire array convenience method */ + if (array_index == -1) { + array_index = 0; + array_index_max = RNA_property_array_length(&ptr, prop); + + /* for single properties, increase max_index so that the property itself gets included, + * but don't do this for standard arrays since that can cause corruption issues + * (extra unused curves) + */ + if (array_index_max == array_index) + array_index_max++; + } + + /* will only loop once unless the array index was -1 */ + for (; array_index < array_index_max; array_index++) { + FCurve *fcu = verify_fcurve(bmain, act, group, &ptr, rna_path, array_index, 0); + + /* check if F-Curve exists and/or whether it can be edited */ + if (fcu == NULL) + continue; + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(reports, + RPT_WARNING, + "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'", + fcu->rna_path, + BKE_idcode_to_name(GS(id->name)), + id->name + 2); + continue; + } + + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + + /* return success */ + ret++; + } + if (ret) { + deg_tag_after_keyframe_delete(bmain, id, adt); + } + /* return success/failure */ + return ret; } /* ******************************************* */ @@ -1561,8 +1733,8 @@ static short clear_keyframe(Main *bmain, ReportList *reports, ID *id, bAction *a /* mode for commonkey_modifykey */ enum { - COMMONKEY_MODE_INSERT = 0, - COMMONKEY_MODE_DELETE, + COMMONKEY_MODE_INSERT = 0, + COMMONKEY_MODE_DELETE, } /*eCommonModifyKey_Modes*/; /* Polling callback for use with ANIM_*_keyframe() operators @@ -1571,128 +1743,144 @@ enum { */ static bool modify_key_op_poll(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - Scene *scene = CTX_data_scene(C); + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); - /* if no area or active scene */ - if (ELEM(NULL, sa, scene)) - return false; + /* if no area or active scene */ + if (ELEM(NULL, sa, scene)) + return false; - /* should be fine */ - return true; + /* should be fine */ + return true; } /* Insert Key Operator ------------------------ */ static int insert_key_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - bool ob_edit_mode = false; - - float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap - short success; - - KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); - if (ks == NULL) { - return OPERATOR_CANCELLED; - } - - /* exit the edit mode to make sure that those object data properties that have been - * updated since the last switching to the edit mode will be keyframed correctly - */ - if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) { - ED_object_mode_toggle(C, OB_MODE_EDIT); - ob_edit_mode = true; - } - - /* try to insert keyframes for the channels specified by KeyingSet */ - success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - if (G.debug & G_DEBUG) - BKE_reportf(op->reports, RPT_INFO, "Keying set '%s' - successfully added %d keyframes", ks->name, success); - - /* restore the edit mode if necessary */ - if (ob_edit_mode) { - ED_object_mode_toggle(C, OB_MODE_EDIT); - } - - /* report failure or do updates? */ - if (success == MODIFYKEY_INVALID_CONTEXT) { - BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); - return OPERATOR_CANCELLED; - } - else if (success) { - /* if the appropriate properties have been set, make a note that we've inserted something */ - if (RNA_boolean_get(op->ptr, "confirm_success")) - BKE_reportf(op->reports, RPT_INFO, "Successfully added %d keyframes for keying set '%s'", success, ks->name); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - } - else - BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes"); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + bool ob_edit_mode = false; + + float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + short success; + + KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); + if (ks == NULL) { + return OPERATOR_CANCELLED; + } + + /* exit the edit mode to make sure that those object data properties that have been + * updated since the last switching to the edit mode will be keyframed correctly + */ + if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) { + ED_object_mode_toggle(C, OB_MODE_EDIT); + ob_edit_mode = true; + } + + /* try to insert keyframes for the channels specified by KeyingSet */ + success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + if (G.debug & G_DEBUG) + BKE_reportf(op->reports, + RPT_INFO, + "Keying set '%s' - successfully added %d keyframes", + ks->name, + success); + + /* restore the edit mode if necessary */ + if (ob_edit_mode) { + ED_object_mode_toggle(C, OB_MODE_EDIT); + } + + /* report failure or do updates? */ + if (success == MODIFYKEY_INVALID_CONTEXT) { + BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); + return OPERATOR_CANCELLED; + } + else if (success) { + /* if the appropriate properties have been set, make a note that we've inserted something */ + if (RNA_boolean_get(op->ptr, "confirm_success")) + BKE_reportf(op->reports, + RPT_INFO, + "Successfully added %d keyframes for keying set '%s'", + success, + ks->name); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + } + else + BKE_report(op->reports, RPT_WARNING, "Keying set failed to insert any keyframes"); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_insert(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Insert Keyframe"; - ot->idname = "ANIM_OT_keyframe_insert"; - ot->description = "Insert keyframes on the current frame for all properties in the specified Keying Set"; - - /* callbacks */ - ot->exec = insert_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - prop = RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Insert", - "Show a popup when the keyframes get successfully added"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Insert Keyframe"; + ot->idname = "ANIM_OT_keyframe_insert"; + ot->description = + "Insert keyframes on the current frame for all properties in the specified Keying Set"; + + /* callbacks */ + ot->exec = insert_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum( + ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + prop = RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Insert", + "Show a popup when the keyframes get successfully added"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* Clone of 'ANIM_OT_keyframe_insert' which uses a name for the keying set instead of an enum. */ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Insert Keyframe (by name)"; - ot->idname = "ANIM_OT_keyframe_insert_by_name"; - ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use"; - - /* callbacks */ - ot->exec = insert_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (idname) */ - prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - prop = RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Insert", - "Show a popup when the keyframes get successfully added"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Insert Keyframe (by name)"; + ot->idname = "ANIM_OT_keyframe_insert_by_name"; + ot->description = "Alternate access to 'Insert Keyframe' for keymaps to use"; + + /* callbacks */ + ot->exec = insert_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (idname) */ + prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + prop = RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Insert", + "Show a popup when the keyframes get successfully added"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* Insert Key Operator (With Menu) ------------------------ */ @@ -1702,190 +1890,207 @@ void ANIM_OT_keyframe_insert_by_name(wmOperatorType *ot) static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Scene *scene = CTX_data_scene(C); - - /* if prompting or no active Keying Set, show the menu */ - if ((scene->active_keyingset == 0) || RNA_boolean_get(op->ptr, "always_prompt")) { - uiPopupMenu *pup; - uiLayout *layout; - - /* call the menu, which will call this operator again, hence the canceled */ - pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); - layout = UI_popup_menu_layout(pup); - uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type"); - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; - } - else { - /* just call the exec() on the active keyingset */ - RNA_enum_set(op->ptr, "type", 0); - RNA_boolean_set(op->ptr, "confirm_success", true); - - return op->type->exec(C, op); - } + Scene *scene = CTX_data_scene(C); + + /* if prompting or no active Keying Set, show the menu */ + if ((scene->active_keyingset == 0) || RNA_boolean_get(op->ptr, "always_prompt")) { + uiPopupMenu *pup; + uiLayout *layout; + + /* call the menu, which will call this operator again, hence the canceled */ + pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); + layout = UI_popup_menu_layout(pup); + uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type"); + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; + } + else { + /* just call the exec() on the active keyingset */ + RNA_enum_set(op->ptr, "type", 0); + RNA_boolean_set(op->ptr, "confirm_success", true); + + return op->type->exec(C, op); + } } void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Insert Keyframe Menu"; - ot->idname = "ANIM_OT_keyframe_insert_menu"; - ot->description = "Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined"; - - /* callbacks */ - ot->invoke = insert_key_menu_invoke; - ot->exec = insert_key_exec; - ot->poll = ED_operator_areaactive; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is disabled so that if a menu is shown, this doesn't come up too - */ - // XXX should this just be always on? - prop = RNA_def_boolean(ot->srna, "confirm_success", 0, "Confirm Successful Insert", - "Show a popup when the keyframes get successfully added"); - RNA_def_property_flag(prop, PROP_HIDDEN); - - /* whether the menu should always be shown - * - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior), - * although in some cases it might be useful to always shown (pre 2.5 behavior) - */ - prop = RNA_def_boolean(ot->srna, "always_prompt", 0, "Always Show Menu", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Insert Keyframe Menu"; + ot->idname = "ANIM_OT_keyframe_insert_menu"; + ot->description = + "Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined"; + + /* callbacks */ + ot->invoke = insert_key_menu_invoke; + ot->exec = insert_key_exec; + ot->poll = ED_operator_areaactive; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum( + ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is disabled so that if a menu is shown, this doesn't come up too + */ + // XXX should this just be always on? + prop = RNA_def_boolean(ot->srna, + "confirm_success", + 0, + "Confirm Successful Insert", + "Show a popup when the keyframes get successfully added"); + RNA_def_property_flag(prop, PROP_HIDDEN); + + /* whether the menu should always be shown + * - by default, the menu should only be shown when there is no active Keying Set (2.5 behavior), + * although in some cases it might be useful to always shown (pre 2.5 behavior) + */ + prop = RNA_def_boolean(ot->srna, "always_prompt", 0, "Always Show Menu", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* Delete Key Operator ------------------------ */ static int delete_key_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap - short success; - - KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); - if (ks == NULL) { - return OPERATOR_CANCELLED; - } - - const int prop_type = RNA_property_type(op->type->prop); - if (prop_type == PROP_ENUM) { - int type = RNA_property_enum_get(op->ptr, op->type->prop); - ks = ANIM_keyingset_get_from_enum_type(scene, type); - if (ks == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active keying set"); - return OPERATOR_CANCELLED; - } - } - else if (prop_type == PROP_STRING) { - char type_id[MAX_ID_NAME - 2]; - RNA_property_string_get(op->ptr, op->type->prop, type_id); - ks = ANIM_keyingset_get_from_idname(scene, type_id); - - if (ks == NULL) { - BKE_reportf(op->reports, RPT_ERROR, "No active keying set '%s' not found", type_id); - return OPERATOR_CANCELLED; - } - } - else { - BLI_assert(0); - } - - /* report failure */ - if (ks == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active Keying Set"); - return OPERATOR_CANCELLED; - } - - /* try to delete keyframes for the channels specified by KeyingSet */ - success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); - if (G.debug & G_DEBUG) - printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, success); - - /* report failure or do updates? */ - if (success == MODIFYKEY_INVALID_CONTEXT) { - BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); - return OPERATOR_CANCELLED; - } - else if (success) { - /* if the appropriate properties have been set, make a note that we've inserted something */ - if (RNA_boolean_get(op->ptr, "confirm_success")) - BKE_reportf(op->reports, RPT_INFO, "Successfully removed %d keyframes for keying set '%s'", success, ks->name); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); - } - else - BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes"); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + short success; + + KeyingSet *ks = keyingset_get_from_op_with_error(op, op->type->prop, scene); + if (ks == NULL) { + return OPERATOR_CANCELLED; + } + + const int prop_type = RNA_property_type(op->type->prop); + if (prop_type == PROP_ENUM) { + int type = RNA_property_enum_get(op->ptr, op->type->prop); + ks = ANIM_keyingset_get_from_enum_type(scene, type); + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active keying set"); + return OPERATOR_CANCELLED; + } + } + else if (prop_type == PROP_STRING) { + char type_id[MAX_ID_NAME - 2]; + RNA_property_string_get(op->ptr, op->type->prop, type_id); + ks = ANIM_keyingset_get_from_idname(scene, type_id); + + if (ks == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "No active keying set '%s' not found", type_id); + return OPERATOR_CANCELLED; + } + } + else { + BLI_assert(0); + } + + /* report failure */ + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active Keying Set"); + return OPERATOR_CANCELLED; + } + + /* try to delete keyframes for the channels specified by KeyingSet */ + success = ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); + if (G.debug & G_DEBUG) + printf("KeyingSet '%s' - Successfully removed %d Keyframes\n", ks->name, success); + + /* report failure or do updates? */ + if (success == MODIFYKEY_INVALID_CONTEXT) { + BKE_report(op->reports, RPT_ERROR, "No suitable context info for active keying set"); + return OPERATOR_CANCELLED; + } + else if (success) { + /* if the appropriate properties have been set, make a note that we've inserted something */ + if (RNA_boolean_get(op->ptr, "confirm_success")) + BKE_reportf(op->reports, + RPT_INFO, + "Successfully removed %d keyframes for keying set '%s'", + success, + ks->name); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + } + else + BKE_report(op->reports, RPT_WARNING, "Keying set failed to remove any keyframes"); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_delete(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - 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"; - - /* callbacks */ - ot->exec = delete_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Delete", - "Show a popup when the keyframes get successfully removed"); + PropertyRNA *prop; + + /* identifiers */ + 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"; + + /* callbacks */ + ot->exec = delete_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum( + ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Delete", + "Show a popup when the keyframes get successfully removed"); } void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Delete Keying-Set Keyframe (by name)"; - ot->idname = "ANIM_OT_keyframe_delete_by_name"; - ot->description = "Alternate access to 'Delete Keyframe' for keymaps to use"; - - /* callbacks */ - ot->exec = delete_key_exec; - ot->poll = modify_key_op_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (idname) */ - prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); - ot->prop = prop; - - /* confirm whether a keyframe was added by showing a popup - * - by default, this is enabled, since this operator is assumed to be called independently - */ - RNA_def_boolean(ot->srna, "confirm_success", 1, "Confirm Successful Delete", - "Show a popup when the keyframes get successfully removed"); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Delete Keying-Set Keyframe (by name)"; + ot->idname = "ANIM_OT_keyframe_delete_by_name"; + ot->description = "Alternate access to 'Delete Keyframe' for keymaps to use"; + + /* callbacks */ + ot->exec = delete_key_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (idname) */ + prop = RNA_def_string_file_path(ot->srna, "type", "Type", MAX_ID_NAME - 2, "", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + ot->prop = prop; + + /* confirm whether a keyframe was added by showing a popup + * - by default, this is enabled, since this operator is assumed to be called independently + */ + RNA_def_boolean(ot->srna, + "confirm_success", + 1, + "Confirm Successful Delete", + "Show a popup when the keyframes get successfully removed"); } /* Delete Key Operator ------------------------ */ @@ -1895,503 +2100,533 @@ void ANIM_OT_keyframe_delete_by_name(wmOperatorType *ot) static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op)) { - bool changed = false; - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - /* just those in active action... */ - if ((ob->adt) && (ob->adt->action)) { - AnimData *adt = ob->adt; - bAction *act = adt->action; - FCurve *fcu, *fcn; - - for (fcu = act->curves.first; fcu; fcu = fcn) { - bool can_delete = false; - - fcn = fcu->next; - - /* in pose mode, only delete the F-Curve if it belongs to a selected bone */ - if (ob->mode & OB_MODE_POSE) { - if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) { - bPoseChannel *pchan; - char *bone_name; - - /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (bone_name) MEM_freeN(bone_name); - - /* delete if bone is selected*/ - if ((pchan) && (pchan->bone)) { - if (pchan->bone->flag & BONE_SELECTED) - can_delete = true; - } - } - } - else { - /* object mode - all of Object's F-Curves are affected */ - can_delete = true; - } - - /* delete F-Curve completely */ - if (can_delete) { - ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - changed = true; - } - } - } - } - CTX_DATA_END; - - if (!changed) { - return OPERATOR_CANCELLED; - } - - /* send updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); - - return OPERATOR_FINISHED; + bool changed = false; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + /* just those in active action... */ + if ((ob->adt) && (ob->adt->action)) { + AnimData *adt = ob->adt; + bAction *act = adt->action; + FCurve *fcu, *fcn; + + for (fcu = act->curves.first; fcu; fcu = fcn) { + bool can_delete = false; + + fcn = fcu->next; + + /* in pose mode, only delete the F-Curve if it belongs to a selected bone */ + if (ob->mode & OB_MODE_POSE) { + if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) { + bPoseChannel *pchan; + char *bone_name; + + /* get bone-name, and check if this bone is selected */ + bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name) + MEM_freeN(bone_name); + + /* delete if bone is selected*/ + if ((pchan) && (pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) + can_delete = true; + } + } + } + else { + /* object mode - all of Object's F-Curves are affected */ + can_delete = true; + } + + /* delete F-Curve completely */ + if (can_delete) { + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + changed = true; + } + } + } + } + CTX_DATA_END; + + if (!changed) { + return OPERATOR_CANCELLED; + } + + /* send updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Animation"; - ot->description = "Remove all keyframe animation for selected objects"; - ot->idname = "ANIM_OT_keyframe_clear_v3d"; + /* identifiers */ + ot->name = "Remove Animation"; + ot->description = "Remove all keyframe animation for selected objects"; + ot->idname = "ANIM_OT_keyframe_clear_v3d"; - /* callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = clear_anim_v3d_exec; + /* callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = clear_anim_v3d_exec; - ot->poll = ED_operator_areaactive; + ot->poll = ED_operator_areaactive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - static int delete_key_v3d_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - float cfra = (float)CFRA; - - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) - { - ID *id = &ob->id; - int success = 0; - - /* just those in active action... */ - if ((ob->adt) && (ob->adt->action)) { - AnimData *adt = ob->adt; - bAction *act = adt->action; - FCurve *fcu, *fcn; - const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); - - for (fcu = act->curves.first; fcu; fcu = fcn) { - fcn = fcu->next; - - /* don't touch protected F-Curves */ - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(op->reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve '%s', object '%s'", - fcu->rna_path, id->name + 2); - continue; - } - - /* special exception for bones, as this makes this operator more convenient to use - * NOTE: This is only done in pose mode. In object mode, we're dealing with the entire object. - */ - if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) { - bPoseChannel *pchan; - char *bone_name; - - /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (bone_name) MEM_freeN(bone_name); - - /* skip if bone is not selected */ - if ((pchan) && (pchan->bone)) { - /* bones are only selected/editable if visible... */ - bArmature *arm = (bArmature *)ob->data; - - /* skipping - not visible on currently visible layers */ - if ((arm->layer & pchan->bone->layer) == 0) - continue; - /* skipping - is currently hidden */ - if (pchan->bone->flag & BONE_HIDDEN_P) - continue; - - /* selection flag... */ - if ((pchan->bone->flag & BONE_SELECTED) == 0) - continue; - } - } - - /* delete keyframes on current frame - * WARNING: this can delete the next F-Curve, hence the "fcn" copying - */ - success += delete_keyframe_fcurve(adt, fcu, cfra_unmap); - } - DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - - /* report success (or failure) */ - if (success) - BKE_reportf(op->reports, RPT_INFO, "Object '%s' successfully had %d keyframes removed", id->name + 2, success); - else - BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2); - - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - } - CTX_DATA_END; - - /* send updates */ - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + float cfra = (float)CFRA; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { + ID *id = &ob->id; + int success = 0; + + /* just those in active action... */ + if ((ob->adt) && (ob->adt->action)) { + AnimData *adt = ob->adt; + bAction *act = adt->action; + FCurve *fcu, *fcn; + const float cfra_unmap = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); + + for (fcu = act->curves.first; fcu; fcu = fcn) { + fcn = fcu->next; + + /* don't touch protected F-Curves */ + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(op->reports, + RPT_WARNING, + "Not deleting keyframe for locked F-Curve '%s', object '%s'", + fcu->rna_path, + id->name + 2); + continue; + } + + /* special exception for bones, as this makes this operator more convenient to use + * NOTE: This is only done in pose mode. In object mode, we're dealing with the entire object. + */ + if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) { + bPoseChannel *pchan; + char *bone_name; + + /* get bone-name, and check if this bone is selected */ + bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + if (bone_name) + MEM_freeN(bone_name); + + /* skip if bone is not selected */ + if ((pchan) && (pchan->bone)) { + /* bones are only selected/editable if visible... */ + bArmature *arm = (bArmature *)ob->data; + + /* skipping - not visible on currently visible layers */ + if ((arm->layer & pchan->bone->layer) == 0) + continue; + /* skipping - is currently hidden */ + if (pchan->bone->flag & BONE_HIDDEN_P) + continue; + + /* selection flag... */ + if ((pchan->bone->flag & BONE_SELECTED) == 0) + continue; + } + } + + /* delete keyframes on current frame + * WARNING: this can delete the next F-Curve, hence the "fcn" copying + */ + success += delete_keyframe_fcurve(adt, fcu, cfra_unmap); + } + DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + + /* report success (or failure) */ + if (success) + BKE_reportf(op->reports, + RPT_INFO, + "Object '%s' successfully had %d keyframes removed", + id->name + 2, + success); + else + BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2); + + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + } + CTX_DATA_END; + + /* send updates */ + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); + + return OPERATOR_FINISHED; } void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Keyframe"; - ot->description = "Remove keyframes on current frame for selected objects and bones"; - ot->idname = "ANIM_OT_keyframe_delete_v3d"; + /* identifiers */ + ot->name = "Delete Keyframe"; + ot->description = "Remove keyframes on current frame for selected objects and bones"; + ot->idname = "ANIM_OT_keyframe_delete_v3d"; - /* callbacks */ - ot->invoke = WM_operator_confirm; - ot->exec = delete_key_v3d_exec; + /* callbacks */ + ot->invoke = WM_operator_confirm; + ot->exec = delete_key_v3d_exec; - ot->poll = ED_operator_areaactive; + ot->poll = ED_operator_areaactive; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - /* Insert Key Button Operator ------------------------ */ static int insert_key_button_exec(bContext *C, wmOperator *op) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - char *path; - uiBut *but; - float cfra = (float)CFRA; - short success = 0; - int index; - const bool all = RNA_boolean_get(op->ptr, "all"); - eInsertKeyFlags flag = INSERTKEY_NOFLAGS; - - - /* flags for inserting keyframes */ - flag = ANIM_get_keyframing_flags(scene, 1); - - /* try to insert keyframe using property retrieved from UI */ - if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) { - if (ptr.type == &RNA_NlaStrip) { - /* Handle special properties for NLA Strips, whose F-Curves are stored on the - * strips themselves. These are stored separately or else the properties will - * not have any effect. - */ - NlaStrip *strip = (NlaStrip *)ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - - if (fcu) { - success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, 0); - } - else { - BKE_report(op->reports, RPT_ERROR, - "This property cannot be animated as it will not get updated correctly"); - } - } - else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) { - /* Driven property - Find driver */ - FCurve *fcu; - bool driven, special; - - fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); - - if (fcu && driven) { - success = insert_keyframe_direct(depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, INSERTKEY_DRIVER); - } - } - else { - /* standard properties */ - path = RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - const char *identifier = RNA_property_identifier(prop); - const char *group = NULL; - - /* Special exception for keyframing transforms: - * Set "group" for this manually, instead of having them appearing at the bottom (ungrouped) - * part of the channels list. Leaving these ungrouped is not a nice user behavior in this case. - * - * TODO: Perhaps we can extend this behavior in future for other properties... - */ - if (ptr.type == &RNA_PoseBone) { - bPoseChannel *pchan = (bPoseChannel *)ptr.data; - group = pchan->name; - } - else if ((ptr.type == &RNA_Object) && - (strstr(identifier, "location") || strstr(identifier, "rotation") || strstr(identifier, "scale"))) - { - /* NOTE: Keep this label in sync with the "ID" case in - * keyingsets_utils.py :: get_transform_generators_base_info() - */ - group = "Object Transforms"; - } - - - if (all) { - /* -1 indicates operating on the entire array (or the property itself otherwise) */ - index = -1; - } - - success = insert_keyframe(bmain, depsgraph, op->reports, ptr.id.data, NULL, group, path, index, cfra, ts->keyframe_type, NULL, flag); - - MEM_freeN(path); - } - else { - BKE_report(op->reports, RPT_WARNING, - "Failed to resolve path to property, " - "try manually specifying this using a Keying Set instead"); - } - } - } - else { - if (prop && !RNA_property_animateable(&ptr, prop)) { - BKE_reportf(op->reports, RPT_WARNING, - "\"%s\" property cannot be animated", - RNA_property_identifier(prop)); - } - else { - BKE_reportf(op->reports, RPT_WARNING, - "Button doesn't appear to have any property information attached (ptr.data = %p, prop = %p)", - (void *)ptr.data, (void *)prop); - } - } - - if (success) { - ID *id = ptr.id.data; - AnimData *adt = BKE_animdata_from_id(id); - if (adt->action != NULL) { - DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); - } - DEG_id_tag_update(id, ID_RECALC_ANIMATION_NO_FLUSH); - - /* send updates */ - UI_context_update_anim_flag(C); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + char *path; + uiBut *but; + float cfra = (float)CFRA; + short success = 0; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + eInsertKeyFlags flag = INSERTKEY_NOFLAGS; + + /* flags for inserting keyframes */ + flag = ANIM_get_keyframing_flags(scene, 1); + + /* try to insert keyframe using property retrieved from UI */ + if (!(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index))) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) { + if (ptr.type == &RNA_NlaStrip) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + + if (fcu) { + success = insert_keyframe_direct( + depsgraph, op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, NULL, 0); + } + else { + BKE_report(op->reports, + RPT_ERROR, + "This property cannot be animated as it will not get updated correctly"); + } + } + else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) { + /* Driven property - Find driver */ + FCurve *fcu; + bool driven, special; + + fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special); + + if (fcu && driven) { + success = insert_keyframe_direct(depsgraph, + op->reports, + ptr, + prop, + fcu, + cfra, + ts->keyframe_type, + NULL, + INSERTKEY_DRIVER); + } + } + else { + /* standard properties */ + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + const char *identifier = RNA_property_identifier(prop); + const char *group = NULL; + + /* Special exception for keyframing transforms: + * Set "group" for this manually, instead of having them appearing at the bottom (ungrouped) + * part of the channels list. Leaving these ungrouped is not a nice user behavior in this case. + * + * TODO: Perhaps we can extend this behavior in future for other properties... + */ + if (ptr.type == &RNA_PoseBone) { + bPoseChannel *pchan = (bPoseChannel *)ptr.data; + group = pchan->name; + } + else if ((ptr.type == &RNA_Object) && + (strstr(identifier, "location") || strstr(identifier, "rotation") || + strstr(identifier, "scale"))) { + /* NOTE: Keep this label in sync with the "ID" case in + * keyingsets_utils.py :: get_transform_generators_base_info() + */ + group = "Object Transforms"; + } + + if (all) { + /* -1 indicates operating on the entire array (or the property itself otherwise) */ + index = -1; + } + + success = insert_keyframe(bmain, + depsgraph, + op->reports, + ptr.id.data, + NULL, + group, + path, + index, + cfra, + ts->keyframe_type, + NULL, + flag); + + MEM_freeN(path); + } + else { + BKE_report(op->reports, + RPT_WARNING, + "Failed to resolve path to property, " + "try manually specifying this using a Keying Set instead"); + } + } + } + else { + if (prop && !RNA_property_animateable(&ptr, prop)) { + BKE_reportf(op->reports, + RPT_WARNING, + "\"%s\" property cannot be animated", + RNA_property_identifier(prop)); + } + else { + BKE_reportf(op->reports, + RPT_WARNING, + "Button doesn't appear to have any property information attached (ptr.data = " + "%p, prop = %p)", + (void *)ptr.data, + (void *)prop); + } + } + + if (success) { + ID *id = ptr.id.data; + AnimData *adt = BKE_animdata_from_id(id); + if (adt->action != NULL) { + DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + DEG_id_tag_update(id, ID_RECALC_ANIMATION_NO_FLUSH); + + /* send updates */ + UI_context_update_anim_flag(C); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyframe_insert_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Insert Keyframe (Buttons)"; - ot->idname = "ANIM_OT_keyframe_insert_button"; - ot->description = "Insert a keyframe for current UI-active property"; + /* identifiers */ + ot->name = "Insert Keyframe (Buttons)"; + ot->idname = "ANIM_OT_keyframe_insert_button"; + ot->description = "Insert a keyframe for current UI-active property"; - /* callbacks */ - ot->exec = insert_key_button_exec; - ot->poll = modify_key_op_poll; + /* callbacks */ + ot->exec = insert_key_button_exec; + ot->poll = modify_key_op_poll; - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array"); } /* Delete Key Button Operator ------------------------ */ static int delete_key_button_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - Main *bmain = CTX_data_main(C); - char *path; - float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap - short success = 0; - int index; - const bool all = RNA_boolean_get(op->ptr, "all"); - - /* try to insert keyframe using property retrieved from UI */ - if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - if (ptr.id.data && ptr.data && prop) { - if (BKE_nlastrip_has_curves_for_property(&ptr, prop)) { - /* Handle special properties for NLA Strips, whose F-Curves are stored on the - * strips themselves. These are stored separately or else the properties will - * not have any effect. - */ - ID *id = ptr.id.data; - NlaStrip *strip = (NlaStrip *)ptr.data; - FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); - - if (fcu) { - if (BKE_fcurve_is_protected(fcu)) { - BKE_reportf(op->reports, RPT_WARNING, - "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", - strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); - } - else { - /* remove the keyframe directly - * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, - * and delete_keyframe() expects the FCurve to be part of an action - */ - bool found = false; - int i; - - /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); - if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards) */ - delete_fcurve_key(fcu, i, 1); - success = true; - } - } - } - } - else { - /* standard properties */ - path = RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - if (all) { - /* -1 indicates operating on the entire array (or the property itself otherwise) */ - index = -1; - } - - success = delete_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0); - MEM_freeN(path); - } - else if (G.debug & G_DEBUG) - printf("Button Delete-Key: no path to property\n"); - } - } - else if (G.debug & G_DEBUG) { - printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); - } - - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + Main *bmain = CTX_data_main(C); + char *path; + float cfra = (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + short success = 0; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + + /* try to insert keyframe using property retrieved from UI */ + if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if (ptr.id.data && ptr.data && prop) { + if (BKE_nlastrip_has_curves_for_property(&ptr, prop)) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ + ID *id = ptr.id.data; + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0); + + if (fcu) { + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf( + op->reports, + RPT_WARNING, + "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", + strip->name, + BKE_idcode_to_name(GS(id->name)), + id->name + 2); + } + else { + /* remove the keyframe directly + * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, + * and delete_keyframe() expects the FCurve to be part of an action + */ + bool found = false; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + success = true; + } + } + } + } + else { + /* standard properties */ + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + if (all) { + /* -1 indicates operating on the entire array (or the property itself otherwise) */ + index = -1; + } + + success = delete_keyframe( + bmain, op->reports, ptr.id.data, NULL, NULL, path, index, cfra, 0); + MEM_freeN(path); + } + else if (G.debug & G_DEBUG) + printf("Button Delete-Key: no path to property\n"); + } + } + else if (G.debug & G_DEBUG) { + printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); + } + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyframe_delete_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Keyframe (Buttons)"; - ot->idname = "ANIM_OT_keyframe_delete_button"; - ot->description = "Delete current keyframe of current UI-active property"; + /* identifiers */ + ot->name = "Delete Keyframe (Buttons)"; + ot->idname = "ANIM_OT_keyframe_delete_button"; + ot->description = "Delete current keyframe of current UI-active property"; - /* callbacks */ - ot->exec = delete_key_button_exec; - ot->poll = modify_key_op_poll; + /* callbacks */ + ot->exec = delete_key_button_exec; + ot->poll = modify_key_op_poll; - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyframes from all elements of the array"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyframes from all elements of the array"); } - /* Clear Key Button Operator ------------------------ */ static int clear_key_button_exec(bContext *C, wmOperator *op) { - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop = NULL; - Main *bmain = CTX_data_main(C); - char *path; - short success = 0; - int index; - const bool all = RNA_boolean_get(op->ptr, "all"); - - /* try to insert keyframe using property retrieved from UI */ - if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - if (ptr.id.data && ptr.data && prop) { - path = RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - if (all) { - /* -1 indicates operating on the entire array (or the property itself otherwise) */ - index = -1; - } - - success += clear_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, 0); - MEM_freeN(path); - } - else if (G.debug & G_DEBUG) - printf("Button Clear-Key: no path to property\n"); - } - else if (G.debug & G_DEBUG) { - printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); - } - - - if (success) { - /* send updates */ - UI_context_update_anim_flag(C); - - /* send notifiers that keyframes have been changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + Main *bmain = CTX_data_main(C); + char *path; + short success = 0; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + + /* try to insert keyframe using property retrieved from UI */ + if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + if (ptr.id.data && ptr.data && prop) { + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + if (all) { + /* -1 indicates operating on the entire array (or the property itself otherwise) */ + index = -1; + } + + success += clear_keyframe(bmain, op->reports, ptr.id.data, NULL, NULL, path, index, 0); + MEM_freeN(path); + } + else if (G.debug & G_DEBUG) + printf("Button Clear-Key: no path to property\n"); + } + else if (G.debug & G_DEBUG) { + printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); + } + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Keyframe (Buttons)"; - ot->idname = "ANIM_OT_keyframe_clear_button"; - ot->description = "Clear all keyframes on the currently active property"; + /* identifiers */ + ot->name = "Clear Keyframe (Buttons)"; + ot->idname = "ANIM_OT_keyframe_clear_button"; + ot->description = "Clear all keyframes on the currently active property"; - /* callbacks */ - ot->exec = clear_key_button_exec; - ot->poll = modify_key_op_poll; + /* callbacks */ + ot->exec = clear_key_button_exec; + ot->poll = modify_key_op_poll; - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Clear keyframes from all elements of the array"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Clear keyframes from all elements of the array"); } /* ******************************************* */ @@ -2399,30 +2634,30 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) bool autokeyframe_cfra_can_key(Scene *scene, ID *id) { - float cfra = (float)CFRA; // XXX for now, this will do - - /* only filter if auto-key mode requires this */ - if (IS_AUTOKEY_ON(scene) == 0) - return false; - - if (IS_AUTOKEY_MODE(scene, EDITKEYS)) { - /* Replace Mode: - * For whole block, only key if there's a keyframe on that frame already - * This is a valid assumption when we're blocking + tweaking - */ - return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL); - } - else { - /* Normal Mode (or treat as being normal mode): - * - * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode) - * let's set the "normal" flag too, so that it will all be sane everywhere... - */ - scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL; - - /* Can insert anytime we like... */ - return true; - } + float cfra = (float)CFRA; // XXX for now, this will do + + /* only filter if auto-key mode requires this */ + if (IS_AUTOKEY_ON(scene) == 0) + return false; + + if (IS_AUTOKEY_MODE(scene, EDITKEYS)) { + /* Replace Mode: + * For whole block, only key if there's a keyframe on that frame already + * This is a valid assumption when we're blocking + tweaking + */ + return id_frame_has_keyframe(id, cfra, ANIMFILTER_KEYS_LOCAL); + } + else { + /* Normal Mode (or treat as being normal mode): + * + * Just in case the flags aren't set properly (i.e. only on/off is set, without a mode) + * let's set the "normal" flag too, so that it will all be sane everywhere... + */ + scene->toolsettings->autokey_mode = AUTOKEY_MODE_NORMAL; + + /* Can insert anytime we like... */ + return true; + } } /* ******************************************* */ @@ -2433,48 +2668,49 @@ bool autokeyframe_cfra_can_key(Scene *scene, ID *id) /* Checks if some F-Curve has a keyframe for a given frame */ bool fcurve_frame_has_keyframe(FCurve *fcu, float frame, short filter) { - /* quick sanity check */ - if (ELEM(NULL, fcu, fcu->bezt)) - return false; - - /* we either include all regardless of muting, or only non-muted */ - if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED) == 0) { - bool replace; - int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace); - - /* binarysearch_bezt_index will set replace to be 0 or 1 - * - obviously, 1 represents a match - */ - if (replace) { - /* sanity check: 'i' may in rare cases exceed arraylen */ - if ((i >= 0) && (i < fcu->totvert)) - return true; - } - } - - return false; + /* quick sanity check */ + if (ELEM(NULL, fcu, fcu->bezt)) + return false; + + /* we either include all regardless of muting, or only non-muted */ + if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED) == 0) { + bool replace; + int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace); + + /* binarysearch_bezt_index will set replace to be 0 or 1 + * - obviously, 1 represents a match + */ + if (replace) { + /* sanity check: 'i' may in rare cases exceed arraylen */ + if ((i >= 0) && (i < fcu->totvert)) + return true; + } + } + + return false; } /* Returns whether the current value of a given property differs from the interpolated value. */ bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float frame) { - PathResolvedRNA anim_rna; - anim_rna.ptr = ptr; - anim_rna.prop = prop; - anim_rna.prop_index = fcu->array_index; + PathResolvedRNA anim_rna; + anim_rna.ptr = ptr; + anim_rna.prop = prop; + anim_rna.prop_index = fcu->array_index; - float buffer[RNA_MAX_ARRAY_LENGTH]; - int count, index = fcu->array_index; - float *values = setting_get_rna_values(NULL, &ptr, prop, false, buffer, RNA_MAX_ARRAY_LENGTH, &count); + float buffer[RNA_MAX_ARRAY_LENGTH]; + int count, index = fcu->array_index; + float *values = setting_get_rna_values( + NULL, &ptr, prop, false, buffer, RNA_MAX_ARRAY_LENGTH, &count); - float fcurve_val = calculate_fcurve(&anim_rna, fcu, frame); - float cur_val = (index >= 0 && index < count) ? values[index] : 0.0f; + float fcurve_val = calculate_fcurve(&anim_rna, fcu, frame); + float cur_val = (index >= 0 && index < count) ? values[index] : 0.0f; - if (values != buffer) { - MEM_freeN(values); - } + if (values != buffer) { + MEM_freeN(values); + } - return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64); + return !compare_ff_relative(fcurve_val, cur_val, FLT_EPSILON, 64); } /* Checks whether an Action has a keyframe for a given frame @@ -2482,91 +2718,91 @@ bool fcurve_is_changed(PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float fra */ static bool action_frame_has_keyframe(bAction *act, float frame, short filter) { - FCurve *fcu; - - /* can only find if there is data */ - if (act == NULL) - return false; - - /* if only check non-muted, check if muted */ - if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED)) - return false; - - /* loop over F-Curves, using binary-search to try to find matches - * - this assumes that keyframes are only beztriples - */ - for (fcu = act->curves.first; fcu; fcu = fcu->next) { - /* only check if there are keyframes (currently only of type BezTriple) */ - if (fcu->bezt && fcu->totvert) { - if (fcurve_frame_has_keyframe(fcu, frame, filter)) - return true; - } - } - - /* nothing found */ - return false; + FCurve *fcu; + + /* can only find if there is data */ + if (act == NULL) + return false; + + /* if only check non-muted, check if muted */ + if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED)) + return false; + + /* loop over F-Curves, using binary-search to try to find matches + * - this assumes that keyframes are only beztriples + */ + for (fcu = act->curves.first; fcu; fcu = fcu->next) { + /* only check if there are keyframes (currently only of type BezTriple) */ + if (fcu->bezt && fcu->totvert) { + if (fcurve_frame_has_keyframe(fcu, frame, filter)) + return true; + } + } + + /* nothing found */ + return false; } /* Checks whether an Object has a keyframe for a given frame */ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) { - /* error checking */ - if (ob == NULL) - return false; - - /* check own animation data - specifically, the action it contains */ - if ((ob->adt) && (ob->adt->action)) { - /* T41525 - When the active action is a NLA strip being edited, - * we need to correct the frame number to "look inside" the - * remapped action - */ - float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP); - - if (action_frame_has_keyframe(ob->adt->action, ob_frame, filter)) - return true; - } - - /* try shapekey keyframes (if available, and allowed by filter) */ - if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY)) { - Key *key = BKE_key_from_object(ob); - - /* shapekeys can have keyframes ('Relative Shape Keys') - * or depend on time (old 'Absolute Shape Keys') - */ - - /* 1. test for relative (with keyframes) */ - if (id_frame_has_keyframe((ID *)key, frame, filter)) - return true; - - /* 2. test for time */ - /* TODO... yet to be implemented (this feature may evolve before then anyway) */ - } - - /* try materials */ - if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT)) { - /* if only active, then we can skip a lot of looping */ - if (filter & ANIMFILTER_KEYS_ACTIVE) { - Material *ma = give_current_material(ob, (ob->actcol + 1)); - - /* we only retrieve the active material... */ - if (id_frame_has_keyframe((ID *)ma, frame, filter)) - return true; - } - else { - int a; - - /* loop over materials */ - for (a = 0; a < ob->totcol; a++) { - Material *ma = give_current_material(ob, a + 1); - - if (id_frame_has_keyframe((ID *)ma, frame, filter)) - return true; - } - } - } - - /* nothing found */ - return false; + /* error checking */ + if (ob == NULL) + return false; + + /* check own animation data - specifically, the action it contains */ + if ((ob->adt) && (ob->adt->action)) { + /* T41525 - When the active action is a NLA strip being edited, + * we need to correct the frame number to "look inside" the + * remapped action + */ + float ob_frame = BKE_nla_tweakedit_remap(ob->adt, frame, NLATIME_CONVERT_UNMAP); + + if (action_frame_has_keyframe(ob->adt->action, ob_frame, filter)) + return true; + } + + /* try shapekey keyframes (if available, and allowed by filter) */ + if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOSKEY)) { + Key *key = BKE_key_from_object(ob); + + /* shapekeys can have keyframes ('Relative Shape Keys') + * or depend on time (old 'Absolute Shape Keys') + */ + + /* 1. test for relative (with keyframes) */ + if (id_frame_has_keyframe((ID *)key, frame, filter)) + return true; + + /* 2. test for time */ + /* TODO... yet to be implemented (this feature may evolve before then anyway) */ + } + + /* try materials */ + if (!(filter & ANIMFILTER_KEYS_LOCAL) && !(filter & ANIMFILTER_KEYS_NOMAT)) { + /* if only active, then we can skip a lot of looping */ + if (filter & ANIMFILTER_KEYS_ACTIVE) { + Material *ma = give_current_material(ob, (ob->actcol + 1)); + + /* we only retrieve the active material... */ + if (id_frame_has_keyframe((ID *)ma, frame, filter)) + return true; + } + else { + int a; + + /* loop over materials */ + for (a = 0; a < ob->totcol; a++) { + Material *ma = give_current_material(ob, a + 1); + + if (id_frame_has_keyframe((ID *)ma, frame, filter)) + return true; + } + } + } + + /* nothing found */ + return false; } /* --------------- API ------------------- */ @@ -2574,88 +2810,88 @@ static bool object_frame_has_keyframe(Object *ob, float frame, short filter) /* Checks whether a keyframe exists for the given ID-block one the given frame */ bool id_frame_has_keyframe(ID *id, float frame, short filter) { - /* sanity checks */ - if (id == NULL) - return false; - - /* perform special checks for 'macro' types */ - switch (GS(id->name)) { - case ID_OB: /* object */ - return object_frame_has_keyframe((Object *)id, frame, filter); + /* sanity checks */ + if (id == NULL) + return false; + + /* perform special checks for 'macro' types */ + switch (GS(id->name)) { + case ID_OB: /* object */ + return object_frame_has_keyframe((Object *)id, frame, filter); #if 0 - // XXX TODO... for now, just use 'normal' behavior - case ID_SCE: /* scene */ - break; + // XXX TODO... for now, just use 'normal' behavior + case ID_SCE: /* scene */ + break; #endif - default: /* 'normal type' */ - { - AnimData *adt = BKE_animdata_from_id(id); - - /* only check keyframes in active action */ - if (adt) - return action_frame_has_keyframe(adt->action, frame, filter); - break; - } - } - - - /* no keyframe found */ - return false; + default: /* 'normal type' */ + { + AnimData *adt = BKE_animdata_from_id(id); + + /* only check keyframes in active action */ + if (adt) + return action_frame_has_keyframe(adt->action, frame, filter); + break; + } + } + + /* no keyframe found */ + return false; } /* ************************************************** */ bool ED_autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks) { - /* auto keyframing */ - if (autokeyframe_cfra_can_key(scene, &ob->id)) { - ListBase dsources = {NULL, NULL}; - - /* now insert the keyframe(s) using the Keying Set - * 1) add datasource override for the Object - * 2) insert keyframes - * 3) free the extra info - */ - ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - BLI_freelistN(&dsources); - - return true; - } - else { - return false; - } + /* auto keyframing */ + if (autokeyframe_cfra_can_key(scene, &ob->id)) { + ListBase dsources = {NULL, NULL}; + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the Object + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); + + return true; + } + else { + return false; + } } -bool ED_autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks) +bool ED_autokeyframe_pchan( + bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks) { - if (autokeyframe_cfra_can_key(scene, &ob->id)) { - ListBase dsources = {NULL, NULL}; - - /* now insert the keyframe(s) using the Keying Set - * 1) add datasource override for the PoseChannel - * 2) insert keyframes - * 3) free the extra info - */ - ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); - ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); - BLI_freelistN(&dsources); - - /* clear any unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag &= ~BONE_UNKEYED; - } - - return true; - } - else { - /* add unkeyed tags */ - if (pchan->bone) { - pchan->bone->flag |= BONE_UNKEYED; - } - - return false; - } + if (autokeyframe_cfra_can_key(scene, &ob->id)) { + ListBase dsources = {NULL, NULL}; + + /* now insert the keyframe(s) using the Keying Set + * 1) add datasource override for the PoseChannel + * 2) insert keyframes + * 3) free the extra info + */ + ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); + ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); + BLI_freelistN(&dsources); + + /* clear any unkeyed tags */ + if (pchan->bone) { + pchan->bone->flag &= ~BONE_UNKEYED; + } + + return true; + } + else { + /* add unkeyed tags */ + if (pchan->bone) { + pchan->bone->flag |= BONE_UNKEYED; + } + + return false; + } } /* -------------------------------------------------------------------- */ @@ -2665,28 +2901,28 @@ bool ED_autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel * /** Use for insert/delete key-frame. */ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *prop, Scene *scene) { - KeyingSet *ks = NULL; - const int prop_type = RNA_property_type(prop); - if (prop_type == PROP_ENUM) { - int type = RNA_property_enum_get(op->ptr, prop); - ks = ANIM_keyingset_get_from_enum_type(scene, type); - if (ks == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active keying set"); - } - } - else if (prop_type == PROP_STRING) { - char type_id[MAX_ID_NAME - 2]; - RNA_property_string_get(op->ptr, prop, type_id); - ks = ANIM_keyingset_get_from_idname(scene, type_id); - - if (ks == NULL) { - BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id); - } - } - else { - BLI_assert(0); - } - return ks; + KeyingSet *ks = NULL; + const int prop_type = RNA_property_type(prop); + if (prop_type == PROP_ENUM) { + int type = RNA_property_enum_get(op->ptr, prop); + ks = ANIM_keyingset_get_from_enum_type(scene, type); + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active keying set"); + } + } + else if (prop_type == PROP_STRING) { + char type_id[MAX_ID_NAME - 2]; + RNA_property_string_get(op->ptr, prop, type_id); + ks = ANIM_keyingset_get_from_idname(scene, type_id); + + if (ks == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id); + } + } + else { + BLI_assert(0); + } + return ks; } /** \} */ diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 654543c9d5d..93bae636571 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -21,7 +21,6 @@ * \ingroup edanimation */ - #include #include #include @@ -68,209 +67,208 @@ /* poll callback for adding default KeyingSet */ static bool keyingset_poll_default_add(bContext *C) { - /* as long as there's an active Scene, it's fine */ - return (CTX_data_scene(C) != NULL); + /* as long as there's an active Scene, it's fine */ + return (CTX_data_scene(C) != NULL); } /* poll callback for editing active KeyingSet */ static bool keyingset_poll_active_edit(bContext *C) { - Scene *scene = CTX_data_scene(C); + Scene *scene = CTX_data_scene(C); - if (scene == NULL) - return 0; + if (scene == NULL) + return 0; - /* there must be an active KeyingSet (and KeyingSets) */ - return ((scene->active_keyingset > 0) && (scene->keyingsets.first)); + /* there must be an active KeyingSet (and KeyingSets) */ + return ((scene->active_keyingset > 0) && (scene->keyingsets.first)); } /* poll callback for editing active KeyingSet Path */ static bool keyingset_poll_activePath_edit(bContext *C) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks; - - if (scene == NULL) - return 0; - if (scene->active_keyingset <= 0) - return 0; - else - ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - - /* there must be an active KeyingSet and an active path */ - return ((ks) && (ks->paths.first) && (ks->active_path > 0)); + Scene *scene = CTX_data_scene(C); + KeyingSet *ks; + + if (scene == NULL) + return 0; + if (scene->active_keyingset <= 0) + return 0; + else + ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + + /* there must be an active KeyingSet and an active path */ + return ((ks) && (ks->paths.first) && (ks->active_path > 0)); } - /* Add a Default (Empty) Keying Set ------------------------- */ static int add_default_keyingset_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - short flag = 0, keyingflag = 0; + Scene *scene = CTX_data_scene(C); + short flag = 0, keyingflag = 0; - /* validate flags - * - absolute KeyingSets should be created by default - */ - flag |= KEYINGSET_ABSOLUTE; + /* validate flags + * - absolute KeyingSets should be created by default + */ + flag |= KEYINGSET_ABSOLUTE; - /* 2nd arg is 0 to indicate that we don't want to include autokeying mode related settings */ - keyingflag = ANIM_get_keyframing_flags(scene, 0); + /* 2nd arg is 0 to indicate that we don't want to include autokeying mode related settings */ + keyingflag = ANIM_get_keyframing_flags(scene, 0); - /* call the API func, and set the active keyingset index */ - BKE_keyingset_add(&scene->keyingsets, NULL, NULL, flag, keyingflag); + /* call the API func, and set the active keyingset index */ + BKE_keyingset_add(&scene->keyingsets, NULL, NULL, flag, keyingflag); - scene->active_keyingset = BLI_listbase_count(&scene->keyingsets); + scene->active_keyingset = BLI_listbase_count(&scene->keyingsets); - /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + /* send notifiers */ + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ANIM_OT_keying_set_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Empty Keying Set"; - ot->idname = "ANIM_OT_keying_set_add"; - ot->description = "Add a new (empty) Keying Set to the active Scene"; - - /* callbacks */ - ot->exec = add_default_keyingset_exec; - ot->poll = keyingset_poll_default_add; + /* identifiers */ + ot->name = "Add Empty Keying Set"; + ot->idname = "ANIM_OT_keying_set_add"; + ot->description = "Add a new (empty) Keying Set to the active Scene"; + + /* callbacks */ + ot->exec = add_default_keyingset_exec; + ot->poll = keyingset_poll_default_add; } /* Remove 'Active' Keying Set ------------------------- */ static int remove_active_keyingset_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks; - - /* verify the Keying Set to use: - * - use the active one - * - return error if it doesn't exist - */ - if (scene->active_keyingset == 0) { - BKE_report(op->reports, RPT_ERROR, "No active keying set to remove"); - return OPERATOR_CANCELLED; - } - else if (scene->active_keyingset < 0) { - BKE_report(op->reports, RPT_ERROR, "Cannot remove built in keying set"); - return OPERATOR_CANCELLED; - } - else - ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - - /* free KeyingSet's data, then remove it from the scene */ - BKE_keyingset_free(ks); - BLI_freelinkN(&scene->keyingsets, ks); - - /* the active one should now be the previously second-to-last one */ - scene->active_keyingset--; - - /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + KeyingSet *ks; + + /* verify the Keying Set to use: + * - use the active one + * - return error if it doesn't exist + */ + if (scene->active_keyingset == 0) { + BKE_report(op->reports, RPT_ERROR, "No active keying set to remove"); + return OPERATOR_CANCELLED; + } + else if (scene->active_keyingset < 0) { + BKE_report(op->reports, RPT_ERROR, "Cannot remove built in keying set"); + return OPERATOR_CANCELLED; + } + else + ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + + /* free KeyingSet's data, then remove it from the scene */ + BKE_keyingset_free(ks); + BLI_freelinkN(&scene->keyingsets, ks); + + /* the active one should now be the previously second-to-last one */ + scene->active_keyingset--; + + /* send notifiers */ + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + + return OPERATOR_FINISHED; } void ANIM_OT_keying_set_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Active Keying Set"; - ot->idname = "ANIM_OT_keying_set_remove"; - ot->description = "Remove the active Keying Set"; - - /* callbacks */ - ot->exec = remove_active_keyingset_exec; - ot->poll = keyingset_poll_active_edit; + /* identifiers */ + ot->name = "Remove Active Keying Set"; + ot->idname = "ANIM_OT_keying_set_remove"; + ot->description = "Remove the active Keying Set"; + + /* callbacks */ + ot->exec = remove_active_keyingset_exec; + ot->poll = keyingset_poll_active_edit; } /* Add Empty Keying Set Path ------------------------- */ static int add_empty_ks_path_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks; - KS_Path *ksp; - - /* verify the Keying Set to use: - * - use the active one - * - return error if it doesn't exist - */ - if (scene->active_keyingset == 0) { - BKE_report(op->reports, RPT_ERROR, "No active keying set to add empty path to"); - return OPERATOR_CANCELLED; - } - else - ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - - /* don't use the API method for this, since that checks on values... */ - ksp = MEM_callocN(sizeof(KS_Path), "KeyingSetPath Empty"); - BLI_addtail(&ks->paths, ksp); - ks->active_path = BLI_listbase_count(&ks->paths); - - ksp->groupmode = KSP_GROUP_KSNAME; // XXX? - ksp->idtype = ID_OB; - ksp->flag = KSP_FLAG_WHOLE_ARRAY; - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + KeyingSet *ks; + KS_Path *ksp; + + /* verify the Keying Set to use: + * - use the active one + * - return error if it doesn't exist + */ + if (scene->active_keyingset == 0) { + BKE_report(op->reports, RPT_ERROR, "No active keying set to add empty path to"); + return OPERATOR_CANCELLED; + } + else + ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + + /* don't use the API method for this, since that checks on values... */ + ksp = MEM_callocN(sizeof(KS_Path), "KeyingSetPath Empty"); + BLI_addtail(&ks->paths, ksp); + ks->active_path = BLI_listbase_count(&ks->paths); + + ksp->groupmode = KSP_GROUP_KSNAME; // XXX? + ksp->idtype = ID_OB; + ksp->flag = KSP_FLAG_WHOLE_ARRAY; + + return OPERATOR_FINISHED; } void ANIM_OT_keying_set_path_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add Empty Keying Set Path"; - ot->idname = "ANIM_OT_keying_set_path_add"; - ot->description = "Add empty path to active Keying Set"; - - /* callbacks */ - ot->exec = add_empty_ks_path_exec; - ot->poll = keyingset_poll_active_edit; + /* identifiers */ + ot->name = "Add Empty Keying Set Path"; + ot->idname = "ANIM_OT_keying_set_path_add"; + ot->description = "Add empty path to active Keying Set"; + + /* callbacks */ + ot->exec = add_empty_ks_path_exec; + ot->poll = keyingset_poll_active_edit; } /* Remove Active Keying Set Path ------------------------- */ static int remove_active_ks_path_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - - /* if there is a KeyingSet, find the nominated path to remove */ - if (ks) { - KS_Path *ksp = BLI_findlink(&ks->paths, ks->active_path - 1); - - if (ksp) { - /* remove the active path from the KeyingSet */ - BKE_keyingset_free_path(ks, ksp); - - /* the active path should now be the previously second-to-last active one */ - ks->active_path--; - } - else { - BKE_report(op->reports, RPT_ERROR, "No active keying set path to remove"); - return OPERATOR_CANCELLED; - } - } - else { - BKE_report(op->reports, RPT_ERROR, "No active keying set to remove a path from"); - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + KeyingSet *ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + + /* if there is a KeyingSet, find the nominated path to remove */ + if (ks) { + KS_Path *ksp = BLI_findlink(&ks->paths, ks->active_path - 1); + + if (ksp) { + /* remove the active path from the KeyingSet */ + BKE_keyingset_free_path(ks, ksp); + + /* the active path should now be the previously second-to-last active one */ + ks->active_path--; + } + else { + BKE_report(op->reports, RPT_ERROR, "No active keying set path to remove"); + return OPERATOR_CANCELLED; + } + } + else { + BKE_report(op->reports, RPT_ERROR, "No active keying set to remove a path from"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; } void ANIM_OT_keying_set_path_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove Active Keying Set Path"; - ot->idname = "ANIM_OT_keying_set_path_remove"; - ot->description = "Remove active Path from active Keying Set"; - - /* callbacks */ - ot->exec = remove_active_ks_path_exec; - ot->poll = keyingset_poll_activePath_edit; + /* identifiers */ + ot->name = "Remove Active Keying Set Path"; + ot->idname = "ANIM_OT_keying_set_path_remove"; + ot->description = "Remove active Path from active Keying Set"; + + /* callbacks */ + ot->exec = remove_active_ks_path_exec; + ot->poll = keyingset_poll_activePath_edit; } /* ************************************************** */ @@ -280,184 +278,184 @@ void ANIM_OT_keying_set_path_remove(wmOperatorType *ot) static int add_keyingset_button_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks = NULL; - PropertyRNA *prop = NULL; - PointerRNA ptr = {{NULL}}; - char *path = NULL; - short success = 0; - int index = 0, pflag = 0; - const bool all = RNA_boolean_get(op->ptr, "all"); - - /* try to add to keyingset using property retrieved from UI */ - if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - /* verify the Keying Set to use: - * - use the active one for now (more control over this can be added later) - * - add a new one if it doesn't exist - */ - if (scene->active_keyingset == 0) { - short flag = 0, keyingflag = 0; - - /* validate flags - * - absolute KeyingSets should be created by default - */ - flag |= KEYINGSET_ABSOLUTE; - - keyingflag |= ANIM_get_keyframing_flags(scene, 0); - - if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) - keyingflag |= INSERTKEY_XYZ2RGB; - - /* call the API func, and set the active keyingset index */ - ks = BKE_keyingset_add(&scene->keyingsets, "ButtonKeyingSet", "Button Keying Set", flag, keyingflag); - - scene->active_keyingset = BLI_listbase_count(&scene->keyingsets); - } - else if (scene->active_keyingset < 0) { - BKE_report(op->reports, RPT_ERROR, "Cannot add property to built in keying set"); - return OPERATOR_CANCELLED; - } - else { - ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - } - - /* check if property is able to be added */ - if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - path = RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - /* set flags */ - if (all) { - pflag |= KSP_FLAG_WHOLE_ARRAY; - - /* we need to set the index for this to 0, even though it may break in some cases, this is - * necessary if we want the entire array for most cases to get included without the user - * having to worry about where they clicked - */ - index = 0; - } - - /* add path to this setting */ - BKE_keyingset_add_path(ks, ptr.id.data, NULL, path, index, pflag, KSP_GROUP_KSNAME); - ks->active_path = BLI_listbase_count(&ks->paths); - success = 1; - - /* free the temp path created */ - MEM_freeN(path); - } - } - - if (success) { - /* send updates */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); - - /* show notification/report header, so that users notice that something changed */ - BKE_reportf(op->reports, RPT_INFO, "Property added to Keying Set: '%s'", ks->name); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + KeyingSet *ks = NULL; + PropertyRNA *prop = NULL; + PointerRNA ptr = {{NULL}}; + char *path = NULL; + short success = 0; + int index = 0, pflag = 0; + const bool all = RNA_boolean_get(op->ptr, "all"); + + /* try to add to keyingset using property retrieved from UI */ + if (!UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + /* verify the Keying Set to use: + * - use the active one for now (more control over this can be added later) + * - add a new one if it doesn't exist + */ + if (scene->active_keyingset == 0) { + short flag = 0, keyingflag = 0; + + /* validate flags + * - absolute KeyingSets should be created by default + */ + flag |= KEYINGSET_ABSOLUTE; + + keyingflag |= ANIM_get_keyframing_flags(scene, 0); + + if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) + keyingflag |= INSERTKEY_XYZ2RGB; + + /* call the API func, and set the active keyingset index */ + ks = BKE_keyingset_add( + &scene->keyingsets, "ButtonKeyingSet", "Button Keying Set", flag, keyingflag); + + scene->active_keyingset = BLI_listbase_count(&scene->keyingsets); + } + else if (scene->active_keyingset < 0) { + BKE_report(op->reports, RPT_ERROR, "Cannot add property to built in keying set"); + return OPERATOR_CANCELLED; + } + else { + ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + } + + /* check if property is able to be added */ + if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + /* set flags */ + if (all) { + pflag |= KSP_FLAG_WHOLE_ARRAY; + + /* we need to set the index for this to 0, even though it may break in some cases, this is + * necessary if we want the entire array for most cases to get included without the user + * having to worry about where they clicked + */ + index = 0; + } + + /* add path to this setting */ + BKE_keyingset_add_path(ks, ptr.id.data, NULL, path, index, pflag, KSP_GROUP_KSNAME); + ks->active_path = BLI_listbase_count(&ks->paths); + success = 1; + + /* free the temp path created */ + MEM_freeN(path); + } + } + + if (success) { + /* send updates */ + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + + /* show notification/report header, so that users notice that something changed */ + BKE_reportf(op->reports, RPT_INFO, "Property added to Keying Set: '%s'", ks->name); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyingset_button_add(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Add to Keying Set"; - ot->idname = "ANIM_OT_keyingset_button_add"; - ot->description = "Add current UI-active property to current keying set"; + /* identifiers */ + ot->name = "Add to Keying Set"; + ot->idname = "ANIM_OT_keyingset_button_add"; + ot->description = "Add current UI-active property to current keying set"; - /* callbacks */ - ot->exec = add_keyingset_button_exec; - //op->poll = ??? + /* callbacks */ + ot->exec = add_keyingset_button_exec; + //op->poll = ??? - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - RNA_def_boolean(ot->srna, "all", 1, "All", "Add all elements of the array to a Keying Set"); + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Add all elements of the array to a Keying Set"); } /* Remove from KeyingSet Button Operator ------------------------ */ static int remove_keyingset_button_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks = NULL; - PropertyRNA *prop = NULL; - PointerRNA ptr = {{NULL}}; - char *path = NULL; - short success = 0; - int index = 0; - - /* try to add to keyingset using property retrieved from UI */ - if (UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { - /* pass event on if no active button found */ - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - /* verify the Keying Set to use: - * - use the active one for now (more control over this can be added later) - * - return error if it doesn't exist - */ - if (scene->active_keyingset == 0) { - BKE_report(op->reports, RPT_ERROR, "No active keying set to remove property from"); - return OPERATOR_CANCELLED; - } - else if (scene->active_keyingset < 0) { - BKE_report(op->reports, RPT_ERROR, "Cannot remove property from built in keying set"); - return OPERATOR_CANCELLED; - } - else { - ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - } - - if (ptr.id.data && ptr.data && prop) { - path = RNA_path_from_ID_to_property(&ptr, prop); - - if (path) { - KS_Path *ksp; - - /* try to find a path matching this description */ - ksp = BKE_keyingset_find_path(ks, ptr.id.data, ks->name, path, index, KSP_GROUP_KSNAME); - - if (ksp) { - BKE_keyingset_free_path(ks, ksp); - success = 1; - } - - /* free temp path used */ - MEM_freeN(path); - } - } - - - if (success) { - /* send updates */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); - - /* show warning */ - BKE_report(op->reports, RPT_INFO, "Property removed from Keying Set"); - } - - return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + Scene *scene = CTX_data_scene(C); + KeyingSet *ks = NULL; + PropertyRNA *prop = NULL; + PointerRNA ptr = {{NULL}}; + char *path = NULL; + short success = 0; + int index = 0; + + /* try to add to keyingset using property retrieved from UI */ + if (UI_context_active_but_prop_get(C, &ptr, &prop, &index)) { + /* pass event on if no active button found */ + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + /* verify the Keying Set to use: + * - use the active one for now (more control over this can be added later) + * - return error if it doesn't exist + */ + if (scene->active_keyingset == 0) { + BKE_report(op->reports, RPT_ERROR, "No active keying set to remove property from"); + return OPERATOR_CANCELLED; + } + else if (scene->active_keyingset < 0) { + BKE_report(op->reports, RPT_ERROR, "Cannot remove property from built in keying set"); + return OPERATOR_CANCELLED; + } + else { + ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + } + + if (ptr.id.data && ptr.data && prop) { + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + KS_Path *ksp; + + /* try to find a path matching this description */ + ksp = BKE_keyingset_find_path(ks, ptr.id.data, ks->name, path, index, KSP_GROUP_KSNAME); + + if (ksp) { + BKE_keyingset_free_path(ks, ksp); + success = 1; + } + + /* free temp path used */ + MEM_freeN(path); + } + } + + if (success) { + /* send updates */ + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + + /* show warning */ + BKE_report(op->reports, RPT_INFO, "Property removed from Keying Set"); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void ANIM_OT_keyingset_button_remove(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Remove from Keying Set"; - ot->idname = "ANIM_OT_keyingset_button_remove"; - ot->description = "Remove current UI-active property from current keying set"; + /* identifiers */ + ot->name = "Remove from Keying Set"; + ot->idname = "ANIM_OT_keyingset_button_remove"; + ot->description = "Remove current UI-active property from current keying set"; - /* callbacks */ - ot->exec = remove_keyingset_button_exec; - //op->poll = ??? + /* callbacks */ + ot->exec = remove_keyingset_button_exec; + //op->poll = ??? - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************************************* */ @@ -467,53 +465,54 @@ void ANIM_OT_keyingset_button_remove(wmOperatorType *ot) static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - uiPopupMenu *pup; - uiLayout *layout; + uiPopupMenu *pup; + uiLayout *layout; - /* call the menu, which will call this operator again, hence the canceled */ - pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); - layout = UI_popup_menu_layout(pup); - uiItemsEnumO(layout, "ANIM_OT_keying_set_active_set", "type"); - UI_popup_menu_end(C, pup); + /* call the menu, which will call this operator again, hence the canceled */ + pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); + layout = UI_popup_menu_layout(pup); + uiItemsEnumO(layout, "ANIM_OT_keying_set_active_set", "type"); + UI_popup_menu_end(C, pup); - return OPERATOR_INTERFACE; + return OPERATOR_INTERFACE; } static int keyingset_active_menu_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - int type = RNA_enum_get(op->ptr, "type"); + Scene *scene = CTX_data_scene(C); + int type = RNA_enum_get(op->ptr, "type"); - /* If type == 0, it will deselect any active keying set. */ - scene->active_keyingset = type; + /* If type == 0, it will deselect any active keying set. */ + scene->active_keyingset = type; - /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + /* send notifiers */ + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void ANIM_OT_keying_set_active_set(wmOperatorType *ot) { - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Set Active Keying Set"; - ot->idname = "ANIM_OT_keying_set_active_set"; - ot->description = "Select a new keying set as the active one"; - - /* callbacks */ - ot->invoke = keyingset_active_menu_invoke; - ot->exec = keyingset_active_menu_exec; - ot->poll = ED_operator_areaactive; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* keyingset to use (dynamic enum) */ - prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); - RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); - // RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Set Active Keying Set"; + ot->idname = "ANIM_OT_keying_set_active_set"; + ot->description = "Select a new keying set as the active one"; + + /* callbacks */ + ot->invoke = keyingset_active_menu_invoke; + ot->exec = keyingset_active_menu_exec; + ot->poll = ED_operator_areaactive; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* keyingset to use (dynamic enum) */ + prop = RNA_def_enum( + ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); + RNA_def_enum_funcs(prop, ANIM_keying_sets_enum_itemf); + // RNA_def_property_flag(prop, PROP_HIDDEN); } /* ******************************************* */ @@ -530,42 +529,42 @@ ListBase builtin_keyingsets = {NULL, NULL}; /* Find KeyingSet type info given a name */ KeyingSetInfo *ANIM_keyingset_info_find_name(const char name[]) { - /* sanity checks */ - if ((name == NULL) || (name[0] == 0)) - return NULL; + /* sanity checks */ + if ((name == NULL) || (name[0] == 0)) + return NULL; - /* search by comparing names */ - return BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname)); + /* search by comparing names */ + return BLI_findstring(&keyingset_type_infos, name, offsetof(KeyingSetInfo, idname)); } /* Find builtin KeyingSet by name */ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[]) { - KeyingSet *ks, *first = NULL; + KeyingSet *ks, *first = NULL; - /* sanity checks any name to check? */ - if (name[0] == 0) - return NULL; + /* sanity checks any name to check? */ + if (name[0] == 0) + return NULL; - /* get first KeyingSet to use */ - if (prevKS && prevKS->next) - first = prevKS->next; - else - first = builtin_keyingsets.first; + /* get first KeyingSet to use */ + if (prevKS && prevKS->next) + first = prevKS->next; + else + first = builtin_keyingsets.first; - /* loop over KeyingSets checking names */ - for (ks = first; ks; ks = ks->next) { - if (STREQ(name, ks->idname)) - return ks; - } + /* loop over KeyingSets checking names */ + for (ks = first; ks; ks = ks->next) { + if (STREQ(name, ks->idname)) + return ks; + } - /* complain about missing keying sets on debug builds */ + /* complain about missing keying sets on debug builds */ #ifndef NDEBUG - printf("%s: '%s' not found\n", __func__, name); + printf("%s: '%s' not found\n", __func__, name); #endif - /* no matches found */ - return NULL; + /* no matches found */ + return NULL; } /* --------------- */ @@ -573,79 +572,79 @@ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[] /* Add the given KeyingSetInfo to the list of type infos, and create an appropriate builtin set too */ void ANIM_keyingset_info_register(KeyingSetInfo *ksi) { - KeyingSet *ks; + KeyingSet *ks; - /* create a new KeyingSet - * - inherit name and keyframing settings from the typeinfo - */ - ks = BKE_keyingset_add(&builtin_keyingsets, ksi->idname, ksi->name, 1, ksi->keyingflag); + /* create a new KeyingSet + * - inherit name and keyframing settings from the typeinfo + */ + ks = BKE_keyingset_add(&builtin_keyingsets, ksi->idname, ksi->name, 1, ksi->keyingflag); - /* link this KeyingSet with its typeinfo */ - memcpy(&ks->typeinfo, ksi->idname, sizeof(ks->typeinfo)); + /* link this KeyingSet with its typeinfo */ + memcpy(&ks->typeinfo, ksi->idname, sizeof(ks->typeinfo)); - /* Copy description... */ - BLI_strncpy(ks->description, ksi->description, sizeof(ks->description)); + /* Copy description... */ + BLI_strncpy(ks->description, ksi->description, sizeof(ks->description)); - /* add type-info to the list */ - BLI_addtail(&keyingset_type_infos, ksi); + /* add type-info to the list */ + BLI_addtail(&keyingset_type_infos, ksi); } /* Remove the given KeyingSetInfo from the list of type infos, and also remove the builtin set if appropriate */ void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi) { - KeyingSet *ks, *ksn; + KeyingSet *ks, *ksn; - /* find relevant builtin KeyingSets which use this, and remove them */ - /* TODO: this isn't done now, since unregister is really only used atm when we - * reload the scripts, which kindof defeats the purpose of "builtin"? */ - for (ks = builtin_keyingsets.first; ks; ks = ksn) { - ksn = ks->next; + /* find relevant builtin KeyingSets which use this, and remove them */ + /* TODO: this isn't done now, since unregister is really only used atm when we + * reload the scripts, which kindof defeats the purpose of "builtin"? */ + for (ks = builtin_keyingsets.first; ks; ks = ksn) { + ksn = ks->next; - /* remove if matching typeinfo name */ - if (STREQ(ks->typeinfo, ksi->idname)) { - Scene *scene; - BKE_keyingset_free(ks); - BLI_remlink(&builtin_keyingsets, ks); + /* remove if matching typeinfo name */ + if (STREQ(ks->typeinfo, ksi->idname)) { + Scene *scene; + BKE_keyingset_free(ks); + BLI_remlink(&builtin_keyingsets, ks); - for (scene = bmain->scenes.first; scene; scene = scene->id.next) - BLI_remlink_safe(&scene->keyingsets, ks); + for (scene = bmain->scenes.first; scene; scene = scene->id.next) + BLI_remlink_safe(&scene->keyingsets, ks); - MEM_freeN(ks); - } - } + MEM_freeN(ks); + } + } - /* free the type info */ - BLI_freelinkN(&keyingset_type_infos, ksi); + /* free the type info */ + BLI_freelinkN(&keyingset_type_infos, ksi); } /* --------------- */ void ANIM_keyingset_infos_exit(void) { - KeyingSetInfo *ksi, *next; + KeyingSetInfo *ksi, *next; - /* free type infos */ - for (ksi = keyingset_type_infos.first; ksi; ksi = next) { - next = ksi->next; + /* free type infos */ + for (ksi = keyingset_type_infos.first; ksi; ksi = next) { + next = ksi->next; - /* free extra RNA data, and remove from list */ - if (ksi->ext.free) - ksi->ext.free(ksi->ext.data); - BLI_freelinkN(&keyingset_type_infos, ksi); - } + /* free extra RNA data, and remove from list */ + if (ksi->ext.free) + ksi->ext.free(ksi->ext.data); + BLI_freelinkN(&keyingset_type_infos, ksi); + } - /* free builtin sets */ - BKE_keyingsets_free(&builtin_keyingsets); + /* free builtin sets */ + BKE_keyingsets_free(&builtin_keyingsets); } /* Check if the ID appears in the paths specified by the KeyingSet */ bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id) { - /* sanity checks */ - if (ELEM(NULL, ks, id)) - return false; + /* sanity checks */ + if (ELEM(NULL, ks, id)) + return false; - return BLI_findptr(&ks->paths, id, offsetof(KS_Path, id)) != NULL; + return BLI_findptr(&ks->paths, id, offsetof(KS_Path, id)) != NULL; } /* ******************************************* */ @@ -656,132 +655,135 @@ bool ANIM_keyingset_find_id(KeyingSet *ks, ID *id) /* Get the active Keying Set for the Scene provided */ KeyingSet *ANIM_scene_get_active_keyingset(Scene *scene) { - /* if no scene, we've got no hope of finding the Keying Set */ - if (scene == NULL) - return NULL; - - /* currently, there are several possibilities here: - * - 0: no active keying set - * - > 0: one of the user-defined Keying Sets, but indices start from 0 (hence the -1) - * - < 0: a builtin keying set - */ - if (scene->active_keyingset > 0) - return BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - else - return BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1); + /* if no scene, we've got no hope of finding the Keying Set */ + if (scene == NULL) + return NULL; + + /* currently, there are several possibilities here: + * - 0: no active keying set + * - > 0: one of the user-defined Keying Sets, but indices start from 0 (hence the -1) + * - < 0: a builtin keying set + */ + if (scene->active_keyingset > 0) + return BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + else + return BLI_findlink(&builtin_keyingsets, (-scene->active_keyingset) - 1); } /* Get the index of the Keying Set provided, for the given Scene */ int ANIM_scene_get_keyingset_index(Scene *scene, KeyingSet *ks) { - int index; - - /* if no KeyingSet provided, have none */ - if (ks == NULL) - return 0; - - /* check if the KeyingSet exists in scene list */ - if (scene) { - /* get index and if valid, return - * - (absolute) Scene KeyingSets are from (>= 1) - */ - index = BLI_findindex(&scene->keyingsets, ks); - if (index != -1) - return (index + 1); - } - - /* still here, so try builtins list too - * - builtins are from (<= -1) - * - none/invalid is (= 0) - */ - index = BLI_findindex(&builtin_keyingsets, ks); - if (index != -1) - return -(index + 1); - else - return 0; + int index; + + /* if no KeyingSet provided, have none */ + if (ks == NULL) + return 0; + + /* check if the KeyingSet exists in scene list */ + if (scene) { + /* get index and if valid, return + * - (absolute) Scene KeyingSets are from (>= 1) + */ + index = BLI_findindex(&scene->keyingsets, ks); + if (index != -1) + return (index + 1); + } + + /* still here, so try builtins list too + * - builtins are from (<= -1) + * - none/invalid is (= 0) + */ + index = BLI_findindex(&builtin_keyingsets, ks); + if (index != -1) + return -(index + 1); + else + return 0; } /* Get Keying Set to use for Auto-Keyframing some transforms */ KeyingSet *ANIM_get_keyingset_for_autokeying(Scene *scene, const char *transformKSName) { - /* get KeyingSet to use - * - use the active KeyingSet if defined (and user wants to use it for all autokeying), - * or otherwise key transforms only - */ - if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (scene->active_keyingset)) - return ANIM_scene_get_active_keyingset(scene); - else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) - return ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_AVAILABLE_ID); - else - return ANIM_builtin_keyingset_get_named(NULL, transformKSName); + /* get KeyingSet to use + * - use the active KeyingSet if defined (and user wants to use it for all autokeying), + * or otherwise key transforms only + */ + if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (scene->active_keyingset)) + return ANIM_scene_get_active_keyingset(scene); + else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) + return ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_AVAILABLE_ID); + else + return ANIM_builtin_keyingset_get_named(NULL, transformKSName); } /* Menu of All Keying Sets ----------------------------- */ /* Dynamically populate an enum of Keying Sets */ -const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - Scene *scene = CTX_data_scene(C); - KeyingSet *ks; - EnumPropertyItem *item = NULL, item_tmp = {0}; - int totitem = 0; - int i = 0; - - if (C == NULL) { - return DummyRNA_DEFAULT_items; - } - - /* active Keying Set - * - only include entry if it exists - */ - if (scene->active_keyingset) { - /* active Keying Set */ - item_tmp.identifier = "__ACTIVE__"; - item_tmp.name = "Active Keying Set"; - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - - /* separator */ - RNA_enum_item_add_separator(&item, &totitem); - } - - i++; - - /* user-defined Keying Sets - * - 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, i++) { - if (ANIM_keyingset_context_ok_poll(C, ks)) { - item_tmp.identifier = ks->idname; - item_tmp.name = ks->name; - item_tmp.description = ks->description; - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } - } - - /* separator */ - RNA_enum_item_add_separator(&item, &totitem); - } - - /* builtin Keying Sets */ - i = -1; - 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)) { - item_tmp.identifier = ks->idname; - item_tmp.name = ks->name; - item_tmp.description = ks->description; - item_tmp.value = i; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; + Scene *scene = CTX_data_scene(C); + KeyingSet *ks; + EnumPropertyItem *item = NULL, item_tmp = {0}; + int totitem = 0; + int i = 0; + + if (C == NULL) { + return DummyRNA_DEFAULT_items; + } + + /* active Keying Set + * - only include entry if it exists + */ + if (scene->active_keyingset) { + /* active Keying Set */ + item_tmp.identifier = "__ACTIVE__"; + item_tmp.name = "Active Keying Set"; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + + /* separator */ + RNA_enum_item_add_separator(&item, &totitem); + } + + i++; + + /* user-defined Keying Sets + * - 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, i++) { + if (ANIM_keyingset_context_ok_poll(C, ks)) { + item_tmp.identifier = ks->idname; + item_tmp.name = ks->name; + item_tmp.description = ks->description; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + + /* separator */ + RNA_enum_item_add_separator(&item, &totitem); + } + + /* builtin Keying Sets */ + i = -1; + 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)) { + item_tmp.identifier = ks->idname; + item_tmp.name = ks->name; + item_tmp.description = ks->description; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; } /** @@ -794,28 +796,28 @@ const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C, PointerRNA *UNU */ KeyingSet *ANIM_keyingset_get_from_enum_type(Scene *scene, int type) { - KeyingSet *ks = NULL; - - if (type == 0) { - type = scene->active_keyingset; - } - - if (type > 0) { - ks = BLI_findlink(&scene->keyingsets, type - 1); - } - else { - ks = BLI_findlink(&builtin_keyingsets, -type - 1); - } - return ks; + KeyingSet *ks = NULL; + + if (type == 0) { + type = scene->active_keyingset; + } + + if (type > 0) { + ks = BLI_findlink(&scene->keyingsets, type - 1); + } + else { + ks = BLI_findlink(&builtin_keyingsets, -type - 1); + } + return ks; } KeyingSet *ANIM_keyingset_get_from_idname(Scene *scene, const char *idname) { - KeyingSet *ks = BLI_findstring(&scene->keyingsets, idname, offsetof(KeyingSet, idname)); - if (ks == NULL) { - ks = BLI_findstring(&builtin_keyingsets, idname, offsetof(KeyingSet, idname)); - } - return ks; + KeyingSet *ks = BLI_findstring(&scene->keyingsets, idname, offsetof(KeyingSet, idname)); + if (ks == NULL) { + ks = BLI_findstring(&builtin_keyingsets, idname, offsetof(KeyingSet, idname)); + } + return ks; } /* ******************************************* */ @@ -826,19 +828,19 @@ KeyingSet *ANIM_keyingset_get_from_idname(Scene *scene, const char *idname) /* Check if KeyingSet can be used in the current context */ bool ANIM_keyingset_context_ok_poll(bContext *C, KeyingSet *ks) { - if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { - KeyingSetInfo *ksi = ANIM_keyingset_info_find_name(ks->typeinfo); + if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { + KeyingSetInfo *ksi = ANIM_keyingset_info_find_name(ks->typeinfo); - /* get the associated 'type info' for this KeyingSet */ - if (ksi == NULL) - return 0; - /* TODO: check for missing callbacks! */ + /* get the associated 'type info' for this KeyingSet */ + if (ksi == NULL) + return 0; + /* TODO: check for missing callbacks! */ - /* check if it can be used in the current context */ - return (ksi->poll(ksi, C)); - } + /* check if it can be used in the current context */ + return (ksi->poll(ksi, C)); + } - return true; + return true; } /* Special 'Overrides' Iterator for Relative KeyingSets ------ */ @@ -848,48 +850,50 @@ bool ANIM_keyingset_context_ok_poll(bContext *C, KeyingSet *ks) * - do not allow this to be accessed from outside for now */ typedef struct tRKS_DSource { - struct tRKS_DSource *next, *prev; - PointerRNA ptr; /* the whole point of this exercise! */ + struct tRKS_DSource *next, *prev; + PointerRNA ptr; /* the whole point of this exercise! */ } tRKS_DSource; - /* Iterator used for overriding the behavior of iterators defined for * relative Keying Sets, with the main usage of this being operators * requiring Auto Keyframing. Internal Use Only! */ -static void RKS_ITER_overrides_list(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks, ListBase *dsources) +static void RKS_ITER_overrides_list(KeyingSetInfo *ksi, + bContext *C, + KeyingSet *ks, + ListBase *dsources) { - tRKS_DSource *ds; + tRKS_DSource *ds; - for (ds = dsources->first; ds; ds = ds->next) { - /* run generate callback on this data */ - ksi->generate(ksi, C, ks, &ds->ptr); - } + for (ds = dsources->first; ds; ds = ds->next) { + /* run generate callback on this data */ + ksi->generate(ksi, C, ks, &ds->ptr); + } } /* Add new data source for relative Keying Sets */ void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *srna, void *data) { - tRKS_DSource *ds; - - /* sanity checks - * - we must have somewhere to output the data - * - we must have both srna+data (and with id too optionally), or id by itself only - */ - if (dsources == NULL) - return; - if (ELEM(NULL, srna, data) && (id == NULL)) - return; - - /* allocate new elem, and add to the list */ - ds = MEM_callocN(sizeof(tRKS_DSource), "tRKS_DSource"); - BLI_addtail(dsources, ds); - - /* depending on what data we have, create using ID or full pointer call */ - if (srna && data) - RNA_pointer_create(id, srna, data, &ds->ptr); - else - RNA_id_pointer_create(id, &ds->ptr); + tRKS_DSource *ds; + + /* sanity checks + * - we must have somewhere to output the data + * - we must have both srna+data (and with id too optionally), or id by itself only + */ + if (dsources == NULL) + return; + if (ELEM(NULL, srna, data) && (id == NULL)) + return; + + /* allocate new elem, and add to the list */ + ds = MEM_callocN(sizeof(tRKS_DSource), "tRKS_DSource"); + BLI_addtail(dsources, ds); + + /* depending on what data we have, create using ID or full pointer call */ + if (srna && data) + RNA_pointer_create(id, srna, data, &ds->ptr); + else + RNA_id_pointer_create(id, &ds->ptr); } /* KeyingSet Operations (Insert/Delete Keyframes) ------------ */ @@ -903,198 +907,216 @@ void ANIM_relative_keyingset_add_source(ListBase *dsources, ID *id, StructRNA *s */ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks) { - /* sanity check */ - if (ks == NULL) - return 0; - - /* if relative Keying Sets, poll and build up the paths */ - if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { - KeyingSetInfo *ksi = ANIM_keyingset_info_find_name(ks->typeinfo); - - /* clear all existing paths - * NOTE: BKE_keyingset_free() frees all of the paths for the KeyingSet, but not the set itself - */ - BKE_keyingset_free(ks); - - /* get the associated 'type info' for this KeyingSet */ - if (ksi == NULL) - return MODIFYKEY_MISSING_TYPEINFO; - /* TODO: check for missing callbacks! */ - - /* check if it can be used in the current context */ - if (ksi->poll(ksi, C)) { - /* if a list of data sources are provided, run a special iterator over them, - * otherwise, just continue per normal - */ - if (dsources) - RKS_ITER_overrides_list(ksi, C, ks, dsources); - else - ksi->iter(ksi, C, ks); - - /* if we don't have any paths now, then this still qualifies as invalid context */ - // FIXME: we need some error conditions (to be retrieved from the iterator why this failed!) - if (BLI_listbase_is_empty(&ks->paths)) - return MODIFYKEY_INVALID_CONTEXT; - } - else { - /* poll callback tells us that KeyingSet is useless in current context */ - // FIXME: the poll callback needs to give us more info why - return MODIFYKEY_INVALID_CONTEXT; - } - } - - /* succeeded; return 0 to tag error free */ - return 0; + /* sanity check */ + if (ks == NULL) + return 0; + + /* if relative Keying Sets, poll and build up the paths */ + if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) { + KeyingSetInfo *ksi = ANIM_keyingset_info_find_name(ks->typeinfo); + + /* clear all existing paths + * NOTE: BKE_keyingset_free() frees all of the paths for the KeyingSet, but not the set itself + */ + BKE_keyingset_free(ks); + + /* get the associated 'type info' for this KeyingSet */ + if (ksi == NULL) + return MODIFYKEY_MISSING_TYPEINFO; + /* TODO: check for missing callbacks! */ + + /* check if it can be used in the current context */ + if (ksi->poll(ksi, C)) { + /* if a list of data sources are provided, run a special iterator over them, + * otherwise, just continue per normal + */ + if (dsources) + RKS_ITER_overrides_list(ksi, C, ks, dsources); + else + ksi->iter(ksi, C, ks); + + /* if we don't have any paths now, then this still qualifies as invalid context */ + // FIXME: we need some error conditions (to be retrieved from the iterator why this failed!) + if (BLI_listbase_is_empty(&ks->paths)) + return MODIFYKEY_INVALID_CONTEXT; + } + else { + /* poll callback tells us that KeyingSet is useless in current context */ + // FIXME: the poll callback needs to give us more info why + return MODIFYKEY_INVALID_CONTEXT; + } + } + + /* succeeded; return 0 to tag error free */ + return 0; } /* Determine which keying flags apply based on the override flags */ -static short keyingset_apply_keying_flags(const short base_flags, const short overrides, const short own_flags) +static short keyingset_apply_keying_flags(const short base_flags, + const short overrides, + const short own_flags) { - /* Pass through all flags by default (i.e. even not explicitly listed ones). */ - short result = base_flags; - - /* The logic for whether a keying flag applies is as follows: - * - If the flag in question is set in "overrides", that means that the - * status of that flag in "own_flags" is used - * - If however the flag isn't set, then its value in "base_flags" is used - * instead (i.e. no override) - */ + /* Pass through all flags by default (i.e. even not explicitly listed ones). */ + short result = base_flags; + + /* The logic for whether a keying flag applies is as follows: + * - If the flag in question is set in "overrides", that means that the + * status of that flag in "own_flags" is used + * - If however the flag isn't set, then its value in "base_flags" is used + * instead (i.e. no override) + */ #define APPLY_KEYINGFLAG_OVERRIDE(kflag) \ - if (overrides & kflag) { \ - result &= ~kflag; \ - result |= (own_flags & kflag); \ - } - - /* Apply the flags one by one... - * (See rna_def_common_keying_flags() for the supported flags) - */ - APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_NEEDED) - APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_MATRIX) - APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_XYZ2RGB) + if (overrides & kflag) { \ + result &= ~kflag; \ + result |= (own_flags & kflag); \ + } + + /* Apply the flags one by one... + * (See rna_def_common_keying_flags() for the supported flags) + */ + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_NEEDED) + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_MATRIX) + APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_XYZ2RGB) #undef APPLY_KEYINGFLAG_OVERRIDE - return result; + return result; } /* Given a KeyingSet and context info (if required), modify keyframes for the channels specified * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets. * Returns the number of channels that keyframes were added to */ -int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) +int ANIM_apply_keyingset( + bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ReportList *reports = CTX_wm_reports(C); - KS_Path *ksp; - ListBase nla_cache = {NULL, NULL}; - const short base_kflags = ANIM_get_keyframing_flags(scene, 1); - const char *groupname = NULL; - short kflag = 0, success = 0; - char keytype = scene->toolsettings->keyframe_type; - - /* sanity checks */ - if (ks == NULL) - return 0; - - /* get flags to use */ - if (mode == MODIFYKEY_MODE_INSERT) { - /* use context settings as base */ - kflag = keyingset_apply_keying_flags(base_kflags, ks->keyingoverride, ks->keyingflag); - } - else if (mode == MODIFYKEY_MODE_DELETE) - kflag = 0; - - /* if relative Keying Sets, poll and build up the paths */ - success = ANIM_validate_keyingset(C, dsources, ks); - - if (success != 0) { - /* return error code if failed */ - return success; - } - - /* apply the paths as specified in the KeyingSet now */ - for (ksp = ks->paths.first; ksp; ksp = ksp->next) { - 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, apply the settings for this path first */ - kflag2 = keyingset_apply_keying_flags(kflag, ksp->keyingoverride, ksp->keyingflag); - - /* get pointer to name of group to add channels to */ - if (ksp->groupmode == KSP_GROUP_NONE) - groupname = NULL; - else if (ksp->groupmode == KSP_GROUP_KSNAME) - groupname = ks->name; - else - groupname = ksp->group; - - /* init arraylen and i - arraylen should be greater than i so that - * normal non-array entries get keyframed correctly - */ - i = ksp->array_index; - arraylen = i; - - /* get length of array if whole array option is enabled */ - if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) { - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - - RNA_id_pointer_create(ksp->id, &id_ptr); - if (RNA_path_resolve_property(&id_ptr, ksp->rna_path, &ptr, &prop)) { - arraylen = RNA_property_array_length(&ptr, prop); - /* start from start of array, instead of the previously specified index - T48020 */ - i = 0; - } - } - - /* we should do at least one step */ - if (arraylen == i) - arraylen++; - - /* for each possible index, perform operation - * - assume that arraylen is greater than index - */ - for (; i < arraylen; i++) { - /* action to take depends on mode */ - if (mode == MODIFYKEY_MODE_INSERT) - success += insert_keyframe(bmain, depsgraph, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, &nla_cache, kflag2); - else if (mode == MODIFYKEY_MODE_DELETE) - success += delete_keyframe(bmain, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); - } - - /* set recalc-flags */ - switch (GS(ksp->id->name)) { - case ID_OB: /* Object (or Object-Related) Keyframes */ - { - Object *ob = (Object *)ksp->id; - - // XXX: only object transforms? - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); - break; - } - default: - DEG_id_tag_update(ksp->id, ID_RECALC_ANIMATION_NO_FLUSH); - break; - } - - /* send notifiers for updates (this doesn't require context to work!) */ - WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); - } - - BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); - - /* return the number of channels successfully affected */ - return success; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ReportList *reports = CTX_wm_reports(C); + KS_Path *ksp; + ListBase nla_cache = {NULL, NULL}; + const short base_kflags = ANIM_get_keyframing_flags(scene, 1); + const char *groupname = NULL; + short kflag = 0, success = 0; + char keytype = scene->toolsettings->keyframe_type; + + /* sanity checks */ + if (ks == NULL) + return 0; + + /* get flags to use */ + if (mode == MODIFYKEY_MODE_INSERT) { + /* use context settings as base */ + kflag = keyingset_apply_keying_flags(base_kflags, ks->keyingoverride, ks->keyingflag); + } + else if (mode == MODIFYKEY_MODE_DELETE) + kflag = 0; + + /* if relative Keying Sets, poll and build up the paths */ + success = ANIM_validate_keyingset(C, dsources, ks); + + if (success != 0) { + /* return error code if failed */ + return success; + } + + /* apply the paths as specified in the KeyingSet now */ + for (ksp = ks->paths.first; ksp; ksp = ksp->next) { + 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, apply the settings for this path first */ + kflag2 = keyingset_apply_keying_flags(kflag, ksp->keyingoverride, ksp->keyingflag); + + /* get pointer to name of group to add channels to */ + if (ksp->groupmode == KSP_GROUP_NONE) + groupname = NULL; + else if (ksp->groupmode == KSP_GROUP_KSNAME) + groupname = ks->name; + else + groupname = ksp->group; + + /* init arraylen and i - arraylen should be greater than i so that + * normal non-array entries get keyframed correctly + */ + i = ksp->array_index; + arraylen = i; + + /* get length of array if whole array option is enabled */ + if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) { + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + + RNA_id_pointer_create(ksp->id, &id_ptr); + if (RNA_path_resolve_property(&id_ptr, ksp->rna_path, &ptr, &prop)) { + arraylen = RNA_property_array_length(&ptr, prop); + /* start from start of array, instead of the previously specified index - T48020 */ + i = 0; + } + } + + /* we should do at least one step */ + if (arraylen == i) + arraylen++; + + /* for each possible index, perform operation + * - assume that arraylen is greater than index + */ + for (; i < arraylen; i++) { + /* action to take depends on mode */ + if (mode == MODIFYKEY_MODE_INSERT) + success += insert_keyframe(bmain, + depsgraph, + reports, + ksp->id, + act, + groupname, + ksp->rna_path, + i, + cfra, + keytype, + &nla_cache, + kflag2); + else if (mode == MODIFYKEY_MODE_DELETE) + success += delete_keyframe( + bmain, reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); + } + + /* set recalc-flags */ + switch (GS(ksp->id->name)) { + case ID_OB: /* Object (or Object-Related) Keyframes */ + { + Object *ob = (Object *)ksp->id; + + // XXX: only object transforms? + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + break; + } + default: + DEG_id_tag_update(ksp->id, ID_RECALC_ANIMATION_NO_FLUSH); + break; + } + + /* send notifiers for updates (this doesn't require context to work!) */ + WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + } + + BKE_animsys_free_nla_keyframing_context_cache(&nla_cache); + + /* return the number of channels successfully affected */ + return success; } /* ************************************************** */ -- cgit v1.2.3