Multitouch trackpad 2 fingers gestures implementation
authorDamien Plisson <damien.plisson@yahoo.fr>
Mon, 11 Jan 2010 11:14:36 +0000 (11:14 +0000)
committerDamien Plisson <damien.plisson@yahoo.fr>
Mon, 11 Jan 2010 11:14:36 +0000 (11:14 +0000)
- 2 fingers scroll (MOUSEPAN / GHOST_kTrackpadEventScroll event) pans/scrolls the view
- 2 fingers pinch (MOUSEZOOM / GHOST_kTrackpadEventMagnify event) zooms the view
And in 3D view:
- alt + 2 fingers scroll rotates the view
- 2 fingers rotation (MOUSEROTATE / GHOST_kTrackpadEventRotate) orbits the view.

The implementation uses a new GHOST event type: GHOST_kEventTrackpad, that is then dispatched as Blender MOUSEPAN, MOUSEZOOM
or MOUSEROTATE events.

This is currently fully implemented for OSX (GHOST Cocoa fires the new events), with auto-detection of the source peripheral, so that a regular mouse still sends MOUSEWHEEL events.

14 files changed:
intern/ghost/GHOST_Types.h
intern/ghost/intern/GHOST_EventTrackpad.h [new file with mode: 0644]
intern/ghost/intern/GHOST_SystemCocoa.mm
source/blender/editors/interface/view2d_ops.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_outliner/outliner.c
source/blender/editors/space_text/space_text.c
source/blender/editors/space_text/text_ops.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_ops.c
source/blender/makesrna/intern/rna_wm.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/wm_event_types.h

