From e4ac8ab212769b569334d0cd15d4bf04f42cbc89 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 29 May 2019 00:48:48 +1000 Subject: [PATCH] WM: support X/Y axis cursor wrapping Operator flags to wrap on a single axis. D4865 by @Gvgeo with updates. Resolves T64585 --- intern/ghost/GHOST_C-api.h | 1 + intern/ghost/GHOST_IWindow.h | 1 + intern/ghost/GHOST_Rect.h | 31 +++++++++++----- intern/ghost/GHOST_Types.h | 7 ++++ intern/ghost/intern/GHOST_C-api.cpp | 3 +- intern/ghost/intern/GHOST_SystemCocoa.mm | 4 +- intern/ghost/intern/GHOST_SystemSDL.cpp | 6 +-- intern/ghost/intern/GHOST_SystemWin32.cpp | 7 ++-- intern/ghost/intern/GHOST_SystemX11.cpp | 7 ++-- intern/ghost/intern/GHOST_Window.cpp | 5 ++- intern/ghost/intern/GHOST_Window.h | 10 +++++ .../blender/editors/animation/anim_markers.c | 2 +- source/blender/editors/animation/anim_ops.c | 2 +- .../editors/interface/interface_handlers.c | 2 +- source/blender/editors/interface/view2d_ops.c | 4 +- source/blender/editors/mesh/editmesh_bevel.c | 2 +- source/blender/editors/mesh/editmesh_inset.c | 2 +- source/blender/editors/space_clip/clip_ops.c | 4 +- .../blender/editors/space_clip/tracking_ops.c | 2 +- .../editors/space_clip/tracking_ops_plane.c | 2 +- .../blender/editors/space_graph/graph_ops.c | 2 +- .../blender/editors/space_image/image_ops.c | 4 +- source/blender/editors/space_node/node_view.c | 2 +- source/blender/editors/space_text/text_ops.c | 2 +- .../editors/space_view3d/view3d_edit.c | 8 ++-- .../editors/uvedit/uvedit_unwrap_ops.c | 2 +- source/blender/makesrna/intern/rna_wm.c | 4 +- source/blender/windowmanager/WM_api.h | 2 +- source/blender/windowmanager/WM_types.h | 26 +++++++++---- .../windowmanager/gizmo/intern/wm_gizmo_map.c | 2 +- .../blender/windowmanager/intern/wm_cursors.c | 18 +++++++-- .../windowmanager/intern/wm_event_system.c | 37 +++++++++---------- .../windowmanager/intern/wm_operator_type.c | 15 ++++++-- 33 files changed, 148 insertions(+), 80 deletions(-) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index fa783c17e8c..3238be8fd87 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -410,6 +410,7 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, */ extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, GHOST_TGrabCursorMode mode, + GHOST_TAxisFlag warp_axis, int bounds[4], const int mouse_ungrab_xy[2]); diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 6a9e0b9588a..8042244c536 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -314,6 +314,7 @@ class GHOST_IWindow { * \return Indication of success. */ virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode /*mode*/, + GHOST_TAxisFlag /*wrap_axis*/, GHOST_Rect * /*bounds*/, GHOST_TInt32 /*mouse_ungrab_xy*/[2]) { diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h index 831d3ef1445..88053f83fb9 100644 --- a/intern/ghost/GHOST_Rect.h +++ b/intern/ghost/GHOST_Rect.h @@ -125,7 +125,10 @@ class GHOST_Rect { * \param x The x-coordinate of the point. * \param y The y-coordinate of the point. */ - virtual inline void wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs); + virtual inline void wrapPoint(GHOST_TInt32 &x, + GHOST_TInt32 &y, + GHOST_TInt32 ofs, + GHOST_TAxisFlag axis); /** * Returns whether the point is inside this rectangle. @@ -236,7 +239,11 @@ inline void GHOST_Rect::unionPoint(GHOST_TInt32 x, GHOST_TInt32 y) if (y > m_b) m_b = y; } -inline void GHOST_Rect::wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs) + +inline void GHOST_Rect::wrapPoint(GHOST_TInt32 &x, + GHOST_TInt32 &y, + GHOST_TInt32 ofs, + GHOST_TAxisFlag axis) { GHOST_TInt32 w = getWidth(); GHOST_TInt32 h = getHeight(); @@ -246,14 +253,18 @@ inline void GHOST_Rect::wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 return; } - while (x - ofs < m_l) - x += w - (ofs * 2); - while (y - ofs < m_t) - y += h - (ofs * 2); - while (x + ofs > m_r) - x -= w - (ofs * 2); - while (y + ofs > m_b) - y -= h - (ofs * 2); + if (axis & GHOST_kAxisX) { + while (x - ofs < m_l) + x += w - (ofs * 2); + while (x + ofs > m_r) + x -= w - (ofs * 2); + } + if (axis & GHOST_kGrabAxisY) { + while (y - ofs < m_t) + y += h - (ofs * 2); + while (y + ofs > m_b) + y -= h - (ofs * 2); + } } inline bool GHOST_Rect::isInside(GHOST_TInt32 x, GHOST_TInt32 y) const diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index f38154cbf94..68516c3ecf8 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -374,6 +374,13 @@ typedef enum { GHOST_kGrabHide, } GHOST_TGrabCursorMode; +typedef enum { + /** Axis that cursor grab will wrap. */ + GHOST_kGrabAxisNone = 0, + GHOST_kAxisX = (1 << 0), + GHOST_kGrabAxisY = (1 << 1), +} GHOST_TAxisFlag; + typedef void *GHOST_TEventDataPtr; typedef struct { diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index c8ee2e44efe..38ddf9819f9 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -324,6 +324,7 @@ GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, GHOST_TGrabCursorMode mode, + GHOST_TAxisFlag wrap_axis, int bounds[4], const int mouse_ungrab_xy[2]) { @@ -340,7 +341,7 @@ GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, } return window->setCursorGrab( - mode, bounds ? &bounds_rect : NULL, mouse_ungrab_xy ? mouse_xy : NULL); + mode, wrap_axis, bounds ? &bounds_rect : NULL, mouse_ungrab_xy ? mouse_xy : NULL); } GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index f13c9d470a5..eb54ed20fe1 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -1590,7 +1590,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) // Warp mouse cursor if needed GHOST_TInt32 warped_x_mouse = x_mouse; GHOST_TInt32 warped_y_mouse = y_mouse; - correctedBounds.wrapPoint(warped_x_mouse, warped_y_mouse, 4); + + correctedBounds.wrapPoint( + warped_x_mouse, warped_y_mouse, 4, window->getCursorGrabAxis()); // Set new cursor position if (x_mouse != warped_x_mouse || y_mouse != warped_y_mouse) { diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp index 8fc7046565d..520c62719f8 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cpp +++ b/intern/ghost/intern/GHOST_SystemSDL.cpp @@ -369,9 +369,9 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event) if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) window->getClientBounds(bounds); - /* could also clamp to screen bounds - * wrap with a window outside the view will fail atm */ - bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */ + /* Could also clamp to screen bounds wrap with a window outside the view will fail atm. + * Use offset of 8 in case the window is at screen bounds. */ + bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis()); window->getCursorGrabAccum(x_accum, y_accum); // cant use setCursorPosition because the mouse may have no focus! diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 9f7b6f75e41..0cc1b36f369 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -934,10 +934,9 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, window->getClientBounds(bounds); } - /* could also clamp to screen bounds - * wrap with a window outside the view will fail atm */ - - bounds.wrapPoint(x_new, y_new, 2); /* offset of one incase blender is at screen bounds */ + /* Could also clamp to screen bounds wrap with a window outside the view will fail atm. + * Use offset of 8 in case the window is at screen bounds. */ + bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis()); window->getCursorGrabAccum(x_accum, y_accum); if (x_new != x_screen || y_new != y_screen) { diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index b95e5fe3846..31411c823ae 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -868,9 +868,10 @@ void GHOST_SystemX11::processEvent(XEvent *xe) if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) window->getClientBounds(bounds); - /* could also clamp to screen bounds - * wrap with a window outside the view will fail atm */ - bounds.wrapPoint(x_new, y_new, 8); /* offset of one incase blender is at screen bounds */ + /* Could also clamp to screen bounds wrap with a window outside the view will fail atm. + * Use offset of 8 in case the window is at screen bounds. */ + bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis()); + window->getCursorGrabAccum(x_accum, y_accum); if (x_new != xme.x_root || y_new != xme.y_root) { diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index 85283a34d2e..5649386063d 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -136,6 +136,7 @@ GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) } GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode, + GHOST_TAxisFlag wrap_axis, GHOST_Rect *bounds, GHOST_TInt32 mouse_ungrab_xy[2]) { @@ -151,8 +152,9 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode, if (setWindowCursorGrab(mode)) { - if (mode == GHOST_kGrabDisable) + if (mode == GHOST_kGrabDisable) { m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; + } else if (bounds) { m_cursorGrabBounds = *bounds; } @@ -160,6 +162,7 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode, getClientBounds(m_cursorGrabBounds); } m_cursorGrab = mode; + m_cursorGrabAxis = wrap_axis; return GHOST_kSuccess; } else { diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index b5399ec803e..acd0c93ff87 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -145,6 +145,7 @@ class GHOST_Window : public GHOST_IWindow { inline bool getCursorVisibility() const; inline GHOST_TGrabCursorMode getCursorGrabMode() const; inline bool getCursorGrabModeIsWarp() const; + inline GHOST_TAxisFlag getCursorGrabAxis() const; inline void getCursorGrabInitPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const; inline void getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const; inline void setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y); @@ -162,6 +163,7 @@ class GHOST_Window : public GHOST_IWindow { * \return Indication of success. */ GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, + GHOST_TAxisFlag wrap_axis, GHOST_Rect *bounds, GHOST_TInt32 mouse_ungrab_xy[2]); @@ -367,6 +369,9 @@ class GHOST_Window : public GHOST_IWindow { /** The current grabbed state of the cursor */ GHOST_TGrabCursorMode m_cursorGrab; + /** Grab cursor axis.*/ + GHOST_TAxisFlag m_cursorGrabAxis; + /** Initial grab location. */ GHOST_TInt32 m_cursorGrabInitPos[2]; @@ -426,6 +431,11 @@ inline bool GHOST_Window::getCursorGrabModeIsWarp() const return (m_cursorGrab == GHOST_kGrabWrap) || (m_cursorGrab == GHOST_kGrabHide); } +inline GHOST_TAxisFlag GHOST_Window::getCursorGrabAxis() const +{ + return m_cursorGrabAxis; +} + inline void GHOST_Window::getCursorGrabInitPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const { x = m_cursorGrabInitPos[0]; diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 90632da8a7c..b8db63ce1ad 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -1073,7 +1073,7 @@ static void MARKER_OT_move(wmOperatorType *ot) ot->cancel = ed_marker_move_cancel; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* rna storage */ RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 45bb8f3b11e..abec3563d0c 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -267,7 +267,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->poll = change_frame_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X | OPTYPE_UNDO_GROUPED; ot->undo_group = "Frame Change"; /* rna */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index b8e97f58c2f..101703c4140 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -7320,7 +7320,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s /* number editing */ if (state == BUTTON_STATE_NUM_EDITING) { if (ui_but_is_cursor_warp(but)) { - WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL); + WM_cursor_grab_enable(CTX_wm_window(C), CURSOR_WRAP_XY, true, NULL); } ui_numedit_begin(but, data); } diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 68ee38bc99f..b400b9bf4ed 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -335,7 +335,7 @@ static void VIEW2D_OT_pan(wmOperatorType *ot) ot->cancel = view_pan_cancel; /* operator is modal */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* rna - must keep these in sync with the other operators */ RNA_def_int(ot->srna, "deltax", 0, INT_MIN, INT_MAX, "Delta X", "", INT_MIN, INT_MAX); @@ -1241,7 +1241,7 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot) ot->poll = view_zoom_poll; /* operator is repeatable */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* rna - must keep these in sync with the other operators */ prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX); diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 1cd4e95314b..28153dc7716 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -920,7 +920,7 @@ void MESH_OT_bevel(wmOperatorType *ot) ot->poll_property = edbm_bevel_poll_property; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING; RNA_def_enum( ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures"); diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 2955488a597..9c7b234028c 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -577,7 +577,7 @@ void MESH_OT_inset(wmOperatorType *ot) ot->poll = ED_operator_editmesh; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING; /* properties */ RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries"); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 710a46fdd51..532d89f6fa2 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -495,7 +495,7 @@ void CLIP_OT_view_pan(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* properties */ RNA_def_float_vector(ot->srna, @@ -685,7 +685,7 @@ void CLIP_OT_view_zoom(wmOperatorType *ot) ot->poll = ED_space_clip_view_clip_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* properties */ prop = RNA_def_float(ot->srna, diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 0425d6da3d8..c19b0583a5c 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -991,7 +991,7 @@ void CLIP_OT_slide_marker(wmOperatorType *ot) ot->modal = slide_marker_modal; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING; /* properties */ RNA_def_float_vector(ot->srna, diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c index fc6a9ee1478..89478375658 100644 --- a/source/blender/editors/space_clip/tracking_ops_plane.c +++ b/source/blender/editors/space_clip/tracking_ops_plane.c @@ -391,5 +391,5 @@ void CLIP_OT_slide_plane_marker(wmOperatorType *ot) ot->modal = slide_plane_marker_modal; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING; } diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 5c7035a4c04..3450ca5a431 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -222,7 +222,7 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot) ot->poll = graphview_cursor_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_X | OPTYPE_UNDO; /* rna */ RNA_def_float(ot->srna, "frame", 0, MINAFRAMEF, MAXFRAMEF, "Frame", "", MINAFRAMEF, MAXFRAMEF); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 8121c577706..5b8b93b3af8 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -409,7 +409,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot) ot->poll = space_image_main_region_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS; /* properties */ RNA_def_float_vector(ot->srna, @@ -633,7 +633,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot) ot->poll = space_image_main_region_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS; /* properties */ prop = RNA_def_float(ot->srna, diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 15eb12ecf39..b33960bb454 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -284,7 +284,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot) ot->cancel = snode_bg_viewmove_cancel; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; } static int backimage_zoom_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 2593571d9a3..63d4f3e3119 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -2562,7 +2562,7 @@ void TEXT_OT_scroll(wmOperatorType *ot) ot->poll = text_scroll_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_INTERNAL; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_INTERNAL; /* properties */ RNA_def_int( diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 80153a38128..b12d081325f 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -987,7 +987,7 @@ void VIEW3D_OT_rotate(wmOperatorType *ot) ot->cancel = viewrotate_cancel; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); } @@ -1798,7 +1798,7 @@ void VIEW3D_OT_move(wmOperatorType *ot) ot->cancel = viewmove_cancel; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* properties */ view3d_operator_properties_common(ot, V3D_OP_PROP_USE_MOUSE_INIT); @@ -2359,7 +2359,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) ot->cancel = viewzoom_cancel; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* properties */ view3d_operator_properties_common( @@ -2672,7 +2672,7 @@ void VIEW3D_OT_dolly(wmOperatorType *ot) ot->cancel = viewdolly_cancel; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* properties */ view3d_operator_properties_common( diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 717bc347cf7..796594802c4 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -889,7 +889,7 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /* identifiers */ ot->name = "Minimize Stretch"; ot->idname = "UV_OT_minimize_stretch"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING; ot->description = "Reduce UV stretching by relaxing angles"; /* api callbacks */ diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 14994340ad3..860f57e374a 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -445,12 +445,14 @@ static const EnumPropertyItem operator_flag_items[] = { "Push a single undo event for repetead instances of this operator"}, {OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"}, {OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"}, - {OPTYPE_GRAB_CURSOR, + {OPTYPE_GRAB_CURSOR_XY, "GRAB_CURSOR", 0, "Grab Pointer", "Use so the operator grabs the mouse focus, enables wrapping when continuous grab " "is enabled"}, + {OPTYPE_GRAB_CURSOR_X, "GRAB_CURSOR_X", 0, "Grab Pointer X", "Grab, only warping the X axis"}, + {OPTYPE_GRAB_CURSOR_Y, "GRAB_CURSOR_Y", 0, "Grab Pointer Y", "Grab, only warping the Y axis"}, {OPTYPE_PRESET, "PRESET", 0, "Preset", "Display a preset button with the operators settings"}, {OPTYPE_INTERNAL, "INTERNAL", 0, "Internal", "Removes the operator from search results"}, {0, NULL, 0, NULL, NULL}, diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index a5eb892841c..de6db8876f7 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -184,7 +184,7 @@ bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const AReg void WM_cursor_modal_set(struct wmWindow *win, int curs); void WM_cursor_modal_restore(struct wmWindow *win); void WM_cursor_wait(bool val); -void WM_cursor_grab_enable(struct wmWindow *win, bool wrap, bool hide, int bounds[4]); +void WM_cursor_grab_enable(struct wmWindow *win, int wrap, bool hide, int bounds[4]); void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]); void WM_cursor_time(struct wmWindow *win, int nr); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index eddea3b2062..00c43450de7 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -141,21 +141,33 @@ enum { OPTYPE_UNDO = (1 << 1), /* do undo push after after */ OPTYPE_BLOCKING = (1 << 2), /* let blender grab all input from the WM (X11) */ OPTYPE_MACRO = (1 << 3), - OPTYPE_GRAB_CURSOR = - (1 << 4), /* grabs the cursor and optionally enables continuous cursor wrapping */ - OPTYPE_PRESET = (1 << 5), /* show preset menu */ + + /* grabs the cursor and optionally enables continuous cursor wrapping. */ + OPTYPE_GRAB_CURSOR_XY = (1 << 4), + OPTYPE_GRAB_CURSOR_X = (1 << 5), /* Only X axis. */ + OPTYPE_GRAB_CURSOR_Y = (1 << 6), /* Only Y axis. */ + + OPTYPE_PRESET = (1 << 7), /* show preset menu */ /* some operators are mainly for internal use * and don't make sense to be accessed from the * search menu, even if poll() returns true. * currently only used for the search toolbox */ - OPTYPE_INTERNAL = (1 << 6), + OPTYPE_INTERNAL = (1 << 8), - OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */ + OPTYPE_LOCK_BYPASS = (1 << 9), /* Allow operator to run when interface is locked */ OPTYPE_UNDO_GROUPED = - (1 << 8), /* Special type of undo which doesn't store itself multiple times */ + (1 << 10), /* Special type of undo which doesn't store itself multiple times */ OPTYPE_USE_EVAL_DATA = - (1 << 9), /* Need evaluated data (i.e. a valid, up-to-date depsgraph for current context) */ + (1 << 11), /* Need evaluated data (i.e. a valid, up-to-date depsgraph for current context) */ +}; + +/* Wrap Axis. */ +enum { + CURSOR_WRAP_NONE = 0, + CURSOR_WRAP_X, + CURSOR_WRAP_Y, + CURSOR_WRAP_XY, }; /* context to call operator in for WM_operator_name_call */ diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 6783a294500..ba9d59e82d6 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -1038,7 +1038,7 @@ void wm_gizmomap_modal_set( gzmap->gzmap_context.modal = gz; if ((gz->flag & WM_GIZMO_MOVE_CURSOR) && (event->is_motion_absolute == false)) { - WM_cursor_grab_enable(win, true, true, NULL); + WM_cursor_grab_enable(win, CURSOR_WRAP_XY, true, NULL); copy_v2_v2_int(gzmap->gzmap_context.event_xy, &event->x); gzmap->gzmap_context.event_grabcursor = win->grabcursor; } diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 58cfc350b17..eeea3bf498c 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -223,12 +223,13 @@ void WM_cursor_wait(bool val) /** * \param bounds: can be NULL */ -void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4]) +void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4]) { /* Only grab cursor when not running debug. * It helps not to get a stuck WM when hitting a breakpoint * */ GHOST_TGrabCursorMode mode = GHOST_kGrabNormal; + GHOST_TAxisFlag mode_axis = GHOST_kAxisX | GHOST_kGrabAxisY; if (bounds) { wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]); @@ -240,12 +241,20 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4]) } else if (wrap) { mode = GHOST_kGrabWrap; + + if (wrap == CURSOR_WRAP_X) { + mode_axis = GHOST_kAxisX; + } + if (wrap == CURSOR_WRAP_Y) { + mode_axis = GHOST_kGrabAxisY; + } } + if ((G.debug & G_DEBUG) == 0) { if (win->ghostwin) { /* Note: There is no tabletdata on Windows if no tablet device is connected. */ if (win->eventstate->is_motion_absolute == false) { - GHOST_SetCursorGrab(win->ghostwin, mode, bounds, NULL); + GHOST_SetCursorGrab(win->ghostwin, mode, mode_axis, bounds, NULL); } win->grabcursor = mode; @@ -260,10 +269,11 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2]) if (mouse_ungrab_xy) { int mouse_xy[2] = {mouse_ungrab_xy[0], mouse_ungrab_xy[1]}; wm_cursor_position_to_ghost(win, &mouse_xy[0], &mouse_xy[1]); - GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, mouse_xy); + GHOST_SetCursorGrab( + win->ghostwin, GHOST_kGrabDisable, GHOST_kGrabAxisNone, NULL, mouse_xy); } else { - GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, NULL); + GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kGrabAxisNone, NULL, NULL); } win->grabcursor = GHOST_kGrabDisable; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 51b2ca6a3d0..ac2bf1985d4 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1469,26 +1469,20 @@ static int wm_operator_invoke(bContext *C, */ if (ot->flag & OPTYPE_BLOCKING || (op->opm && op->opm->type->flag & OPTYPE_BLOCKING)) { int bounds[4] = {-1, -1, -1, -1}; - bool wrap; + int wrap = CURSOR_WRAP_NONE; - if (event == NULL) { - wrap = false; - } - else if (op->opm) { - wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && - ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || - (op->opm->type->flag & OPTYPE_GRAB_CURSOR)); - } - else { - wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && - ((op->flag & OP_IS_MODAL_GRAB_CURSOR) || (ot->flag & OPTYPE_GRAB_CURSOR)); - } - - /* exception, cont. grab in header is annoying */ - if (wrap) { - ARegion *ar = CTX_wm_region(C); - if (ar && ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER)) { - wrap = false; + if (event && (U.uiflag & USER_CONTINUOUS_MOUSE)) { + const wmOperator *op_test = op->opm ? op->opm : op; + const wmOperatorType *ot_test = op_test->type; + if ((ot_test->flag & OPTYPE_GRAB_CURSOR_XY) || + (op_test->flag & OP_IS_MODAL_GRAB_CURSOR)) { + wrap = CURSOR_WRAP_XY; + } + else if (ot_test->flag & OPTYPE_GRAB_CURSOR_X) { + wrap = CURSOR_WRAP_X; + } + else if (ot_test->flag & OPTYPE_GRAB_CURSOR_Y) { + wrap = CURSOR_WRAP_Y; } } @@ -1497,6 +1491,11 @@ static int wm_operator_invoke(bContext *C, ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); + /* Wrap only in X for header. */ + if (ar && ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER)) { + wrap = CURSOR_WRAP_X; + } + if (ar && ar->regiontype == RGN_TYPE_WINDOW && BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) { winrect = &ar->winrct; diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c index 179b4402200..7ae28f3f448 100644 --- a/source/blender/windowmanager/intern/wm_operator_type.c +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -430,9 +430,18 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event) * */ if (op->opm->type->flag & OPTYPE_BLOCKING) { int bounds[4] = {-1, -1, -1, -1}; - const bool wrap = ((U.uiflag & USER_CONTINUOUS_MOUSE) && - ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || - (op->opm->type->flag & OPTYPE_GRAB_CURSOR))); + int wrap = CURSOR_WRAP_NONE; + + if ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || + (op->opm->type->flag & OPTYPE_GRAB_CURSOR_XY)) { + wrap = CURSOR_WRAP_XY; + } + else if (op->opm->type->flag & OPTYPE_GRAB_CURSOR_X) { + wrap = CURSOR_WRAP_X; + } + else if (op->opm->type->flag & OPTYPE_GRAB_CURSOR_Y) { + wrap = CURSOR_WRAP_Y; + } if (wrap) { ARegion *ar = CTX_wm_region(C);