Allow enabling individual touch gesture events

Implement support for enabling just some gesture events instead of
having to choose between getting none or all of them.

Also make wxTOUCH_NONE really disable the gestures events generation
instead of just doing nothing as before.
This commit is contained in:
Vadim Zeitlin
2017-11-21 22:46:56 +01:00
parent 842dd1cfd9
commit a8dfaa569b
5 changed files with 356 additions and 87 deletions

View File

@@ -136,8 +136,15 @@ enum wxShowEffect
// Values for EnableTouchEvents() mask.
enum
{
wxTOUCH_NONE = 0x0000,
wxTOUCH_ALL_GESTURES = 0x00ff
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()

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()
*/
@@ -3427,6 +3489,15 @@ public:
/**
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.

View File

@@ -238,7 +238,7 @@ static bool gs_inSizeAllocate;
class wxWindowGesturesData
{
public:
wxWindowGesturesData(wxWindow* win, GtkWidget *widget);
wxWindowGesturesData(wxWindow* win, GtkWidget *widget, int eventsMask);
~wxWindowGesturesData();
unsigned int m_touchCount;
@@ -3344,7 +3344,9 @@ touch_callback(GtkWidget* WXUNUSED(widget), GdkEventTouch* gdk_event, wxWindowGT
}
}
wxWindowGesturesData::wxWindowGesturesData(wxWindowGTK* win, GtkWidget *widget)
wxWindowGesturesData::wxWindowGesturesData(wxWindowGTK* win,
GtkWidget *widget,
int eventsMask)
{
m_touchCount = 0;
m_lastTouchTime = 0;
@@ -3353,84 +3355,137 @@ wxWindowGesturesData::wxWindowGesturesData(wxWindowGTK* win, GtkWidget *widget)
m_activeGestures = 0;
m_touchSequence = NULL;
m_vertical_pan_gesture = gtk_gesture_pan_new(widget, GTK_ORIENTATION_VERTICAL);
if ( eventsMask & wxTOUCH_VERTICAL_PAN_GESTURE )
{
eventsMask &= ~wxTOUCH_VERTICAL_PAN_GESTURE;
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_vertical_pan_gesture), GTK_PHASE_TARGET);
m_vertical_pan_gesture = gtk_gesture_pan_new(widget, GTK_ORIENTATION_VERTICAL);
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);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_vertical_pan_gesture), GTK_PHASE_TARGET);
m_horizontal_pan_gesture = gtk_gesture_pan_new(widget, GTK_ORIENTATION_HORIZONTAL);
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;
}
// 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.
if ( eventsMask & wxTOUCH_HORIZONTAL_PAN_GESTURE )
{
eventsMask &= ~wxTOUCH_HORIZONTAL_PAN_GESTURE;
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_horizontal_pan_gesture), GTK_PHASE_TARGET);
m_horizontal_pan_gesture = gtk_gesture_pan_new(widget, GTK_ORIENTATION_HORIZONTAL);
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);
// 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.
m_zoom_gesture = gtk_gesture_zoom_new(widget);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_horizontal_pan_gesture), GTK_PHASE_TARGET);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_zoom_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;
}
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);
if ( eventsMask & wxTOUCH_ZOOM_GESTURE )
{
eventsMask &= ~wxTOUCH_ZOOM_GESTURE;
m_rotate_gesture = gtk_gesture_rotate_new(widget);
m_zoom_gesture = gtk_gesture_zoom_new(widget);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_rotate_gesture), GTK_PHASE_TARGET);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER(m_zoom_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);
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;
}
m_long_press_gesture = gtk_gesture_long_press_new(widget);
if ( eventsMask & wxTOUCH_ROTATE_GESTURE )
{
eventsMask &= ~wxTOUCH_ROTATE_GESTURE;
// "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.
m_rotate_gesture = gtk_gesture_rotate_new(widget);
gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(m_long_press_gesture), GTK_PHASE_TARGET);
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" );
g_signal_connect (m_long_press_gesture, "pressed",
G_CALLBACK(long_press_gesture_callback), win);
g_signal_connect (widget, "touch-event",
G_CALLBACK(touch_callback), win);
}
wxWindowGesturesData::~wxWindowGesturesData()
{
g_object_unref(m_vertical_pan_gesture);
g_object_unref(m_horizontal_pan_gesture);
g_object_unref(m_zoom_gesture);
g_object_unref(m_rotate_gesture);
g_object_unref(m_long_press_gesture);
if ( m_vertical_pan_gesture )
g_object_unref(m_vertical_pan_gesture);
if ( m_horizontal_pan_gesture )
g_object_unref(m_horizontal_pan_gesture);
if ( m_zoom_gesture )
g_object_unref(m_zoom_gesture);
if ( m_rotate_gesture )
g_object_unref(m_rotate_gesture);
if ( m_long_press_gesture )
g_object_unref(m_long_press_gesture);
}
#endif // wxGTK_HAS_GESTURES_SUPPORT
@@ -3445,7 +3500,21 @@ bool wxWindowGTK::EnableTouchEvents(int eventsMask)
// Check if gestures support is also available during run-time.
if ( gtk_check_version(3, 14, 0) == NULL )
{
m_gesturesData = new wxWindowGesturesData(this, GetConnectWidget());
if ( eventsMask == wxTOUCH_NONE )
{
delete m_gesturesData;
m_gesturesData = NULL;
}
else
{
m_gesturesData = new wxWindowGesturesData
(
this,
GetConnectWidget(),
eventsMask
);
}
return true;
}
#endif // wxGTK_HAS_GESTURES_SUPPORT

View File

@@ -51,6 +51,7 @@
#include "wx/textctrl.h"
#include "wx/menuitem.h"
#include "wx/module.h"
#include "wx/vector.h"
#endif
#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
@@ -909,17 +910,105 @@ void wxWindowMSW::WarpPointer(int x, int y)
bool wxWindowMSW::EnableTouchEvents(int eventsMask)
{
#ifdef WM_GESTURE
if ( GestureFuncs::IsOk() && eventsMask == wxTOUCH_ALL_GESTURES )
if ( GestureFuncs::IsOk() )
{
// Configure to receive all gestures
GESTURECONFIG gestureConfig = {0, GC_ALLGESTURES, 0};
// 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.
1, // Number of gesture configurations.
&gestureConfig, // Pointer to the first one.
numConfigs, // Number of gesture configurations.
ptrConfigs, // Pointer to the first one.
sizeof(GESTURECONFIG) // Size of each configuration.
)
)

View File

@@ -3293,27 +3293,65 @@ bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask)
{
if ( IsUserPane() )
{
if ( eventsMask == wxTOUCH_NONE )
{
[m_panGestureRecognizer release];
[m_magnificationGestureRecognizer release];
[m_rotationGestureRecognizer release];
[m_pressGestureRecognizer release];
[m_osxView setAcceptsTouchEvents:NO];
return true;
}
Class cls = [m_osxView class];
m_panGestureRecognizer =
[[NSPanGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handlePanGesture:)];
if ( !class_respondsToSelector(cls, @selector(handlePanGesture:)) )
class_addMethod(cls, @selector(handlePanGesture:), (IMP) wxOSX_panGestureEvent, "v@:@" );
if ( eventsMask & wxTOUCH_PAN_GESTURES )
{
eventsMask &= ~wxTOUCH_PAN_GESTURES;
m_magnificationGestureRecognizer =
[[NSMagnificationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleZoomGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleZoomGesture:)) )
class_addMethod(cls, @selector(handleZoomGesture:), (IMP) wxOSX_zoomGestureEvent, "v@:@" );
m_panGestureRecognizer =
[[NSPanGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handlePanGesture:)];
if ( !class_respondsToSelector(cls, @selector(handlePanGesture:)) )
class_addMethod(cls, @selector(handlePanGesture:), (IMP) wxOSX_panGestureEvent, "v@:@" );
[m_osxView addGestureRecognizer:m_panGestureRecognizer];
}
m_rotationGestureRecognizer =
[[NSRotationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleRotateGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleRotateGesture:)) )
class_addMethod(cls, @selector(handleRotateGesture:), (IMP) wxOSX_rotateGestureEvent, "v@:@" );
if ( eventsMask & wxTOUCH_ZOOM_GESTURE )
{
eventsMask &= ~wxTOUCH_ZOOM_GESTURE;
m_pressGestureRecognizer =
[[NSPressGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleLongPressGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleLongPressGesture:)) )
class_addMethod(cls, @selector(handleLongPressGesture:), (IMP) wxOSX_longPressEvent, "v@:@" );
m_magnificationGestureRecognizer =
[[NSMagnificationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleZoomGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleZoomGesture:)) )
class_addMethod(cls, @selector(handleZoomGesture:), (IMP) wxOSX_zoomGestureEvent, "v@:@" );
[m_osxView addGestureRecognizer:m_magnificationGestureRecognizer];
}
if ( eventsMask & wxTOUCH_ROTATE_GESTURE )
{
eventsMask &= ~wxTOUCH_ROTATE_GESTURE;
m_rotationGestureRecognizer =
[[NSRotationGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleRotateGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleRotateGesture:)) )
class_addMethod(cls, @selector(handleRotateGesture:), (IMP) wxOSX_rotateGestureEvent, "v@:@" );
[m_osxView addGestureRecognizer:m_rotationGestureRecognizer];
}
if ( eventsMask & wxTOUCH_PRESS_GESTURES )
{
eventsMask &= ~wxTOUCH_PRESS_GESTURES;
m_pressGestureRecognizer =
[[NSPressGestureRecognizer alloc] initWithTarget:m_osxView action: @selector(handleLongPressGesture:)];
if ( !class_respondsToSelector(cls, @selector(handleLongPressGesture:)) )
class_addMethod(cls, @selector(handleLongPressGesture:), (IMP) wxOSX_longPressEvent, "v@:@" );
[m_osxView addGestureRecognizer:m_pressGestureRecognizer];
}
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@:@" );
@@ -3322,11 +3360,6 @@ bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask)
if ( !class_respondsToSelector(cls, @selector(touchesEndedWithEvent:)) )
class_addMethod(cls, @selector(touchesEndedWithEvent:), (IMP) wxOSX_touchesEnded, "v@:@" );
[m_osxView addGestureRecognizer:m_panGestureRecognizer];
[m_osxView addGestureRecognizer:m_magnificationGestureRecognizer];
[m_osxView addGestureRecognizer:m_rotationGestureRecognizer];
[m_osxView addGestureRecognizer:m_pressGestureRecognizer];
[m_osxView setAcceptsTouchEvents:YES];
return true;