diff options
-rw-r--r-- | release/scripts/ui/space_graph.py | 1 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_edit.c | 217 | ||||
-rw-r--r-- | source/blender/editors/include/ED_keyframes_edit.h | 44 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_ops.c | 13 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_select.c | 25 |
5 files changed, 222 insertions, 78 deletions
diff --git a/release/scripts/ui/space_graph.py b/release/scripts/ui/space_graph.py index cdf7f653eb6..0106833ce0d 100644 --- a/release/scripts/ui/space_graph.py +++ b/release/scripts/ui/space_graph.py @@ -114,6 +114,7 @@ class GRAPH_MT_select(bpy.types.Menu): layout.separator() layout.operator("graph.select_border") layout.operator("graph.select_border", text="Border Axis Range").axis_range = True + layout.operator("graph.select_border", text="Border (Include Handles)").include_handles = True layout.separator() layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS' diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 629161defee..3175e9e34a7 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -84,9 +84,11 @@ /* This function is used to loop over BezTriples in the given F-Curve, applying a given * operation on them, and optionally applies an F-Curve validation function afterwards. */ -short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb) +// 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; int i; /* sanity check */ @@ -97,23 +99,30 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEdi 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 (bezt_cb) { + 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 (bezt_ok) { + if (key_ok) { for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) { - if (ked) ked->curIndex= 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 fullfills the criteria of the validation func */ - if (bezt_ok(ked, bezt)) { + 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 (bezt_cb(ked, bezt)) return 1; + if (key_cb(ked, bezt)) return 1; } } } @@ -124,7 +133,7 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEdi /* Exit with return-code '1' if function returns positive * This is useful if finding if some BezTriple satisfies a condition. */ - if (bezt_cb(ked, bezt)) return 1; + if (key_cb(ked, bezt)) return 1; } } } @@ -133,6 +142,7 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEdi 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 */ @@ -146,7 +156,7 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEdi /* -------------------------------- 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 bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb) +static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) { FCurve *fcu; @@ -156,7 +166,7 @@ static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, Keyf /* 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, bezt_ok, bezt_cb, fcu_cb)) + if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) return 1; } @@ -164,7 +174,7 @@ static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, Keyf } /* This function is used to loop over the keyframe data in an Action */ -static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb) +static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) { FCurve *fcu; @@ -174,7 +184,7 @@ static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEdi /* just loop through all F-Curves */ for (fcu= act->curves.first; fcu; fcu= fcu->next) { - if (ANIM_fcurve_keyframes_loop(ked, fcu, bezt_ok, bezt_cb, fcu_cb)) + if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) return 1; } @@ -182,7 +192,7 @@ static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEdi } /* This function is used to loop over the keyframe data of an AnimData block */ -static short adt_keyframes_loop(KeyframeEditData *ked, AnimData *adt, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag) +static short adt_keyframes_loop(KeyframeEditData *ked, AnimData *adt, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) { /* sanity check */ if (adt == NULL) @@ -194,13 +204,13 @@ static short adt_keyframes_loop(KeyframeEditData *ked, AnimData *adt, KeyframeEd /* just loop through all F-Curves acting as Drivers */ for (fcu= adt->drivers.first; fcu; fcu= fcu->next) { - if (ANIM_fcurve_keyframes_loop(ked, fcu, bezt_ok, bezt_cb, fcu_cb)) + if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb)) return 1; } } else if (adt->action) { /* call the function for actions */ - if (act_keyframes_loop(ked, adt->action, bezt_ok, bezt_cb, fcu_cb)) + if (act_keyframes_loop(ked, adt->action, key_ok, key_cb, fcu_cb)) return 1; } @@ -208,7 +218,7 @@ static short adt_keyframes_loop(KeyframeEditData *ked, AnimData *adt, KeyframeEd } /* This function is used to loop over the keyframe data in an Object */ -static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag) +static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) { Key *key= ob_get_key(ob); @@ -218,13 +228,13 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu /* firstly, Object's own AnimData */ if (ob->adt) { - if (adt_keyframes_loop(ked, ob->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, ob->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } /* shapekeys */ if ((key && key->adt) && !(filterflag & ADS_FILTER_NOSHAPEKEYS)) { - if (adt_keyframes_loop(ked, key->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, key->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } @@ -240,7 +250,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu continue; /* add material's data */ - if (adt_keyframes_loop(ked, ma->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, ma->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -252,7 +262,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu Camera *ca= (Camera *)ob->data; if ((ca->adt) && !(filterflag & ADS_FILTER_NOCAM)) { - if (adt_keyframes_loop(ked, ca->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, ca->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -262,7 +272,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu Lamp *la= (Lamp *)ob->data; if ((la->adt) && !(filterflag & ADS_FILTER_NOLAM)) { - if (adt_keyframes_loop(ked, la->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, la->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -274,7 +284,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu Curve *cu= (Curve *)ob->data; if ((cu->adt) && !(filterflag & ADS_FILTER_NOCUR)) { - if (adt_keyframes_loop(ked, cu->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, cu->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -284,7 +294,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu MetaBall *mb= (MetaBall *)ob->data; if ((mb->adt) && !(filterflag & ADS_FILTER_NOMBA)) { - if (adt_keyframes_loop(ked, mb->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, mb->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -294,7 +304,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu bArmature *arm= (bArmature *)ob->data; if ((arm->adt) && !(filterflag & ADS_FILTER_NOARM)) { - if (adt_keyframes_loop(ked, arm->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, arm->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -304,7 +314,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu Mesh *me= (Mesh *)ob->data; if ((me->adt) && !(filterflag & ADS_FILTER_NOMESH)) { - if (adt_keyframes_loop(ked, me->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, me->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -319,7 +329,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu if (ELEM(NULL, psys->part, psys->part->adt)) continue; - if (adt_keyframes_loop(ked, psys->part->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, psys->part->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } } @@ -328,7 +338,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, Object *ob, KeyframeEditFu } /* This function is used to loop over the keyframe data in a Scene */ -static short scene_keyframes_loop(KeyframeEditData *ked, Scene *sce, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag) +static short scene_keyframes_loop(KeyframeEditData *ked, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) { World *wo= (sce) ? sce->world : NULL; bNodeTree *ntree= (sce) ? sce->nodetree : NULL; @@ -339,19 +349,19 @@ static short scene_keyframes_loop(KeyframeEditData *ked, Scene *sce, KeyframeEdi /* Scene's own animation */ if (sce->adt) { - if (adt_keyframes_loop(ked, sce->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, sce->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } /* World */ if (wo && wo->adt) { - if (adt_keyframes_loop(ked, wo->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, wo->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } /* NodeTree */ if (ntree && ntree->adt) { - if (adt_keyframes_loop(ked, ntree->adt, bezt_ok, bezt_cb, fcu_cb, filterflag)) + if (adt_keyframes_loop(ked, ntree->adt, key_ok, key_cb, fcu_cb, filterflag)) return 1; } @@ -360,7 +370,7 @@ static short scene_keyframes_loop(KeyframeEditData *ked, Scene *sce, KeyframeEdi } /* This function is used to loop over the keyframe data in a DopeSheet summary */ -static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag) +static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -376,7 +386,7 @@ static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, Key /* loop through each F-Curve, working on the keyframes until the first curve aborts */ for (ale= anim_data.first; ale; ale= ale->next) { - ret_code= ANIM_fcurve_keyframes_loop(ked, ale->data, bezt_ok, bezt_cb, fcu_cb); + ret_code= ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb); if (ret_code) break; @@ -390,7 +400,7 @@ static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, Key /* --- */ /* This function is used to apply operation to all keyframes, regardless of the type */ -short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bAnimListElem *ale, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag) +short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) { /* sanity checks */ if (ale == NULL) @@ -400,29 +410,29 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bAnimListElem *ale, switch (ale->datatype) { /* direct keyframe data (these loops are exposed) */ case ALE_FCURVE: /* F-Curve */ - return ANIM_fcurve_keyframes_loop(ked, ale->key_data, bezt_ok, bezt_cb, fcu_cb); + 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, bezt_ok, bezt_cb, fcu_cb); + 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, bezt_ok, bezt_cb, fcu_cb); + return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb); case ALE_OB: /* object */ - return ob_keyframes_loop(ked, (Object *)ale->key_data, bezt_ok, bezt_cb, fcu_cb, filterflag); + return ob_keyframes_loop(ked, (Object *)ale->key_data, key_ok, key_cb, fcu_cb, filterflag); case ALE_SCE: /* scene */ - return scene_keyframes_loop(ked, (Scene *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag); + return scene_keyframes_loop(ked, (Scene *)ale->data, key_ok, key_cb, fcu_cb, filterflag); case ALE_ALL: /* 'all' (DopeSheet summary) */ - return summary_keyframes_loop(ked, (bAnimContext *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag); + return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb, filterflag); } return 0; } /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */ -short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, void *data, int keytype, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag) +short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag) { /* sanity checks */ if (data == NULL) @@ -432,22 +442,22 @@ short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, void *data, int switch (keytype) { /* direct keyframe data (these loops are exposed) */ case ALE_FCURVE: /* F-Curve */ - return ANIM_fcurve_keyframes_loop(ked, data, bezt_ok, bezt_cb, fcu_cb); + 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, bezt_ok, bezt_cb, fcu_cb); + return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb); case ALE_ACT: /* action */ - return act_keyframes_loop(ked, (bAction *)data, bezt_ok, bezt_cb, fcu_cb); + return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb); case ALE_OB: /* object */ - return ob_keyframes_loop(ked, (Object *)data, bezt_ok, bezt_cb, fcu_cb, filterflag); + return ob_keyframes_loop(ked, (Object *)data, key_ok, key_cb, fcu_cb, filterflag); case ALE_SCE: /* scene */ - return scene_keyframes_loop(ked, (Scene *)data, bezt_ok, bezt_cb, fcu_cb, filterflag); + return scene_keyframes_loop(ked, (Scene *)data, key_ok, key_cb, fcu_cb, filterflag); case ALE_ALL: /* 'all' (DopeSheet summary) */ - return summary_keyframes_loop(ked, (bAnimContext *)data, bezt_ok, bezt_cb, fcu_cb, filterflag); + return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb, filterflag); } return 0; @@ -484,44 +494,107 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac) /* ************************************************************************** */ /* BezTriple Validation Callbacks */ +/* ------------------------ */ +/* Some macros to make this easier... */ + +/* run the given check on the 3 handles + * - check should be a macro, which takes the handle index as its single arg, which it substitutes later + * - requires that a var, of type short, is named 'ok', and has been initialised ot 0 + */ +#define KEYFRAME_OK_CHECKS(check) \ + { \ + 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; \ + } \ + } + +/* ------------------------ */ + static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt) { + short ok = 0; + /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */ - return IS_EQ(bezt->vec[1][0], ked->f1); + #define KEY_CHECK_OK(_index) IS_EQ(bezt->vec[_index][0], ked->f1) + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + #undef KEY_CHECK_OK + + /* return ok flags */ + return ok; } static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt) { + short ok = 0; + /* frame range is stored in float properties */ - return ((bezt->vec[1][0] > ked->f1) && (bezt->vec[1][0] < ked->f2)); + #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2)) + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + #undef KEY_CHECK_OK + + /* return ok flags */ + return ok; } static short ok_bezier_selected(KeyframeEditData *ked, BezTriple *bezt) { - /* this macro checks all beztriple handles for selection... */ - return BEZSELECTED(bezt); + /* this macro checks all beztriple handles for selection... + * only one of the verts has to be selected for this to be ok... + */ + if (BEZSELECTED(bezt)) + return KEYFRAME_OK_ALL; + else + return 0; } static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt) -{ +{ + 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? */ - return IS_EQ(bezt->vec[1][1], ked->f1); + #define KEY_CHECK_OK(_index) IS_EQ(bezt->vec[_index][1], ked->f1) + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + #undef KEY_CHECK_OK + + /* return ok flags */ + return ok; } static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt) { + short ok = 0; + /* value range is stored in float properties */ - return ((bezt->vec[1][1] > ked->f1) && (bezt->vec[1][1] < ked->f2)); + #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2)) + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + #undef KEY_CHECK_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) - return BLI_in_rctf(ked->data, bezt->vec[1][0], bezt->vec[1][1]); + if (ked->data) { + short ok = 0; + + #define KEY_CHECK_OK(_index) BLI_in_rctf(ked->data, bezt->vec[_index][0], bezt->vec[_index][1]) + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); + #undef KEY_CHECK_OK + + /* return ok flags */ + return ok; + } else return 0; } @@ -586,11 +659,11 @@ short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt) } /* used to remap times from one range to another - * requires: ked->data = BeztEditCD_Remap + * requires: ked->data = KeyframeEditCD_Remap */ void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt) { - BeztEditCD_Remap *rmap= (BeztEditCD_Remap*)ked->data; + 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 */ @@ -932,21 +1005,43 @@ KeyframeEditFunc ANIM_editkeyframes_keytype(short code) static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt) { - /* Select the bezier triple */ - BEZ_SEL(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 { + BEZ_SEL(bezt); + } + return 0; } static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt) { - /* Deselect the bezier triple */ - BEZ_DESEL(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 { + BEZ_DESEL(bezt); + } + return 0; } static short select_bezier_invert(KeyframeEditData *ked, BezTriple *bezt) { - /* Invert the selection for the bezier triple */ + /* Invert the selection for the whole bezier triple */ bezt->f2 ^= SELECT; if (bezt->f2 & SELECT) { bezt->f1 |= SELECT; diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 29f92fff001..60f2526191c 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -60,10 +60,14 @@ typedef enum eEditKeyframes_Validate { /* select modes */ typedef enum eEditKeyframes_Select { + /* SELECT_SUBTRACT for all, followed by SELECT_ADD for some */ SELECT_REPLACE = (1<<0), + /* add ok keyframes to selection */ SELECT_ADD = (1<<1), + /* remove ok keyframes from selection */ SELECT_SUBTRACT = (1<<2), - SELECT_INVERT = (1<<4), + /* flip ok status of keyframes based on key status */ + SELECT_INVERT = (1<<3), } eEditKeyframes_Select; /* "selection map" building modes */ @@ -94,7 +98,7 @@ typedef enum eEditKeyframes_Mirror { /* ************************************************ */ /* Non-Destuctive Editing API (keyframes_edit.c) */ -/* --- Generic Properties for Bezier Edit Tools ----- */ +/* --- Generic Properties for Keyframe Edit Tools ----- */ typedef struct KeyframeEditData { /* generic properties/data access */ @@ -107,6 +111,10 @@ typedef struct KeyframeEditData { /* current iteration data */ struct FCurve *fcu; /* F-Curve that is being iterated over */ int curIndex; /* index of current keyframe being iterated over */ + + /* flags */ + short curflags; /* current flags for the keyframe we're reached in the iteration process */ + short iterflags; /* settings for iteration process */ // XXX: unused... } KeyframeEditData; /* ------- Function Pointer Typedefs ---------------- */ @@ -116,27 +124,47 @@ typedef void (*FcuEditFunc)(struct FCurve *fcu); /* callback function that operates on the given BezTriple */ typedef short (*KeyframeEditFunc)(KeyframeEditData *ked, struct BezTriple *bezt); +/* ---------- Defines for 'OK' polls ----------------- */ + +/* which verts of a keyframe is active (after polling) */ +typedef enum eKeyframeVertOk { + /* 'key' itself is ok */ + KEYFRAME_OK_KEY = (1<<0), + /* 'handle 1' is ok */ + KEYFRAME_OK_H1 = (1<<1), + /* 'handle 2' is ok */ + KEYFRAME_OK_H2 = (1<<2), + /* all flags */ + KEYFRAME_OK_ALL = (KEYFRAME_OK_KEY|KEYFRAME_OK_H1|KEYFRAME_OK_H2) +} eKeyframeVertOk; + +/* Flags for use during iteration */ +typedef enum eKeyframeIterFlags { + /* consider handles in addition to key itself */ + KEYFRAME_ITER_INCL_HANDLES = (1<<0), +} eKeyframeIterFlags; + /* ------- Custom Data Type Defines ------------------ */ /* Custom data for remapping one range to another in a fixed way */ -typedef struct BeztEditCD_Remap { +typedef struct KeyframeEditCD_Remap { float oldMin, oldMax; /* old range */ float newMin, newMax; /* new range */ -} BeztEditCD_Remap; +} KeyframeEditCD_Remap; /* ---------------- Looping API --------------------- */ /* functions for looping over keyframes */ /* function for working with F-Curve data only (i.e. when filters have been chosen to explicitly use this) */ -short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, struct FCurve *fcu, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb); +short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, struct FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb); /* function for working with any type (i.e. one of the known types) of animation channel * - filterflag is bDopeSheet->flag (DOPESHEET_FILTERFLAG) */ -short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, struct bAnimListElem *ale, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag); +short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, struct bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag); /* same as above, except bAnimListElem wrapper is not needed... * - keytype is eAnim_KeyType */ -short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, void *data, int keytype, KeyframeEditFunc bezt_ok, KeyframeEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag); +short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb, int filterflag); /* functions for making sure all keyframes are in good order */ void ANIM_editkeyframes_refresh(struct bAnimContext *ac); @@ -175,7 +203,7 @@ short bezt_calc_average(KeyframeEditData *ked, struct BezTriple *bezt); short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt); /* used to remap times from one range to another - * requires: ked->custom = BeztEditCD_Remap + * requires: ked->custom = KeyframeEditCD_Remap */ void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index b8b3dc97edf..07a9034e526 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -298,9 +298,16 @@ static void graphedit_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap) RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1); /* borderselect */ - WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, 0, 0); - RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1); - + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "axis_range", 1); + + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "include_handles", 1); + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "axis_range", 1); + RNA_boolean_set(kmi->ptr, "include_handles", 1); + /* column select */ RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_KEYS); RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_CFRA); diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index e15dc797186..c8b31f38f59 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -196,10 +196,11 @@ void GRAPH_OT_select_all_toggle (wmOperatorType *ot) */ /* Borderselect only selects keyframes now, as overshooting handles often get caught too, - * which means that they may be inadvertantly moved as well. - * Also, for convenience, handles should get same status as keyframe (if it was within bounds) + * which means that they may be inadvertantly moved as well. However, incl_handles overrides + * this, and allow handles to be considered independently too. + * Also, for convenience, handles should get same status as keyframe (if it was within bounds). */ -static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, short selectmode) +static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, short selectmode, short incl_handles) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -227,6 +228,10 @@ static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, sho memset(&ked, 0, sizeof(KeyframeEditData)); ked.data= &rectf; + /* treat handles separately? */ + if (incl_handles) + ked.iterflags |= KEYFRAME_ITER_INCL_HANDLES; + /* loop over data, doing border select */ for (ale= anim_data.first; ale; ale= ale->next) { AnimData *adt= ANIM_nla_mapping_get(ac, ale); @@ -286,16 +291,23 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) bAnimContext ac; rcti rect; short mode=0, selectmode=0; + short incl_handles; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + + /* get select mode + * - 'gesture_mode' from the operator specifies how to select + * - 'include_handles' from the operator specifies whether to include handles in the selection + */ if (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT) selectmode= SELECT_ADD; else selectmode= SELECT_SUBTRACT; - + + incl_handles = RNA_boolean_get(op->ptr, "include_handles"); + /* get settings from operator */ rect.xmin= RNA_int_get(op->ptr, "xmin"); rect.ymin= RNA_int_get(op->ptr, "ymin"); @@ -318,7 +330,7 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) mode= BEZT_OK_REGION; /* apply borderselect action */ - borderselect_graphkeys(&ac, rect, mode, selectmode); + borderselect_graphkeys(&ac, rect, mode, selectmode, incl_handles); /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL); @@ -347,6 +359,7 @@ void GRAPH_OT_select_border(wmOperatorType *ot) WM_operator_properties_gesture_border(ot, FALSE); ot->prop= RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); + RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria"); } /* ******************** Column Select Operator **************************** */ |