Adjustments to continuous grab
authorCampbell Barton <ideasman42@gmail.com>
Sat, 17 Oct 2009 14:08:01 +0000 (14:08 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 17 Oct 2009 14:08:01 +0000 (14:08 +0000)
- Use an enum for grab modes rather then boolean options.
 -- GHOST_kGrabNormal: continuous grab userpref disabled
 -- GHOST_kGrabWrap: wrap the mouse at the screen bounds *
 -- GHOST_kGrabHide: hide the mouse while grabbing and restore the mouse where it was initially pressed *

GrabWrap is nice for transform and tools where you want some idea where the cursor is, previously I found both restoring the mouse at its original location and restoring at a clamped location was confusing with operators like transform, wrapping is not ideal but IMHO the best of a bad bunch of options.
GrabHide  is for numbuts, where restoring the mouse at the initial location isnt so confusing.

15 files changed:
intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_IWindow.h
intern/ghost/GHOST_Rect.h
intern/ghost/GHOST_Types.h
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_SystemX11.cpp
intern/ghost/intern/GHOST_Window.cpp
intern/ghost/intern/GHOST_Window.h
intern/ghost/intern/GHOST_WindowCocoa.h
intern/ghost/intern/GHOST_WindowX11.cpp
intern/ghost/intern/GHOST_WindowX11.h
source/blender/editors/interface/interface_handlers.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_cursors.c
source/blender/windowmanager/intern/wm_event_system.c

index 00d2cdb1e3b62d75f754346a47a11715da01e245..93bd12437ab80521d405bb8c731d51c65003a4ac 100644 (file)
@@ -376,7 +376,7 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
  * @return     Indication of success.
  */
 extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
-                                                                                 int grab, int warp, int restore);
+                                                                                               GHOST_TGrabCursorMode mode);
 
 /***************************************************************************************
  ** Access to mouse button and keyboard states.
index 993b41a4d4fd282c398b367fb148fe3926ecd451..3ab9bef2bfa20f49d28522efcc935d0485a15835 100644 (file)
@@ -271,7 +271,7 @@ public:
         * @param       grab The new grab state of the cursor.
         * @return      Indication of success.
         */
-       virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp, bool restore) { return GHOST_kSuccess; };
+       virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode) { return GHOST_kSuccess; };
 
 };
 
index 6271ecad408ebbac5d4aafebeda7d553b51ebef7..98169ad2aa496c4e20ef25b721f3ecf1042e1d4b 100644 (file)
@@ -126,6 +126,13 @@ public:
         */
        virtual inline void unionPoint(GHOST_TInt32 x, GHOST_TInt32 y);
 
+       /**
+        * Grows the rectangle to included a point.
+        * @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);
+
        /**
         * Returns whether the point is inside this rectangle.
         * Point on the boundary is considered inside.
@@ -222,6 +229,21 @@ 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)
+{
+       GHOST_TInt32 w= getWidth();
+       GHOST_TInt32 h= getHeight();
+
+       /* highly unlikely but avoid eternal loop */
+       if(w-ofs <= 0 || h-ofs <= 0)
+               return;
+
+       while(x-ofs < m_l)              x+= w;
+       while(y-ofs < m_t)              y+= h;
+       while(x+ofs > m_r)              x-= w;
+       while(y+ofs > m_b)              y-= h;
+}
+
 inline bool GHOST_Rect::isInside(GHOST_TInt32 x, GHOST_TInt32 y) const
 {
        return (x >= m_l) && (x <= m_r) && (y >= m_t) && (y <= m_b);
index 14e3c4bb5f7bb0fcda55842fa402b9aae783a8b0..e98e58740ada8a723cea9c6d561be4e42b540efa 100644 (file)
@@ -341,6 +341,12 @@ typedef enum {
        GHOST_kKeyF24
 } GHOST_TKey;
 
+typedef enum {
+       GHOST_kGrabDisable = 0, /* grab not set */
+       GHOST_kGrabNormal,      /* no cursor adjustments */
+       GHOST_kGrabWrap,                /* wrap the mouse location to prevent limiting screen bounds */
+       GHOST_kGrabHide,                /* hide the mouse while grabbing and restore the original location on release (numbuts) */
+} GHOST_TGrabCursorMode;
 
 typedef void* GHOST_TEventDataPtr;
 
index e225ad4fd90a719c4efb9d13469f1d159395f5f5..5563e0d1aa8a9100286519c0139db61256774699 100644 (file)
@@ -355,11 +355,11 @@ GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
 
 
 GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
-                                                                  int grab, int warp, int restore)
+                                                                               GHOST_TGrabCursorMode mode)
 {
        GHOST_IWindow* window = (GHOST_IWindow*) windowhandle;
        
-       return window->setCursorGrab(grab?true:false, warp?true:false, restore?true:false);
+       return window->setCursorGrab(mode);
 }
 
 