index 5c888e218d84287ffc0a08856ea59b3a2a049596..e26013c1ecd2bb78963b57120601f7e3321beb93 100644 (file)
@@ -151,6 +151,7 @@ typedef enum {
        GHOST_kEventButtonDown,         /// Mouse button event
        GHOST_kEventButtonUp,           /// Mouse button event
        GHOST_kEventWheel,                      /// Mouse wheel event
+       GHOST_kEventTrackpad,           /// Trackpad event
 
        GHOST_kEventNDOFMotion,         /// N degree of freedom device motion event
        GHOST_kEventNDOFButton,         /// N degree of freedom device button event
@@ -373,6 +374,28 @@ typedef struct {
        GHOST_TInt32 z; 
 } GHOST_TEventWheelData;
 
+typedef enum {
+       GHOST_kTrackpadEventUnknown =0,
+       GHOST_kTrackpadEventScroll,
+       GHOST_kTrackpadEventRotate,
+       GHOST_kTrackpadEventSwipe, /* Reserved, not used for now */
+       GHOST_kTrackpadEventMagnify
+} GHOST_TTrackpadEventSubTypes;
+       
+
+typedef struct {
+       /** The event subtype */
+       GHOST_TTrackpadEventSubTypes subtype;
+       /** The x-location of the trackpad event */
+       GHOST_TInt32 x;
+       /** The y-location of the trackpad event */
+       GHOST_TInt32 y;
+       /** The x-delta or value of the trackpad event */
+       GHOST_TInt32 deltaX;
+       /** The y-delta (currently only for scroll subtype) of the trackpad event */
+       GHOST_TInt32 deltaY;
+} GHOST_TEventTrackpadData;
+
 
 typedef enum {
        GHOST_kDragnDropTypeUnknown =0,
diff --git a/intern/ghost/intern/GHOST_EventTrackpad.h b/intern/ghost/intern/GHOST_EventTrackpad.h
new file mode 100644 (file)
index 0000000..c2332d8
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):  James Deery                11/2009
+ *                                     Damien Plisson  12/2009
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+/**
+ * @file       GHOST_EventTrackpad.h
+ * Declaration of GHOST_EventTrackpad class.
+ */
+
+#ifndef _GHOST_EVENT_TRACKPAD_H_
+#define _GHOST_EVENT_TRACKPAD_H_
+
+#include "GHOST_Event.h"
+
+/**
+ * Trackpad (scroll, magnify, rotate, ...) event.
+ */
+class GHOST_EventTrackpad : public GHOST_Event
+{
+public:
+       /**
+        * Constructor.
+        * @param msec          The time this event was generated.
+        * @param type          The type of this event.
+        * @param subtype       The subtype of the event.
+        * @param x                     The x-delta of the pan event.
+        * @param y                     The y-delta of the pan event.
+        */
+       GHOST_EventTrackpad(GHOST_TUns64 msec, GHOST_IWindow* window, GHOST_TTrackpadEventSubTypes subtype, GHOST_TInt32 x, GHOST_TInt32 y, GHOST_TInt32 deltaX, GHOST_TInt32 deltaY)
+               : GHOST_Event(msec, GHOST_kEventTrackpad, window)
+       {
+               m_trackpadEventData.subtype = subtype;
+               m_trackpadEventData.x = x;
+               m_trackpadEventData.y = y;
+               m_trackpadEventData.deltaX = deltaX;
+               m_trackpadEventData.deltaY = deltaY;
+               m_data = &m_trackpadEventData;
+       }
+
+protected:
+       /** The mouse pan data */
+       GHOST_TEventTrackpadData m_trackpadEventData;
+};
+
+
+#endif // _GHOST_EVENT_PAN_H_
+
index 1ba20315512d18230903903ab518eb9b9b1e6129..735efcda3958df6c74a0c41128d09e237305e670 100644 (file)
@@ -41,6 +41,7 @@
 #include "GHOST_EventCursor.h"
 #include "GHOST_EventWheel.h"
 #include "GHOST_EventNDOF.h"
+#include "GHOST_EventTrackpad.h"
 #include "GHOST_EventDragnDrop.h"
 
 #include "GHOST_TimerManager.h"
@@ -376,6 +377,24 @@ static GHOST_TKey convertKey(int rawCode, unichar recvChar)
 
 #pragma mark defines for 10.6 api not documented in 10.5
 #ifndef MAC_OS_X_VERSION_10_6
+enum {
+       /* The following event types are available on some hardware on 10.5.2 and later */
+       NSEventTypeGesture          = 29,
+       NSEventTypeMagnify          = 30,
+       NSEventTypeSwipe            = 31,
+       NSEventTypeRotate           = 18,
+       NSEventTypeBeginGesture     = 19,
+       NSEventTypeEndGesture       = 20
+};
+
+@interface NSEvent(GestureEvents)
+/* This message is valid for events of type NSEventTypeMagnify, on 10.5.2 or later */
+#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
+- (float)magnification;       // change in magnification.
+#else
+- (CGFloat)magnification;       // change in magnification.
+#endif
+@end 
 
 @interface NSEvent(SnowLeopardEvents)
 /* modifier keys currently down.  This returns the state of devices combined
@@ -596,7 +615,7 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
                }
                
                [NSApp finishLaunching];
-                               
+               
                [pool drain];
     }
     return success;
@@ -846,7 +865,9 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
                                case NSScrollWheel:
                                case NSOtherMouseDown:
                                case NSOtherMouseUp:
-                               case NSOtherMouseDragged:                               
+                               case NSOtherMouseDragged:
+                               case NSEventTypeMagnify:
+                               case NSEventTypeRotate:
                                        handleMouseEvent(event);
                                        break;
                                        
@@ -855,11 +876,9 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
                                        handleTabletEvent(event,[event type]);
                                        break;
                                        
-                                       /* Trackpad features, will need OS X 10.6 for implementation
+                                       /* Trackpad features, fired only from OS X 10.5.2
                                         case NSEventTypeGesture:
-                                        case NSEventTypeMagnify:
                                         case NSEventTypeSwipe:
-                                        case NSEventTypeRotate:
                                         case NSEventTypeBeginGesture:
                                         case NSEventTypeEndGesture:
                                         break; */
@@ -1316,16 +1335,53 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
                        
                case NSScrollWheel:
                        {
-                               GHOST_TInt32 delta;
-                               
-                               double deltaF = [event deltaY];
-                               if (deltaF == 0.0) break; //discard trackpad delta=0 events
-                               
-                               delta = deltaF > 0.0 ? 1 : -1;
-                               pushEvent(new GHOST_EventWheel([event timestamp]*1000, window, delta));
+                               /* Send Wheel event if sent from the mouse, trackpad event otherwise */
+                               if ([event subtype] == NSMouseEventSubtype) {
+                                       GHOST_TInt32 delta;
+                                       
+                                       double deltaF = [event deltaY];
+                                       if (deltaF == 0.0) break; //discard trackpad delta=0 events
+                                       
+                                       delta = deltaF > 0.0 ? 1 : -1;
+                                       pushEvent(new GHOST_EventWheel([event timestamp]*1000, window, delta));
+                               }
+                               else {
+                                       NSPoint mousePos = [event locationInWindow];
+                                       double dx = [event deltaX];
+                                       double dy = -[event deltaY];
+                                       
+                                       const double deltaMax = 50.0;
+                                       
+                                       if ((dx == 0) && (dy == 0)) break;
+                                       
+                                       /* Quadratic acceleration */
+                                       dx = dx*(fabs(dx)+0.5);
+                                       if (dx<0.0) dx-=0.5; else dx+=0.5;
+                                       if (dx< -deltaMax) dx= -deltaMax; else if (dx>deltaMax) dx=deltaMax;
+                                       
+                                       dy = dy*(fabs(dy)+0.5);
+                                       if (dy<0.0) dy-=0.5; else dy+=0.5;
+                                       if (dy< -deltaMax) dy= -deltaMax; else if (dy>deltaMax) dy=deltaMax;
+
+                                       pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventScroll, mousePos.x, mousePos.y, dx, dy));
+                               }
                        }
                        break;
                        
