Event System: drag events no longer default to the drag start location

This avoids transform jumping which is a problem when tweaking values a
small amount. A fix for T40549 was made box-select used the location
when the key was pressed.

While it's important for box-select or any operator where it's expected
the drag-start location is used, this is only needed in some cases.
Since the event stores the click location and the current location,
no longer overwrite the events real location. Operators that depend on
using the drag-start can use this location if they need.

In some cases the region relative cursor location (Event.mval) now needs
to be calculated based on the click location.

- Added `WM_event_drag_start_mval` for convenient access to the region
  relative drag-start location (for drag events).
- Added `WM_event_drag_start_xy` for window relative coordinates.
- Added Python property Event.mouse_prev_click_x/y

Resolves T93599.

Reviewed By: Severin

Ref D14213
This commit is contained in:
Campbell Barton 2022-03-09 08:36:36 +11:00
parent 156e07232e
commit b8960267dd
Notes: blender-bot 2023-02-14 07:45:38 +01:00
Referenced by commit 90b2ed6c4b, Fix T100277: Grease pencil lines don't start at click-start
Referenced by commit 9d0777e514, Fix T99368: Annotation lines doesn't start where clicked
Referenced by issue #100277, Regression: Grease pencil lines don't start where i click
Referenced by issue #99368, Regression: Annotation lines doesn't start where clicked
Referenced by issue #93599, Smooth Drag Threshold for Tweak Events
21 changed files with 147 additions and 34 deletions

View File

@ -9394,7 +9394,9 @@ static int ui_list_activate_hovered_row(bContext *C,
}
}
const int *mouse_xy = (event->val == KM_CLICK_DRAG) ? event->prev_click_xy : event->xy;
int mouse_xy[2];
WM_event_drag_start_xy(event, mouse_xy);
uiBut *listrow = ui_list_row_find_mouse_over(region, mouse_xy);
if (listrow) {
wmOperatorType *custom_activate_optype = ui_list->dyn_data->custom_activate_optype;
@ -9421,7 +9423,9 @@ static bool ui_list_is_hovering_draggable_but(bContext *C,
const wmEvent *event)
{
/* On a tweak event, uses the coordinates from where tweaking was started. */
const int *mouse_xy = (event->val == KM_CLICK_DRAG) ? event->prev_click_xy : event->xy;
int mouse_xy[2];
WM_event_drag_start_xy(event, mouse_xy);
const uiBut *hovered_but = ui_but_find_mouse_over_ex(region, mouse_xy, false, NULL, NULL);
if (list->dyn_data->custom_drag_optype) {

View File

@ -511,8 +511,12 @@ static int actkeys_box_select_invoke(bContext *C, wmOperator *op, const wmEvent
}
bool tweak = RNA_boolean_get(op->ptr, "tweak");
if (tweak && actkeys_is_key_at_position(&ac, event->mval[0], event->mval[1])) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
if (tweak) {
int mval[2];
WM_event_drag_start_mval(event, ac.region, mval);
if (actkeys_is_key_at_position(&ac, mval[0], mval[1])) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
}
return WM_gesture_box_invoke(C, op, event);

View File

@ -799,7 +799,9 @@ static int graphkeys_box_select_invoke(bContext *C, wmOperator *op, const wmEven
}
if (RNA_boolean_get(op->ptr, "tweak")) {
tNearestVertInfo *under_mouse = find_nearest_fcurve_vert(&ac, event->mval);
int mval[2];
WM_event_drag_start_mval(event, ac.region, mval);
tNearestVertInfo *under_mouse = find_nearest_fcurve_vert(&ac, mval);
bool mouse_is_over_element = under_mouse != NULL;
if (under_mouse) {
MEM_freeN(under_mouse);

View File

@ -955,8 +955,10 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
int mval[2];
WM_event_drag_start_mval(event, region, mval);
float mx, my;
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mx, &my);
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &mx, &my);
float dx = (mx - nsw->mxstart) / UI_DPI_FAC;
float dy = (my - nsw->mystart) / UI_DPI_FAC;
@ -1057,7 +1059,9 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* convert mouse coordinates to v2d space */
float cursor[2];
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
int mval[2];
WM_event_drag_start_mval(event, region, mval);
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
const NodeResizeDirection dir = node_get_resize_direction(node, cursor[0], cursor[1]);
if (dir == NODE_RESIZE_NONE) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;

View File

@ -1177,8 +1177,11 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool detach = RNA_boolean_get(op->ptr, "detach");
int mval[2];
WM_event_drag_start_mval(event, &region, mval);
float2 cursor;
UI_view2d_region_to_view(&region.v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]);
UI_view2d_region_to_view(&region.v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
RNA_float_set_array(op->ptr, "drag_start", cursor);
RNA_boolean_set(op->ptr, "has_link_picked", false);

View File

@ -185,7 +185,11 @@ static bool is_event_over_node_or_socket(bContext *C, const wmEvent *event)
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
float2 mouse;
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &mouse.x, &mouse.y);
int mval[2];
WM_event_drag_start_mval(event, region, mval);
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &mouse.x, &mouse.y);
return is_position_over_node_or_socket(*snode, mouse);
}