index 8c87abf16bc2e34d5897c7b6f24d0b3e25ec3468..abf0b612f9a7b65a993c76b0faf7fa609309ace6 100644 (file)
@@ -388,31 +388,36 @@ GHOST_SystemX11::processEvent(XEvent *xe)
                {
                        XMotionEvent &xme = xe->xmotion;
                        
-                       if(window->getCursorWarp()) {
-                               /* Calculate offscreen location and re-center the mouse */
-                               GHOST_TInt32 x_warp, y_warp,  x_new, y_new, x_accum, y_accum;
-
-                               window->getCursorWarpPos(x_warp, y_warp);
-                               getCursorPosition(x_new, y_new);
-
-                               if(x_warp != x_new || y_warp != y_new) {
-                                       window->getCursorWarpAccum(x_accum, y_accum);
-                                       x_accum += x_new - x_warp;
-                                       y_accum += y_new - y_warp;
-
-                                       window->setCursorWarpAccum(x_accum, y_accum);
-                                       setCursorPosition(x_warp, y_warp); /* reset */
-
-                                       g_event = new
-                                       GHOST_EventCursor(
-                                               getMilliSeconds(),
-                                               GHOST_kEventCursorMove,
-                                               window,
-                                               x_warp + x_accum,
-                                               y_warp + y_accum
-                                       );
+                       if(window->getCursorGrabMode() != GHOST_kGrabDisable && window->getCursorGrabMode() != GHOST_kGrabNormal)
+                       {
+                               GHOST_TInt32 x_new= xme.x_root;
+                               GHOST_TInt32 y_new= xme.y_root;
+                               GHOST_TInt32 x_accum, y_accum;
+                               GHOST_Rect bounds;
+
+                               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, 1); /* offset of one incase blender is at screen bounds */
 
+                               window->getCursorGrabAccum(x_accum, y_accum);
+
+                               if(x_new != xme.x_root || y_new != xme.y_root) {
+                                       setCursorPosition(x_new, y_new); /* wrap */
+                                       window->setCursorGrabAccum(x_accum + (xme.x_root - x_new), y_accum + (xme.y_root - y_new));
                                }
+
+                               g_event = new
+                               GHOST_EventCursor(
+                                       getMilliSeconds(),
+                                       GHOST_kEventCursorMove,
+                                       window,
+                                       xme.x_root + x_accum,
+                                       xme.y_root + y_accum
+                               );
+
                        }
                        else {
                                g_event = new
index 94feb83e003b6d4a54d5386ceb4387ad10e3f1c1..cda6bfa06eed8ab0563c89539c1da9ba1c5a3b3d 100644 (file)
@@ -48,15 +48,14 @@ GHOST_Window::GHOST_Window(
 :
        m_drawingContextType(type),
        m_cursorVisible(true),
-       m_cursorGrabbed(false),
-       m_cursorWarp(false),
+       m_cursorGrab(GHOST_kGrabDisable),
        m_cursorShape(GHOST_kStandardCursorDefault),
        m_stereoVisual(stereoVisual)
 {
        m_isUnsavedChanges = false;
        
-    m_cursorWarpAccumPos[0] = 0;
-    m_cursorWarpAccumPos[1] = 0;
+    m_cursorGrabAccumPos[0] = 0;
+    m_cursorGrabAccumPos[1] = 0;
 
     m_fullScreen = state == GHOST_kWindowStateFullScreen;
     if (m_fullScreen) {
@@ -98,13 +97,13 @@ GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible)
        }
 }
 
-GHOST_TSuccess GHOST_Window::setCursorGrab(bool grab, bool warp, bool restore)
+GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode)
 {
-       if(m_cursorGrabbed == grab)
+       if(m_cursorGrab == mode)
                return GHOST_kSuccess;
 
-       if (setWindowCursorGrab(grab, warp, restore)) {
-               m_cursorGrabbed = grab;
+       if (setWindowCursorGrab(mode)) {
+               m_cursorGrab = mode;
                return GHOST_kSuccess;
        }
        else {
index 786918716c51ce57cf69dcc74861cce248dd45d6..e66a3c2fd36c90e0cbf17ecac2cd1fd3fce87742 100644 (file)
@@ -158,10 +158,9 @@ public:
         * @return      The visibility state of the cursor.
         */
        inline virtual bool getCursorVisibility() const;
-       inline virtual bool getCursorWarp() const;
-       inline virtual bool getCursorWarpPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const;
-       inline virtual bool getCursorWarpAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const;
-       inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y);
+       inline virtual GHOST_TGrabCursorMode getCursorGrabMode() const;
+       inline virtual void getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const;
+       inline virtual void setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y);
 
        /**
         * Shows or hides the cursor.
@@ -175,7 +174,7 @@ public:
         * @param       grab The new grab state of the cursor.
         * @return      Indication of success.
         */
-       virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp, bool restore);
+       virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode);
 
        /**
         * Sets the window "modified" status, indicating unsaved changes
@@ -247,7 +246,7 @@ protected:
         * Sets the cursor grab on the window using
         * native window system calls.
         */
-       virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp, bool restore) { return GHOST_kSuccess; };
+       virtual GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) { return GHOST_kSuccess; };
        
        /**
         * Sets the cursor shape on the window using
@@ -274,16 +273,13 @@ protected:
        bool m_cursorVisible;
 
        /** The current grabbed state of the cursor */