+               case NSEventTypeMagnify:
+                       {
+                               NSPoint mousePos = [event locationInWindow];
+                               pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventMagnify, mousePos.x, mousePos.y,
+                                                                                                 [event magnification]*250.0 + 0.1, 0));
+                       }
+                       break;
+
+               case NSEventTypeRotate:
+                       {
+                               NSPoint mousePos = [event locationInWindow];
+                               pushEvent(new GHOST_EventTrackpad([event timestamp]*1000, window, GHOST_kTrackpadEventRotate, mousePos.x, mousePos.y,
+                                                                                                 -[event rotation] * 5.0, 0));
+                       }
                default:
                        return GHOST_kFailure;
                        break;
index 57882b7dd0dbf21c551352eb87b25c4a914b78e2..bd325eb79eb3a1744c1c53e9dce9ea8459a6563f 100644 (file)
@@ -199,6 +199,16 @@ static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
        /* set initial settings */
        vpd->startx= vpd->lastx= event->x;
        vpd->starty= vpd->lasty= event->y;
+
+       if (event->type == MOUSEPAN) {
+               RNA_int_set(op->ptr, "deltax", event->prevx - event->x);
+               RNA_int_set(op->ptr, "deltay", event->prevy - event->y);
+               
+               view_pan_apply(C, op);
+               view_pan_exit(C, op);
+               return OPERATOR_FINISHED;
+       }
+       
        RNA_int_set(op->ptr, "deltax", 0);
        RNA_int_set(op->ptr, "deltay", 0);
        
@@ -789,6 +799,26 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event)
        vzd= op->customdata;
        v2d= vzd->v2d;
        
+       if (event->type == MOUSEZOOM) {
+               float dx, dy, fac;
+               
+               vzd->lastx= event->prevx;
+               vzd->lasty= event->prevy;
+               
+               /* As we have only 1D information (magnify value), feed both axes
+               with magnify information that is stored in x axis */
+               fac= 0.01f * (event->x - event->prevx);
+               dx= fac * (v2d->cur.xmax - v2d->cur.xmin) / 10.0f;
+               dy= fac * (v2d->cur.ymax - v2d->cur.ymin) / 10.0f;
+
+               RNA_float_set(op->ptr, "deltax", dx);
+               RNA_float_set(op->ptr, "deltay", dy);
+               
+               view_zoomdrag_apply(C, op);
+               view_zoomdrag_exit(C, op);
+               return OPERATOR_FINISHED;
+       }       
+       
        /* set initial settings */
        vzd->lastx= event->x;
        vzd->lasty= event->y;
@@ -1467,6 +1497,8 @@ void UI_view2d_keymap(wmKeyConfig *keyconf)
        WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
        
+       WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MOUSEPAN, 0, 0, 0);
+       
        WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_right", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_left", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0);
        
@@ -1489,6 +1521,7 @@ void UI_view2d_keymap(wmKeyConfig *keyconf)
        
        /* zoom - drag */
        WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0);
        
        /* borderzoom - drag */
        WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0);