View File

@ -1360,7 +1360,10 @@ static TreeElement *outliner_item_drag_element_find(SpaceOutliner *space_outline
{
/* NOTE: using click-drag events to trigger dragging is fine,
* it sends coordinates from where dragging was started */
const float my = UI_view2d_region_to_view_y(&region->v2d, event->mval[1]);
int mval[2];
WM_event_drag_start_mval(event, region, mval);
const float my = UI_view2d_region_to_view_y(&region->v2d, mval[1]);
return outliner_find_item_at_y(space_outliner, &space_outliner->tree, my);
}
@ -1372,6 +1375,9 @@ static int outliner_item_drag_drop_invoke(bContext *C,
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te = outliner_item_drag_element_find(space_outliner, region, event);
int mval[2];
WM_event_drag_start_mval(event, region, mval);
if (!te) {
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
@ -1383,8 +1389,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
float view_mval[2];
UI_view2d_region_to_view(
&region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}

View File

@ -225,8 +225,11 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE
const bool toggle_all = RNA_boolean_get(op->ptr, "all");
float view_mval[2];
UI_view2d_region_to_view(
&region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
int mval[2];
WM_event_drag_start_mval(event, region, mval);
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);

View File

@ -1082,7 +1082,8 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
ARegion *region = ruler_info->region;
const float mval_fl[2] = {UNPACK2(event->mval)};
float mval_fl[2];
WM_event_drag_start_mval_fl(event, region, mval_fl);
#ifdef USE_AXIS_CONSTRAINTS
ruler_info->constrain_axis = CONSTRAIN_AXIS_NONE;
@ -1311,6 +1312,9 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_CANCELLED;
}
int mval[2];
WM_event_drag_start_mval(event, region, mval);
/* Create new line */
RulerItem *ruler_item;
ruler_item = ruler_item_add(gzgroup);
@ -1329,7 +1333,7 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
depsgraph,
ruler_info,
ruler_item,
event->mval,
mval,
false
#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
,
@ -1344,7 +1348,7 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
else {
negate_v3_v3(inter->drag_start_co, rv3d->ofs);
copy_v3_v3(ruler_item->co[0], inter->drag_start_co);
view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval);
view3d_ruler_item_project(ruler_info, ruler_item->co[0], mval);
}
copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);

View File

@ -733,9 +733,11 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv
* the current cursor location instead of the drag-start. */
if (event->val == KM_CLICK_DRAG) {
/* Set this flag so snapping always updated. */
int mval[2];
WM_event_drag_start_mval(event, ipd->region, mval);
int flag_orig = snap_state_new->flag;
snap_state_new->flag |= V3D_SNAPCURSOR_TOGGLE_ALWAYS_TRUE;
ED_view3d_cursor_snap_data_get(snap_state_new, C, event->mval[0], event->mval[1]);
ED_view3d_cursor_snap_data_get(snap_state_new, C, mval[0], mval[1]);
snap_state_new->flag = flag_orig;
}
}
@ -1168,7 +1170,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve
}
if (do_cursor_update) {
const float mval_fl[2] = {UNPACK2(event->mval)};
float mval_fl[2];
WM_event_drag_start_mval_fl(event, region, mval_fl);
/* Calculate the snap location on mouse-move or when toggling snap. */
ipd->is_snap_found = false;

View File

@ -1706,6 +1706,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->launch_event = LEFTMOUSE;
}
if (options & CTX_CURSOR) {
/* Cursor should always use the drag start as the combination of click-drag to place & move
* doesn't work well if the click location isn't used when transforming. */
t->flag |= T_EVENT_DRAG_START;
}
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
@ -1819,7 +1825,15 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
use_accurate = true;
}
}
initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate);
int mval[2];
if (t->flag & T_EVENT_DRAG_START) {
WM_event_drag_start_mval(event, t->region, mval);
}
else {
copy_v2_v2_int(mval, event->mval);
}
initMouseInput(t, &t->mouse, t->center2d, mval, use_accurate);
}
transform_mode_init(t, op, mode);

