Merge branch 'gesture-events'

Integrate GSoC 2017 work by Prashant Kumar implementing support for
gesture events.

Closes https://github.com/wxWidgets/wxWidgets/pull/551

Closes https://github.com/wxWidgets/wxWidgets/pull/565
This commit is contained in:
Vadim Zeitlin
2017-12-02 18:46:53 +01:00
28 changed files with 2894 additions and 17 deletions

View File

@@ -3104,6 +3104,12 @@ DECLARE_WXCOCOA_OBJC_CLASS(NSView);
DECLARE_WXCOCOA_OBJC_CLASS(NSOpenGLContext); DECLARE_WXCOCOA_OBJC_CLASS(NSOpenGLContext);
DECLARE_WXCOCOA_OBJC_CLASS(NSOpenGLPixelFormat); DECLARE_WXCOCOA_OBJC_CLASS(NSOpenGLPixelFormat);
DECLARE_WXCOCOA_OBJC_CLASS( NSPrintInfo ); 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__ */ #endif /* __WXMAC__ &__DARWIN__ */
#ifdef __WXMAC__ #ifdef __WXMAC__
@@ -3267,6 +3273,7 @@ typedef struct _GdkDragContext GdkDragContext;
#if defined(__WXGTK3__) #if defined(__WXGTK3__)
typedef struct _GdkWindow GdkWindow; typedef struct _GdkWindow GdkWindow;
typedef struct _GdkEventSequence GdkEventSequence;
#elif defined(__WXGTK20__) #elif defined(__WXGTK20__)
typedef struct _GdkDrawable GdkWindow; typedef struct _GdkDrawable GdkWindow;
typedef struct _GdkDrawable GdkPixmap; typedef struct _GdkDrawable GdkPixmap;

View File