@@ -1499,9 +1532,11 @@ void UI_view2d_keymap(wmKeyConfig *keyconf)
        /* Alternative keymap for buttons listview */
        keymap= WM_keymap_find(keyconf, "View2D Buttons List", 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MOUSEPAN, 0, 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "VIEW2D_OT_reset", HOMEKEY, KM_PRESS, 0, 0);
index 827b2ddeac269b1fa384cacb0db38bd873caafde..cef92153725d48e71cebac97758aef8e226a5f00 100644 (file)
@@ -214,8 +214,21 @@ static int view_pan_exec(bContext *C, wmOperator *op)
 
 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-       view_pan_init(C, op, event);
-       return OPERATOR_RUNNING_MODAL;
+       if (event->type == MOUSEPAN) {
+               SpaceImage *sima= CTX_wm_space_image(C);
+               float offset[2];
+               
+               offset[0]= (event->x - event->prevx)/sima->zoom;
+               offset[1]= (event->y - event->prevy)/sima->zoom;
+               RNA_float_set_array(op->ptr, "offset", offset);
+
+               view_pan_exec(C, op);
+               return OPERATOR_FINISHED;
+       }
+       else {
+               view_pan_init(C, op, event);
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
@@ -331,8 +344,22 @@ static int view_zoom_exec(bContext *C, wmOperator *op)
 
 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-       view_zoom_init(C, op, event);
-       return OPERATOR_RUNNING_MODAL;
+       if (event->type == MOUSEZOOM) {
+               SpaceImage *sima= CTX_wm_space_image(C);
+               ARegion *ar= CTX_wm_region(C);
+               float factor;
+               
+               factor= 1.0 + (event->x-event->prevx+event->y-event->prevy)/300.0f;
+               RNA_float_set(op->ptr, "factor", factor);
+               sima_zoom_set(sima, ar, sima->zoom*factor);
+               ED_area_tag_redraw(CTX_wm_area(C));
+               
+               return OPERATOR_FINISHED;
+       }
+       else {
+               view_zoom_init(C, op, event);
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
index 4622962bac51c501e4bd3e2412753d13a4e51e39..6c325d9722fb5f8b38ca77dd1fd461d060049b70 100644 (file)
@@ -219,12 +219,14 @@ void image_keymap(struct wmKeyConfig *keyconf)
        WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MOUSEPAN, 0, 0, 0);
 
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", PADMINUS, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEZOOM, 0, 0, 0);
 
        RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 8.0f);
        RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "ratio", 4.0f);
index 93b3208661481a06bd045ce468d82e101d8d1d7c..79a16a5054443ca5f8f07bbce4c13e1c14109d44 100644 (file)
@@ -5104,6 +5104,9 @@ static char *keymap_mouse_menu(void)
        str += sprintf(str, formatstr, "Wheel Down", WHEELDOWNMOUSE);
        str += sprintf(str, formatstr, "Wheel In", WHEELINMOUSE);
        str += sprintf(str, formatstr, "Wheel Out", WHEELOUTMOUSE);
+       str += sprintf(str, formatstr, "Mouse/Trackpad Pan", MOUSEPAN);
+       str += sprintf(str, formatstr, "Mouse/Trackpad Zoom", MOUSEZOOM);
+       str += sprintf(str, formatstr, "Mouse/Trackpad Rotate", MOUSEROTATE);
        
        return string;
 }
