diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index df253d619c9..f8b6b5171da 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -335,6 +335,12 @@ void WM_event_timer_sleep(struct wmWindowManager *wm, /* operator api, default callbacks */ /* invoke callback, uses enum property named "type" */ +int WM_generic_select_modal(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event); +int WM_generic_select_invoke(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event); void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); int WM_operator_smooth_viewtx_get(const struct wmOperator *op); int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext); @@ -474,6 +480,7 @@ void WM_operator_properties_select_random(struct wmOperatorType *ot); int WM_operator_properties_select_random_seed_increment_get(wmOperator *op); void WM_operator_properties_select_operation(struct wmOperatorType *ot); void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot); +void WM_operator_properties_generic_select(struct wmOperatorType *ot); struct CheckerIntervalParams { int nth; /* bypass when set to zero */ int skip; diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index a8feb22cbf8..395de89c0da 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -396,6 +396,16 @@ void WM_operator_properties_select_operation_simple(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } +void WM_operator_properties_generic_select(wmOperatorType *ot) +{ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "wait_to_deselect_others", true, "Wait to Deselect Others", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX); +} + void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot) { WM_operator_properties_border(ot); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 97771d40b2c..292e27c3cbf 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -700,6 +700,82 @@ void WM_operator_properties_free(PointerRNA *ptr) /** \name Default Operator Callbacks * \{ */ +int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr, + "wait_to_deselect_others"); + const short init_event_type = (short)POINTER_AS_INT(op->customdata); + int ret_value = 0; + + /* get settings from RNA properties for operator */ + int mval[2]; + mval[0] = RNA_int_get(op->ptr, "mouse_x"); + mval[1] = RNA_int_get(op->ptr, "mouse_y"); + + if (init_event_type == 0) { + if (event->val == KM_PRESS) { + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, true); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + op->customdata = POINTER_FROM_INT((int)event->type); + if (ret_value & OPERATOR_RUNNING_MODAL) { + WM_event_add_modal_handler(C, op); + } + return ret_value | OPERATOR_PASS_THROUGH; + } + else { + /* If we are in init phase, and cannot validate init of modal operations, + * just fall back to basic exec. + */ + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + return ret_value | OPERATOR_PASS_THROUGH; + } + } + else if (event->type == init_event_type && event->val == KM_RELEASE) { + RNA_property_boolean_set(op->ptr, wait_to_deselect_prop, false); + + ret_value = op->type->exec(C, op); + OPERATOR_RETVAL_CHECK(ret_value); + + return ret_value | OPERATOR_PASS_THROUGH; + } + else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + const int drag_delta[2] = { + mval[0] - event->mval[0], + mval[1] - event->mval[1], + }; + /* If user moves mouse more than defined threshold, we consider select operator as + * finished. Otherwise, it is still running until we get an 'release' event. In any + * case, we pass through event, but select op is not finished yet. */ + if (WM_event_drag_test_with_delta(event, drag_delta)) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + else { + /* Important not to return anything other than PASS_THROUGH here, + * otherwise it prevents underlying tweak detection code to work properly. */ + return OPERATOR_PASS_THROUGH; + } + } + + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; +} + +int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + RNA_int_set(op->ptr, "mouse_x", event->mval[0]); + RNA_int_set(op->ptr, "mouse_y", event->mval[1]); + + op->customdata = POINTER_FROM_INT(0); + + return op->type->modal(C, op, event); +} + void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op) { if (op->flag & OP_IS_INVOKE) {