View File

@ -137,6 +137,9 @@ typedef enum {
/** Runs auto-merge & splits. */
T_AUTOSPLIT = 1 << 21,
/** Use drag-start position of the event, otherwise use the cursor coordinates (unmodified). */
T_EVENT_DRAG_START = (1 << 22),
/** No cursor wrapping on region bounds */
T_NO_CURSOR_WRAP = 1 << 23,
} eTFlag;

View File

@ -216,7 +216,12 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
int mval[2];
if (event) {
copy_v2_v2_int(mval, event->mval);
if (t->flag & T_EVENT_DRAG_START) {
WM_event_drag_start_mval(event, region, mval);
}
else {
copy_v2_v2_int(mval, event->mval);
}
}
else {
zero_v2_int(mval);

View File

@ -2102,6 +2102,20 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Mouse Previous Y Position", "The window relative vertical location of the mouse");
prop = RNA_def_property(srna, "mouse_prev_press_x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "prev_click_xy[0]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Mouse Previous X Press Position",
"The window relative horizontal location of the last press event");
prop = RNA_def_property(srna, "mouse_prev_press_y", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "prev_click_xy[1]");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Mouse Previous Y Press Position",
"The window relative vertical location of the last press event");
prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);

View File

@ -1453,6 +1453,9 @@ bool WM_cursor_test_motion_and_update(const int mval[2]) ATTR_NONNULL(1) ATTR_WA
int WM_event_drag_threshold(const struct wmEvent *event);
bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]);
bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]);
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2]);
void WM_event_drag_start_mval_fl(const wmEvent *event, const ARegion *region, float r_mval[2]);
void WM_event_drag_start_xy(const wmEvent *event, int r_xy[2]);
/**
* Event map that takes preferences into account.

View File

@ -267,6 +267,10 @@ enum {
KM_RELEASE = 2,
KM_CLICK = 3,
KM_DBL_CLICK = 4,
/**
* \note The cursor location at the point dragging starts is set to #wmEvent.prev_click_xy
* some operators such as box selection should use this location instead of #wmEvent.xy.
*/
KM_CLICK_DRAG = 5,
};

View File

@ -815,6 +815,14 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
BLI_buffer_declare_static(wmGizmo *, visible_3d_gizmos, BLI_BUFFER_NOP, 128);
bool do_step[WM_GIZMOMAP_DRAWSTEP_MAX];
int mval[2];
if (event->val == KM_CLICK_DRAG) {
WM_event_drag_start_mval(event, CTX_wm_region(C), mval);
}
else {
copy_v2_v2_int(mval, event->mval);
}
for (int i = 0; i < ARRAY_SIZE(do_step); i++) {
do_step[i] = WM_gizmo_context_check_drawstep(C, i);
}
@ -841,7 +849,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
}
else if (step == WM_GIZMOMAP_DRAWSTEP_2D) {
if ((gz = wm_gizmogroup_find_intersected_gizmo(
wm, gzgroup, C, event->modifier, event->mval, r_part))) {
wm, gzgroup, C, event->modifier, mval, r_part))) {
break;
}
}
@ -853,7 +861,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
/* 2D gizmos get priority. */
if (gz == NULL) {
gz = gizmo_find_intersected_3d(
C, event->mval, visible_3d_gizmos.data, visible_3d_gizmos.count, r_part);
C, mval, visible_3d_gizmos.data, visible_3d_gizmos.count, r_part);
}
}
BLI_buffer_free(&visible_3d_gizmos);

