diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-10-16 13:58:51 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-10-16 14:21:46 +0300 |
commit | 870b4b673511094cf0beaeaf07305407ccdda47a (patch) | |
tree | fb91f7c424f1971c35d537e520c519117e38f9d9 /source/blender/windowmanager | |
parent | 6d8f63a8343a6c0b44318f0a856dcd0fd0206131 (diff) |
WM: refactor gestures for use as tools
Border and circle select wait for input by default.
This commit uses bool properties on the operators instead of
magic number (called "gesture_mode").
Keymaps that define 'deselect' for border/circle select
begin immediately, exiting when on button release.
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 8 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_types.h | 3 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_gesture.c | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operator_props.c | 48 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 133 | ||||
-rw-r--r-- | source/blender/windowmanager/wm_event_types.h | 2 |
6 files changed, 161 insertions, 34 deletions
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index aa52e7d2248..595050e12f7 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -308,11 +308,17 @@ void WM_operator_properties_filesel( void WM_operator_properties_border(struct wmOperatorType *ot); void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect); void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect); -void WM_operator_properties_gesture_border(struct wmOperatorType *ot, bool extend); +void WM_operator_properties_gesture_border_ex(struct wmOperatorType *ot, bool deselect, bool extend); +void WM_operator_properties_gesture_border(struct wmOperatorType *ot); +void WM_operator_properties_gesture_border_select(struct wmOperatorType *ot); +void WM_operator_properties_gesture_border_zoom(struct wmOperatorType *ot); void WM_operator_properties_gesture_lasso_ex(struct wmOperatorType *ot, bool deselect, bool extend); void WM_operator_properties_gesture_lasso(struct wmOperatorType *ot); +void WM_operator_properties_gesture_lasso_select(struct wmOperatorType *ot); void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor); +void WM_operator_properties_gesture_circle_ex(struct wmOperatorType *ot, bool deselect); void WM_operator_properties_gesture_circle(struct wmOperatorType *ot); +void WM_operator_properties_gesture_circle_select(struct wmOperatorType *ot); void WM_operator_properties_mouse_select(struct wmOperatorType *ot); void WM_operator_properties_select_all(struct wmOperatorType *ot); void WM_operator_properties_select_action(struct wmOperatorType *ot, int default_action); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index d8ec26f55da..6c47d61c535 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -413,10 +413,13 @@ typedef struct wmGesture { int swinid; /* initial subwindow id where it started */ int points; /* optional, amount of points stored */ int points_alloc; /* optional, maximum amount of points stored */ + int modal_state; /* For modal operators which may be running idle, waiting for an event to activate the gesture. * Typically this is set when the user is click-dragging the gesture (border and circle select for eg). */ uint is_active : 1; + /* Use for gestures that support both immediate or delayed activation. */ + uint wait_for_input : 1; void *customdata; /* customdata for border is a recti */ diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 11f39dc934c..b63962ffce2 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -72,6 +72,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type) gesture->event_type = event->type; gesture->swinid = ar->swinid; /* means only in area-region context! */ gesture->userdata_free = true; /* Free if userdata is set. */ + gesture->modal_state = GESTURE_MODAL_NOP; wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy); diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index b8b52798175..4873a6bbf81 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -227,17 +227,36 @@ void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect) /** * Use with #WM_gesture_border_invoke */ -void WM_operator_properties_gesture_border(wmOperatorType *ot, bool extend) +void WM_operator_properties_gesture_border_ex(wmOperatorType *ot, bool deselect, bool extend) { - RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX); - WM_operator_properties_border(ot); + if (deselect) { + RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); + } if (extend) { RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } } +void WM_operator_properties_gesture_border_select(wmOperatorType *ot) +{ + WM_operator_properties_gesture_border_ex(ot, true, true); +} +void WM_operator_properties_gesture_border(wmOperatorType *ot) +{ + WM_operator_properties_gesture_border_ex(ot, false, false); +} + +void WM_operator_properties_gesture_border_zoom(wmOperatorType *ot) +{ + WM_operator_properties_border(ot); + + PropertyRNA *prop; + prop = RNA_def_boolean(ot->srna, "zoom_out", false, "Zoom Out", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + /** * Use with #WM_gesture_lasso_invoke */ @@ -257,6 +276,11 @@ void WM_operator_properties_gesture_lasso_ex(wmOperatorType *ot, bool deselect, void WM_operator_properties_gesture_lasso(wmOperatorType *ot) { + WM_operator_properties_gesture_lasso_ex(ot, false, false); +} + +void WM_operator_properties_gesture_lasso_select(wmOperatorType *ot) +{ WM_operator_properties_gesture_lasso_ex(ot, true, true); } @@ -286,7 +310,7 @@ void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor) /** * Use with #WM_gesture_circle_invoke */ -void WM_operator_properties_gesture_circle(wmOperatorType *ot) +void WM_operator_properties_gesture_circle_ex(wmOperatorType *ot, bool deselect) { PropertyRNA *prop; const int radius_default = 25; @@ -296,8 +320,20 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot) prop = RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); RNA_def_int(ot->srna, "radius", radius_default, 1, INT_MAX, "Radius", "", 1, INT_MAX); - prop = RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + if (deselect) { + RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); + } +} + +void WM_operator_properties_gesture_circle(wmOperatorType *ot) +{ + WM_operator_properties_gesture_circle_ex(ot, false); +} + +void WM_operator_properties_gesture_circle_select(wmOperatorType *ot) +{ + WM_operator_properties_gesture_circle_ex(ot, true); } void WM_operator_properties_mouse_select(wmOperatorType *ot) diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 42f13257095..9a1c01487b5 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2250,6 +2250,43 @@ void WM_paint_cursor_end(wmWindowManager *wm, void *handle) * These are default callbacks for use in operators requiring gesture input */ +static void gesture_modal_state_to_operator(wmOperator *op, int modal_state) +{ + PropertyRNA *prop; + + switch (modal_state) { + case GESTURE_MODAL_SELECT: + case GESTURE_MODAL_DESELECT: + if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) { + RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT)); + } + break; + case GESTURE_MODAL_IN: + case GESTURE_MODAL_OUT: + if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) { + RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_OUT)); + } + break; + } +} + +static int gesture_modal_state_from_operator(wmOperator *op) +{ + PropertyRNA *prop; + + if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) { + if (RNA_property_is_set(op->ptr, prop)) { + return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_DESELECT : GESTURE_MODAL_SELECT; + } + } + if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) { + if (RNA_property_is_set(op->ptr, prop)) { + return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_OUT : GESTURE_MODAL_IN; + } + } + return GESTURE_MODAL_NOP; +} + /* **************** Border gesture *************** */ /** @@ -2260,7 +2297,7 @@ void WM_paint_cursor_end(wmWindowManager *wm, void *handle) * It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type) */ -static int border_apply_rect(wmOperator *op) +static bool gesture_border_apply_rect(wmOperator *op) { wmGesture *gesture = op->customdata; rcti *rect = gesture->customdata; @@ -2278,20 +2315,18 @@ static int border_apply_rect(wmOperator *op) return 1; } -static int border_apply(bContext *C, wmOperator *op, int gesture_mode) +static bool gesture_border_apply(bContext *C, wmOperator *op) { - PropertyRNA *prop; + wmGesture *gesture = op->customdata; int retval; - if (!border_apply_rect(op)) + if (!gesture_border_apply_rect(op)) { return 0; - - /* XXX weak; border should be configured for this without reading event types */ - if ((prop = RNA_struct_find_property(op->ptr, "gesture_mode"))) { - RNA_property_int_set(op->ptr, prop, gesture_mode); } + gesture_modal_state_to_operator(op, gesture->modal_state); + retval = op->type->exec(C, op); OPERATOR_RETVAL_CHECK(retval); @@ -2314,14 +2349,28 @@ static void wm_gesture_end(bContext *C, wmOperator *op) int WM_gesture_border_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (ISTWEAK(event->type)) + int modal_state = gesture_modal_state_from_operator(op); + + if (ISTWEAK(event->type) || (modal_state != GESTURE_MODAL_NOP)) { op->customdata = WM_gesture_new(C, event, WM_GESTURE_RECT); - else + } + else { op->customdata = WM_gesture_new(C, event, WM_GESTURE_CROSS_RECT); + } + + /* Starting with the mode starts immediately, like having 'wait_for_input' disabled (some tools use this). */ + if (modal_state == GESTURE_MODAL_NOP) { + wmGesture *gesture = op->customdata; + gesture->wait_for_input = true; + } + else { + wmGesture *gesture = op->customdata; + gesture->modal_state = modal_state; + } /* add modal handler */ WM_event_add_modal_handler(C, op); - + wm_gesture_tag_redraw(C); return OPERATOR_RUNNING_MODAL; @@ -2344,7 +2393,7 @@ int WM_gesture_border_modal(bContext *C, wmOperator *op, const wmEvent *event) rect->xmax = event->x - sx; rect->ymax = event->y - sy; } - border_apply_rect(op); + gesture_border_apply_rect(op); wm_gesture_tag_redraw(C); } @@ -2360,7 +2409,10 @@ int WM_gesture_border_modal(bContext *C, wmOperator *op, const wmEvent *event) case GESTURE_MODAL_DESELECT: case GESTURE_MODAL_IN: case GESTURE_MODAL_OUT: - if (border_apply(C, op, event->val)) { + if (gesture->wait_for_input) { + gesture->modal_state = event->val; + } + if (gesture_border_apply(C, op)) { wm_gesture_end(C, op); return OPERATOR_FINISHED; } @@ -2394,8 +2446,12 @@ void WM_gesture_border_cancel(bContext *C, wmOperator *op) /* **************** circle gesture *************** */ /* works now only for selection or modal paint stuff, calls exec while hold mouse, exit on release */ +static void gesture_circle_apply(bContext *C, wmOperator *op); + int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + int modal_state = gesture_modal_state_from_operator(op); + op->customdata = WM_gesture_new(C, event, WM_GESTURE_CIRCLE); wmGesture *gesture = op->customdata; rcti *rect = gesture->customdata; @@ -2403,6 +2459,16 @@ int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* Default or previously stored value. */ rect->xmax = RNA_int_get(op->ptr, "radius"); + /* Starting with the mode starts immediately, like having 'wait_for_input' disabled (some tools use this). */ + if (modal_state == GESTURE_MODAL_NOP) { + gesture->wait_for_input = true; + } + else { + gesture->is_active = true; + gesture->modal_state = modal_state; + gesture_circle_apply(C, op); + } + /* add modal handler */ WM_event_add_modal_handler(C, op); @@ -2415,15 +2481,18 @@ static void gesture_circle_apply(bContext *C, wmOperator *op) { wmGesture *gesture = op->customdata; rcti *rect = gesture->customdata; - - if (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_NOP) + + if (gesture->modal_state == GESTURE_MODAL_NOP) { return; + } /* operator arguments and storage. */ RNA_int_set(op->ptr, "x", rect->xmin); RNA_int_set(op->ptr, "y", rect->ymin); RNA_int_set(op->ptr, "radius", rect->xmax); - + + gesture_modal_state_to_operator(op, gesture->modal_state); + if (op->type->exec) { int retval; retval = op->type->exec(C, op); @@ -2451,6 +2520,7 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event) } else if (event->type == EVT_MODAL_MAP) { bool is_circle_size = false; + bool is_finished = false; float fac; switch (event->val) { @@ -2476,12 +2546,16 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event) case GESTURE_MODAL_DESELECT: case GESTURE_MODAL_NOP: { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "gesture_mode"); - if (prop != NULL) { - RNA_property_int_set(op->ptr, prop, event->val); + if (gesture->wait_for_input) { + gesture->modal_state = event->val; } - - if (event->val != GESTURE_MODAL_NOP) { + if (event->val == GESTURE_MODAL_NOP) { + /* Single action, click-drag & release to exit. */ + if (gesture->wait_for_input == false) { + is_finished = true; + } + } + else { /* apply first click */ gesture_circle_apply(C, op); gesture->is_active = true; @@ -2491,8 +2565,12 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event) } case GESTURE_MODAL_CANCEL: case GESTURE_MODAL_CONFIRM: - wm_gesture_end(C, op); - return OPERATOR_FINISHED; /* use finish or we don't get an undo */ + is_finished = true; + } + + if (is_finished) { + wm_gesture_end(C, op); + return OPERATOR_FINISHED; /* use finish or we don't get an undo */ } if (is_circle_size) { @@ -4288,14 +4366,15 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_SELECT); + /* Note: use 'KM_ANY' for release, so the circle exits on any mouse release, + * this is needed when circle select is activated as a tool. */ + /* left mouse shift for deselect too */ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_DESELECT); - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_NOP); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_NOP); WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_DESELECT); // default 2.4x - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP); // default 2.4x - - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP); + WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_NOP); // default 2.4x WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB); WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 3085f138846..090c8c90280 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -431,6 +431,7 @@ enum { GESTURE_MODAL_CANCEL = 1, GESTURE_MODAL_CONFIRM = 2, + /* Uses 'deselect' operator property. */ GESTURE_MODAL_SELECT = 3, GESTURE_MODAL_DESELECT = 4, @@ -441,6 +442,7 @@ enum { GESTURE_MODAL_BEGIN = 8, /* border select/straight line, activate, use release to detect which button */ + /* Uses 'zoom_out' operator property. */ GESTURE_MODAL_IN = 9, GESTURE_MODAL_OUT = 10, |