@@ -631,6 +631,13 @@ class WXDLLIMPEXP_FWD_CORE wxInitDialogEvent;
class WXDLLIMPEXP_FWD_CORE wxUpdateUIEvent; class WXDLLIMPEXP_FWD_CORE wxUpdateUIEvent;
class WXDLLIMPEXP_FWD_CORE wxClipboardTextEvent; class WXDLLIMPEXP_FWD_CORE wxClipboardTextEvent;
class WXDLLIMPEXP_FWD_CORE wxHelpEvent; 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 // 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_THUMBTRACK, wxScrollWinEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SCROLLWIN_THUMBRELEASE, 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 // System events
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SIZE, wxSizeEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SIZE, wxSizeEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_MOVE, wxMoveEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_MOVE, wxMoveEvent);
@@ -1850,6 +1865,197 @@ private:
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxSetCursorEvent); 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)
{
}
wxPanGestureEvent(const wxPanGestureEvent& event)
: wxGestureEvent(event),
m_delta(event.m_delta)
{
}
wxPoint GetDelta() const { return m_delta; }
void SetDelta(const wxPoint& delta) { m_delta = delta; }
virtual wxEvent *Clone() const { return new wxPanGestureEvent(*this); }
private:
wxPoint m_delta;
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 // Keyboard input event class
/* /*
@@ -3908,7 +4114,12 @@ typedef void (wxEvtHandler::*wxContextMenuEventFunction)(wxContextMenuEvent&);
typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureChangedEvent&); typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureChangedEvent&);
typedef void (wxEvtHandler::*wxMouseCaptureLostEventFunction)(wxMouseCaptureLostEvent&); typedef void (wxEvtHandler::*wxMouseCaptureLostEventFunction)(wxMouseCaptureLostEvent&);
typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&); 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) \ #define wxCommandEventHandler(func) \
wxEVENT_HANDLER_CAST(wxCommandEventFunction, func) wxEVENT_HANDLER_CAST(wxCommandEventFunction, func)
@@ -3983,6 +4194,18 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
wxEVENT_HANDLER_CAST(wxMouseCaptureLostEventFunction, func) wxEVENT_HANDLER_CAST(wxMouseCaptureLostEventFunction, func)
#define wxClipboardTextEventHandler(func) \ #define wxClipboardTextEventHandler(func) \
wxEVENT_HANDLER_CAST(wxClipboardTextEventFunction, 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 #endif // wxUSE_GUI
@@ -4317,6 +4540,14 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&
EVT_COMMAND_SCROLL_THUMBRELEASE(winid, func) \ EVT_COMMAND_SCROLL_THUMBRELEASE(winid, func) \
EVT_COMMAND_SCROLL_CHANGED(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 // Convenience macros for commonly-used commands
#define EVT_CHECKBOX(winid, func) wx__DECLARE_EVT1(wxEVT_CHECKBOX, winid, wxCommandEventHandler(func)) #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)) #define EVT_CHOICE(winid, func) wx__DECLARE_EVT1(wxEVT_CHOICE, winid, wxCommandEventHandler(func))

View File

@@ -77,6 +77,9 @@ public:
virtual bool Reparent( wxWindowBase *newParent ) wxOVERRIDE; virtual bool Reparent( wxWindowBase *newParent ) wxOVERRIDE;
virtual void WarpPointer(int x, int y) wxOVERRIDE; virtual void WarpPointer(int x, int y) wxOVERRIDE;
#ifdef __WXGTK3__
virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE;
#endif // __WXGTK3__
virtual void Refresh( bool eraseBackground = true, virtual void Refresh( bool eraseBackground = true,
const wxRect *rect = (const wxRect *) NULL ) wxOVERRIDE; const wxRect *rect = (const wxRect *) NULL ) wxOVERRIDE;

View File

@@ -100,6 +100,7 @@ public:
virtual bool Reparent(wxWindowBase *newParent) wxOVERRIDE; virtual bool Reparent(wxWindowBase *newParent) wxOVERRIDE;
virtual void WarpPointer(int x, int y) wxOVERRIDE; virtual void WarpPointer(int x, int y) wxOVERRIDE;
virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE;
virtual void Refresh( bool eraseBackground = true, virtual void Refresh( bool eraseBackground = true,
const wxRect *rect = (const wxRect *) NULL ) wxOVERRIDE; const wxRect *rect = (const wxRect *) NULL ) wxOVERRIDE;
@@ -360,6 +361,16 @@ public:
bool HandleMouseWheel(wxMouseWheelAxis axis, bool HandleMouseWheel(wxMouseWheelAxis axis,
WXWPARAM wParam, WXLPARAM lParam); WXWPARAM wParam, WXLPARAM lParam);
// Common gesture event initialization, returns true if it is the initial
// event (GF_BEGIN set in flags), false otherwise.
bool InitGestureEvent(wxGestureEvent& event, const wxPoint& pt, WXDWORD flags);
bool HandlePanGesture(const wxPoint& pt, WXDWORD flags);
bool HandleZoomGesture(const wxPoint& pt, WXDWORD fingerDistance, WXDWORD flags);
bool HandleRotateGesture(const wxPoint& pt, WXDWORD angleArgument, WXDWORD flags);
bool HandleTwoFingerTap(const wxPoint& pt, WXDWORD flags);
bool HandlePressAndTap(const wxPoint& pt, WXDWORD flags);
bool HandleChar(WXWPARAM wParam, WXLPARAM lParam); bool HandleChar(WXWPARAM wParam, WXLPARAM lParam);
bool HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam); bool HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam);
bool HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam); bool HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam);

View File

@@ -128,6 +128,7 @@ public :
void SetToolTip( wxToolTip* tooltip ); void SetToolTip( wxToolTip* tooltip );
void InstallEventHandler( WXWidget control = NULL ); void InstallEventHandler( WXWidget control = NULL );
bool EnableTouchEvents(int eventsMask);
virtual bool ShouldHandleKeyNavigation(const wxKeyEvent &event) const; virtual bool ShouldHandleKeyNavigation(const wxKeyEvent &event) const;
bool DoHandleKeyNavigation(const wxKeyEvent &event); bool DoHandleKeyNavigation(const wxKeyEvent &event);
@@ -143,6 +144,15 @@ public :
void SetupCoordinates(wxCoord &x, wxCoord &y, NSEvent *nsEvent); void SetupCoordinates(wxCoord &x, wxCoord &y, NSEvent *nsEvent);
virtual bool SetupCursor(NSEvent* event); 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 #if !wxOSX_USE_NATIVE_FLIPPED
void SetFlipped(bool flipped); void SetFlipped(bool flipped);

View File

@@ -326,6 +326,8 @@ public :
virtual void InstallEventHandler( WXWidget control = NULL ) = 0; virtual void InstallEventHandler( WXWidget control = NULL ) = 0;
virtual bool EnableTouchEvents(int eventsMask) = 0;
// Mechanism used to keep track of whether a change should send an event // Mechanism used to keep track of whether a change should send an event
// Do SendEvents(false) when starting actions that would trigger programmatic events // Do SendEvents(false) when starting actions that would trigger programmatic events
// and SendEvents(true) at the end of the block. // and SendEvents(true) at the end of the block.

View File

@@ -105,6 +105,7 @@ public :
void SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack = true ); void SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack = true );
void InstallEventHandler( WXWidget control = NULL ); void InstallEventHandler( WXWidget control = NULL );
bool EnableTouchEvents(int WXUNUSED(eventsMask)) { return false; }
virtual void DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* otherWindow); virtual void DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* otherWindow);

View File

@@ -77,6 +77,7 @@ public:
virtual void SetFocus() wxOVERRIDE; virtual void SetFocus() wxOVERRIDE;
virtual void WarpPointer( int x, int y ) wxOVERRIDE; virtual void WarpPointer( int x, int y ) wxOVERRIDE;
virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE;
virtual void Refresh( bool eraseBackground = true, virtual void Refresh( bool eraseBackground = true,
const wxRect *rect = NULL ) wxOVERRIDE; const wxRect *rect = NULL ) wxOVERRIDE;

View File

@@ -0,0 +1,84 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/private/extfield.h
// Purpose: Declare wxExternalField helper
// Author: Vadim Zeitlin
// Created: 2017-11-21
// Copyright: (c) 2017 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PRIVATE_EXTFIELD_H_
#define _WX_PRIVATE_EXTFIELD_H_
// ----------------------------------------------------------------------------
// wxExternalField: store object data outside of it
// ----------------------------------------------------------------------------
// This class allows to store some data without consuming space for the objects
// that don't need it and can be useful for avoiding to add rarely used fields
// to the classes that are used by many objects, e.g. wxWindow.
//
// Note that using this class costs in speed and convenience of access to the
// field, which requires a hash lookup instead of accessing it directly. It
// also only currently works for heap-allocated fields as it's probably never
// worth using it for fields of simple types.
//
// Template parameter Object is the class that "contains" the field, Field is
// the type of the field itself and FieldMap is the hash map, defined
// separately using WX_DECLARE_HASH_MAP(), with Object* as the key and Field*
// as the value type.
template <typename Object, typename Field, typename FieldMap>
class wxExternalField
{
public:
typedef Object ObjectType;
typedef Field FieldType;
typedef FieldMap MapType;
// Store the field object to be used for the given object, replacing the
// existing one, if any.
//
// This method takes ownership of the field pointer which will be destroyed
// by EraseForObject().
static void StoreForObject(ObjectType* obj, FieldType* field)
{
const typename MapType::iterator it = ms_map.find(obj);
if ( it != ms_map.end() )
{
delete it->second;
it->second = field;
}
else
{
ms_map.insert(typename MapType::value_type(obj, field));
}
}
// Find the object for the corresponding window.
static FieldType* FromObject(ObjectType* obj)
{
const typename MapType::const_iterator it = ms_map.find(obj);
return it == ms_map.end() ? NULL : it->second;
}
// Erase the object used for the corresponding window, return true if there
// was one or false otherwise.
static bool EraseForObject(ObjectType* obj)
{
const typename MapType::iterator it = ms_map.find(obj);
if ( it == ms_map.end() )
return false;
delete it->second;
ms_map.erase(it);
return true;
}
private:
static FieldMap ms_map;
};
template <typename O, typename F, typename M>
M wxExternalField<O, F, M>::ms_map;
#endif // _WX_PRIVATE_EXTFIELD_H_

View File

@@ -133,6 +133,20 @@ enum wxShowEffect
wxSHOW_EFFECT_MAX wxSHOW_EFFECT_MAX
}; };
// Values for EnableTouchEvents() mask.
enum
{
wxTOUCH_NONE = 0x0000,
wxTOUCH_VERTICAL_PAN_GESTURE = 0x0001,
wxTOUCH_HORIZONTAL_PAN_GESTURE = 0x0002,
wxTOUCH_PAN_GESTURES = wxTOUCH_VERTICAL_PAN_GESTURE |
wxTOUCH_HORIZONTAL_PAN_GESTURE,
wxTOUCH_ZOOM_GESTURE = 0x0004,
wxTOUCH_ROTATE_GESTURE = 0x0008,
wxTOUCH_PRESS_GESTURES = 0x0010,
wxTOUCH_ALL_GESTURES = 0x001f
};
// flags for SendSizeEvent() // flags for SendSizeEvent()
enum enum
{ {
@@ -1033,6 +1047,13 @@ public:
virtual bool HasCapture() const virtual bool HasCapture() const
{ return (wxWindow *)this == GetCapture(); } { return (wxWindow *)this == GetCapture(); }
// enable the specified touch events for this window, return false if
// the requested events are not supported
virtual bool EnableTouchEvents(int WXUNUSED(eventsMask))
{
return false;
}
// painting the window // painting the window
// ------------------- // -------------------

View File

@@ -3644,6 +3644,251 @@ public:
void SetPosition(int pos); void SetPosition(int pos);
}; };
/** @class wxGestureEvent
This is the base class for all supported gesture events.
@note Gesture events are not generated by default, you must call
wxWindow::EnableTouchEvents() with the appropriate parameter to
request their generation.
@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 distance covered since the previous panning event.
*/
wxPoint GetDelta() const;
/**
Sets the distance covered since the previous panning event.
*/
void SetDelta(const wxPoint& delta);
};
/** @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 #endif // wxUSE_GUI
#if wxUSE_BASE #if wxUSE_BASE

View File

@@ -52,6 +52,68 @@ enum wxShowEffect
}; };
/**
Values for wxWindow::EnableTouchEvents() mask.
The values other than ::wxTOUCH_NONE and ::wxTOUCH_ALL_GESTURES can be
combined together to request enabling events for the specified gestures and
for them only.
@since 3.1.1
*/
enum
{
/**
Don't generate any touch events.
*/
wxTOUCH_NONE,
/**
Generate wxPanGestureEvent for vertical pans.
Note that under macOS horizontal pan events are also enabled when this
flag is specified.
*/
wxTOUCH_VERTICAL_PAN_GESTURE,
/**
Generate wxPanGestureEvent for horizontal pans.
Note that under macOS vertical pan events are also enabled when this
flag is specified.
*/
wxTOUCH_HORIZONTAL_PAN_GESTURE,
/**
Generate wxPanGestureEvent for any pans.
This is just a convenient combination of wxTOUCH_VERTICAL_PAN_GESTURE
and wxTOUCH_HORIZONTAL_PAN_GESTURE.
*/
wxTOUCH_PAN_GESTURES,
/**
Generate wxZoomGestureEvent.
*/
wxTOUCH_ZOOM_GESTURE,
/**
Generate wxRotateGestureEvent.
*/
wxTOUCH_ROTATE_GESTURE,
/**
Generate events for press or tap gestures such as wxTwoFingerTapEvent,
wxLongPressEvent and wxPressAndTapEvent.
*/
wxTOUCH_PRESS_GESTURES,
/**
Enable all supported gesture events.
*/
wxTOUCH_ALL_GESTURES
};
/** /**
flags for SendSizeEvent() flags for SendSizeEvent()
*/ */
@@ -3424,6 +3486,28 @@ public:
*/ */
virtual void WarpPointer(int x, int y); virtual void WarpPointer(int x, int y);
/**
Request generation of touch events for this window.
Each call to this function supersedes the previous ones, i.e. if you
want to receive events for both zoom and rotate gestures, you need to
call
@code
EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_ROTATE_GESTURE);
@endcode
instead of calling it twice in a row as the second call would disable
the first gesture.
@param eventsMask Either wxTOUCH_NONE or wxTOUCH_ALL_GESTURES to
disable or enable gesture events for this window.
@return @true if the specified events were enabled or @false if the
current platform doesn't support touch events.
@since 3.1.1
*/
virtual bool EnableTouchEvents(int eventsMask);
//@} //@}