-       bool m_cursorGrabbed;
-       
-       /** The current warped state of the cursor */
-       bool m_cursorWarp;
+       GHOST_TGrabCursorMode m_cursorGrab;
 
        /** Initial grab location. */
-       GHOST_TInt32 m_cursorWarpInitPos[2];
+       GHOST_TInt32 m_cursorGrabInitPos[2];
 
-       /** Accumulated offset from m_cursorWarpInitPos. */
-       GHOST_TInt32 m_cursorWarpAccumPos[2];
+       /** Accumulated offset from m_cursorGrabInitPos. */
+       GHOST_TInt32 m_cursorGrabAccumPos[2];
 
        /** The current shape of the cursor */
        GHOST_TStandardCursor m_cursorShape;
@@ -317,40 +313,21 @@ inline bool GHOST_Window::getCursorVisibility() const
        return m_cursorVisible;
 }
 
-inline bool GHOST_Window::getCursorWarp() const
-{
-       return m_cursorWarp;
-}
-
-inline bool GHOST_Window::getCursorWarpPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const
+inline GHOST_TGrabCursorMode GHOST_Window::getCursorGrabMode() const
 {
-       if(m_cursorWarp==false)
-               return GHOST_kFailure;
-
-       x= m_cursorWarpInitPos[0];
-       y= m_cursorWarpInitPos[1];
-       return GHOST_kSuccess;
+       return m_cursorGrab;
 }
 
-inline bool GHOST_Window::getCursorWarpAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const
+inline void GHOST_Window::getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const
 {
-       if(m_cursorWarp==false)
-               return GHOST_kFailure;
-
-       x= m_cursorWarpAccumPos[0];
-       y= m_cursorWarpAccumPos[1];
-       return GHOST_kSuccess;
+       x= m_cursorGrabAccumPos[0];
+       y= m_cursorGrabAccumPos[1];
 }
 