index 292249bb0e80b52ac456e137c0092284399df16a..c7601ef692e55e1450c5d6d9bae305b4845562ad 100644 (file)
@@ -313,6 +313,7 @@ static void text_keymap(struct wmKeyConfig *keyconf)
        WM_keymap_add_item(keymap, "TEXT_OT_overwrite_toggle", INSERTKEY, KM_PRESS, 0, 0);
 
        WM_keymap_add_item(keymap, "TEXT_OT_scroll", MIDDLEMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "TEXT_OT_scroll", MOUSEPAN, 0, 0, 0);
        WM_keymap_add_item(keymap, "TEXT_OT_scroll_bar", LEFTMOUSE, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "TEXT_OT_cursor_set", LEFTMOUSE, KM_PRESS, 0, 0);
        RNA_boolean_set(WM_keymap_add_item(keymap, "TEXT_OT_cursor_set", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "select", 1);
index 0504db51a72b4a3bf4ccfb2dbc2b965a2a607072..e5a1e772523a6296685e4e2d5db8036a384491f7 100644 (file)
@@ -1720,25 +1720,6 @@ static int scroll_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
-static int scroll_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
-       SpaceText *st= CTX_wm_space_text(C);
-       TextScroll *tsc;
-
-       if(RNA_property_is_set(op->ptr, "lines"))
-               return scroll_exec(C, op);
-       
-       tsc= MEM_callocN(sizeof(TextScroll), "TextScroll");
-       tsc->first= 1;
-       op->customdata= tsc;
-       
-       st->flags|= ST_SCROLL_SELECT;
-
-       WM_event_add_modal_handler(C, op);
-
-       return OPERATOR_RUNNING_MODAL;
-}
-
 static void scroll_apply(bContext *C, wmOperator *op, wmEvent *event)
 {
        SpaceText *st= CTX_wm_space_text(C);
@@ -1816,6 +1797,40 @@ static int scroll_cancel(bContext *C, wmOperator *op)
        return OPERATOR_CANCELLED;
 }
 
+static int scroll_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       SpaceText *st= CTX_wm_space_text(C);
+       TextScroll *tsc;
+       
+       if(RNA_property_is_set(op->ptr, "lines"))
+               return scroll_exec(C, op);
+       
+       tsc= MEM_callocN(sizeof(TextScroll), "TextScroll");
+       tsc->first= 1;
+       op->customdata= tsc;
+       
+       st->flags|= ST_SCROLL_SELECT;
+       
+       if (event->type == MOUSEPAN) {
+               text_update_character_width(st);
+               
+               tsc->hold[0] = event->prevx;
+               tsc->hold[1] = event->prevy;
+               /* Sensitivity of scroll set to 4pix per line/char */
+               event->mval[0] = event->prevx + (event->x - event->prevx)*st->cwidth/4;
+               event->mval[1] = event->prevy + (event->y - event->prevy)*st->lheight/4;
+               tsc->first = 0;
+               tsc->scrollbar = 0;
+               scroll_apply(C, op, event);
+               scroll_exit(C, op);
+               return OPERATOR_FINISHED;
+       }       
+       
+       WM_event_add_modal_handler(C, op);
+       
+       return OPERATOR_RUNNING_MODAL;
+}
+
 void TEXT_OT_scroll(wmOperatorType *ot)
 {
        /* identifiers */
index 1e23d27fe77dccf6ad921226c4a5813ec717104e..288918c3c1e9f0a39c2c2afe4597a6b5b7b4c8f2 100644 (file)
@@ -554,7 +554,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
                invert_m3_m3(m_inv,m);
 
                /* Determine the direction of the x vector (for rotating up and down) */
-               /* This can likely be compuated directly from the quaternion. */
+               /* This can likely be computed directly from the quaternion. */
                mul_m3_v3(m_inv,xvec);
 
                /* Perform the up/down rotation */
@@ -690,11 +690,30 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
                        vod->rv3d->persp= RV3D_PERSP;
                ED_region_tag_redraw(vod->ar);
        }