View File

@@ -49,7 +49,8 @@ EVENT_CXXFLAGS = -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) $(__DEBUG_DEFINE_p) \
$(SAMPLES_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(SAMPLES_CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \ EVENT_OBJECTS = \
$(__event___win32rc) \ $(__event___win32rc) \
event_event.o event_event.o \
event_gestures.o
### Conditionally set variables: ### ### Conditionally set variables: ###
@@ -177,6 +178,8 @@ event_sample_rc.o: $(srcdir)/../../samples/sample.rc
event_event.o: $(srcdir)/event.cpp event_event.o: $(srcdir)/event.cpp
$(CXXC) -c -o $@ $(EVENT_CXXFLAGS) $(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: # Include dependency info, if present:
@IF_GNU_MAKE@-include ./.deps/*.d @IF_GNU_MAKE@-include ./.deps/*.d

View File

@@ -4,7 +4,8 @@
<include file="../../build/bakefiles/common_samples.bkl"/> <include file="../../build/bakefiles/common_samples.bkl"/>
<exe id="event" template="wx_sample" template_append="wx_append"> <exe id="event" template="wx_sample" template_append="wx_append">
<sources>event.cpp</sources> <sources> event.cpp gestures.cpp </sources>
<headers> gestures.h </headers>
<wx-lib>core</wx-lib> <wx-lib>core</wx-lib>
<wx-lib>base</wx-lib> <wx-lib>base</wx-lib>
</exe> </exe>

View File

@@ -35,6 +35,7 @@
#include <wx/statline.h> #include <wx/statline.h>
#include <wx/log.h> #include <wx/log.h>
#include "gestures.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// event constants // event constants
@@ -144,6 +145,9 @@ public:
void OnClickDynamicHandlerButton(wxCommandEvent& event); void OnClickDynamicHandlerButton(wxCommandEvent& event);
void OnClickStaticHandlerFrame(wxCommandEvent& event); void OnClickStaticHandlerFrame(wxCommandEvent& event);
// Gesture
void OnGesture(wxCommandEvent& event);
private: private:
// symbolic names for the status bar fields // symbolic names for the status bar fields
enum enum
@@ -178,6 +182,8 @@ private:
// the button used to highlight the event handlers execution order // the button used to highlight the event handlers execution order
MyEvtTestButton *m_testBtn; MyEvtTestButton *m_testBtn;
wxWindowRef m_gestureFrame;
// any class wishing to process wxWidgets events must use this macro // any class wishing to process wxWidgets events must use this macro
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
@@ -220,7 +226,8 @@ enum
Event_Push, Event_Push,
Event_Pop, Event_Pop,
Event_Custom, 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_Test, MyFrame::OnTest)
EVT_MENU(Event_Push, MyFrame::OnPushEventHandler) EVT_MENU(Event_Push, MyFrame::OnPushEventHandler)
EVT_MENU(Event_Pop, MyFrame::OnPopEventHandler) EVT_MENU(Event_Pop, MyFrame::OnPopEventHandler)
EVT_MENU(Event_Gesture, MyFrame::OnGesture)
EVT_UPDATE_UI(Event_Pop, MyFrame::OnUpdateUIPop) EVT_UPDATE_UI(Event_Pop, MyFrame::OnUpdateUIPop)
@@ -381,6 +389,8 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
menuEvent->AppendSeparator(); menuEvent->AppendSeparator();
menuEvent->Append(Event_Custom, wxT("Fire c&ustom event\tCtrl-U"), menuEvent->Append(Event_Custom, wxT("Fire c&ustom event\tCtrl-U"),
wxT("Generate a custom event")); 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... // now append the freshly created menu to the menu bar...
wxMenuBar *menuBar = new wxMenuBar(); wxMenuBar *menuBar = new wxMenuBar();
@@ -447,7 +457,8 @@ MyFrame::~MyFrame()
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{ {
// true is to force the frame to close if ( m_gestureFrame )
m_gestureFrame->Close(true);
Close(true); Close(true);
} }
@@ -577,6 +588,19 @@ void MyFrame::OnPopEventHandler(wxCommandEvent& WXUNUSED(event))
#endif // wxUSE_STATUSBAR #endif // wxUSE_STATUSBAR
} }
void MyFrame::OnGesture(wxCommandEvent& WXUNUSED(event))
{
if ( m_gestureFrame )
{
m_gestureFrame->Raise();
}
else
{
m_gestureFrame = new MyGestureFrame();
m_gestureFrame->Show(true);
}
}
void MyFrame::OnTest(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnTest(wxCommandEvent& WXUNUSED(event))
{ {
wxLogMessage(wxT("This is the test event handler in the main frame")); wxLogMessage(wxT("This is the test event handler in the main frame"));
@@ -602,4 +626,3 @@ void MyFrame::OnProcessCustom(wxCommandEvent& WXUNUSED(event))
{ {
wxLogMessage(wxT("Got a custom event!")); wxLogMessage(wxT("Got a custom event!"));
} }

View File

@@ -286,6 +286,17 @@
<File <File
RelativePath=".\event.cpp"> RelativePath=".\event.cpp">
</File> </File>
<File
RelativePath=".\gestures.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\gestures.h">
</File>
</Filter> </Filter>
<Filter <Filter
Name="Resource Files" Name="Resource Files"

View File

@@ -810,6 +810,20 @@
RelativePath=".\event.cpp" RelativePath=".\event.cpp"
> >
</File> </File>
<File
RelativePath=".\gestures.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\gestures.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Resource Files" Name="Resource Files"

View File

@@ -782,6 +782,20 @@
RelativePath=".\event.cpp" RelativePath=".\event.cpp"
> >
</File> </File>
<File
RelativePath=".\gestures.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\gestures.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Resource Files" Name="Resource Files"

221
samples/event/gestures.cpp Normal file
View File

@@ -0,0 +1,221 @@
#include "gestures.h"
#include "wx/dcgraph.h"
#include "../image/horse.xpm"
MyGestureFrame::MyGestureFrame()
: wxFrame(NULL, wxID_ANY, "Multi-touch Gestures", wxDefaultPosition, wxSize(800, 600))
{
// Create controls
MyGesturePanel *myPanel = new MyGesturePanel(this);
m_logText = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(wxDefaultCoord, 100), wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH);
// Add controls to sizer
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->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),
m_bitmap(horse_xpm)
{
Bind(wxEVT_PAINT, &MyGesturePanel::OnPaint, this);
if ( !EnableTouchEvents(wxTOUCH_ALL_GESTURES) )
{
wxLogError("Failed to enable touch events");
// Still bind event handlers just in case they still work?
}
// 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");
}
const wxPoint delta = event.GetDelta();
wxLogMessage("Pan gesture performed with delta = (%d,%d), "
"with current position (%d,%d)",
delta.x, delta.y,
event.GetPosition().x, event.GetPosition().y);
// Transform the distance using the transpose of the matrix,
// in order to translate the image to match the screen coordinates
wxMatrix2D m;
m_affineMatrix.Get(&m, NULL);
wxPoint2DDouble deltaD(m.m_11 * delta.x + m.m_12 * delta.y,
m.m_21 * delta.x + m.m_22 * delta.y);
// Add it to the total translation
m_translateDistance += deltaD;
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");
}
}

39
samples/event/gestures.h Normal file
View File

@@ -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_

View File

@@ -36,7 +36,8 @@ EVENT_CXXFLAGS = $(__RUNTIME_LIBS_7) -I$(BCCDIR)\include $(__DEBUGINFO) \
-I$(SETUPHDIR) -I.\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES_p) -I. \ -I$(SETUPHDIR) -I.\..\..\include $(____CAIRO_INCLUDEDIR_FILENAMES_p) -I. \
$(__DLLFLAG_p) -I.\..\..\samples -DNOPCH $(CPPFLAGS) $(CXXFLAGS) $(__DLLFLAG_p) -I.\..\..\samples -DNOPCH $(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \ EVENT_OBJECTS = \
$(OBJS)\event_event.obj $(OBJS)\event_event.obj \
$(OBJS)\event_gestures.obj
### Conditionally set variables: ### ### Conditionally set variables: ###
@@ -237,3 +238,5 @@ $(OBJS)\event_sample.res: .\..\..\samples\sample.rc
$(OBJS)\event_event.obj: .\event.cpp $(OBJS)\event_event.obj: .\event.cpp
$(CXX) -q -c -P -o$@ $(EVENT_CXXFLAGS) .\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

View File

@@ -30,7 +30,8 @@ EVENT_CXXFLAGS = $(__DEBUGINFO) $(__OPTIMIZEFLAG_2) $(__THREADSFLAG) \
$(__EXCEPTIONSFLAG_6) -Wno-ctor-dtor-privacy $(CPPFLAGS) $(CXXFLAGS) $(__EXCEPTIONSFLAG_6) -Wno-ctor-dtor-privacy $(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \ EVENT_OBJECTS = \
$(OBJS)\event_sample_rc.o \ $(OBJS)\event_sample_rc.o \
$(OBJS)\event_event.o $(OBJS)\event_event.o \
$(OBJS)\event_gestures.o
### Conditionally set variables: ### ### Conditionally set variables: ###
@@ -226,6 +227,9 @@ $(OBJS)\event_sample_rc.o: ./../../samples/sample.rc
$(OBJS)\event_event.o: ./event.cpp $(OBJS)\event_event.o: ./event.cpp
$(CXX) -c -o $@ $(EVENT_CXXFLAGS) $(CPPDEPS) $< $(CXX) -c -o $@ $(EVENT_CXXFLAGS) $(CPPDEPS) $<
$(OBJS)\event_gestures.o: ./gestures.cpp
$(CXX) -c -o $@ $(EVENT_CXXFLAGS) $(CPPDEPS) $<
.PHONY: all clean .PHONY: all clean

View File

@@ -31,7 +31,8 @@ EVENT_CXXFLAGS = /M$(__RUNTIME_LIBS_10)$(__DEBUGRUNTIME_4) /DWIN32 \
/I.\..\..\samples /DNOPCH $(__RTTIFLAG_11) $(__EXCEPTIONSFLAG_12) \ /I.\..\..\samples /DNOPCH $(__RTTIFLAG_11) $(__EXCEPTIONSFLAG_12) \
$(CPPFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(CXXFLAGS)
EVENT_OBJECTS = \ EVENT_OBJECTS = \
$(OBJS)\event_event.obj $(OBJS)\event_event.obj \
$(OBJS)\event_gestures.obj
EVENT_RESOURCES = \ EVENT_RESOURCES = \
$(OBJS)\event_sample.res $(OBJS)\event_sample.res
@@ -360,3 +361,5 @@ $(OBJS)\event_sample.res: .\..\..\samples\sample.rc
$(OBJS)\event_event.obj: .\event.cpp $(OBJS)\event_event.obj: .\event.cpp
$(CXX) /c /nologo /TP /Fo$@ $(EVENT_CXXFLAGS) .\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

View File

@@ -103,6 +103,13 @@
wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent); 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 #endif // wxUSE_GUI
#if wxUSE_BASE #if wxUSE_BASE
@@ -258,6 +265,14 @@ wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWinEvent );
wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEvent ); wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEvent );
wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBRELEASE, 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 // System events
wxDEFINE_EVENT( wxEVT_SIZE, wxSizeEvent ); wxDEFINE_EVENT( wxEVT_SIZE, wxSizeEvent );
wxDEFINE_EVENT( wxEVT_SIZING, wxSizeEvent ); wxDEFINE_EVENT( wxEVT_SIZING, wxSizeEvent );

View File

@@ -227,6 +227,80 @@ static GList* gs_sizeRevalidateList;
static bool gs_inSizeAllocate; static bool gs_inSizeAllocate;
#endif #endif
#if GTK_CHECK_VERSION(3,14,0)
#define wxGTK_HAS_GESTURES_SUPPORT
#endif
#ifdef wxGTK_HAS_GESTURES_SUPPORT
#include "wx/hashmap.h"
#include "wx/private/extfield.h"
namespace
{
// Per-window data for gestures support.
class wxWindowGesturesData
{
public:
// This class has rather unusual "resurrectable" semantics: it is
// initialized by the ctor as usual, but may then be uninitialized by
// calling Free() and re-initialized again by calling Reinit().
wxWindowGesturesData(wxWindow* win, GtkWidget *widget, int eventsMask)
{
Reinit(win, widget, eventsMask);
}
~wxWindowGesturesData()
{
Free();
}
void Reinit(wxWindow* win, GtkWidget *widget, int eventsMask);
void Free();
unsigned int m_touchCount;
unsigned int m_lastTouchTime;
int m_gestureState;
int m_allowedGestures;
int m_activeGestures;
wxPoint m_lastTouchPoint;
GdkEventSequence* m_touchSequence;
GtkGesture* m_vertical_pan_gesture;
GtkGesture* m_horizontal_pan_gesture;
GtkGesture* m_zoom_gesture;
GtkGesture* m_rotate_gesture;
GtkGesture* m_long_press_gesture;
};
WX_DECLARE_HASH_MAP(wxWindow*, wxWindowGesturesData*,
wxPointerHash, wxPointerEqual,
wxWindowGesturesMap);
typedef wxExternalField<wxWindow,
wxWindowGesturesData,
wxWindowGesturesMap> wxWindowGestures;
} // anonymous namespace
// 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 // wxGTK_HAS_GESTURES_SUPPORT
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// debug // debug
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -2624,6 +2698,10 @@ wxWindowGTK::~wxWindowGTK()
gs_sizeRevalidateList = g_list_remove_all(gs_sizeRevalidateList, this); gs_sizeRevalidateList = g_list_remove_all(gs_sizeRevalidateList, this);
#endif #endif
#ifdef wxGTK_HAS_GESTURES_SUPPORT
wxWindowGestures::EraseForObject(this);
#endif // wxGTK_HAS_GESTURES_SUPPORT
if (m_widget) if (m_widget)
{ {
// Note that gtk_widget_destroy() does not destroy the widget, it just // Note that gtk_widget_destroy() does not destroy the widget, it just
@@ -2825,6 +2903,676 @@ static gboolean source_dispatch(GSource*, GSourceFunc, void*)
} }
} }
#ifdef wxGTK_HAS_GESTURES_SUPPORT
// 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)
{
wxWindowGesturesData* const data = wxWindowGestures::FromObject(win);
if ( !data )
return;
// Do not process horizontal pan, if there was no "pan" signal for it.
if ( !(data->m_allowedGestures & horizontal_pan) )
{
return;
}
gdouble x, y;
if ( !gtk_gesture_get_point(gesture, sequence, &x, &y) )
{
return;
}
data->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)
{
wxWindowGesturesData* const data = wxWindowGestures::FromObject(win);
if ( !data )
return;
// Do not process vertical pan, if there was no "pan" signal for it.
if ( !(data->m_allowedGestures & vertical_pan) )
{
return;
}
gdouble x, y;
if ( !gtk_gesture_get_point(gesture, sequence, &x, &y) )
{
return;
}
data->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)));
wxWindowGesturesData* const data = wxWindowGestures::FromObject(win);
if ( !data )
return;
// 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:
data->m_allowedGestures |= vertical_pan;
event.SetDelta(wxPoint(0, -delta));
break;
case GTK_PAN_DIRECTION_DOWN:
data->m_allowedGestures |= vertical_pan;
event.SetDelta(wxPoint(0, delta));
break;
case GTK_PAN_DIRECTION_RIGHT:
data->m_allowedGestures |= horizontal_pan;
event.SetDelta(wxPoint(delta, 0));
break;
case GTK_PAN_DIRECTION_LEFT:
data->m_allowedGestures |= horizontal_pan;
event.SetDelta(wxPoint(-delta, 0));
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( !(data->m_activeGestures & press_and_tap) )
{
data->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);
wxWindowGesturesData* const data = wxWindowGestures::FromObject(win);
if ( !data )
return;
// Cancel "Two FInger Tap Event" if scale has changed
if ( wxRound(scale * 1000) != wxRound(gs_lastScale * 1000) )
{
data->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);
wxWindowGesturesData* const data = wxWindowGestures::FromObject(win);
if ( !data )
return;
double lastX = data->m_lastTouchPoint.x;
double lastY = data->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);
wxWindowGesturesData* const data = wxWindowGestures::FromObject(win);
if ( !data )
return;
switch ( data->m_gestureState )
{
case begin:
event.SetGestureStart();
break;
case update:
// Update touch point as the touch corresponding to "press" is moving
if ( data->m_touchSequence == gdk_event->sequence )
{
data->m_lastTouchPoint.x = gdk_event->x;
data->m_lastTouchPoint.y = gdk_event->y;
}
break;
case end:
event.SetGestureEnd();
break;
}
event.SetPosition(data->m_lastTouchPoint);
win->GTKProcessEvent(event);
}
static void
touch_callback(GtkWidget* WXUNUSED(widget), GdkEventTouch* gdk_event, wxWindowGTK* win)
{
wxWindowGesturesData* const data = wxWindowGestures::FromObject(win);
if ( !data )
return;
switch ( gdk_event->type )
{
case GDK_TOUCH_BEGIN:
data->m_touchCount++;
data->m_allowedGestures &= ~two_finger_tap;
if ( data->m_touchCount == 1 )
{
data->m_lastTouchTime = gdk_event->time;
data->m_lastTouchPoint.x = gdk_event->x;
data->m_lastTouchPoint.y = gdk_event->y;
// Save the sequence which identifies touch corresponding to "press"
data->m_touchSequence = gdk_event->sequence;
// "Press and Tap Event" may occur in future
data->m_allowedGestures |= press_and_tap;
}
// Check if two fingers are placed together .i.e difference between their time stamps is <= 200 milliseconds
else if ( data->m_touchCount == 2 && gdk_event->time - data->m_lastTouchTime <= wxTwoFingerTimeInterval )
{
// "Two Finger Tap Event" may be possible in the future
data->m_allowedGestures |= two_finger_tap;
// Cancel "Press and Tap Event"
data->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 ( (data->m_activeGestures & press_and_tap) && gdk_event->sequence == data->m_touchSequence )
{
data->m_gestureState = update;
wxEmitPressAndTapEvent(gdk_event, win);
}
break;
case GDK_TOUCH_END:
case GDK_TOUCH_CANCEL:
data->m_touchCount--;
if ( data->m_touchCount == 1 )
{
data->m_lastTouchTime = gdk_event->time;
// If the touch corresponding to "press" is present and "tap" is produced by some ather touch
if ( (data->m_allowedGestures & press_and_tap) && gdk_event->sequence != data->m_touchSequence )
{
// Press and Tap gesture becomes active now
if ( !(data->m_activeGestures & press_and_tap) )
{
data->m_gestureState = begin;
data->m_activeGestures |= press_and_tap;
}
else
{
data->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 ( (data->m_allowedGestures & two_finger_tap) && !data->m_touchCount
&& gdk_event->time - data->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 ( (data->m_activeGestures & press_and_tap) && gdk_event->sequence == data->m_touchSequence )
{
data->m_gestureState = end;
data->m_activeGestures &= ~press_and_tap;
data->m_allowedGestures &= ~press_and_tap;
wxEmitPressAndTapEvent(gdk_event, win);
}
break;
default:
break;
}
}
void wxWindowGesturesData::Reinit(wxWindowGTK* win,
GtkWidget *widget,
int eventsMask)
{
m_touchCount = 0;
m_lastTouchTime = 0;
m_gestureState = 0;
m_allowedGestures = 0;
m_activeGestures = 0;
m_touchSequence = NULL;
if ( eventsMask & wxTOUCH_VERTICAL_PAN_GESTURE )
{
eventsMask &= ~wxTOUCH_VERTICAL_PAN_GESTURE;
m_vertical_pan_gesture = gtk_gesture_pan_new(widget, GTK_ORIENTATION_VERTICAL);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_vertical_pan_gesture), GTK_PHASE_TARGET);
g_signal_connect (m_vertical_pan_gesture, "begin",
G_CALLBACK(pan_gesture_begin_callback), win);
g_signal_connect (m_vertical_pan_gesture, "pan",
G_CALLBACK(pan_gesture_callback), win);
g_signal_connect (m_vertical_pan_gesture, "end",
G_CALLBACK(vertical_pan_gesture_end_callback), win);
g_signal_connect (m_vertical_pan_gesture, "cancel",
G_CALLBACK(vertical_pan_gesture_end_callback), win);
}
else
{
m_vertical_pan_gesture = NULL;
}
if ( eventsMask & wxTOUCH_HORIZONTAL_PAN_GESTURE )
{
eventsMask &= ~wxTOUCH_HORIZONTAL_PAN_GESTURE;
m_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(m_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(m_horizontal_pan_gesture), GTK_PHASE_TARGET);
g_signal_connect (m_horizontal_pan_gesture, "begin",
G_CALLBACK(pan_gesture_begin_callback), win);
g_signal_connect (m_horizontal_pan_gesture, "pan",
G_CALLBACK(pan_gesture_callback), win);
g_signal_connect (m_horizontal_pan_gesture, "end",
G_CALLBACK(horizontal_pan_gesture_end_callback), win);
g_signal_connect (m_horizontal_pan_gesture, "cancel",
G_CALLBACK(horizontal_pan_gesture_end_callback), win);
}
else
{
m_horizontal_pan_gesture = NULL;
}
if ( eventsMask & wxTOUCH_ZOOM_GESTURE )
{
eventsMask &= ~wxTOUCH_ZOOM_GESTURE;
m_zoom_gesture = gtk_gesture_zoom_new(widget);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_zoom_gesture), GTK_PHASE_TARGET);
g_signal_connect (m_zoom_gesture, "begin",
G_CALLBACK(zoom_gesture_begin_callback), win);
g_signal_connect (m_zoom_gesture, "scale-changed",
G_CALLBACK(zoom_gesture_callback), win);
g_signal_connect (m_zoom_gesture, "end",
G_CALLBACK(zoom_gesture_end_callback), win);
g_signal_connect (m_zoom_gesture, "cancel",
G_CALLBACK(zoom_gesture_end_callback), win);
}
else
{
m_zoom_gesture = NULL;
}
if ( eventsMask & wxTOUCH_ROTATE_GESTURE )
{
eventsMask &= ~wxTOUCH_ROTATE_GESTURE;
m_rotate_gesture = gtk_gesture_rotate_new(widget);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_rotate_gesture), GTK_PHASE_TARGET);
g_signal_connect (m_rotate_gesture, "begin",
G_CALLBACK(rotate_gesture_begin_callback), win);
g_signal_connect (m_rotate_gesture, "angle-changed",
G_CALLBACK(rotate_gesture_callback), win);
g_signal_connect (m_rotate_gesture, "end",
G_CALLBACK(rotate_gesture_end_callback), win);
g_signal_connect (m_rotate_gesture, "cancel",
G_CALLBACK(rotate_gesture_end_callback), win);
}
else
{
m_rotate_gesture = NULL;
}
if ( eventsMask & wxTOUCH_PRESS_GESTURES )
{
eventsMask &= ~wxTOUCH_PRESS_GESTURES;
m_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(m_long_press_gesture), TRUE)
// which will allow "pressed" signal only for Touch events.
gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(m_long_press_gesture), GTK_PHASE_TARGET);
g_signal_connect (m_long_press_gesture, "pressed",
G_CALLBACK(long_press_gesture_callback), win);
}
else
{
m_long_press_gesture = NULL;
}
wxASSERT_MSG( eventsMask == 0, "Unknown touch event mask bit specified" );
gtk_widget_add_events(widget, GDK_TOUCHPAD_GESTURE_MASK);
g_signal_connect (widget, "touch-event",
G_CALLBACK(touch_callback), win);
}
void wxWindowGesturesData::Free()
{
g_clear_object(&m_vertical_pan_gesture);
g_clear_object(&m_horizontal_pan_gesture);
g_clear_object(&m_zoom_gesture);
g_clear_object(&m_rotate_gesture);
g_clear_object(&m_long_press_gesture);
// We don't current remove GDK_TOUCHPAD_GESTURE_MASK as this can't be done
// for a window as long as it's realized, and this might still be the case
// if we're called from EnableTouchEvents(wxTOUCH_NONE) and not from the
// dtor, but it shouldn't really be a problem.
}
#endif // wxGTK_HAS_GESTURES_SUPPORT
// This method must be always defined for GTK+ 3 as it's declared in the
// header, where we can't (easily) test for wxGTK_HAS_GESTURES_SUPPORT.
#ifdef __WXGTK3__
bool wxWindowGTK::EnableTouchEvents(int eventsMask)
{
#ifdef wxGTK_HAS_GESTURES_SUPPORT
// Check if gestures support is also available during run-time.
if ( gtk_check_version(3, 14, 0) == NULL )
{
wxWindowGesturesData* const dataOld = wxWindowGestures::FromObject(this);
if ( eventsMask == wxTOUCH_NONE )
{
// Reset the gestures data used by this object, but don't destroy
// it, as we could be called from an event handler, in which case
// this object could be still used after the event handler returns.
if ( dataOld )
dataOld->Free();
}
else
{
GtkWidget* const widget = GetConnectWidget();
if ( dataOld )
{
dataOld->Reinit(this, widget, eventsMask);
}
else
{
wxWindowGesturesData* const
dataNew = new wxWindowGesturesData(this, widget, eventsMask);
wxWindowGestures::StoreForObject(this, dataNew);
}
}
return true;
}
#endif // wxGTK_HAS_GESTURES_SUPPORT
return wxWindowBase::EnableTouchEvents(eventsMask);
}
#endif // __WXGTK3__
void wxWindowGTK::ConnectWidget( GtkWidget *widget ) void wxWindowGTK::ConnectWidget( GtkWidget *widget )
{ {
static bool isSourceAttached; static bool isSourceAttached;

View File

@@ -51,6 +51,7 @@
#include "wx/textctrl.h" #include "wx/textctrl.h"
#include "wx/menuitem.h" #include "wx/menuitem.h"
#include "wx/module.h" #include "wx/module.h"
#include "wx/vector.h"
#endif #endif
#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__) #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
@@ -205,6 +206,82 @@ bool gs_insideCaptureChanged = false;
} // anonymous namespace } // anonymous namespace
#ifdef WM_GESTURE
namespace
{
// Class used to dynamically load gestures related API functions.
class GestureFuncs
{
public:
// Must be called before using any other methods of this class (and they
// can't be used if this one returns false).
static bool IsOk()
{
if ( !ms_gestureSymbolsLoaded )
{
ms_gestureSymbolsLoaded = true;
LoadGestureSymbols();
}
return ms_pfnGetGestureInfo &&
ms_pfnCloseGestureInfoHandle &&
ms_pfnSetGestureConfig;
}
typedef BOOL (WINAPI *GetGestureInfo_t)(HGESTUREINFO, PGESTUREINFO);
static GetGestureInfo_t GetGestureInfo()
{
return ms_pfnGetGestureInfo;
}
typedef BOOL (WINAPI *CloseGestureInfoHandle_t)(HGESTUREINFO);
static CloseGestureInfoHandle_t CloseGestureInfoHandle()
{
return ms_pfnCloseGestureInfoHandle;
}
typedef BOOL
(WINAPI *SetGestureConfig_t)(HWND, DWORD, UINT, PGESTURECONFIG, UINT);
static SetGestureConfig_t SetGestureConfig()
{
return ms_pfnSetGestureConfig;
}
private:
static void LoadGestureSymbols()
{
wxLoadedDLL dll(wxS("user32.dll"));
wxDL_INIT_FUNC(ms_pfn, GetGestureInfo, dll);
wxDL_INIT_FUNC(ms_pfn, CloseGestureInfoHandle, dll);
wxDL_INIT_FUNC(ms_pfn, SetGestureConfig, dll);
}
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;
} // anonymous namespace
#endif // WM_GESTURE
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// private functions // private functions
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -830,6 +907,123 @@ void wxWindowMSW::WarpPointer(int x, int y)
} }
} }
bool wxWindowMSW::EnableTouchEvents(int eventsMask)
{
#ifdef WM_GESTURE
if ( GestureFuncs::IsOk() )
{
// Static struct used when we need to use just a single configuration.
GESTURECONFIG config = {0, 0, 0};
GESTURECONFIG* ptrConfigs = &config;
UINT numConfigs = 1;
// This is used only if we need to allocate the configurations
// dynamically.
wxVector<GESTURECONFIG> configs;
// There are two simple cases: enabling or disabling all gestures.
if ( eventsMask == wxTOUCH_NONE )
{
config.dwBlock = GC_ALLGESTURES;
}
else if ( eventsMask == wxTOUCH_ALL_GESTURES )
{
config.dwWant = GC_ALLGESTURES;
}
else // Need to enable the individual gestures
{
int wantedPan = 0;
switch ( eventsMask & wxTOUCH_PAN_GESTURES )
{
case wxTOUCH_VERTICAL_PAN_GESTURE:
wantedPan = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
break;
case wxTOUCH_HORIZONTAL_PAN_GESTURE:
wantedPan = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
break;
case wxTOUCH_PAN_GESTURES:
wantedPan = GC_PAN;
break;
case 0:
// This is the only other possibility and wantedPan is
// already initialized to 0 anyhow, so don't do anything,
// just list it for completeness.
break;
}
if ( wantedPan )
{
eventsMask &= ~wxTOUCH_PAN_GESTURES;
config.dwID = GID_PAN;
config.dwWant = wantedPan;
configs.push_back(config);
}
if ( eventsMask & wxTOUCH_ZOOM_GESTURE )
{
eventsMask &= ~wxTOUCH_ZOOM_GESTURE;
config.dwID = GID_ZOOM;
config.dwWant = GC_ZOOM;
configs.push_back(config);
}
if ( eventsMask & wxTOUCH_ROTATE_GESTURE )
{
eventsMask &= ~wxTOUCH_ROTATE_GESTURE;
config.dwID = GID_ROTATE;
config.dwWant = GC_ROTATE;
configs.push_back(config);
}
if ( eventsMask & wxTOUCH_PRESS_GESTURES )
{
eventsMask &= ~wxTOUCH_PRESS_GESTURES;
config.dwID = GID_TWOFINGERTAP;
config.dwWant = GC_TWOFINGERTAP;
configs.push_back(config);
config.dwID = GID_PRESSANDTAP;
config.dwWant = GC_PRESSANDTAP;
configs.push_back(config);
}
// As we clear all the known bits if they're set in the code above,
// there should be nothing left.
wxCHECK_MSG( eventsMask == 0, false,
wxS("Unknown touch event mask bit specified") );
ptrConfigs = &configs[0];
}
if ( !GestureFuncs::SetGestureConfig()
(
m_hWnd,
0, // Reserved, must be always 0.
numConfigs, // Number of gesture configurations.
ptrConfigs, // Pointer to the first one.
sizeof(GESTURECONFIG) // Size of each configuration.
)
)
{
wxLogLastError("SetGestureConfig");
return false;
}
return true;
}
#endif // WM_GESTURE
return wxWindowBase::EnableTouchEvents(eventsMask);
}
void wxWindowMSW::MSWUpdateUIState(int action, int state) void wxWindowMSW::MSWUpdateUIState(int action, int state)
{ {
// we send WM_CHANGEUISTATE so if nothing needs changing then the system // we send WM_CHANGEUISTATE so if nothing needs changing then the system
@@ -3124,6 +3318,84 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
} }
break; break;
#ifdef WM_GESTURE
case WM_GESTURE:
{
if ( !GestureFuncs::IsOk() )
break;
HGESTUREINFO hGestureInfo = reinterpret_cast<HGESTUREINFO>(lParam);
WinStruct<GESTUREINFO> gestureInfo;
if ( !GestureFuncs::GetGestureInfo()(hGestureInfo, &gestureInfo) )
{
wxLogLastError("GetGestureInfo");
break;
}
if ( gestureInfo.hwndTarget != GetHWND() )
{
wxLogDebug("This is Not the window targeted by this gesture!");
}
const wxPoint pt = ScreenToClient
(
wxPoint(gestureInfo.ptsLocation.x,
gestureInfo.ptsLocation.y)
);
// dwID field is used to determine the type of gesture
switch ( gestureInfo.dwID )
{
case GID_PAN:
// Point contains the current position of the pan.
processed = HandlePanGesture(pt, gestureInfo.dwFlags);
break;
case GID_ZOOM:
// Point is the mid-point of 2 fingers and ullArgument
// contains the distance between the fingers in its lower
// half
processed = HandleZoomGesture
(
pt,
static_cast<DWORD>(gestureInfo.ullArguments),
gestureInfo.dwFlags
);
break;
case GID_ROTATE:
// Point is the center point of rotation and ullArguments
// contains the angle of rotation
processed = HandleRotateGesture
(
pt,
static_cast<DWORD>(gestureInfo.ullArguments),
gestureInfo.dwFlags
);
break;
case GID_TWOFINGERTAP:
processed = HandleTwoFingerTap(pt, gestureInfo.dwFlags);
break;
case GID_PRESSANDTAP:
processed = HandlePressAndTap(pt, gestureInfo.dwFlags);
break;
}
if ( processed )
{
// If processed, we must call this to avoid memory leaks
if ( !GestureFuncs::CloseGestureInfoHandle()(hGestureInfo) )
{
wxLogLastError("CloseGestureInfoHandle");
}
}
}
break;
#endif // WM_GESTURE
// CTLCOLOR messages are sent by children to query the parent for their // CTLCOLOR messages are sent by children to query the parent for their
// colors // colors
case WM_CTLCOLORMSGBOX: case WM_CTLCOLORMSGBOX:
@@ -5474,6 +5746,144 @@ void wxWindowMSW::GenerateMouseLeave()
(void)HandleWindowEvent(event); (void)HandleWindowEvent(event);
} }
#ifdef WM_GESTURE
// ---------------------------------------------------------------------------
// Gesture events
// ---------------------------------------------------------------------------
bool wxWindowMSW::InitGestureEvent(wxGestureEvent& event,
const wxPoint& pt,
WXDWORD flags)
{
event.SetEventObject(this);
event.SetTimestamp(::GetMessageTime());
event.SetPosition(pt);
if ( flags & GF_BEGIN )
event.SetGestureStart();
if ( flags & GF_END )
event.SetGestureEnd();
return (flags & GF_BEGIN) != 0;
}
bool wxWindowMSW::HandlePanGesture(const wxPoint& pt, WXDWORD flags)
{
// wxEVT_GESTURE_PAN
wxPanGestureEvent event(GetId());
// This is used to calculate the pan delta.
static wxPoint s_previousLocation;
// If the gesture has just started, store the current point to determine
// the pan delta later on.
if ( InitGestureEvent(event, pt, flags) )
{
s_previousLocation = pt;
}
// Determine the horizontal and vertical changes
event.SetDelta(pt - s_previousLocation);
// Update the last gesture event point
s_previousLocation = pt;
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandleZoomGesture(const wxPoint& pt,
WXDWORD fingerDistance,
WXDWORD flags)
{
// wxEVT_GESTURE_ZOOM
wxZoomGestureEvent event(GetId());
// These are used to calculate the center of the zoom and zoom factor
static wxPoint s_previousLocation;
static int s_intialFingerDistance;
// This flag indicates that the gesture has just started, store the current
// point and distance between the fingers for future calculations.
if ( InitGestureEvent(event, pt, flags) )
{
s_previousLocation = pt;
s_intialFingerDistance = fingerDistance;
}
// Calculate center point of the zoom. Human beings are not very good at
// moving two fingers at exactly the same rate outwards/inwards and 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.
const wxPoint ptCenter = (s_previousLocation + pt)/2;
const double zoomFactor = (double) fingerDistance / s_intialFingerDistance;
event.SetZoomFactor(zoomFactor);
event.SetPosition(ptCenter);
// Update gesture event point
s_previousLocation = pt;
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandleRotateGesture(const wxPoint& pt,
WXDWORD angleArgument,
WXDWORD flags)
{
// wxEVT_GESTURE_ROTATE
wxRotateGestureEvent event(GetId());
if ( InitGestureEvent(event, pt, flags) )
{
event.SetRotationAngle(angleArgument);
}
else // Not the first event.
{
// Use angleArgument to obtain the cumulative angle since the gesture
// was first started. This angle is in radians and 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);
}
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandleTwoFingerTap(const wxPoint& pt, WXDWORD flags)
{
// wxEVT_TWO_FINGER_TAP
wxTwoFingerTapEvent event(GetId());
InitGestureEvent(event, pt, flags);
return HandleWindowEvent(event);
}
bool wxWindowMSW::HandlePressAndTap(const wxPoint& pt, WXDWORD flags)
{
wxPressAndTapEvent event(GetId());
InitGestureEvent(event, pt, flags);
return HandleWindowEvent(event);
}
#endif // WM_GESTURE
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// keyboard handling // keyboard handling
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@@ -528,29 +528,35 @@ bool g_lastButtonWasFakeRight = false ;
- (CGFloat)scrollingDeltaY; - (CGFloat)scrollingDeltaY;
@end @end
void wxWidgetCocoaImpl::SetupCoordinates(wxCoord &x, wxCoord &y, NSEvent* nsEvent) static void
wxSetupCoordinates(NSView* view, wxCoord &x, wxCoord &y, NSEvent* nsEvent)
{ {
NSRect locationInWindow = NSZeroRect; NSRect locationInWindow = NSZeroRect;
locationInWindow.origin = [nsEvent locationInWindow]; locationInWindow.origin = [nsEvent locationInWindow];
// adjust coordinates for the window of the target view // adjust coordinates for the window of the target view
if ( [nsEvent window] != [m_osxView window] ) if ( [nsEvent window] != [view window] )
{ {
if ( [nsEvent window] != nil ) if ( [nsEvent window] != nil )
locationInWindow = [[nsEvent window] convertRectToScreen:locationInWindow]; locationInWindow = [[nsEvent window] convertRectToScreen:locationInWindow];
if ( [m_osxView window] != nil ) if ( [view window] != nil )
locationInWindow = [[m_osxView window] convertRectFromScreen:locationInWindow]; locationInWindow = [[view window] convertRectFromScreen:locationInWindow];
} }
NSPoint locationInView = [m_osxView convertPoint:locationInWindow.origin fromView:nil]; NSPoint locationInView = [view convertPoint:locationInWindow.origin fromView:nil];
wxPoint locationInViewWX = wxFromNSPoint( m_osxView, locationInView ); wxPoint locationInViewWX = wxFromNSPoint( view, locationInView );
x = locationInViewWX.x; x = locationInViewWX.x;
y = locationInViewWX.y; y = locationInViewWX.y;
} }
void wxWidgetCocoaImpl::SetupCoordinates(wxCoord &x, wxCoord &y, NSEvent* nsEvent)
{
wxSetupCoordinates(m_osxView, x, y, nsEvent);
}
void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent ) void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
{ {
int eventType = [nsEvent type]; int eventType = [nsEvent type];
@@ -1042,6 +1048,71 @@ void wxOSX_insertText(NSView* self, SEL _cmd, NSString* text)
impl->insertText(text, self, _cmd); 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) BOOL wxOSX_performKeyEquivalent(NSView* self, SEL _cmd, NSEvent *event)
{ {
wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
@@ -1428,6 +1499,559 @@ void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
m_lastKeyDownEvent = NULL; m_lastKeyDownEvent = NULL;
} }
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
// Class containing data used for gestures support.
class wxCocoaGesturesImpl
{
public:
wxCocoaGesturesImpl(wxWidgetCocoaImpl* impl, NSView* view, int eventsMask)
: m_win(impl->GetWXPeer()),
m_view(view)
{
m_touchCount = 0;
m_lastTouchTime = 0;
m_allowedGestures = 0;
m_activeGestures = 0;
m_initialTouch = NULL;
Class cls = [m_view class];
if ( eventsMask & wxTOUCH_PAN_GESTURES )
{
eventsMask &= ~wxTOUCH_PAN_GESTURES;
m_panGestureRecognizer =
[[NSPanGestureRecognizer alloc] initWithTarget:m_view action: @selector(handlePanGesture:)];
if ( !class_respondsToSelector(cls, @selector(handlePanGesture:)) )
class_addMethod(cls, @selector(handlePanGesture:), (IMP) wxOSX_panGestureEvent, "v@:@" );
[m_view addGestureRecognizer:m_panGestureRecognizer];
}
else
{
m_panGestureRecognizer = nil;
}
if ( eventsMask & wxTOUCH_ZOOM_GESTURE )
{
eventsMask &= ~wxTOUCH_ZOOM_GESTURE;
m_magnificationGestureRecognizer =
[[NSMagnificationGestureRecognizer alloc] initWithTarget:m_view action: @selector(handleZoomGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleZoomGesture:)) )
class_addMethod(cls, @selector(handleZoomGesture:), (IMP) wxOSX_zoomGestureEvent, "v@:@" );
[m_view addGestureRecognizer:m_magnificationGestureRecognizer];
}
else
{
m_magnificationGestureRecognizer = nil;
}
if ( eventsMask & wxTOUCH_ROTATE_GESTURE )
{
eventsMask &= ~wxTOUCH_ROTATE_GESTURE;
m_rotationGestureRecognizer =
[[NSRotationGestureRecognizer alloc] initWithTarget:m_view action: @selector(handleRotateGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleRotateGesture:)) )
class_addMethod(cls, @selector(handleRotateGesture:), (IMP) wxOSX_rotateGestureEvent, "v@:@" );
[m_view addGestureRecognizer:m_rotationGestureRecognizer];
}
else
{
m_rotationGestureRecognizer = nil;
}
if ( eventsMask & wxTOUCH_PRESS_GESTURES )
{
eventsMask &= ~wxTOUCH_PRESS_GESTURES;
m_pressGestureRecognizer =
[[NSPressGestureRecognizer alloc] initWithTarget:m_view action: @selector(handleLongPressGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleLongPressGesture:)) )
class_addMethod(cls, @selector(handleLongPressGesture:), (IMP) wxOSX_longPressEvent, "v@:@" );
[m_view addGestureRecognizer:m_pressGestureRecognizer];
}
else
{
m_pressGestureRecognizer = nil;
}
wxASSERT_MSG( eventsMask == 0, "Unknown touch event mask bit specified" );
if ( !class_respondsToSelector(cls, @selector(touchesBeganWithEvent:)) )
class_addMethod(cls, @selector(touchesBeganWithEvent:), (IMP) wxOSX_touchesBegan, "v@:@" );
if ( !class_respondsToSelector(cls, @selector(touchesMovedWithEvent:)) )
class_addMethod(cls, @selector(touchesMovedWithEvent:), (IMP) wxOSX_touchesMoved, "v@:@" );
if ( !class_respondsToSelector(cls, @selector(touchesEndedWithEvent:)) )
class_addMethod(cls, @selector(touchesEndedWithEvent:), (IMP) wxOSX_touchesEnded, "v@:@" );
}
~wxCocoaGesturesImpl()
{
[m_panGestureRecognizer release];
[m_magnificationGestureRecognizer release];
[m_rotationGestureRecognizer release];
[m_pressGestureRecognizer release];
[m_initialTouch release];
}
void TouchesBegan(NSEvent* event);
void TouchesMoved(NSEvent* event);
void TouchesEnded(NSEvent* event);
private:
wxWindowMac* const m_win;
NSView* const m_view;
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;
wxDECLARE_NO_COPY_CLASS(wxCocoaGesturesImpl);
};
// We keep all existing wxCocoaGesturesImpl objects in a
// wxWidgetCocoaImpl-indexed map. We do this instead of just having a data
// member containing wxCocoaGesturesImpl pointer in wxWidgetCocoaImpl
// itself because most windows don't need it and it seems wasteful to
// always increase their size unnecessarily.
#include "wx/hashmap.h"
WX_DECLARE_HASH_MAP(wxWidgetCocoaImpl*, wxCocoaGesturesImpl*,
wxPointerHash, wxPointerEqual,
wxCocoaGesturesImplMap);
#include "wx/private/extfield.h"
typedef wxExternalField<wxWidgetCocoaImpl,
wxCocoaGesturesImpl,
wxCocoaGesturesImplMap> wxCocoaGestures;
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 wxPoint s_lastLocation;
if ( gestureState == NSGestureRecognizerStateBegan )
{
wxevent.SetGestureStart();
s_lastLocation = wxPoint(0, 0);
}
if ( gestureState == NSGestureRecognizerStateEnded )
{
wxevent.SetGestureEnd();
}
// Set the offset
wxevent.SetDelta(pt - s_lastLocation);
s_lastLocation = pt;
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)
{
if ( wxCocoaGesturesImpl* gestures = wxCocoaGestures::FromObject(this) )
gestures->TouchesBegan(event);
}
void wxCocoaGesturesImpl::TouchesBegan(NSEvent* event)
{
NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:m_view];
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_view];
// 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)
{
if ( wxCocoaGesturesImpl* gestures = wxCocoaGestures::FromObject(this) )
gestures->TouchesMoved(event);
}
void wxCocoaGesturesImpl::TouchesMoved(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_view];
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(m_win->GetId());
wxevent.SetEventObject(m_win);
// Get the mouse coordinates
wxCoord x, y;
wxSetupCoordinates(m_view, x, y, event);
wxevent.SetPosition(wxPoint (x,y));
m_win->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)
{
if ( wxCocoaGesturesImpl* gestures = wxCocoaGestures::FromObject(this) )
gestures->TouchesEnded(event);
}
void wxCocoaGesturesImpl::TouchesEnded(NSEvent* event)
{
NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:m_view];
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(m_win->GetId());
wxevent.SetEventObject(m_win);
wxevent.SetGestureStart();
wxevent.SetGestureEnd();
// Get the mouse coordinates
wxCoord x, y;
wxSetupCoordinates(m_view, x, y, event);
wxevent.SetPosition(wxPoint (x,y));
m_win->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(m_win->GetId());
wxevent.SetEventObject(m_win);
// Get the mouse coordinates
wxCoord x, y;
wxSetupCoordinates(m_view, 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];
}
m_win->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) void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd)
{ {
bool result = false; bool result = false;
@@ -1775,7 +2399,7 @@ void wxOSXCocoaClassAddWXMethods(Class c)
wxOSX_CLASS_ADD_METHOD(c, @selector(scrollWheel:), (IMP) wxOSX_mouseEvent, "v@:@" ) 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(mouseEntered:), (IMP) wxOSX_mouseEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(mouseExited:), (IMP) wxOSX_mouseEvent, "v@:@" ) wxOSX_CLASS_ADD_METHOD(c, @selector(mouseExited:), (IMP) wxOSX_mouseEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(magnifyWithEvent:), (IMP)wxOSX_mouseEvent, "v@:@") wxOSX_CLASS_ADD_METHOD(c, @selector(magnifyWithEvent:), (IMP)wxOSX_mouseEvent, "v@:@")
wxOSX_CLASS_ADD_METHOD(c, @selector(cursorUpdate:), (IMP) wxOSX_cursorUpdate, "v@:@" ) wxOSX_CLASS_ADD_METHOD(c, @selector(cursorUpdate:), (IMP) wxOSX_cursorUpdate, "v@:@" )
@@ -1875,6 +2499,10 @@ wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
// gc aware handling // gc aware handling
if ( m_osxView ) if ( m_osxView )
CFRelease(m_osxView); CFRelease(m_osxView);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
wxCocoaGestures::EraseForObject(this);
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
} }
bool wxWidgetCocoaImpl::IsVisible() const bool wxWidgetCocoaImpl::IsVisible() const
@@ -2791,7 +3419,42 @@ void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control )
NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil]; NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil];
[m_osxView addTrackingArea: area]; [m_osxView addTrackingArea: area];
[area release]; [area release];
} }
bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
if ( wxPlatformInfo::Get().CheckOSVersion(10, 10) )
{
if ( IsUserPane() )
{
if ( eventsMask == wxTOUCH_NONE )
{
if ( wxCocoaGestures::EraseForObject(this) )
{
[m_osxView setAcceptsTouchEvents:NO];
}
//else: we didn't have any gesture data anyhow
}
else // We do want to have gesture events.
{
wxCocoaGestures::StoreForObject
(
this,
new wxCocoaGesturesImpl(this, m_osxView, eventsMask)
);
[m_osxView setAcceptsTouchEvents:YES];
}
return true;
}
}
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
wxUnusedVar(eventsMask);
return false;
}
bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text) bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text)
{ {

View File

@@ -1429,6 +1429,11 @@ void wxWindowMac::WarpPointer(int x_pos, int y_pos)
#endif #endif
} }
bool wxWindowMac::EnableTouchEvents(int eventsMask)
{
return GetPeer() ? GetPeer()->EnableTouchEvents(eventsMask) : false;
}
int wxWindowMac::GetScrollPos(int orient) const int wxWindowMac::GetScrollPos(int orient) const
{ {
#if wxUSE_SCROLLBAR #if wxUSE_SCROLLBAR