-inline bool GHOST_Window::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y)
+inline void GHOST_Window::setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y)
 {
-       if(m_cursorWarp==false)
-               return GHOST_kFailure;
-
-       m_cursorWarpAccumPos[0]= x;
-       m_cursorWarpAccumPos[1]= y;
-
-       return GHOST_kSuccess;
+       m_cursorGrabAccumPos[0]= x;
+       m_cursorGrabAccumPos[1]= y;
 }
 
 inline GHOST_TStandardCursor GHOST_Window::getCursorShape() const
index d6c154535a9f4e549c062bbd3d887c0dd42e6848..e5fff75c66ed7d3d236a22eadd4b91eea00ce9a4 100644 (file)
@@ -239,7 +239,7 @@ protected:
        /**
         * Sets the cursor warp accumulator. Overriden for workaround due to Cocoa next event after cursor set giving delta values non zero
         */
-       inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y);
+       inline virtual bool setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y);
        
        /**
         * Sets the cursor grab on the window using
index d197b5343526f08961d7b5fa3aa970937824daea..9914bad23c8039e96ed86cc03c55bdc39d9fc8df 100644 (file)
@@ -1400,47 +1400,27 @@ setWindowCursorVisibility(
        GHOST_TSuccess
 GHOST_WindowX11::
 setWindowCursorGrab(
-       bool grab, bool warp, bool restore
+       GHOST_TGrabCursorMode mode
 ){
-       if(grab) {
-               if(warp) {
-                       m_system->getCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]);
+       if(mode != GHOST_kGrabDisable) {
+               if(mode != GHOST_kGrabNormal) {
+                       m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
+                       setCursorGrabAccum(0, 0);
+
+                       if(mode == GHOST_kGrabHide)
+                               setWindowCursorVisibility(false);
 
-                       setCursorWarpAccum(0, 0);
-                       setWindowCursorVisibility(false);
-                       m_cursorWarp= true;
                }
                XGrabPointer(m_display, m_window, True, ButtonPressMask| ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
        }
        else {
-               if(m_cursorWarp) { /* are we exiting warp */
+               if (m_cursorGrab==GHOST_kGrabHide) {
+                       m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
                        setWindowCursorVisibility(true);
-                       /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
-                       if(restore) {
-                               GHOST_Rect bounds;
-                               GHOST_TInt32 x_new, y_new, x_rel, y_rel;
-
-                               getClientBounds(bounds);
-
-                               x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0];
-                               y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1];
-
-                               screenToClient(x_new, y_new, x_rel, y_rel);
-
-                               if(x_rel < 0)           x_new = (x_new-x_rel) + 2;
-                               if(y_rel < 0)           y_new = (y_new-y_rel) + 2;
-                               if(x_rel > bounds.getWidth())   x_new -= (x_rel-bounds.getWidth()) + 2;
-                               if(y_rel > bounds.getHeight())  y_new -= (y_rel-bounds.getHeight()) + 2;
-                               m_system->setCursorPosition(x_new, y_new);
-
-                       }
-                       else {
-                               m_system->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]);
-                       }
-
-                       setCursorWarpAccum(0, 0);
-                       m_cursorWarp= false;
                }
+
+               /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
+               setCursorGrabAccum(0, 0);
                XUngrabPointer(m_display, CurrentTime);
        }
 
index eb0689ab4105c9b99abe401cd56e800183c8339f..0dba1776553a30311671be88574ee1ff57c7f192 100644 (file)
@@ -256,9 +256,12 @@ protected:
         */
                GHOST_TSuccess 
        setWindowCursorGrab(
-               bool grab, bool warp, bool restore
+               GHOST_TGrabCursorMode mode
        );
 