+       
+       if (event->type == MOUSEPAN) {
+               viewrotate_apply(vod, event->prevx, event->prevy);
+               request_depth_update(CTX_wm_region_view3d(C));
+               
+               viewops_data_free(C, op);
+               
+               return OPERATOR_FINISHED;
+       }
+       else if (event->type == MOUSEROTATE) {
+               /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
+               viewrotate_apply(vod, event->prevx, event->y);
+               request_depth_update(CTX_wm_region_view3d(C));
+               
+               viewops_data_free(C, op);
+               
+               return OPERATOR_FINISHED;
+       }
+       else {          
+               /* add temp handler */
+               WM_event_add_modal_handler(C, op);
 
-       /* add temp handler */
-       WM_event_add_modal_handler(C, op);
-
-       return OPERATOR_RUNNING_MODAL;
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
 static int ED_operator_view3d_rotate(bContext *C)
@@ -838,13 +857,23 @@ static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
        /* makes op->customdata */
        viewops_data_create(C, op, event);
 
-       /* add temp handler */
-       WM_event_add_modal_handler(C, op);
+       if (event->type == MOUSEPAN) {
+               ViewOpsData *vod= op->customdata;
+               viewmove_apply(vod, event->prevx, event->prevy);
+               request_depth_update(CTX_wm_region_view3d(C));
+               
+               viewops_data_free(C, op);               
+               
+               return OPERATOR_FINISHED;
+       }
+       else {
+               /* add temp handler */
+               WM_event_add_modal_handler(C, op);
 
-       return OPERATOR_RUNNING_MODAL;
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
-
 void VIEW3D_OT_move(wmOperatorType *ot)
 {
 
@@ -940,11 +969,11 @@ static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
 }
 
 
-static void viewzoom_apply(ViewOpsData *vod, int x, int y)
+static void viewzoom_apply(ViewOpsData *vod, int x, int y, short viewzoom)
 {
        float zfac=1.0;
 
-       if(U.viewzoom==USER_ZOOM_CONT) {
+       if(viewzoom==USER_ZOOM_CONT) {
                double time= PIL_check_seconds_timer();
                float time_step= (float)(time - vod->timer_lastdraw);
 
@@ -952,7 +981,7 @@ static void viewzoom_apply(ViewOpsData *vod, int x, int y)
                zfac = 1.0f + (((float)(vod->origx - x + vod->origy - y)/20.0) * time_step);
                vod->timer_lastdraw= time;
        }
-       else if(U.viewzoom==USER_ZOOM_SCALE) {
+       else if(viewzoom==USER_ZOOM_SCALE) {
                int ctr[2], len1, len2;
                // method which zooms based on how far you move the mouse
 
@@ -986,7 +1015,7 @@ static void viewzoom_apply(ViewOpsData *vod, int x, int y)
                view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
 
 
-       if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
+       if ((U.uiflag & USER_ORBIT_ZBUF) && (viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
                float upvec[3], mat[3][3];
 
                /* Secret apricot feature, translate the view when in continues mode */
@@ -1043,7 +1072,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
        }
 
        if(event_code==VIEW_APPLY) {
-               viewzoom_apply(vod, event->x, event->y);
+               viewzoom_apply(vod, event->x, event->y, U.viewzoom);
        }
        else if (event_code==VIEW_CONFIRM) {
                request_depth_update(CTX_wm_region_view3d(C));
@@ -1114,13 +1143,34 @@ static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
 
                vod= op->customdata;
 
-               vod->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
-               vod->timer_lastdraw= PIL_check_seconds_timer();
+               if (event->type == MOUSEZOOM) {
+                       if (U.uiflag & USER_ZOOM_INVERT) /* Bypass Zoom invert flag */
+                               SWAP(int, event->x, event->prevx);
 
-               /* add temp handler */
-               WM_event_add_modal_handler(C, op);
+                       if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
+                               vod->origx = vod->oldx = event->x;
+                               viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
+                       }
+                       else {
+                               
+                               /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
+                               vod->origy = vod->oldy = event->x;
+                               viewzoom_apply(vod, event->x, event->prevx, USER_ZOOM_DOLLY);
+                       }
+                       request_depth_update(CTX_wm_region_view3d(C));
+                       
+                       viewops_data_free(C, op);
+                       return OPERATOR_FINISHED;
+               }
+               else {
+                       vod->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+                       vod->timer_lastdraw= PIL_check_seconds_timer();
 
-               return OPERATOR_RUNNING_MODAL;
+                       /* add temp handler */
+                       WM_event_add_modal_handler(C, op);
+
+                       return OPERATOR_RUNNING_MODAL;
+               }
        }
        return OPERATOR_FINISHED;
 }
index 2bcd78b3d3d0209b251984a5a6b0205ce0137265..2e134da7e0253865c6db903870c91e939ff2ebab 100644 (file)
@@ -133,6 +133,11 @@ void view3d_keymap(wmKeyConfig *keyconf)
 
        WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
        
+       WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, KM_ALT, 0);
+       WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEROTATE, 0, 0, 0);
+       WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, 0, 0);
+       WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEZOOM, 0, 0, 0);
+       
        RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADPLUSKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
        RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADMINUS, KM_PRESS, 0, 0)->ptr, "delta", -1);
        RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", WHEELINMOUSE, KM_PRESS, 0, 0)->ptr, "delta", 1);