View File

@ -338,6 +338,25 @@ bool WM_event_drag_test(const wmEvent *event, const int prev_xy[2])
return WM_event_drag_test_with_delta(event, drag_delta);
}
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
{
const int *xy = (event->val == KM_CLICK_DRAG) ? event->prev_click_xy : event->xy;
r_mval[0] = xy[0] - region->winrct.xmin;
r_mval[1] = xy[1] - region->winrct.ymin;
}
void WM_event_drag_start_mval_fl(const wmEvent *event, const ARegion *region, float r_mval[2])
{
const int *xy = (event->val == KM_CLICK_DRAG) ? event->prev_click_xy : event->xy;
r_mval[0] = xy[0] - region->winrct.xmin;
r_mval[1] = xy[1] - region->winrct.ymin;
}
void WM_event_drag_start_xy(const wmEvent *event, int r_xy[2])
{
copy_v2_v2_int(r_xy, (event->val == KM_CLICK_DRAG) ? event->prev_click_xy : event->xy);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -3169,13 +3169,13 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
win->event_queue_check_drag_handled = true;
const int direction = WM_event_drag_direction(event);
const int prev_xy[2] = {UNPACK2(event->xy)};
/* Intentionally leave `event->xy` as-is, event users are expected to use
* `event->prev_click_xy` if they need to access the drag start location. */
const short prev_val = event->val;
const short prev_type = event->type;
const uint8_t prev_modifier = event->modifier;
const short prev_keymodifier = event->keymodifier;
copy_v2_v2_int(event->xy, event->prev_click_xy);
event->val = KM_CLICK_DRAG;
event->type = event->prev_click_type;
event->modifier = event->prev_click_modifier;
@ -3191,7 +3191,6 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
event->modifier = prev_modifier;
event->val = prev_val;
event->type = prev_type;
copy_v2_v2_int(event->xy, prev_xy);
win->event_queue_check_click = false;
if (!((action & WM_HANDLER_BREAK) == 0 || wm_action_not_handled(action))) {

View File

@ -49,6 +49,9 @@ wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent
gesture->modal_state = GESTURE_MODAL_NOP;
gesture->move = false;
int xy[2];
WM_event_drag_start_xy(event, xy);
if (ELEM(type,
WM_GESTURE_RECT,
WM_GESTURE_CROSS_RECT,
@ -57,14 +60,14 @@ wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent
rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
gesture->customdata = rect;
rect->xmin = event->xy[0] - gesture->winrct.xmin;
rect->ymin = event->xy[1] - gesture->winrct.ymin;
rect->xmin = xy[0] - gesture->winrct.xmin;
rect->ymin = xy[1] - gesture->winrct.ymin;
if (type == WM_GESTURE_CIRCLE) {
/* caller is responsible for initializing 'xmax' to radius. */
}
else {
rect->xmax = event->xy[0] - gesture->winrct.xmin;
rect->ymax = event->xy[1] - gesture->winrct.ymin;
rect->xmax = xy[0] - gesture->winrct.xmin;
rect->ymax = xy[1] - gesture->winrct.ymin;
}
}
else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
@ -72,8 +75,8 @@ wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent
gesture->points_alloc = 1024;
gesture->customdata = lasso = MEM_mallocN(sizeof(short[2]) * gesture->points_alloc,
"lasso points");
lasso[0] = event->xy[0] - gesture->winrct.xmin;
lasso[1] = event->xy[1] - gesture->winrct.ymin;
lasso[0] = xy[0] - gesture->winrct.xmin;
lasso[1] = xy[1] - gesture->winrct.ymin;
gesture->points = 1;
}

View File

@ -956,8 +956,13 @@ int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
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]);
ARegion *region = CTX_wm_region(C);
int mval[2];
WM_event_drag_start_mval(event, region, mval);
RNA_int_set(op->ptr, "mouse_x", mval[0]);
RNA_int_set(op->ptr, "mouse_y", mval[1]);
op->customdata = POINTER_FROM_INT(0);