Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/ui/space_graph.py1
-rw-r--r--source/blender/editors/animation/keyframes_edit.c217
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h44
-rw-r--r--source/blender/editors/space_graph/graph_ops.c13
-rw-r--r--source/blender/editors/space_graph/graph_select.c25
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 **************************** */