index 513f2f8f0ec81fc8e6d76b16441c04e5d5960603..a3a2bc35dc1a995aecc5e52b0812d04aecf08e99 100644 (file)
@@ -85,6 +85,9 @@ EnumPropertyItem event_mouse_type_items[]= {
        {SELECTMOUSE, "SELECTMOUSE", 0, "Select", ""},
        {0, "", 0, NULL, NULL},
        {MOUSEMOVE, "MOUSEMOVE", 0, "Move", ""},
+       {MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""},
+       {MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""},
+       {MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", ""},
        {0, "", 0, NULL, NULL},
        {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""},
        {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""},
@@ -112,6 +115,9 @@ EnumPropertyItem event_type_items[] = {
        {SELECTMOUSE, "SELECTMOUSE", 0, "Select Mouse", ""},
        {0, "", 0, NULL, NULL},
        {MOUSEMOVE, "MOUSEMOVE", 0, "Mouse Move", ""},
+       {MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""},
+       {MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""},
+       {MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", ""},
        {0, "", 0, NULL, NULL},
        {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""},
        {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""},
index aff843dc1cb02634a94629ef7bad9fd3c18c1eb0..f513488eca81de878f41c2ade639b050b9b51bc8 100644 (file)
@@ -1760,6 +1760,40 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata)
                        }
                        break;
                }
+               case GHOST_kEventTrackpad: {
+                       if (win->active) {
+                               GHOST_TEventTrackpadData * pd = customdata;
+                               switch (pd->subtype) {
+                                       case GHOST_kTrackpadEventMagnify:
+                                               event.type = MOUSEZOOM;
+                                               break;
+                                       case GHOST_kTrackpadEventRotate:
+                                               event.type = MOUSEROTATE;
+                                               break;
+                                       case GHOST_kTrackpadEventScroll:
+                                       default:
+                                               event.type= MOUSEPAN;
+                                               break;
+                               }
+#if defined(__APPLE__) && defined(GHOST_COCOA)
+                               //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event
+                               event.x= evt->x = pd->x;
+                               event.y = evt->y = pd->y;
+#else
+                               int cx, cy;
+                               GHOST_ScreenToClient(win->ghostwin, pd->x, pd->y, &cx, &cy);
+                               event.x= evt->x= cx;
+                               event.y= evt->y= (win->sizey-1) - cy;
+#endif
+                               // Use prevx/prevy so we can calculate the delta later
+                               event.prevx= event.x - pd->deltaX;
+                               event.prevy= event.y - pd->deltaY;
+                               
+                               update_tablet_data(win, &event);
+                               wm_event_add(win, &event);
+                       }                       
+                       break;
+               }
                /* mouse button */
                case GHOST_kEventButtonDown:
                case GHOST_kEventButtonUp: {
index 8179154fc98322b7f6cfe474107bce7ac6afccaa..a90eb70206938edefc8d01dd033b48a43b3b57ea 100644 (file)
                /* only use if you want user option switch possible */
 #define ACTIONMOUSE            0x005
 #define SELECTMOUSE            0x006
-/* Extra mouse buttons */
+               /* Extra mouse buttons */
 #define BUTTON4MOUSE   0x007  
 #define BUTTON5MOUSE   0x008
+               /* Extra trackpad gestures */
+#define MOUSEPAN               0x00e
+#define MOUSEZOOM              0x00f
+#define MOUSEROTATE            0x010
                /* defaults from ghost */
 #define WHEELUPMOUSE   0x00a   
 #define WHEELDOWNMOUSE 0x00b
@@ -67,7 +71,7 @@
 #define WHEELOUTMOUSE  0x00d
 
 
-/* SYSTEM : 0x01x */
+/* SYSTEM : 0x01xx */
 #define        INPUTCHANGE             0x0103  /* input connected or disconnected */
 #define WINDEACTIVATE  0x0104  /* window is deactivated, focus lost */
 
 #define ISKEYBOARD(event)      (event >=' ' && event <=320)
 
        /* test whether the event is a mouse button */
-#define ISMOUSE(event) (event >= LEFTMOUSE && event <= WHEELOUTMOUSE)
+#define ISMOUSE(event) (event >= LEFTMOUSE && event <= MOUSEROTATE)
 
        /* test whether the event is timer event */
 #define ISTIMER(event) (event >= TIMER && event <= TIMERAUTOSAVE)