+               GHOST_TGrabCursorMode
+       getWindowCursorGrab() const;
+
        /**
         * Sets the cursor shape on the window using
         * native window system calls.
index 479c72304b252838dff5bacc800cc11172d260b9..bce3806689963d71ddad6b76fadba8be71b2719d 100644 (file)
@@ -3723,12 +3723,12 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
        /* number editing */
        if(state == BUTTON_STATE_NUM_EDITING) {
                if(ui_is_a_warp_but(but))
-                       WM_cursor_grab(CTX_wm_window(C), TRUE);
+                       WM_cursor_grab(CTX_wm_window(C), TRUE, TRUE);
                ui_numedit_begin(but, data);
        } else if(data->state == BUTTON_STATE_NUM_EDITING) {
                ui_numedit_end(but, data);
                if(ui_is_a_warp_but(but))
-                       WM_cursor_ungrab(CTX_wm_window(C), FALSE);
+                       WM_cursor_ungrab(CTX_wm_window(C));
        }
        /* menu open */
        if(state == BUTTON_STATE_MENU_OPEN)
index 958b388f574997336163a14945b61ea014911c51..d90d812d0bb5fb5c8ec85b490e13b063f2c9a7b2 100644 (file)
@@ -76,8 +76,8 @@ void          WM_cursor_set           (struct wmWindow *win, int curs);
 void           WM_cursor_modal         (struct wmWindow *win, int curs);
 void           WM_cursor_restore       (struct wmWindow *win);
 void           WM_cursor_wait          (int val);
-void           WM_cursor_grab(struct wmWindow *win, int warp);
-void           WM_cursor_ungrab(wmWindow *win, int restore);
+void           WM_cursor_grab(struct wmWindow *win, int wrap, int hide);
+void           WM_cursor_ungrab(struct wmWindow *win);
 void           WM_timecursor           (struct wmWindow *win, int nr);
 
 void           *WM_paint_cursor_activate(struct wmWindowManager *wm, int (*poll)(struct bContext *C), void (*draw)(struct bContext *C, int, int, void *customdata), void *customdata);
index c1dfd9ee9fb00af21aafd6312ed79c277c8943d1..1d5b10f2583c0c08658d68fff2f6e706737b0aee 100644 (file)
@@ -163,21 +163,26 @@ void WM_cursor_wait(int val)
        }
 }
 
-void WM_cursor_grab(wmWindow *win, int warp)
+void WM_cursor_grab(wmWindow *win, int wrap, int hide)
 {
        /* Only grab cursor when not running debug.
         * It helps not to get a stuck WM when hitting a breakpoint  
         * */
+       GHOST_TGrabCursorMode mode = GHOST_kGrabNormal;
+
+       if(hide)                mode = GHOST_kGrabHide;
+       else if(wrap)   mode = GHOST_kGrabWrap;
+
        if ((G.f & G_DEBUG) == 0)
                if(win)
-                       GHOST_SetCursorGrab(win->ghostwin, 1, warp, -1);
+                       GHOST_SetCursorGrab(win->ghostwin, mode);
 }
 
-void WM_cursor_ungrab(wmWindow *win, int restore)
+void WM_cursor_ungrab(wmWindow *win)
 {
        if ((G.f & G_DEBUG) == 0)
                if(win)
-                       GHOST_SetCursorGrab(win->ghostwin, 0, -1, restore);
+                       GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable);
 }
 
 /* afer this you can call restore too */
index f1104feaf5b067c22d7f8a455bff4daa69397b12..9e5f982880e011f490fa2575e7f42ff07187d799 100644 (file)
@@ -464,7 +464,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
                        /* grab cursor during blocking modal ops (X11) */
                        if(ot->flag & OPTYPE_BLOCKING) {
                                int warp = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER));
-                               WM_cursor_grab(CTX_wm_window(C), warp);
+                               WM_cursor_grab(CTX_wm_window(C), warp, FALSE);
                        }
                }
                else
@@ -660,7 +660,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
                                CTX_wm_region_set(C, region);
                        }
 
-                       WM_cursor_ungrab(CTX_wm_window(C), TRUE);
+                       WM_cursor_ungrab(CTX_wm_window(C));
                        WM_operator_free(handler->op);
                }
                else if(handler->ui_remove) {
@@ -858,7 +858,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        
                        /* remove modal handler, operator itself should have been cancelled and freed */
                        if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
-                               WM_cursor_ungrab(CTX_wm_window(C), TRUE);
+                               WM_cursor_ungrab(CTX_wm_window(C));
 
                                BLI_remlink(handlers, handler);
                                wm_event_free_handler(handler);