WM: Utilities for select operators to work with click-dragging items
Based on work by Bastien and Brecht in the Node Editor, this adds more generalized support for selecting items so that click+drag actions on items (nodes, makers, dopesheet keys, etc.) works as wanted. Note that this only adds the barebones to support this in other editors, it's not used yet (will be done in followup commits). The behavior is supposed to work as follows: * Clicking an unselected item immediately selects it, and deselects other items (doesn't wait for release events). * Click+drag on an unselected item immediately selects it, deselects others and drags it in one go (don't require selecting it first!). * Click+drag on a selected item won't change the selection state (and won't send an undo push) and start dragging all selected items as soon as the drag event is recognized. * Clicking on a selected item will still deselect others, but that will only happen on mouse release, when we know the intention is not to drag the item. Included in: https://developer.blender.org/D5979 Reviewed by: Brecht van Lommel, William Reynish
This commit is contained in:
parent
0bcada85b3
commit
be2cd4bb53
Notes:
blender-bot
2023-02-14 19:07:42 +01:00
Referenced by commit 7dea058546
, UI: Move all Selected NLA-Strips when Dragging
Referenced by issue blender/blender-addons#70581, Ctrl+Shift+Click on a node does't work if the node is already selected (Link Viewer, Node Wrangler)
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue