From fa24ad1fd50cdd6a6af2b76736fe8e1430ee3cd7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 9 Mar 2014 16:20:04 +1100 Subject: Graph Editor: add lasso select for fcurves --- source/blender/editors/animation/keyframes_edit.c | 42 ++++++++ source/blender/editors/include/ED_keyframes_edit.h | 12 ++- source/blender/editors/space_graph/graph_intern.h | 1 + source/blender/editors/space_graph/graph_ops.c | 8 +- source/blender/editors/space_graph/graph_select.c | 114 +++++++++++++++++++-- 5 files changed, 167 insertions(+), 10 deletions(-) (limited to 'source') diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 6010a64bd06..6b294c93b42 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_lasso.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" @@ -523,6 +524,45 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) return 0; } +/** + * only called from #ok_bezier_region_lasso + */ +static bool bezier_region_lasso_test( + const struct KeyframeEdit_LassoData *data_lasso, + const float xy[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); + + 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; +} + +static short ok_bezier_region_lasso(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; + +#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index]) + KEYFRAME_OK_CHECKS(KEY_CHECK_OK); +#undef KEY_CHECK_OK + + /* check for lasso */ + + /* return ok flags */ + return ok; + } + else + return 0; +} + KeyframeEditFunc ANIM_editkeyframes_ok(short mode) { @@ -540,6 +580,8 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode) 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; default: /* nothing was ok */ return NULL; } diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index c99c70377ab..4e68b6a9494 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -56,7 +56,8 @@ typedef enum eEditKeyframes_Validate { BEZT_OK_SELECTED, BEZT_OK_VALUE, BEZT_OK_VALUERANGE, - BEZT_OK_REGION + BEZT_OK_REGION, + BEZT_OK_REGION_LASSO, } eEditKeyframes_Validate; /* ------------ */ @@ -98,6 +99,15 @@ typedef enum eEditKeyframes_Mirror { MIRROR_KEYS_VALUE } eEditKeyframes_Mirror; +/* use with BEZT_OK_REGION_LASSO */ +struct KeyframeEdit_LassoData { + const rctf *rectf_scaled; + const rctf *rectf_view; + const int (*mcords)[2]; + int mcords_tot; +}; + + /* ************************************************ */ /* Non-Destuctive Editing API (keyframes_edit.c) */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 8dc5e9a441d..567b0a60bb0 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -61,6 +61,7 @@ void graph_draw_ghost_curves(struct bAnimContext *ac, struct SpaceIpo *sipo, str void GRAPH_OT_select_all_toggle(struct wmOperatorType *ot); void GRAPH_OT_select_border(struct wmOperatorType *ot); +void GRAPH_OT_select_lasso(struct wmOperatorType *ot); void GRAPH_OT_select_column(struct wmOperatorType *ot); void GRAPH_OT_select_linked(struct wmOperatorType *ot); void GRAPH_OT_select_more(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 7078c287d9a..0b9936ff14e 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -213,6 +213,7 @@ void graphedit_operatortypes(void) WM_operatortype_append(GRAPH_OT_clickselect); WM_operatortype_append(GRAPH_OT_select_all_toggle); WM_operatortype_append(GRAPH_OT_select_border); + WM_operatortype_append(GRAPH_OT_select_lasso); WM_operatortype_append(GRAPH_OT_select_column); WM_operatortype_append(GRAPH_OT_select_linked); WM_operatortype_append(GRAPH_OT_select_more); @@ -344,7 +345,12 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) 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", TRUE); RNA_boolean_set(kmi->ptr, "include_handles", TRUE); - + + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "deselect", true); + /* 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 a8beaadd711..342a2d18b99 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLI_lasso.h" #include "DNA_anim_types.h" #include "DNA_object_types.h" @@ -217,7 +218,9 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot) * 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, short incl_handles) +static void borderselect_graphkeys( + bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, bool incl_handles, + struct KeyframeEdit_LassoData *data_lasso) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -230,8 +233,8 @@ static void borderselect_graphkeys(bAnimContext *ac, rcti rect, short mode, shor rctf rectf, scaled_rectf; /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ - UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin); - UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax); + UI_view2d_region_to_view(v2d, rectf_view->xmin, rectf_view->ymin, &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, rectf_view->xmax, rectf_view->ymax, &rectf.xmax, &rectf.ymax); /* filter data */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); @@ -243,7 +246,13 @@ static void borderselect_graphkeys(bAnimContext *ac, rcti rect, short mode, shor /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); - ked.data = &scaled_rectf; + if (data_lasso) { + data_lasso->rectf_scaled = &scaled_rectf; + ked.data = data_lasso; + } + else { + ked.data = &scaled_rectf; + } /* treat handles separately? */ if (incl_handles) { @@ -313,9 +322,10 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; rcti rect; + rctf rect_fl; short mode = 0, selectmode = 0; - short incl_handles; - int extend; + bool incl_handles; + bool extend; /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -354,9 +364,11 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) } else mode = BEZT_OK_REGION; - + + BLI_rctf_rcti_copy(&rect_fl, &rect); + /* apply borderselect action */ - borderselect_graphkeys(&ac, rect, mode, selectmode, incl_handles); + borderselect_graphkeys(&ac, &rect_fl, mode, selectmode, incl_handles, NULL); /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); @@ -389,6 +401,92 @@ void GRAPH_OT_select_border(wmOperatorType *ot) RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria"); } +static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + rcti rect; + rctf rect_fl; + short selectmode; + bool incl_handles; + bool extend; + + struct KeyframeEdit_LassoData data_lasso; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data_lasso.rectf_view = &rect_fl; + data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); + if (data_lasso.mcords == NULL) + return OPERATOR_CANCELLED; + + /* clear all selection if not extending selection */ + extend = RNA_boolean_get(op->ptr, "extend"); + if (!extend) + deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, TRUE); + + if (!RNA_boolean_get(op->ptr, "deselect")) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + + if (ac.spacetype == SPACE_IPO) { + SpaceIpo *sipo = (SpaceIpo *)ac.sl; + if (selectmode == SELECT_ADD) { + incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || + (sipo->flag & SIPO_NOHANDLES)) == 0; + } + else { + incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; + } + } + else { + incl_handles = false; + } + + + /* get settings from operator */ + BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + + BLI_rctf_rcti_copy(&rect_fl, &rect); + + /* apply borderselect action */ + borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso); + + MEM_freeN((void *)data_lasso.mcords); + + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + + +void GRAPH_OT_select_lasso(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Lasso Select"; + ot->description = "Select keyframe points using lasso selection"; + ot->idname = "GRAPH_OT_select_lasso"; + + /* api callbacks */ + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = graphkeys_lassoselect_exec; + ot->poll = graphop_visible_keyframes_poll; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); + RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); +} + /* ******************** Column Select Operator **************************** */ /* This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) -- cgit v1.2.3