diff --git a/include/wx/defs.h b/include/wx/defs.h
index bdf417e3ce..2c5cdeeeb6 100644
--- a/include/wx/defs.h
+++ b/include/wx/defs.h
@@ -3104,6 +3104,12 @@ DECLARE_WXCOCOA_OBJC_CLASS(NSView);
DECLARE_WXCOCOA_OBJC_CLASS(NSOpenGLContext);
DECLARE_WXCOCOA_OBJC_CLASS(NSOpenGLPixelFormat);
DECLARE_WXCOCOA_OBJC_CLASS( NSPrintInfo );
+DECLARE_WXCOCOA_OBJC_CLASS(NSGestureRecognizer);
+DECLARE_WXCOCOA_OBJC_CLASS(NSPanGestureRecognizer);
+DECLARE_WXCOCOA_OBJC_CLASS(NSMagnificationGestureRecognizer);
+DECLARE_WXCOCOA_OBJC_CLASS(NSRotationGestureRecognizer);
+DECLARE_WXCOCOA_OBJC_CLASS(NSPressGestureRecognizer);
+DECLARE_WXCOCOA_OBJC_CLASS(NSTouch);
#endif /* __WXMAC__ &__DARWIN__ */
#ifdef __WXMAC__
@@ -3267,6 +3273,7 @@ typedef struct _GdkDragContext GdkDragContext;
#if defined(__WXGTK3__)
typedef struct _GdkWindow GdkWindow;
+ typedef struct _GdkEventSequence GdkEventSequence;
#elif defined(__WXGTK20__)
typedef struct _GdkDrawable GdkWindow;
typedef struct _GdkDrawable GdkPixmap;
diff --git a/include/wx/event.h b/include/wx/event.h
index e6e58464cc..70852f9965 100644
--- a/include/wx/event.h
+++ b/include/wx/event.h
@@ -631,6 +631,13 @@ class WXDLLIMPEXP_FWD_CORE wxInitDialogEvent;
class WXDLLIMPEXP_FWD_CORE wxUpdateUIEvent;
class WXDLLIMPEXP_FWD_CORE wxClipboardTextEvent;
class WXDLLIMPEXP_FWD_CORE wxHelpEvent;
+class WXDLLIMPEXP_FWD_CORE wxGestureEvent;
+class WXDLLIMPEXP_FWD_CORE wxPanGestureEvent;
+class WXDLLIMPEXP_FWD_CORE wxZoomGestureEvent;
+class WXDLLIMPEXP_FWD_CORE wxRotateGestureEvent;
+class WXDLLIMPEXP_FWD_CORE wxTwoFingerTapEvent;
+class WXDLLIMPEXP_FWD_CORE wxLongPressEvent;
+class WXDLLIMPEXP_FWD_CORE wxPressAndTapEvent;
// Command events
@@ -736,6 +743,14 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWin
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEvent);
+ // Gesture events
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_GESTURE_PAN, wxPanGestureEvent);
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_GESTURE_ZOOM, wxZoomGestureEvent);
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_GESTURE_ROTATE, wxRotateGestureEvent);
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_TWO_FINGER_TAP, wxTwoFingerTapEvent);
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_LONG_PRESS, wxLongPressEvent);
+wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_PRESS_AND_TAP, wxPressAndTapEvent);
+
// System events
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SIZE, wxSizeEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_MOVE, wxMoveEvent);
@@ -1850,6 +1865,201 @@ private:
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxSetCursorEvent);
};
+ // Gesture Event
+
+const unsigned int wxTwoFingerTimeInterval = 200;
+
+class WXDLLIMPEXP_CORE wxGestureEvent : public wxEvent
+{
+public:
+ wxGestureEvent(wxWindowID winid = 0, wxEventType type = wxEVT_NULL)
+ : wxEvent(winid, type)
+ {
+ m_isStart = false;
+ m_isEnd = false;
+ }
+
+ wxGestureEvent(const wxGestureEvent& event) : wxEvent(event)
+ {
+ m_pos = event.m_pos;
+ m_isStart = event.m_isStart;
+ m_isEnd = event.m_isEnd;
+ }
+
+ const wxPoint& GetPosition() const { return m_pos; }
+ void SetPosition(const wxPoint& pos) { m_pos = pos; }
+ bool IsGestureStart() const { return m_isStart; }
+ void SetGestureStart(bool isStart = true) { m_isStart = isStart; }
+ bool IsGestureEnd() const { return m_isEnd; }
+ void SetGestureEnd(bool isEnd = true) { m_isEnd = isEnd; }
+
+ virtual wxEvent *Clone() const { return new wxGestureEvent(*this); }
+
+protected:
+ wxPoint m_pos;
+ bool m_isStart, m_isEnd;
+
+ wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxGestureEvent);
+
+};
+
+ // Pan Gesture Event
+
+ /*
+ wxEVT_GESTURE_PAN
+ */
+
+class WXDLLIMPEXP_CORE wxPanGestureEvent : public wxGestureEvent
+{
+public:
+ wxPanGestureEvent(wxWindowID winid = 0)
+ : wxGestureEvent(winid, wxEVT_GESTURE_PAN)
+ {
+ m_deltaX = 0;
+ m_deltaY = 0;
+ }
+
+ wxPanGestureEvent(const wxPanGestureEvent& event) : wxGestureEvent(event)
+ {
+ m_deltaX = event.m_deltaX;
+ m_deltaY = event.m_deltaY;
+ }
+
+ int GetDeltaX() const { return m_deltaX; }
+ void SetDeltaX(int DeltaX) { m_deltaX = DeltaX; }
+ int GetDeltaY() const { return m_deltaY; }
+ void SetDeltaY(int DeltaY) { m_deltaY = DeltaY; }
+
+ virtual wxEvent *Clone() const { return new wxPanGestureEvent(*this); }
+
+private:
+ int m_deltaX, m_deltaY;
+
+ wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxPanGestureEvent);
+};
+
+ // Zoom Gesture Event
+
+ /*
+ wxEVT_GESTURE_ZOOM
+ */
+
+class WXDLLIMPEXP_CORE wxZoomGestureEvent : public wxGestureEvent
+{
+public:
+ wxZoomGestureEvent(wxWindowID winid = 0)
+ : wxGestureEvent(winid, wxEVT_GESTURE_ZOOM)
+ { m_zoomFactor = 1.0; }
+
+ wxZoomGestureEvent(const wxZoomGestureEvent& event) : wxGestureEvent(event)
+ {
+ m_zoomFactor = event.m_zoomFactor;
+ }
+
+ double GetZoomFactor() const { return m_zoomFactor; }
+ void SetZoomFactor(double zoomFactor) { m_zoomFactor = zoomFactor; }
+
+ virtual wxEvent *Clone() const { return new wxZoomGestureEvent(*this); }
+
+private:
+ double m_zoomFactor;
+
+ wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxZoomGestureEvent);
+};
+
+ // Rotate Gesture Event
+
+ /*
+ wxEVT_GESTURE_ROTATE
+ */
+
+class WXDLLIMPEXP_CORE wxRotateGestureEvent : public wxGestureEvent
+{
+public:
+ wxRotateGestureEvent(wxWindowID winid = 0)
+ : wxGestureEvent(winid, wxEVT_GESTURE_ROTATE)
+ { m_rotationAngle = 0.0; }
+
+ wxRotateGestureEvent(const wxRotateGestureEvent& event) : wxGestureEvent(event)
+ {
+ m_rotationAngle = event.m_rotationAngle;
+ }
+
+ double GetRotationAngle() const { return m_rotationAngle; }
+ void SetRotationAngle(double rotationAngle) { m_rotationAngle = rotationAngle; }
+
+ virtual wxEvent *Clone() const { return new wxRotateGestureEvent(*this); }
+
+private:
+ double m_rotationAngle;
+
+ wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxRotateGestureEvent);
+};
+
+ // Two Finger Tap Gesture Event
+
+ /*
+ wxEVT_TWO_FINGER_TAP
+ */
+
+class WXDLLIMPEXP_CORE wxTwoFingerTapEvent : public wxGestureEvent
+{
+public:
+ wxTwoFingerTapEvent(wxWindowID winid = 0)
+ : wxGestureEvent(winid, wxEVT_TWO_FINGER_TAP)
+ { }
+
+ wxTwoFingerTapEvent(const wxTwoFingerTapEvent& event) : wxGestureEvent(event)
+ { }
+
+ virtual wxEvent *Clone() const { return new wxTwoFingerTapEvent(*this); }
+
+private:
+ wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxTwoFingerTapEvent);
+};
+
+ // Long Press Gesture Event
+
+ /*
+ wxEVT_LONG_PRESS
+ */
+
+class WXDLLIMPEXP_CORE wxLongPressEvent : public wxGestureEvent
+{
+public:
+ wxLongPressEvent(wxWindowID winid = 0)
+ : wxGestureEvent(winid, wxEVT_LONG_PRESS)
+ { }
+
+ wxLongPressEvent(const wxLongPressEvent& event) : wxGestureEvent(event)
+ { }
+
+ virtual wxEvent *Clone() const { return new wxLongPressEvent(*this); }
+private:
+ wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxLongPressEvent);
+};
+
+ // Press And Tap Gesture Event
+
+ /*
+ wxEVT_PRESS_AND_TAP
+ */
+
+class WXDLLIMPEXP_CORE wxPressAndTapEvent : public wxGestureEvent
+{
+public:
+ wxPressAndTapEvent(wxWindowID winid = 0)
+ : wxGestureEvent(winid, wxEVT_PRESS_AND_TAP)
+ { }
+
+ wxPressAndTapEvent(const wxPressAndTapEvent& event) : wxGestureEvent(event)
+ { }
+
+ virtual wxEvent *Clone() const { return new wxPressAndTapEvent(*this); }
+private:
+ wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxPressAndTapEvent);
+};
+
// Keyboard input event class
/*
@@ -3908,7 +4118,12 @@ typedef void (wxEvtHandler::*wxContextMenuEventFunction)(wxContextMenuEvent&);
typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureChangedEvent&);
typedef void (wxEvtHandler::*wxMouseCaptureLostEventFunction)(wxMouseCaptureLostEvent&);
typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&);
-
+typedef void (wxEvtHandler::*wxPanGestureEventFunction)(wxPanGestureEvent&);
+typedef void (wxEvtHandler::*wxZoomGestureEventFunction)(wxZoomGestureEvent&);
+typedef void (wxEvtHandler::*wxRotateGestureEventFunction)(wxRotateGestureEvent&);
+typedef void (wxEvtHandler::*wxTwoFingerTapEventFunction)(wxTwoFingerTapEvent&);
+typedef void (wxEvtHandler::*wxLongPressEventFunction)(wxLongPressEvent&);
+typedef void (wxEvtHandler::*wxPressAndTapEventFunction)(wxPressAndTapEvent&);
#define wxCommandEventHandler(func) \
wxEVENT_HANDLER_CAST(wxCommandEventFunction, func)
@@ -3983,6 +4198,18 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
wxEVENT_HANDLER_CAST(wxMouseCaptureLostEventFunction, func)
#define wxClipboardTextEventHandler(func) \
wxEVENT_HANDLER_CAST(wxClipboardTextEventFunction, func)
+#define wxPanGestureEventHandler(func) \
+ wxEVENT_HANDLER_CAST(wxPanGestureEventFunction, func)
+#define wxZoomGestureEventHandler(func) \
+ wxEVENT_HANDLER_CAST(wxZoomGestureEventFunction, func)
+#define wxRotateGestureEventHandler(func) \
+ wxEVENT_HANDLER_CAST(wxRotateGestureEventFunction, func)
+#define wxTwoFingerTapEventHandler(func) \
+ wxEVENT_HANDLER_CAST(wxTwoFingerTapEventFunction, func)
+#define wxLongPressEventHandler(func) \
+ wxEVENT_HANDLER_CAST(wxLongPressEventFunction, func)
+#define wxPressAndTapEvent(func) \
+ wxEVENT_HANDLER_CAST(wxPressAndTapEventFunction, func)
#endif // wxUSE_GUI
@@ -4317,6 +4544,14 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
EVT_COMMAND_SCROLL_THUMBRELEASE(winid, func) \
EVT_COMMAND_SCROLL_CHANGED(winid, func)
+// Gesture events
+#define EVT_GESTURE_PAN(winid, func) wx__DECLARE_EVT1(wxEVT_GESTURE_PAN, winid, wxPanGestureEventHandler(func))
+#define EVT_GESTURE_ZOOM(winid, func) wx__DECLARE_EVT1(wxEVT_GESTURE_ZOOM, winid, wxZoomGestureEventHandler(func))
+#define EVT_GESTURE_ROTATE(winid, func) wx__DECLARE_EVT1(wxEVT_GESTURE_ROTATE, winid, wxRotateGestureEventHandler(func))
+#define EVT_TWO_FINGER_TAP(winid, func) wx__DECLARE_EVT1(wxEVT_TWO_FINGER_TAP, winid, wxTwoFingerTapEventHandler(func))
+#define EVT_LONG_PRESS(winid, func) wx__DECLARE_EVT1(wxEVT_LONG_PRESS, winid, wxLongPressEventHandler(func))
+#define EVT_PRESS_AND_TAP(winid, func) wx__DECLARE_EVT1(wxEVT_PRESS_AND_TAP, winid, wxPressAndTapEvent(func))
+
// Convenience macros for commonly-used commands
#define EVT_CHECKBOX(winid, func) wx__DECLARE_EVT1(wxEVT_CHECKBOX, winid, wxCommandEventHandler(func))
#define EVT_CHOICE(winid, func) wx__DECLARE_EVT1(wxEVT_CHOICE, winid, wxCommandEventHandler(func))
diff --git a/include/wx/gtk/window.h b/include/wx/gtk/window.h
index e4041d9a3b..0639b99ae7 100644
--- a/include/wx/gtk/window.h
+++ b/include/wx/gtk/window.h
@@ -355,6 +355,16 @@ public:
wxRegion m_nativeUpdateRegion; // not transformed for RTL
+#if defined(__WXGTK3__)
+ unsigned int m_touchCount;
+ unsigned int m_lastTouchTime;
+ int m_gestureState;
+ int m_allowedGestures;
+ int m_activeGestures;
+ wxPoint m_lastTouchPoint;
+ GdkEventSequence* m_touchSequence;
+#endif
+
protected:
// implement the base class pure virtuals
virtual void DoGetTextExtent(const wxString& string,
diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h
index 286d9855ad..3ceeabe5f6 100644
--- a/include/wx/msw/window.h
+++ b/include/wx/msw/window.h
@@ -360,6 +360,12 @@ public:
bool HandleMouseWheel(wxMouseWheelAxis axis,
WXWPARAM wParam, WXLPARAM lParam);
+ bool HandlePanGesture(int x, int y, WXDWORD flags);
+ bool HandleZoomGesture(int x, int y, WXDWORD fingerDistance, WXDWORD flags);
+ bool HandleRotateGesture(int x, int y, WXDWORD angleArgument, WXDWORD flags);
+ bool HandleTwoFingerTap(int x, int y, WXDWORD flags);
+ bool HandlePressAndTap(int x, int y, WXDWORD flags);
+
bool HandleChar(WXWPARAM wParam, WXLPARAM lParam);
bool HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam);
bool HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam);
diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h
index 7900204a31..9fd9101a84 100644
--- a/include/wx/osx/cocoa/private.h
+++ b/include/wx/osx/cocoa/private.h
@@ -143,6 +143,15 @@ public :
void SetupCoordinates(wxCoord &x, wxCoord &y, NSEvent *nsEvent);
virtual bool SetupCursor(NSEvent* event);
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+ virtual void PanGestureEvent(NSPanGestureRecognizer *panGestureRecognizer);
+ virtual void ZoomGestureEvent(NSMagnificationGestureRecognizer *magnificationGestureRecognizer);
+ virtual void RotateGestureEvent(NSRotationGestureRecognizer *rotationGestureRecognizer);
+ virtual void LongPressEvent(NSPressGestureRecognizer *pressGestureRecognizer);
+ virtual void TouchesBegan(NSEvent *event);
+ virtual void TouchesMoved(NSEvent *event);
+ virtual void TouchesEnded(NSEvent *event);
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
#if !wxOSX_USE_NATIVE_FLIPPED
void SetFlipped(bool flipped);
@@ -190,6 +199,21 @@ protected:
// events, don't resend them
bool m_hasEditor;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+ NSPanGestureRecognizer *m_panGestureRecognizer;
+ NSMagnificationGestureRecognizer *m_magnificationGestureRecognizer;
+ NSRotationGestureRecognizer *m_rotationGestureRecognizer;
+ NSPressGestureRecognizer *m_pressGestureRecognizer;
+
+ int m_allowedGestures;
+ int m_activeGestures;
+ unsigned int m_touchCount;
+ unsigned int m_lastTouchTime;
+
+ // Used to keep track of the touch corresponding to "press" in Press and Tap gesture
+ NSTouch* m_initialTouch;
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+
wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxWidgetCocoaImpl);
};
diff --git a/interface/wx/event.h b/interface/wx/event.h
index 3d92c2d0db..53030db240 100644
--- a/interface/wx/event.h
+++ b/interface/wx/event.h
@@ -3644,6 +3644,257 @@ public:
void SetPosition(int pos);
};
+
+
+/** @class wxGestureEvent
+ This is the base class for all supported gesture events.
+
+ @library{wxcore}
+ @category{events}
+
+ @see wxPanGestureEvent, wxZoomGestureEvent, wxRotateGestureEvent
+
+ @since 3.1.1
+*/
+class wxGestureEvent : public wxEvent
+{
+public:
+ /**
+ Constructor.
+ */
+ wxGestureEvent(wxWindowID winid = 0, wxEventType type = wxEVT_NULL);
+
+ /**
+ Returns the position where the event took effect, in client coordinates: position of Pan event,
+ center of zoom for Zoom event, center of rotation for Rotate event, center of box formed by 2 fingers
+ for Two Finger Tap event and position of the pressed finger for Press and Tap Event.
+ */
+ const wxPoint& GetPosition() const;
+
+ /**
+ Returns true if the event was the first in a gesture sequence.
+ */
+ bool IsGestureStart() const;
+
+ /**
+ Returns true if the event was the last in a gesture sequence.
+ */
+ bool IsGestureEnd() const;
+
+ /**
+ Sets the position where the event took effect, in client coordinates: position of Pan event,
+ center of zoom for Zoom event, center of rotation for Rotate event.
+ */
+ void SetPosition(const wxPoint& pos);
+
+ /**
+ Sets the event to be the first in a gesture sequence.
+ */
+ void SetGestureStart(bool isStart = true);
+
+ /**
+ Sets the event to be the last in a gesture sequence.
+ */
+ void SetGestureEnd(bool isEnd = true);
+};
+
+
+/** @class wxPanGestureEvent
+
+ This event is generated when the user moves a finger on the surface.
+
+ wxGTK also generates this event during mouse dragging (mouse motion while a left mouse button is depressed).
+
+ Note that OSX requires the primary mouse button to be pressed while performing the finger movement.
+
+ @beginEventTable{wxPanGestureEvent}
+ @event{EVT_GESTURE_PAN(id, func)}
+ Process a @c wxEVT_GESTURE_PAN.
+ @endEventTable
+
+ @library{wxcore}
+ @category{events}
+
+ @since 3.1.1
+*/
+class wxPanGestureEvent : class wxGestureEvent
+{
+public:
+ /**
+ Constructor.
+ */
+ wxPanGestureEvent(wxWindowID winid = 0);
+
+ /**
+ Returns the horizontal component of the distance covered since the previous Pan event.
+ */
+ int GetDeltaX() const;
+
+ /**
+ Returns the vertical component of the distance covered since the previous Pan event.
+ */
+ int GetDeltaY() const;
+
+ /**
+ Sets the horizontal component of the distance covered since the previous Pan event.
+ */
+ int SetDeltaX(int DeltaX);
+
+ /**
+ Sets the vertical component of the distance covered since the previous Pan event.
+ */
+ int SetDeltaY(int DeltaY);
+};
+
+
+/** @class wxZoomGestureEvent
+
+ This event is generated when two fingers pinch the surface to zoom in or out.
+
+ @beginEventTable{wxZoomGestureEvent}
+ @event{EVT_GESTURE_ZOOM(id, func)}
+ Process a @c wxEVT_GESTURE_ZOOM.
+ @endEventTable
+
+ @library{wxcore}
+ @category{events}
+
+ @since 3.1.1
+*/
+class wxZoomGestureEvent : public wxGestureEvent
+{
+public:
+ /**
+ Constructor.
+ */
+ wxZoomGestureEvent(wxWindowID windid = 0);
+
+ /**
+ Returns the zoom Factor since the gesture started. Hence, starting of the gesture
+ is considered as 1:1. A value greater than 1.0 means we should enlarge
+ (or zoom in), a value less than 1.0 means we should shrink (or zoom out).
+ */
+ double GetZoomFactor() const;
+
+ /**
+ Sets the zoom Factor.
+ */
+ double SetZoomFactor() const;
+};
+
+
+/** @class wxRotateGestureEvent
+
+ This event is generated when two fingers move in opposite directions on the surface.
+
+ @beginEventTable{wxRotateGestureEvent}
+ @event{EVT_GESTURE_ROTATE(id, func)}
+ Process a @c wxEVT_GESTURE_ROTATE.
+ @endEventTable
+
+ @library{wxcore}
+ @category{events}
+
+ @since 3.1.1
+*/
+class wxRotateGestureEvent : public wxGestureEvent
+{
+public:
+ /**
+ Constructor.
+ */
+ wxRotateGestureEvent(wxWindowID windid = 0);
+
+ /**
+ Returns the total angle of rotation in radians in clockwise direction since the
+ gesture was first started i.e. when IsGestureStart() returned true. This value is always
+ greater than or equal to zero.
+ */
+ double GetRotationAngle() const;
+
+ /**
+ Sets the total angle of rotation in radians in clockwise direction since the
+ gesture was first started i.e. when IsGestureStart() returned true. This value is always
+ greater than or equal to zero.
+ */
+ void SetRotationAngle(double rotationAngle);
+};
+
+/** @class wxTwoFingerTapEvent
+
+ This event is generated when two fingers touch the surface at the same time.
+
+ @beginEventTable{wxTwoFingerTapEvent}
+ @event{EVT_TWO_FINGER_TAP(id, func)}
+ Process a @c wxEVT_TWO_FINGER_TAP.
+ @endEventTable
+
+ @library{wxcore}
+ @category{events}
+
+ @since 3.1.1
+*/
+class wxTwoFingerTapEvent : public wxGestureEvent
+{
+public:
+ /**
+ Constructor.
+ */
+ wxTwoFingerTapEvent(wxWindowID windid = 0);
+};
+
+/** @class wxLongPressEvent
+
+ This event is generated when one finger touches the surface and remains stationary.
+
+ Note that currently it is only generated under wxGTK and wxOSX.
+
+ wxGTK also generates this event when left mouse button is being pressed for some minimum duration of time.
+
+ @beginEventTable{wxLongPressEvent}
+ @event{EVT_LONG_PRESS(id, func)}
+ Process a @c wxEVT_LONG_PRESS.
+ @endEventTable
+
+ @library{wxcore}
+ @category{events}
+
+ @since 3.1.1
+*/
+class wxLongPressEvent : public wxGestureEvent
+{
+public:
+ /**
+ Constructor.
+ */
+ wxLongPressEvent(wxWindowID windid = 0);
+};
+
+/** @class wxPressAndTapEvent
+
+ This event is generated when the user press the surface with one finger and taps with another.
+
+ Note that once started the event will also be generated when the finger that was pressed moves on surface.
+
+ @beginEventTable{wxPressAndTapEvent}
+ @event{EVT_PRESS_AND_TAP(id, func)}
+ Process a @c wxEVT_PRESS_AND_TAP.
+ @endEventTable
+
+ @library{wxcore}
+ @category{events}
+
+ @since 3.1.1
+*/
+class wxPressAndTapEvent : public wxGestureEvent
+{
+public:
+ /**
+ Constructor.
+ */
+ wxPressAndTapEvent(wxWindowID windid = 0);
+};
+
#endif // wxUSE_GUI
#if wxUSE_BASE
diff --git a/samples/event/Makefile.in b/samples/event/Makefile.in
index a790ba23cd..ea6a06a19e 100644
--- a/samples/event/Makefile.in
+++ b/samples/event/Makefile.in
@@ -49,7 +49,8 @@ EVENT_CXXFLAGS = -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) \
$(SAMPLES_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \
$(__event___win32rc) \
- event_event.o
+ event_event.o \
+ event_gestures.o
### Conditionally set variables: ###
@@ -177,6 +178,8 @@ event_sample_rc.o: $(srcdir)/../../samples/sample.rc
event_event.o: $(srcdir)/event.cpp
$(CXXC) -c -o $@ $(EVENT_CXXFLAGS) $(srcdir)/event.cpp
+event_gestures.o: $(srcdir)/gestures.cpp
+ $(CXXC) -c -o $@ $(EVENT_CXXFLAGS) $(srcdir)/gestures.cpp
# Include dependency info, if present:
@IF_GNU_MAKE@-include ./.deps/*.d
diff --git a/samples/event/event.bkl b/samples/event/event.bkl
index e5b558fac3..6b830fbc66 100644
--- a/samples/event/event.bkl
+++ b/samples/event/event.bkl
@@ -4,7 +4,8 @@
- event.cpp
+ event.cpp gestures.cpp
+ gestures.h
core
base
diff --git a/samples/event/event.cpp b/samples/event/event.cpp
index ef19b8bb63..b397f828aa 100644
--- a/samples/event/event.cpp
+++ b/samples/event/event.cpp
@@ -35,6 +35,7 @@
#include
#include
+#include "gestures.h"
// ----------------------------------------------------------------------------
// event constants
@@ -144,6 +145,9 @@ public:
void OnClickDynamicHandlerButton(wxCommandEvent& event);
void OnClickStaticHandlerFrame(wxCommandEvent& event);
+ // Gesture
+ void OnGesture(wxCommandEvent& event);
+
private:
// symbolic names for the status bar fields
enum
@@ -178,6 +182,8 @@ private:
// the button used to highlight the event handlers execution order
MyEvtTestButton *m_testBtn;
+ MyGestureFrame *m_gestureFrame;
+
// any class wishing to process wxWidgets events must use this macro
wxDECLARE_EVENT_TABLE();
@@ -220,7 +226,8 @@ enum
Event_Push,
Event_Pop,
Event_Custom,
- Event_Test
+ Event_Test,
+ Event_Gesture
};
// ----------------------------------------------------------------------------
@@ -252,6 +259,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Event_Test, MyFrame::OnTest)
EVT_MENU(Event_Push, MyFrame::OnPushEventHandler)
EVT_MENU(Event_Pop, MyFrame::OnPopEventHandler)
+ EVT_MENU(Event_Gesture, MyFrame::OnGesture)
EVT_UPDATE_UI(Event_Pop, MyFrame::OnUpdateUIPop)
@@ -290,6 +298,8 @@ bool MyApp::OnInit()
if ( !wxApp::OnInit() )
return false;
+ wxImage::AddHandler(new wxJPEGHandler);
+
// create the main application window
MyFrame *frame = new MyFrame(wxT("Event wxWidgets Sample"),
wxPoint(50, 50), wxSize(600, 340));
@@ -381,6 +391,8 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
menuEvent->AppendSeparator();
menuEvent->Append(Event_Custom, wxT("Fire c&ustom event\tCtrl-U"),
wxT("Generate a custom event"));
+ menuEvent->Append(Event_Gesture, wxT("&Gesture events\tCtrl-G"),
+ wxT("Gesture event"));
// now append the freshly created menu to the menu bar...
wxMenuBar *menuBar = new wxMenuBar();
@@ -577,6 +589,12 @@ void MyFrame::OnPopEventHandler(wxCommandEvent& WXUNUSED(event))
#endif // wxUSE_STATUSBAR
}
+void MyFrame::OnGesture(wxCommandEvent& WXUNUSED(event))
+{
+ m_gestureFrame = new MyGestureFrame();
+ m_gestureFrame->Show(true);
+}
+
void MyFrame::OnTest(wxCommandEvent& WXUNUSED(event))
{
wxLogMessage(wxT("This is the test event handler in the main frame"));
@@ -602,4 +620,3 @@ void MyFrame::OnProcessCustom(wxCommandEvent& WXUNUSED(event))
{
wxLogMessage(wxT("Got a custom event!"));
}
-
diff --git a/samples/event/event_vc7.vcproj b/samples/event/event_vc7.vcproj
index cbf52c337f..0036a2c140 100644
--- a/samples/event/event_vc7.vcproj
+++ b/samples/event/event_vc7.vcproj
@@ -286,6 +286,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Add(myPanel, wxSizerFlags(1).Expand());
+ sizer->Add(m_logText, wxSizerFlags().Expand());
+ SetSizer(sizer);
+
+ // Log to the text control
+ delete wxLog::SetActiveTarget(new wxLogTextCtrl(m_logText));
+
+ // Bind all gestures to the same event handler, which must run before
+ // the other handlers, to clear the log window
+ myPanel->Bind(wxEVT_GESTURE_PAN, &MyGestureFrame::OnGesture, this);
+ myPanel->Bind(wxEVT_GESTURE_ZOOM, &MyGestureFrame::OnGesture, this);
+ myPanel->Bind(wxEVT_GESTURE_ROTATE, &MyGestureFrame::OnGesture, this);
+ myPanel->Bind(wxEVT_TWO_FINGER_TAP, &MyGestureFrame::OnGesture, this);
+ myPanel->Bind(wxEVT_LONG_PRESS, &MyGestureFrame::OnGesture, this);
+ myPanel->Bind(wxEVT_PRESS_AND_TAP, &MyGestureFrame::OnGesture, this);
+
+ Bind(wxEVT_CLOSE_WINDOW, &MyGestureFrame::OnQuit, this);
+}
+
+MyGesturePanel::MyGesturePanel(MyGestureFrame *parent) : wxPanel(parent, wxID_ANY)
+{
+ // Load an image
+ if ( !m_bitmap.LoadFile("../image/horse.jpg", wxBITMAP_TYPE_JPEG) )
+ {
+ wxLogError("Can't load the image");
+ }
+
+ else
+ {
+ Bind(wxEVT_PAINT, &MyGesturePanel::OnPaint, this);
+ }
+
+ // Event handlers
+ Bind(wxEVT_GESTURE_PAN, &MyGesturePanel::OnPan, this);
+ Bind(wxEVT_GESTURE_ZOOM, &MyGesturePanel::OnZoom, this);
+ Bind(wxEVT_GESTURE_ROTATE, &MyGesturePanel::OnRotate, this);
+ Bind(wxEVT_TWO_FINGER_TAP, &MyGesturePanel::OnTwoFingerTap, this);
+ Bind(wxEVT_LONG_PRESS, &MyGesturePanel::OnLongPress, this);
+ Bind(wxEVT_PRESS_AND_TAP, &MyGesturePanel::OnPressAndTap, this);
+
+ m_lastZoomFactor = 1.0;
+}
+
+void MyGestureFrame::OnQuit(wxCloseEvent& WXUNUSED(event))
+{
+ Destroy();
+}
+
+void MyGestureFrame::OnGesture(wxGestureEvent& event)
+{
+ if ( event.IsGestureStart() )
+ m_logText->Clear();
+
+ event.Skip();
+}
+
+void MyGesturePanel::OnPaint(wxPaintEvent& WXUNUSED(event))
+{
+ wxPaintDC paintDC(this);
+
+ wxGCDC dc(paintDC);
+
+ dc.Clear();
+
+ dc.SetTransformMatrix(m_affineMatrix);
+ dc.DrawBitmap(m_bitmap, wxRound(m_translateDistance.m_x), wxRound(m_translateDistance.m_y));
+}
+
+void MyGesturePanel::OnPan(wxPanGestureEvent& event)
+{
+ if ( event.IsGestureStart() )
+ {
+ wxLogMessage("Pan gesture started\n");
+ }
+
+ wxLogMessage("Pan gesture performed with deltaX = %d and deltaY = %d, with current position (%d,%d)\n",
+ event.GetDeltaX(), event.GetDeltaY(), event.GetPosition().x, event.GetPosition().y);
+
+ // Transform the distance using the tranpose of the matrix,
+ // in order to translate the image to match the screen coordinates
+ wxMatrix2D m;
+ m_affineMatrix.Get(&m, NULL);
+
+ wxPoint2DDouble delta(m.m_11 * event.GetDeltaX() + m.m_12 * event.GetDeltaY(),
+ m.m_21 * event.GetDeltaX() + m.m_22 * event.GetDeltaY());
+
+ // Add it to the total translation
+ m_translateDistance += delta;
+
+ if ( event.IsGestureEnd() )
+ {
+ wxLogMessage("Pan gesture Ended\n");
+ }
+
+ Refresh();
+}
+
+void MyGesturePanel::OnZoom(wxZoomGestureEvent& event)
+{
+ if ( event.IsGestureStart() )
+ {
+ wxLogMessage("Zoom gesture started\n");
+
+ m_lastZoomFactor = 1.0;
+ }
+
+ wxLogMessage("Zoom gesture performed with zoom center at (%d, %d) and zoom Factor = %f\n",
+ event.GetPosition().x, event.GetPosition().y, event.GetZoomFactor());
+
+ const wxPoint& zoomCenter = event.GetPosition();
+
+ // Translate to zoom center
+ m_affineMatrix.Translate(zoomCenter.x, zoomCenter.y);
+ // Scale
+ m_affineMatrix.Scale(event.GetZoomFactor() / m_lastZoomFactor, event.GetZoomFactor() / m_lastZoomFactor);
+ // Translate back
+ m_affineMatrix.Translate(-zoomCenter.x, -zoomCenter.y);
+
+ if ( event.IsGestureEnd() )
+ {
+ wxLogMessage("Zoom gesture Ended\n");
+ }
+
+ m_lastZoomFactor = event.GetZoomFactor();
+
+ Refresh();
+}
+
+void MyGesturePanel::OnRotate(wxRotateGestureEvent& event)
+{
+ if ( event.IsGestureStart() )
+ {
+ wxLogMessage("Rotate gesture started\n");
+
+ m_lastRotationAngle = 0.0;
+ }
+
+ wxLogMessage("Rotate gesture performed with rotation center at (%d, %d) and cumulative rotation angle = %f\n",
+ event.GetPosition().x, event.GetPosition().y, event.GetRotationAngle());
+
+ const wxPoint& rotationCenter = event.GetPosition();
+
+ // Translate to rotation center
+ m_affineMatrix.Translate(rotationCenter.x, rotationCenter.y);
+ // Rotate
+ m_affineMatrix.Rotate(event.GetRotationAngle() - m_lastRotationAngle);
+ // Translate back
+ m_affineMatrix.Translate(-rotationCenter.x, -rotationCenter.y);
+
+ if ( event.IsGestureEnd() )
+ {
+ wxLogMessage("Rotate gesture Ended\n");
+ }
+
+ m_lastRotationAngle = event.GetRotationAngle();
+
+ Refresh();
+}
+
+void MyGesturePanel::OnTwoFingerTap(wxTwoFingerTapEvent& event)
+{
+ if ( event.IsGestureStart() )
+ {
+ wxLogMessage("Two Finger Tap gesture gesture started\n");
+ }
+
+ wxLogMessage("Two Finger Tap gesture performed at (%d, %d)\n", event.GetPosition().x, event.GetPosition().y);
+
+ if ( event.IsGestureEnd() )
+ {
+ wxLogMessage("Two Finger Tap gesture Ended\n");
+ }
+}
+
+void MyGesturePanel::OnLongPress(wxLongPressEvent& event)
+{
+ if ( event.IsGestureStart() )
+ {
+ wxLogMessage("Long Press gesture started\n");
+ }
+
+ wxLogMessage("Long Press gesture performed at (%d,%d)\n", event.GetPosition().x, event.GetPosition().y);
+
+ if ( event.IsGestureEnd() )
+ {
+ wxLogMessage("Long Press gesture Ended\n");
+ }
+}
+
+void MyGesturePanel::OnPressAndTap(wxPressAndTapEvent& event)
+{
+ if ( event.IsGestureStart() )
+ {
+ wxLogMessage("Press and Tap gesture started\n");
+ }
+
+ wxLogMessage("Press and Tap gesture performed at (%d,%d)\n", event.GetPosition().x, event.GetPosition().y);
+
+ if ( event.IsGestureEnd() )
+ {
+ wxLogMessage("Press and Tap gesture Ended\n");
+ }
+}
diff --git a/samples/event/gestures.h b/samples/event/gestures.h
new file mode 100644
index 0000000000..c2add7f344
--- /dev/null
+++ b/samples/event/gestures.h
@@ -0,0 +1,39 @@
+#ifndef _WX_GESTURES_H_
+#define _WX_GESTURES_H_
+
+#include "wx/wx.h"
+
+class MyGestureFrame : public wxFrame
+{
+public:
+ MyGestureFrame();
+
+ void OnGesture(wxGestureEvent& event);
+ void OnQuit(wxCloseEvent& event);
+
+private:
+ wxTextCtrl *m_logText;
+};
+
+class MyGesturePanel : public wxPanel
+{
+public:
+ MyGesturePanel(MyGestureFrame* parent);
+
+ void OnPaint(wxPaintEvent& event);
+ void OnPan(wxPanGestureEvent& event);
+ void OnZoom(wxZoomGestureEvent& event);
+ void OnRotate(wxRotateGestureEvent& event);
+ void OnTwoFingerTap(wxTwoFingerTapEvent& event);
+ void OnLongPress(wxLongPressEvent& event);
+ void OnPressAndTap(wxPressAndTapEvent& event);
+
+private:
+ wxBitmap m_bitmap;
+ wxPoint2DDouble m_translateDistance;
+ wxAffineMatrix2D m_affineMatrix;
+ double m_lastZoomFactor;
+ double m_lastRotationAngle;
+};
+
+#endif // _WX_GESTURES_H_
diff --git a/samples/event/makefile.bcc b/samples/event/makefile.bcc
index c079d2d558..62364b9296 100644
--- a/samples/event/makefile.bcc
+++ b/samples/event/makefile.bcc
@@ -36,7 +36,8 @@ EVENT_CXXFLAGS = $(__RUNTIME_LIBS_7) -I$(BCCDIR)\include $(__DEBUGINFO) \
-I$(SETUPHDIR) -I.\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES_p) -I. \
$(__DLLFLAG_p) -I.\..\..\samples -DNOPCH $(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \
- $(OBJS)\event_event.obj
+ $(OBJS)\event_event.obj \
+ $(OBJS)\event_gestures.obj
### Conditionally set variables: ###
@@ -237,3 +238,5 @@ $(OBJS)\event_sample.res: .\..\..\samples\sample.rc
$(OBJS)\event_event.obj: .\event.cpp
$(CXX) -q -c -P -o$@ $(EVENT_CXXFLAGS) .\event.cpp
+$(OBJS)\event_gestures.obj: .\gestures.cpp
+ $(CXX) -q -c -P -o$@ $(EVENT_CXXFLAGS) .\gestures.cpp
diff --git a/samples/event/makefile.gcc b/samples/event/makefile.gcc
index 2e3508cef9..105c791901 100644
--- a/samples/event/makefile.gcc
+++ b/samples/event/makefile.gcc
@@ -30,7 +30,8 @@ EVENT_CXXFLAGS = $(__DEBUGINFO) $(__OPTIMIZEFLAG_2) $(__THREADSFLAG) \
$(__EXCEPTIONSFLAG_6) -Wno-ctor-dtor-privacy $(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \
$(OBJS)\event_sample_rc.o \
- $(OBJS)\event_event.o
+ $(OBJS)\event_event.o \
+ $(OBJS)\event_gestures.o
### Conditionally set variables: ###
@@ -226,6 +227,9 @@ $(OBJS)\event_sample_rc.o: ./../../samples/sample.rc
$(OBJS)\event_event.o: ./event.cpp
$(CXX) -c -o $@ $(EVENT_CXXFLAGS) $(CPPDEPS) $<
+$(OBJS)\event_gestures.o: ./gestures.cpp
+ $(CXX) -c -o $@ $(EVENT_CXXFLAGS) $(CPPDEPS) $<
+
.PHONY: all clean
diff --git a/samples/event/makefile.vc b/samples/event/makefile.vc
index cf6ad41a6c..bbf86a28b9 100644
--- a/samples/event/makefile.vc
+++ b/samples/event/makefile.vc
@@ -31,7 +31,8 @@ EVENT_CXXFLAGS = /M$(__RUNTIME_LIBS_10)$(__DEBUGRUNTIME_4) /DWIN32 \
/I.\..\..\samples /DNOPCH $(__RTTIFLAG_11) $(__EXCEPTIONSFLAG_12) \
$(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \
- $(OBJS)\event_event.obj
+ $(OBJS)\event_event.obj \
+ $(OBJS)\event_gestures.obj
EVENT_RESOURCES = \
$(OBJS)\event_sample.res
@@ -360,3 +361,5 @@ $(OBJS)\event_sample.res: .\..\..\samples\sample.rc
$(OBJS)\event_event.obj: .\event.cpp
$(CXX) /c /nologo /TP /Fo$@ $(EVENT_CXXFLAGS) .\event.cpp
+$(OBJS)\event_gestures.obj: .\gestures.cpp
+ $(CXX) /c /nologo /TP /Fo$@ $(EVENT_CXXFLAGS) .\gestures.cpp
diff --git a/src/common/event.cpp b/src/common/event.cpp
index ee9f69aec1..d32a21d9d6 100644
--- a/src/common/event.cpp
+++ b/src/common/event.cpp
@@ -103,6 +103,13 @@
wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent);
+ wxIMPLEMENT_DYNAMIC_CLASS(wxGestureEvent, wxEvent);
+ wxIMPLEMENT_DYNAMIC_CLASS(wxPanGestureEvent, wxGestureEvent);
+ wxIMPLEMENT_DYNAMIC_CLASS(wxZoomGestureEvent, wxGestureEvent);
+ wxIMPLEMENT_DYNAMIC_CLASS(wxRotateGestureEvent, wxGestureEvent);
+ wxIMPLEMENT_DYNAMIC_CLASS(wxTwoFingerTapEvent, wxGestureEvent);
+ wxIMPLEMENT_DYNAMIC_CLASS(wxLongPressEvent, wxGestureEvent);
+ wxIMPLEMENT_DYNAMIC_CLASS(wxPressAndTapEvent, wxGestureEvent);
#endif // wxUSE_GUI
#if wxUSE_BASE
@@ -258,6 +265,14 @@ wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWinEvent );
wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEvent );
wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEvent );
+// Gesture events
+wxDEFINE_EVENT( wxEVT_GESTURE_PAN, wxPanGestureEvent );
+wxDEFINE_EVENT( wxEVT_GESTURE_ZOOM, wxZoomGestureEvent );
+wxDEFINE_EVENT( wxEVT_GESTURE_ROTATE, wxRotateGestureEvent );
+wxDEFINE_EVENT( wxEVT_TWO_FINGER_TAP, wxTwoFingerTapEvent );
+wxDEFINE_EVENT( wxEVT_LONG_PRESS, wxLongPressEvent );
+wxDEFINE_EVENT( wxEVT_PRESS_AND_TAP, wxPressAndTapEvent );
+
// System events
wxDEFINE_EVENT( wxEVT_SIZE, wxSizeEvent );
wxDEFINE_EVENT( wxEVT_SIZING, wxSizeEvent );
diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp
index bcf04ba8ad..064ba0fdec 100644
--- a/src/gtk/window.cpp
+++ b/src/gtk/window.cpp
@@ -228,6 +228,23 @@ static GList* gs_sizeRevalidateList;
static bool gs_inSizeAllocate;
#endif
+#if GTK_CHECK_VERSION(3,14,0)
+// This is true when the gesture has just started (currently used for pan gesture only)
+static bool gs_gestureStart = false;
+
+// Last offset for the pan gesture, this is used to calculate deltas for pan gesture event
+static double gs_lastOffset = 0;
+
+// Last scale provided by GTK
+static gdouble gs_lastScale = 1.0;
+
+// This is used to set the angle when rotate gesture ends.
+static gdouble gs_lastAngle = 0;
+
+// Last Zoom/Rotate gesture point
+static wxPoint gs_lastGesturePoint;
+#endif // GTK_CHECK_VERSION(3,14,0)
+
//-----------------------------------------------------------------------------
// debug
//-----------------------------------------------------------------------------
@@ -2430,6 +2447,13 @@ void wxWindowGTK::Init()
m_imKeyEvent = NULL;
m_dirtyTabOrder = false;
+
+#if GTK_CHECK_VERSION(3,14,0)
+ m_touchCount = 0;
+ m_lastTouchTime = 0;
+ m_allowedGestures = 0;
+ m_activeGestures = 0;
+#endif // GTK_CHECK_VERSION(3,14,0)
}
wxWindowGTK::wxWindowGTK()
@@ -2828,6 +2852,455 @@ static gboolean source_dispatch(GSource*, GSourceFunc, void*)
}
}
+#if GTK_CHECK_VERSION(3,14,0)
+// Currently used for Press and Tap gesture only
+enum GestureStates
+{
+ begin = 1,
+ update,
+ end
+};
+
+enum TrackedGestures
+{
+ two_finger_tap = 0x0001,
+ press_and_tap = 0x0002,
+ horizontal_pan = 0x0004,
+ vertical_pan = 0x0008
+};
+
+static void
+pan_gesture_begin_callback(GtkGesture* WXUNUSED(gesture), GdkEventSequence* WXUNUSED(sequence), wxWindowGTK* WXUNUSED(win))
+{
+ gs_gestureStart = true;
+
+ // Set it to 0, as this will be used to calculate the deltas for new pan gesture
+ gs_lastOffset = 0;
+}
+
+static void
+horizontal_pan_gesture_end_callback(GtkGesture* gesture, GdkEventSequence* sequence, wxWindowGTK* win)
+{
+ // Do not process horizontal pan, if there was no "pan" signal for it.
+ if ( !(win->m_allowedGestures & horizontal_pan) )
+ {
+ return;
+ }
+
+ gdouble x, y;
+
+ if ( !gtk_gesture_get_point(gesture, sequence, &x, &y) )
+ {
+ return;
+ }
+
+ win->m_allowedGestures &= ~horizontal_pan;
+
+ wxPanGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+ event.SetGestureEnd();
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+vertical_pan_gesture_end_callback(GtkGesture* gesture, GdkEventSequence* sequence, wxWindowGTK* win)
+{
+ // Do not process vertical pan, if there was no "pan" signal for it.
+ if ( !(win->m_allowedGestures & vertical_pan) )
+ {
+ return;
+ }
+
+ gdouble x, y;
+
+ if ( !gtk_gesture_get_point(gesture, sequence, &x, &y) )
+ {
+ return;
+ }
+
+ win->m_allowedGestures &= ~vertical_pan;
+
+ wxPanGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+ event.SetGestureEnd();
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+pan_gesture_callback(GtkGesture* gesture, GtkPanDirection direction, gdouble offset, wxWindowGTK* win)
+{
+ // The function that retrieves the GdkEventSequence (which will further be used to get the gesture point)
+ // should be called only when the gestrure is active
+ if ( !gtk_gesture_is_active(gesture) )
+ {
+ return;
+ }
+
+ GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
+
+ gdouble x, y;
+
+ if ( !gtk_gesture_get_point(gesture, sequence, &x, &y) )
+ {
+ return;
+ }
+
+ wxPanGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+
+ // This is the difference between this and the last pan gesture event in the current sequence
+ int delta = wxRound(offset - gs_lastOffset);
+
+ switch ( direction )
+ {
+ case GTK_PAN_DIRECTION_UP:
+ win->m_allowedGestures |= vertical_pan;
+ event.SetDeltaY(-delta);
+ break;
+
+ case GTK_PAN_DIRECTION_DOWN:
+ win->m_allowedGestures |= vertical_pan;
+ event.SetDeltaY(delta);
+ break;
+
+ case GTK_PAN_DIRECTION_RIGHT:
+ win->m_allowedGestures |= horizontal_pan;
+ event.SetDeltaX(delta);
+ break;
+
+ case GTK_PAN_DIRECTION_LEFT:
+ win->m_allowedGestures |= horizontal_pan;
+ event.SetDeltaX(-delta);
+ break;
+ }
+
+ // Update gs_lastOffset
+ gs_lastOffset = offset;
+
+ if ( gs_gestureStart )
+ {
+ event.SetGestureStart();
+ gs_gestureStart = false;
+ }
+
+ // Cancel press and tap gesture if it is not active during "pan" signal.
+ if( !(win->m_activeGestures & press_and_tap) )
+ {
+ win->m_allowedGestures &= ~press_and_tap;
+ }
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+zoom_gesture_callback(GtkGesture* gesture, gdouble scale, wxWindowGTK* win)
+{
+ gdouble x, y;
+
+ if ( !gtk_gesture_get_bounding_box_center(gesture, &x, &y) )
+ {
+ return;
+ }
+
+ wxZoomGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+ event.SetZoomFactor(scale);
+
+ // Cancel "Two FInger Tap Event" if scale has changed
+ if ( wxRound(scale * 1000) != wxRound(gs_lastScale * 1000) )
+ {
+ win->m_allowedGestures &= ~two_finger_tap;
+ }
+
+ gs_lastScale = scale;
+
+ // Save this point because the point obtained through gtk_gesture_get_bounding_box_center()
+ // in the "end" signal is not a zoom center
+ gs_lastGesturePoint = wxPoint(wxRound(x), wxRound(y));
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+zoom_gesture_begin_callback(GtkGesture* gesture, GdkEventSequence* WXUNUSED(sequence), wxWindowGTK* win)
+{
+ gdouble x, y;
+
+ if ( !gtk_gesture_get_bounding_box_center(gesture, &x, &y) )
+ {
+ return;
+ }
+
+ gs_lastScale = 1.0;
+
+ wxZoomGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+ event.SetGestureStart();
+
+ // Save this point because the point obtained through gtk_gesture_get_bounding_box_center()
+ // in the "end" signal is not a zoom center
+ gs_lastGesturePoint = wxPoint(wxRound(x), wxRound(y));
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+zoom_gesture_end_callback(GtkGesture* WXUNUSED(gesture), GdkEventSequence* WXUNUSED(sequence), wxWindowGTK* win)
+{
+ wxZoomGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(gs_lastGesturePoint);
+ event.SetGestureEnd();
+ event.SetZoomFactor(gs_lastScale);
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+rotate_gesture_begin_callback(GtkGesture* gesture, GdkEventSequence* WXUNUSED(sequence), wxWindowGTK* win)
+{
+ gdouble x, y;
+
+ if ( !gtk_gesture_get_bounding_box_center(gesture, &x, &y) )
+ {
+ return;
+ }
+
+ wxRotateGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+ event.SetGestureStart();
+
+ // Save this point because the point obtained through gtk_gesture_get_bounding_box_center()
+ // in the "end" signal is not a rotation center
+ gs_lastGesturePoint = wxPoint(wxRound(x), wxRound(y));
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+rotate_gesture_callback(GtkGesture* gesture, gdouble WXUNUSED(angle_delta), gdouble angle, wxWindowGTK* win)
+{
+ gdouble x, y;
+
+ if ( !gtk_gesture_get_bounding_box_center(gesture, &x, &y) )
+ {
+ return;
+ }
+
+ wxRotateGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+
+ event.SetRotationAngle(angle);
+
+ // Save the angle to set it when the gesture ends.
+ gs_lastAngle = angle;
+
+ // Save this point because the point obtained through gtk_gesture_get_bounding_box_center()
+ // in the "end" signal is not a rotation center
+ gs_lastGesturePoint = wxPoint(wxRound(x), wxRound(y));
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+rotate_gesture_end_callback(GtkGesture* WXUNUSED(gesture), GdkEventSequence* WXUNUSED(sequence), wxWindowGTK* win)
+{
+ wxRotateGestureEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(gs_lastGesturePoint);
+ event.SetGestureEnd();
+ event.SetRotationAngle(gs_lastAngle);
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+long_press_gesture_callback(GtkGesture* WXUNUSED(gesture), gdouble x, gdouble y, wxWindowGTK* win)
+{
+ wxLongPressEvent event(win->GetId());
+
+ event.SetEventObject(win);
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+ event.SetGestureStart();
+ event.SetGestureEnd();
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+wxEmitTwoFingerTapEvent(GdkEventTouch* gdk_event, wxWindowGTK* win)
+{
+ wxTwoFingerTapEvent event(win->GetId());
+
+ event.SetEventObject(win);
+
+ double lastX = win->m_lastTouchPoint.x;
+ double lastY = win->m_lastTouchPoint.y;
+
+ // Calculate smaller of x coordinate between 2 touches
+ double left = lastX <= gdk_event->x ? lastX : gdk_event->x;
+
+ // Calculate smaller of y coordinate between 2 touches
+ double up = lastY <= gdk_event->y ? lastY : gdk_event->y;
+
+ // Calculate gesture point .i.e center of the box formed by two touches
+ double x = left + abs(lastX - gdk_event->x)/2;
+ double y = up + abs(lastY - gdk_event->y)/2;
+
+ event.SetPosition(wxPoint(wxRound(x), wxRound(y)));
+ event.SetGestureStart();
+ event.SetGestureEnd();
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+wxEmitPressAndTapEvent(GdkEventTouch* gdk_event, wxWindowGTK* win)
+{
+ wxPressAndTapEvent event(win->GetId());
+
+ event.SetEventObject(win);
+
+ switch ( win->m_gestureState )
+ {
+ case begin:
+ event.SetGestureStart();
+ break;
+
+ case update:
+ // Update touch point as the touch corresponding to "press" is moving
+ if ( win->m_touchSequence == gdk_event->sequence )
+ {
+ win->m_lastTouchPoint.x = gdk_event->x;
+ win->m_lastTouchPoint.y = gdk_event->y;
+ }
+ break;
+
+ case end:
+ event.SetGestureEnd();
+ break;
+ }
+
+ event.SetPosition(win->m_lastTouchPoint);
+
+ win->GTKProcessEvent(event);
+}
+
+static void
+touch_callback(GtkWidget* WXUNUSED(widget), GdkEventTouch* gdk_event, wxWindowGTK* win)
+{
+ switch ( gdk_event->type )
+ {
+ case GDK_TOUCH_BEGIN:
+ win->m_touchCount++;
+
+ win->m_allowedGestures &= ~two_finger_tap;
+
+ if ( win->m_touchCount == 1 )
+ {
+ win->m_lastTouchTime = gdk_event->time;
+ win->m_lastTouchPoint.x = gdk_event->x;
+ win->m_lastTouchPoint.y = gdk_event->y;
+
+ // Save the sequence which identifies touch corresponding to "press"
+ win->m_touchSequence = gdk_event->sequence;
+
+ // "Press and Tap Event" may occur in future
+ win->m_allowedGestures |= press_and_tap;
+ }
+
+ // Check if two fingers are placed together .i.e difference between their time stamps is <= 200 milliseconds
+ else if ( win->m_touchCount == 2 && gdk_event->time - win->m_lastTouchTime <= wxTwoFingerTimeInterval )
+ {
+ // "Two Finger Tap Event" may be possible in the future
+ win->m_allowedGestures |= two_finger_tap;
+
+ // Cancel "Press and Tap Event"
+ win->m_allowedGestures &= ~press_and_tap;
+ }
+ break;
+
+ case GDK_TOUCH_UPDATE:
+ // If press and tap gesture is active and touch corresponding to that gesture is moving
+ if ( (win->m_activeGestures & press_and_tap) && gdk_event->sequence == win->m_touchSequence )
+ {
+ win->m_gestureState = update;
+ wxEmitPressAndTapEvent(gdk_event, win);
+ }
+ break;
+
+ case GDK_TOUCH_END:
+ case GDK_TOUCH_CANCEL:
+ win->m_touchCount--;
+
+ if ( win->m_touchCount == 1 )
+ {
+ win->m_lastTouchTime = gdk_event->time;
+
+ // If the touch corresponding to "press" is present and "tap" is produced by some ather touch
+ if ( (win->m_allowedGestures & press_and_tap) && gdk_event->sequence != win->m_touchSequence )
+ {
+ // Press and Tap gesture becomes active now
+ if ( !(win->m_activeGestures & press_and_tap) )
+ {
+ win->m_gestureState = begin;
+ win->m_activeGestures |= press_and_tap;
+ }
+
+ else
+ {
+ win->m_gestureState = update;
+ }
+
+ wxEmitPressAndTapEvent(gdk_event, win);
+ }
+ }
+
+ // Check if "Two Finger Tap Event" is possible and both the fingers have been lifted up together
+ else if ( (win->m_allowedGestures & two_finger_tap) && !win->m_touchCount
+ && gdk_event->time - win->m_lastTouchTime <= wxTwoFingerTimeInterval )
+ {
+ // Process Two Finger Tap Event
+ wxEmitTwoFingerTapEvent(gdk_event, win);
+ }
+
+ // If the gesture was active and the touch corresponding to "press" is no longer on the screen
+ if ( (win->m_activeGestures & press_and_tap) && gdk_event->sequence == win->m_touchSequence )
+ {
+ win->m_gestureState = end;
+
+ win->m_activeGestures &= ~press_and_tap;
+
+ win->m_allowedGestures &= ~press_and_tap;
+
+ wxEmitPressAndTapEvent(gdk_event, win);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+#endif // GTK_CHECK_VERSION(3,14,0)
+
void wxWindowGTK::ConnectWidget( GtkWidget *widget )
{
static bool isSourceAttached;
@@ -2870,6 +3343,81 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget )
G_CALLBACK (gtk_window_enter_callback), this);
g_signal_connect (widget, "leave_notify_event",
G_CALLBACK (gtk_window_leave_callback), this);
+
+#if GTK_CHECK_VERSION(3,14,0)
+ if ( gtk_check_version(3, 14, 0) == NULL )
+ {
+ GtkGesture* vertical_pan_gesture = gtk_gesture_pan_new(widget, GTK_ORIENTATION_VERTICAL);
+
+ gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(vertical_pan_gesture), GTK_PHASE_TARGET);
+
+ g_signal_connect (vertical_pan_gesture, "begin",
+ G_CALLBACK(pan_gesture_begin_callback), this);
+ g_signal_connect (vertical_pan_gesture, "pan",
+ G_CALLBACK(pan_gesture_callback), this);
+ g_signal_connect (vertical_pan_gesture, "end",
+ G_CALLBACK(vertical_pan_gesture_end_callback), this);
+ g_signal_connect (vertical_pan_gesture, "cancel",
+ G_CALLBACK(vertical_pan_gesture_end_callback), this);
+
+ GtkGesture* horizontal_pan_gesture = gtk_gesture_pan_new(widget, GTK_ORIENTATION_HORIZONTAL);
+
+ // Pan signals are also generated in case of "left mouse down + mouse move". This can be disabled by
+ // calling gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(horizontal_pan_gesture), TRUE) and
+ // gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(verticaal_pan_gesture), TRUE) which will allow
+ // pan signals only for Touch events.
+
+ gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(horizontal_pan_gesture), GTK_PHASE_TARGET);
+
+ g_signal_connect (horizontal_pan_gesture, "begin",
+ G_CALLBACK(pan_gesture_begin_callback), this);
+ g_signal_connect (horizontal_pan_gesture, "pan",
+ G_CALLBACK(pan_gesture_callback), this);
+ g_signal_connect (horizontal_pan_gesture, "end",
+ G_CALLBACK(horizontal_pan_gesture_end_callback), this);
+ g_signal_connect (horizontal_pan_gesture, "cancel",
+ G_CALLBACK(horizontal_pan_gesture_end_callback), this);
+
+ GtkGesture* zoom_gesture = gtk_gesture_zoom_new(widget);
+
+ gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(zoom_gesture), GTK_PHASE_TARGET);
+
+ g_signal_connect (zoom_gesture, "begin",
+ G_CALLBACK(zoom_gesture_begin_callback), this);
+ g_signal_connect (zoom_gesture, "scale-changed",
+ G_CALLBACK(zoom_gesture_callback), this);
+ g_signal_connect (zoom_gesture, "end",
+ G_CALLBACK(zoom_gesture_end_callback), this);
+ g_signal_connect (zoom_gesture, "cancel",
+ G_CALLBACK(zoom_gesture_end_callback), this);
+
+ GtkGesture* rotate_gesture = gtk_gesture_rotate_new(widget);
+
+ gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(rotate_gesture), GTK_PHASE_TARGET);
+
+ g_signal_connect (rotate_gesture, "begin",
+ G_CALLBACK(rotate_gesture_begin_callback), this);
+ g_signal_connect (rotate_gesture, "angle-changed",
+ G_CALLBACK(rotate_gesture_callback), this);
+ g_signal_connect (rotate_gesture, "end",
+ G_CALLBACK(rotate_gesture_end_callback), this);
+ g_signal_connect (rotate_gesture, "cancel",
+ G_CALLBACK(rotate_gesture_end_callback), this);
+
+ GtkGesture* long_press_gesture = gtk_gesture_long_press_new(widget);
+
+ // "pressed" signal is also generated when left mouse is down for some minimum duration of time.
+ // This can be disable by calling gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(long_press_gesture), TRUE)
+ // which will allow "pressed" signal only for Touch events.
+
+ gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(long_press_gesture), GTK_PHASE_TARGET);
+
+ g_signal_connect (long_press_gesture, "pressed",
+ G_CALLBACK(long_press_gesture_callback), this);
+ g_signal_connect (widget, "touch-event",
+ G_CALLBACK(touch_callback), this);
+ }
+#endif // GTK_CHECK_VERSION(3,14,0)
}
void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
diff --git a/src/msw/window.cpp b/src/msw/window.cpp
index 68f0fedcc4..4b88bb2bfd 100644
--- a/src/msw/window.cpp
+++ b/src/msw/window.cpp
@@ -205,6 +205,85 @@ bool gs_insideCaptureChanged = false;
} // anonymous namespace
+namespace
+{
+
+// Class used to dynamically load gestures related API functions.
+#ifdef WM_GESTURE
+class GestureFuncs
+{
+public:
+ static bool IsOk()
+ {
+ if ( !ms_gestureSymbolsLoaded )
+ LoadGestureSymbols();
+
+ return ms_pfnGetGestureInfo && ms_pfnCloseGestureInfoHandle && ms_pfnSetGestureConfig;
+ }
+
+ typedef BOOL (WINAPI *GetGestureInfo_t)(HGESTUREINFO, PGESTUREINFO);
+
+ static GetGestureInfo_t GetGestureInfo()
+ {
+ if ( !ms_gestureSymbolsLoaded )
+ LoadGestureSymbols();
+
+ return ms_pfnGetGestureInfo;
+ }
+
+ typedef BOOL (WINAPI *CloseGestureInfoHandle_t)(HGESTUREINFO);
+
+ static CloseGestureInfoHandle_t CloseGestureInfoHandle()
+ {
+ if ( !ms_gestureSymbolsLoaded )
+ LoadGestureSymbols();
+
+ return ms_pfnCloseGestureInfoHandle;
+ }
+
+ typedef BOOL (WINAPI *SetGestureConfig_t)(HWND, DWORD, UINT, PGESTURECONFIG, UINT);
+
+ static SetGestureConfig_t SetGestureConfig()
+ {
+ if ( !ms_gestureSymbolsLoaded )
+ LoadGestureSymbols();
+
+ return ms_pfnSetGestureConfig;
+ }
+
+private:
+ static void LoadGestureSymbols()
+ {
+ wxDynamicLibrary dll("User32.dll");
+
+ wxDL_INIT_FUNC(ms_pfn, GetGestureInfo, dll);
+ wxDL_INIT_FUNC(ms_pfn, CloseGestureInfoHandle, dll);
+ wxDL_INIT_FUNC(ms_pfn, SetGestureConfig, dll);
+
+ ms_gestureSymbolsLoaded = true;
+ }
+
+ static GetGestureInfo_t ms_pfnGetGestureInfo;
+ static CloseGestureInfoHandle_t ms_pfnCloseGestureInfoHandle;
+ static SetGestureConfig_t ms_pfnSetGestureConfig;
+
+ static bool ms_gestureSymbolsLoaded;
+
+};
+
+GestureFuncs::GetGestureInfo_t
+ GestureFuncs::ms_pfnGetGestureInfo = NULL;
+GestureFuncs::CloseGestureInfoHandle_t
+ GestureFuncs::ms_pfnCloseGestureInfoHandle = NULL;
+GestureFuncs::SetGestureConfig_t
+ GestureFuncs::ms_pfnSetGestureConfig = NULL;
+
+bool GestureFuncs::ms_gestureSymbolsLoaded = false;
+
+#endif // WM_GESTURE
+
+} // anonymous namespace
+
// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------
@@ -3124,6 +3203,97 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
}
break;
+#ifdef WM_GESTURE
+ case WM_GESTURE:
+ {
+ if ( !GestureFuncs::IsOk() )
+ {
+ processed = false;
+ break;
+ }
+
+ // gestureInfo will contain the information about the gesture
+ GESTUREINFO gestureInfo = {0};
+ gestureInfo.cbSize = sizeof(GESTUREINFO);
+
+ // This should fill gestureInfo with the gesture details
+ if ( !GestureFuncs::GetGestureInfo()((HGESTUREINFO)lParam, &gestureInfo) )
+ {
+ wxLogLastError("GetGestureInfo");
+ processed = false;
+ break;
+ }
+
+ if ( gestureInfo.hwndTarget != GetHWND() )
+ {
+ wxLogDebug("This is Not the window targeted by this gesture!");
+ }
+
+ int x = gestureInfo.ptsLocation.x;
+ int y = gestureInfo.ptsLocation.y;
+ ScreenToClient(&x, &y);
+
+ // dwID field is used to determine the type of gesture
+ switch ( gestureInfo.dwID )
+ {
+ // Pan gesture
+ case GID_PAN:
+ {
+ // (x,y) is the current position of the pan
+ processed = HandlePanGesture(x, y, gestureInfo.dwFlags);
+ break;
+ }
+
+ // Zoom gesture
+ case GID_ZOOM:
+ {
+ // (x,y) is the mid-point of 2 fingers
+ // ullArgument field is a 64-bit unsigned integer, but the relevant information
+ // is in it's lower 4 bytes and represents distance between the fingers
+ // this is used to extract those lower 4 bytes
+ DWORD fingerDistance = (DWORD)((gestureInfo.ullArguments) & 0x00000000ffffffff);
+ processed = HandleZoomGesture(x, y, fingerDistance, gestureInfo.dwFlags);
+ break;
+ }
+
+ // Rotate gesture
+ case GID_ROTATE:
+ {
+ // (x,y) is the center point of rotation
+ // Again, we need the lower 4 bytes and this will used as an argument
+ // to obtain the angle to rotate
+ DWORD angleArgument = (DWORD)((gestureInfo.ullArguments) & 0x00000000ffffffff);
+ processed = HandleRotateGesture(x, y, angleArgument, gestureInfo.dwFlags);
+ break;
+ }
+
+ // Two Finger tap gesture
+ case GID_TWOFINGERTAP:
+ {
+ processed = HandleTwoFingerTap(x, y, gestureInfo.dwFlags);
+ break;
+ }
+
+ // Press and Tap gesture
+ case GID_PRESSANDTAP:
+ {
+ processed = HandlePressAndTap(x, y, gestureInfo.dwFlags);
+ break;
+ }
+ }
+
+ if ( processed )
+ {
+ // If processed, we must call this to avoid memory leaks
+ if ( !GestureFuncs::CloseGestureInfoHandle()((HGESTUREINFO)lParam) )
+ {
+ wxLogLastError("CloseGestureInfoHandle");
+ }
+ }
+ }
+ break;
+#endif // WM_GESTURE
+
// CTLCOLOR messages are sent by children to query the parent for their
// colors
case WM_CTLCOLORMSGBOX:
@@ -3660,6 +3830,20 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
return false;
}
+#ifdef WM_GESTURE
+ if ( GestureFuncs::IsOk() )
+ {
+ // Configure to receive all gestures
+ GESTURECONFIG gestureConfig = {0, GC_ALLGESTURES, 0};
+
+ // This functions sets the configuration to the window. Second argument is reserved to be 0.
+ // Third argument is the number of elements in gestureConfig array, currently equal to 1
+ if ( !GestureFuncs::SetGestureConfig()(m_hWnd, 0, 1, &gestureConfig, sizeof(GESTURECONFIG)) )
+ {
+ wxLogLastError("SetGestureConfig");
+ }
+ }
+#endif // WM_GESTURE
SubclassWin(m_hWnd);
@@ -5470,6 +5654,181 @@ void wxWindowMSW::GenerateMouseLeave()
(void)HandleWindowEvent(event);
}
+#ifdef WM_GESTURE
+// ---------------------------------------------------------------------------
+// Gesture events
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandlePanGesture(int x, int y, WXDWORD flags)
+{
+ // wxEVT_GESTURE_PAN
+ wxPanGestureEvent event(GetId());
+
+ // These are used to calculate the pan delta
+ static int s_previousLocationX, s_previousLocationY;
+
+ // This flag indicates that the gesture has just started
+ // Store the current point to determine the pan delta later on
+ if ( flags & GF_BEGIN )
+ {
+ s_previousLocationX = x;
+ s_previousLocationY = y;
+ event.SetGestureStart();
+ }
+
+ if ( flags & GF_END )
+ {
+ event.SetGestureEnd();
+ }
+
+ // Determine the horizontal and vertical changes
+ int DeltaX = x - s_previousLocationX, DeltaY = y - s_previousLocationY;
+
+ event.SetEventObject(this);
+ event.SetTimestamp(::GetMessageTime());
+ event.SetPosition(wxPoint(x, y));
+ event.SetDeltaX(DeltaX);
+ event.SetDeltaY(DeltaY);
+
+ // Update the last gesture event point
+ s_previousLocationX = x;
+ s_previousLocationY = y;
+
+ return HandleWindowEvent(event);
+}
+
+bool wxWindowMSW::HandleZoomGesture(int x, int y, WXDWORD fingerDistance, WXDWORD flags)
+{
+ // wxEVT_GESTURE_ZOOM
+ wxZoomGestureEvent event(GetId());
+
+ // These are used to calculate the center of the zoom and zoom factor
+ static int s_previousLocationX, s_previousLocationY, s_intialFingerDistance;
+
+ // This flag indicates that the gesture has just started
+ // Store the current point and distance between the fingers for future calculations
+ if ( flags & GF_BEGIN )
+ {
+ s_previousLocationX = x;
+ s_previousLocationY = y;
+ s_intialFingerDistance = fingerDistance;
+ event.SetGestureStart();
+ }
+
+ if ( flags & GF_END )
+ {
+ event.SetGestureEnd();
+ }
+
+ // Calculate center point of the zoom
+ // Human beings are not very good at moving two fingers at exactly the same rate outwards/inwards
+ // There is usually some error, which can cause the center to shift slightly
+ // So, it is recommended to take the average of center of fingers in the current and last positions
+ wxPoint pt;
+ pt.x = (s_previousLocationX + x) / 2;
+ pt.y = (s_previousLocationY + y) / 2;
+
+ double zoomFactor = (double) fingerDistance / (double) s_intialFingerDistance;
+
+ event.SetZoomFactor(zoomFactor);
+ event.SetEventObject(this);
+ event.SetTimestamp(::GetMessageTime());
+
+ // This is not a gesture point but the center of a zoom
+ event.SetPosition(pt);
+
+ // Update gesture event point
+ s_previousLocationX = x;
+ s_previousLocationY = y;
+
+ return HandleWindowEvent(event);
+}
+
+bool wxWindowMSW::HandleRotateGesture(int x, int y, WXDWORD angleArgument, WXDWORD flags)
+{
+ // wxEVT_GESTURE_ROTATE
+ wxRotateGestureEvent event(GetId());
+
+ // This flag indicates that the gesture has just started
+ if ( flags & GF_BEGIN )
+ {
+ event.SetGestureStart();
+ }
+
+ else
+ {
+ // Use angleArgument to obtain the cumulative angle since the gesture was first
+ // started. This angle is in radians
+ // MSW returns negative angle for clockwise rotation and positive otherwise
+ // So, multiply angle by -1 for positive angle for clockwise and negative in case of counterclockwise
+ double angle = -GID_ROTATE_ANGLE_FROM_ARGUMENT(angleArgument);
+
+ // If the rotation is anti-clockwise convert the angle to its corresponding positive value in a clockwise sense.
+ if ( angle < 0 )
+ {
+ angle += 2 * M_PI;
+ }
+
+ // Set the angle
+ event.SetRotationAngle(angle);
+ }
+
+ if ( flags & GF_END )
+ {
+ event.SetGestureEnd();
+ }
+
+ event.SetEventObject(this);
+ event.SetTimestamp(::GetMessageTime());
+ event.SetPosition(wxPoint(x, y));
+
+ return HandleWindowEvent(event);
+}
+
+bool wxWindowMSW::HandleTwoFingerTap(int x, int y, WXDWORD flags)
+{
+ // wxEVT_TWO_FINGER_TAP
+ wxTwoFingerTapEvent event(GetId());
+
+ if ( flags & GF_BEGIN )
+ {
+ event.SetGestureStart();
+ }
+
+ event.SetEventObject(this);
+ event.SetTimestamp(::GetMessageTime());
+ event.SetPosition(wxPoint(x, y));
+
+ if ( flags & GF_END )
+ {
+ event.SetGestureEnd();
+ }
+
+ return HandleWindowEvent(event);
+}
+
+bool wxWindowMSW::HandlePressAndTap(int x, int y, WXDWORD flags)
+{
+ wxPressAndTapEvent event(GetId());
+
+ if ( flags & GF_BEGIN )
+ {
+ event.SetGestureStart();
+ }
+
+ event.SetEventObject(this);
+ event.SetTimestamp(::GetMessageTime());
+ event.SetPosition(wxPoint(x, y));
+
+ if ( flags & GF_END )
+ {
+ event.SetGestureEnd();
+ }
+
+ return HandleWindowEvent(event);
+}
+#endif // WM_GESTURE
+
// ---------------------------------------------------------------------------
// keyboard handling
// ---------------------------------------------------------------------------
diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm
index 3a34b6fc65..16f44d1eec 100644
--- a/src/osx/cocoa/window.mm
+++ b/src/osx/cocoa/window.mm
@@ -1042,6 +1042,71 @@ void wxOSX_insertText(NSView* self, SEL _cmd, NSString* text)
impl->insertText(text, self, _cmd);
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+void wxOSX_panGestureEvent(NSView* self, SEL _cmd, NSPanGestureRecognizer* panGestureRecognizer)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( impl == NULL )
+ return;
+
+ impl->PanGestureEvent(panGestureRecognizer);
+}
+
+void wxOSX_zoomGestureEvent(NSView* self, SEL _cmd, NSMagnificationGestureRecognizer* magnificationGestureRecognizer)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( impl == NULL )
+ return;
+
+ impl->ZoomGestureEvent(magnificationGestureRecognizer);
+}
+
+void wxOSX_rotateGestureEvent(NSView* self, SEL _cmd, NSRotationGestureRecognizer* rotationGestureRecognizer)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( impl == NULL )
+ return;
+
+ impl->RotateGestureEvent(rotationGestureRecognizer);
+}
+
+void wxOSX_longPressEvent(NSView* self, SEL _cmd, NSPressGestureRecognizer* pressGestureRecognizer)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( impl ==NULL )
+ return;
+
+ impl->LongPressEvent(pressGestureRecognizer);
+}
+
+void wxOSX_touchesBegan(NSView* self, SEL _cmd, NSEvent *event)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( impl == NULL )
+ return;
+
+ impl->TouchesBegan(event);
+}
+
+void wxOSX_touchesMoved(NSView* self, SEL _cmd, NSEvent *event)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( impl == NULL )
+ return;
+
+ impl->TouchesMoved(event);
+}
+
+void wxOSX_touchesEnded(NSView* self, SEL _cmd, NSEvent *event)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( impl == NULL )
+ return;
+
+ impl->TouchesEnded(event);
+}
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+
BOOL wxOSX_performKeyEquivalent(NSView* self, SEL _cmd, NSEvent *event)
{
wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
@@ -1428,6 +1493,408 @@ void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
m_lastKeyDownEvent = NULL;
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+void wxWidgetCocoaImpl::PanGestureEvent(NSPanGestureRecognizer* panGestureRecognizer)
+{
+ NSGestureRecognizerState gestureState;
+
+ switch ( [panGestureRecognizer state] )
+ {
+ case NSGestureRecognizerStateBegan:
+ gestureState = NSGestureRecognizerStateBegan;
+ break;
+ case NSGestureRecognizerStateChanged:
+ break;
+ case NSGestureRecognizerStateEnded:
+ case NSGestureRecognizerStateCancelled:
+ gestureState = NSGestureRecognizerStateEnded;
+ break;
+ // Do not process any other states
+ default:
+ return;
+ }
+
+ wxPanGestureEvent wxevent(GetWXPeer()->GetId());
+ wxevent.SetEventObject(GetWXPeer());
+
+ NSPoint nspoint = [panGestureRecognizer locationInView:m_osxView];
+ wxPoint pt = wxFromNSPoint(m_osxView, nspoint);
+
+ wxevent.SetPosition(pt);
+
+ nspoint = [panGestureRecognizer translationInView:m_osxView];
+ pt = wxFromNSPoint(m_osxView, nspoint);
+
+ static int s_lastLocationX = 0, s_lastLocationY = 0;
+
+ if ( gestureState == NSGestureRecognizerStateBegan )
+ {
+ wxevent.SetGestureStart();
+ s_lastLocationX = 0;
+ s_lastLocationY = 0;
+ }
+
+ if ( gestureState == NSGestureRecognizerStateEnded )
+ {
+ wxevent.SetGestureEnd();
+ }
+
+ // Set the offsets
+ wxevent.SetDeltaX(pt.x - s_lastLocationX);
+ wxevent.SetDeltaY(pt.y - s_lastLocationY);
+
+ s_lastLocationX = pt.x;
+ s_lastLocationY = pt.y;
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+}
+
+void wxWidgetCocoaImpl::ZoomGestureEvent(NSMagnificationGestureRecognizer* magnificationGestureRecognizer)
+{
+ NSGestureRecognizerState gestureState;
+
+ switch ( [magnificationGestureRecognizer state] )
+ {
+ case NSGestureRecognizerStateBegan:
+ gestureState = NSGestureRecognizerStateBegan;
+ break;
+ case NSGestureRecognizerStateChanged:
+ break;
+ case NSGestureRecognizerStateEnded:
+ case NSGestureRecognizerStateCancelled:
+ gestureState = NSGestureRecognizerStateEnded;
+ break;
+ // Do not process any other states
+ default:
+ return;
+ }
+
+ wxZoomGestureEvent wxevent(GetWXPeer()->GetId());
+ wxevent.SetEventObject(GetWXPeer());
+
+ NSPoint nspoint = [magnificationGestureRecognizer locationInView:m_osxView];
+ wxPoint pt = wxFromNSPoint(m_osxView, nspoint);
+
+ wxevent.SetPosition(pt);
+
+ if ( gestureState == NSGestureRecognizerStateBegan )
+ {
+ wxevent.SetGestureStart();
+ }
+
+ if ( gestureState == NSGestureRecognizerStateEnded )
+ {
+ wxevent.SetGestureEnd();
+ }
+
+ double magnification = [magnificationGestureRecognizer magnification];
+
+ // Add 1.0 get the magnification.
+ magnification += 1.0;
+
+ wxevent.SetZoomFactor(magnification);
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+}
+
+void wxWidgetCocoaImpl::RotateGestureEvent(NSRotationGestureRecognizer* rotationGestureRecognizer)
+{
+ NSGestureRecognizerState gestureState;
+
+ switch ( [rotationGestureRecognizer state] )
+ {
+ case NSGestureRecognizerStateBegan:
+ gestureState = NSGestureRecognizerStateBegan;
+ break;
+ case NSGestureRecognizerStateChanged:
+ break;
+ case NSGestureRecognizerStateEnded:
+ case NSGestureRecognizerStateCancelled:
+ gestureState = NSGestureRecognizerStateEnded;
+ break;
+ // Do not process any other states
+ default:
+ return;
+ }
+
+ wxRotateGestureEvent wxevent(GetWXPeer()->GetId());
+ wxevent.SetEventObject(GetWXPeer());
+
+ NSPoint nspoint = [rotationGestureRecognizer locationInView:m_osxView];
+ wxPoint pt = wxFromNSPoint(m_osxView, nspoint);
+
+ wxevent.SetPosition(pt);
+
+ if ( gestureState == NSGestureRecognizerStateBegan )
+ {
+ wxevent.SetGestureStart();
+ }
+
+ if ( gestureState == NSGestureRecognizerStateEnded )
+ {
+ wxevent.SetGestureEnd();
+ }
+ // Multiply the returned rotation angle with -1 to obtain the angle in a clockwise sense.
+ double angle = -[rotationGestureRecognizer rotation];
+
+ // If the rotation is anti-clockwise convert the angle to its corresponding positive value in a clockwise sense.
+ if ( angle < 0 )
+ {
+ angle += 2 * M_PI;
+ }
+
+ wxevent.SetRotationAngle(angle);
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+}
+
+void wxWidgetCocoaImpl::LongPressEvent(NSPressGestureRecognizer* pressGestureRecognizer)
+{
+ NSGestureRecognizerState gestureState;
+
+ switch ( [pressGestureRecognizer state] )
+ {
+ case NSGestureRecognizerStateBegan:
+ gestureState = NSGestureRecognizerStateBegan;
+ break;
+ case NSGestureRecognizerStateChanged:
+ break;
+ case NSGestureRecognizerStateEnded:
+ case NSGestureRecognizerStateCancelled:
+ gestureState = NSGestureRecognizerStateEnded;
+ break;
+ // Do not process any other states
+ default:
+ return;
+ }
+
+ wxLongPressEvent wxevent(GetWXPeer()->GetId());
+ wxevent.SetEventObject(GetWXPeer());
+
+ NSPoint nspoint = [pressGestureRecognizer locationInView:m_osxView];
+ wxPoint pt = wxFromNSPoint(m_osxView, nspoint);
+
+ wxevent.SetPosition(pt);
+
+ if ( gestureState == NSGestureRecognizerStateBegan )
+ {
+ wxevent.SetGestureStart();
+ }
+
+ if ( gestureState == NSGestureRecognizerStateEnded )
+ {
+ wxevent.SetGestureEnd();
+ }
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+}
+
+enum TrackedGestures
+{
+ two_finger_tap = 0x0001,
+ press_and_tap = 0x0002
+};
+
+void wxWidgetCocoaImpl::TouchesBegan(WX_NSEvent event)
+{
+ NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:m_osxView];
+
+ m_touchCount += touches.count;
+ m_allowedGestures &= ~two_finger_tap;
+
+ // Check if 2 fingers are placed together
+ if ( m_touchCount == 2 && touches.count == 2 )
+ {
+ // Two Finger Tap Event may occur in future
+ m_allowedGestures |= two_finger_tap;
+
+ // Cancel Press and Tap Event
+ m_allowedGestures &= ~press_and_tap;
+
+ return;
+ }
+
+ // Time of event in milliseconds
+ const unsigned int eventTimeStamp = event.timestamp * 1000 + 0.5;
+
+ if ( m_touchCount == 1 )
+ {
+ // Save the time of event
+ m_lastTouchTime = eventTimeStamp;
+
+ // Press and Tap may occur in future
+ m_allowedGestures |= press_and_tap;
+
+ NSArray* array = [touches allObjects];
+
+ // Save the touch corresponding to "press"
+ m_initialTouch = [[array objectAtIndex:0] copy];
+ }
+
+ touches = [event touchesMatchingPhase:NSTouchPhaseStationary inView:m_osxView];
+
+ // Check if 2 fingers are placed within the time interval of 200 milliseconds
+ if ( m_touchCount == 2 && touches.count == 1 && eventTimeStamp - m_lastTouchTime <= wxTwoFingerTimeInterval )
+ {
+ // Two Finger Tap Event may occur in future
+ m_allowedGestures |= two_finger_tap;
+
+ // Cancel Press and Tap
+ m_allowedGestures &= ~press_and_tap;
+
+ [m_initialTouch release];
+ }
+}
+
+void wxWidgetCocoaImpl::TouchesMoved(WX_NSEvent event)
+{
+ // Cancel Two Finger Tap Event if there is any movement
+ m_allowedGestures &= ~two_finger_tap;
+
+ if ( !(m_allowedGestures & press_and_tap) )
+ {
+ return;
+ }
+
+ NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:m_osxView];
+
+ NSArray* array = [touches allObjects];
+
+ // Iterate through all moving touches to check if the touch corresponding to "press"
+ // in Press and Tap event is moving.
+ for ( int i = 0; i < [array count]; ++i )
+ {
+ NSTouch* touch = [array objectAtIndex:i];
+
+ // Check if this touch and m_initialTouch are same
+ if ( [touch.identity isEqual:m_initialTouch.identity] )
+ {
+ // Process Press and Tap Event if the touch corresponding to "press" is moving
+ // and the gesture is active.
+ if ( m_activeGestures & press_and_tap )
+ {
+ wxPressAndTapEvent wxevent(GetWXPeer()->GetId());
+ wxevent.SetEventObject(GetWXPeer());
+
+ // Get the mouse coordinates
+ wxCoord x, y;
+ SetupCoordinates(x, y, event);
+ wxevent.SetPosition(wxPoint (x,y));
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+ }
+
+ // Cancel Press and Tap Event if the touch corresponding to "press" is moving
+ // and the gesture is not active.
+ else
+ {
+ m_allowedGestures &= ~press_and_tap;
+ }
+
+ return;
+ }
+ }
+}
+
+void wxWidgetCocoaImpl::TouchesEnded(WX_NSEvent event)
+{
+ NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:m_osxView];
+
+ m_touchCount -= touches.count;
+
+ // Time of event in milliseconds
+ const unsigned int eventTimeStamp = event.timestamp * 1000 + 0.5;
+
+ // Check if 2 fingers are lifted off together or if 2 fingers are lifted off within the time interval of 200 milliseconds
+ if ( (!m_touchCount && (m_allowedGestures & two_finger_tap)) &&
+ (touches.count == 2 ||
+ (touches.count == 1 && eventTimeStamp - m_lastTouchTime <= wxTwoFingerTimeInterval)) )
+ {
+ wxTwoFingerTapEvent wxevent(GetWXPeer()->GetId());
+ wxevent.SetEventObject(GetWXPeer());
+ wxevent.SetGestureStart();
+ wxevent.SetGestureEnd();
+
+ // Get the mouse coordinates
+ wxCoord x, y;
+ SetupCoordinates(x, y, event);
+ wxevent.SetPosition(wxPoint (x,y));
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+ }
+
+ // If Two Finger Tap Event is possible in future then save the timestamp to use it when the other touch
+ // leaves the surface.
+ else if ( m_touchCount == 1 && (m_allowedGestures & two_finger_tap) )
+ {
+ m_lastTouchTime = eventTimeStamp;
+ }
+
+ // Check if Press and Tap event is possible.
+ else if ( m_allowedGestures & press_and_tap )
+ {
+ NSArray* array = [touches allObjects];
+
+ // True if touch that ended is the touch corresponding to "press"
+ bool isPressTouch = false;
+
+ // Iterate through all ended touches
+ for( int i = 0; i < [array count]; ++i )
+ {
+ NSTouch* touch = [array objectAtIndex:i];
+
+ // Check if touch that ended is the touch corresponding to "press"
+ if ( [touch.identity isEqual:m_initialTouch.identity] )
+ {
+ isPressTouch = true;
+ break;
+ }
+ }
+
+ // Cancel Press and Tap Event if the touch corresponding to press is ended
+ // and Press and Tap was not active
+ if ( isPressTouch && !(m_activeGestures & press_and_tap) )
+ {
+ m_allowedGestures &= ~press_and_tap;
+ return;
+ }
+
+ wxPressAndTapEvent wxevent(GetWXPeer()->GetId());
+ wxevent.SetEventObject(GetWXPeer());
+
+ // Get the mouse coordinates
+ wxCoord x, y;
+ SetupCoordinates(x, y, event);
+ wxevent.SetPosition(wxPoint (x,y));
+
+ if ( !(m_activeGestures & press_and_tap) )
+ {
+ wxevent.SetGestureStart();
+ m_activeGestures |= press_and_tap;
+ }
+
+ // End Press and Tap Event if the touch corresponding to "press" is lifted off
+ else if ( isPressTouch )
+ {
+ wxevent.SetGestureEnd();
+
+ m_activeGestures &= ~press_and_tap;
+ m_allowedGestures &= ~press_and_tap;
+ [m_initialTouch release];
+ }
+
+ GetWXPeer()->HandleWindowEvent(wxevent);
+ }
+
+ else
+ {
+ m_allowedGestures &= ~press_and_tap;
+ m_allowedGestures &= ~two_finger_tap;
+ m_activeGestures &= ~press_and_tap;
+ }
+}
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+
void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd)
{
bool result = false;
@@ -1775,7 +2242,17 @@ void wxOSXCocoaClassAddWXMethods(Class c)
wxOSX_CLASS_ADD_METHOD(c, @selector(scrollWheel:), (IMP) wxOSX_mouseEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(mouseEntered:), (IMP) wxOSX_mouseEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(mouseExited:), (IMP) wxOSX_mouseEvent, "v@:@" )
-
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+ wxOSX_CLASS_ADD_METHOD(c, @selector(handlePanGesture:), (IMP) wxOSX_panGestureEvent, "v@:@" )
+ wxOSX_CLASS_ADD_METHOD(c, @selector(handleZoomGesture:), (IMP) wxOSX_zoomGestureEvent, "v@:@" )
+ wxOSX_CLASS_ADD_METHOD(c, @selector(handleRotateGesture:), (IMP) wxOSX_rotateGestureEvent, "v@:@" )
+ wxOSX_CLASS_ADD_METHOD(c, @selector(handleLongPressGesture:), (IMP) wxOSX_longPressEvent, "v@:@" )
+ wxOSX_CLASS_ADD_METHOD(c, @selector(touchesBeganWithEvent:), (IMP) wxOSX_touchesBegan, "v@:@" )
+ wxOSX_CLASS_ADD_METHOD(c, @selector(touchesMovedWithEvent:), (IMP) wxOSX_touchesMoved, "v@:@" )
+ wxOSX_CLASS_ADD_METHOD(c, @selector(touchesEndedWithEvent:), (IMP) wxOSX_touchesEnded, "v@:@" )
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+
wxOSX_CLASS_ADD_METHOD(c, @selector(magnifyWithEvent:), (IMP)wxOSX_mouseEvent, "v@:@")
wxOSX_CLASS_ADD_METHOD(c, @selector(cursorUpdate:), (IMP) wxOSX_cursorUpdate, "v@:@" )
@@ -1857,6 +2334,14 @@ void wxWidgetCocoaImpl::Init()
#endif
m_lastKeyDownEvent = NULL;
m_hasEditor = false;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+ m_touchCount = 0;
+ m_lastTouchTime = 0;
+ m_allowedGestures = 0;
+ m_activeGestures = 0;
+ m_initialTouch = NULL;
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
}
wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
@@ -1875,6 +2360,22 @@ wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
// gc aware handling
if ( m_osxView )
CFRelease(m_osxView);
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+ if ( wxPlatformInfo::Get().CheckOSVersion(10, 10) )
+ {
+ if ( IsUserPane() )
+ {
+ [m_panGestureRecognizer release];
+ [m_magnificationGestureRecognizer release];
+ [m_rotationGestureRecognizer release];
+ [m_pressGestureRecognizer release];
+
+ if ( m_initialTouch )
+ [m_initialTouch release];
+ }
+ }
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
}
bool wxWidgetCocoaImpl::IsVisible() const
@@ -2791,7 +3292,34 @@ void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control )
NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil];
[m_osxView addTrackingArea: area];
[area release];
- }
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+ if ( wxPlatformInfo::Get().CheckOSVersion(10, 10) )
+ {
+ if ( IsUserPane() )
+ {
+ m_panGestureRecognizer =
+ [[NSPanGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handlePanGesture:)];
+
+ m_magnificationGestureRecognizer =
+ [[NSMagnificationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleZoomGesture:)];
+
+ m_rotationGestureRecognizer =
+ [[NSRotationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleRotateGesture:)];
+
+ m_pressGestureRecognizer =
+ [[NSPressGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleLongPressGesture:)];
+
+ [m_osxView addGestureRecognizer:m_panGestureRecognizer];
+ [m_osxView addGestureRecognizer:m_magnificationGestureRecognizer];
+ [m_osxView addGestureRecognizer:m_rotationGestureRecognizer];
+ [m_osxView addGestureRecognizer:m_pressGestureRecognizer];
+
+ [m_osxView setAcceptsTouchEvents:YES];
+ }
+ }
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
+}
bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text)
{