summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-08-05 16:57:25 (GMT)
committerDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-08-10 12:21:44 (GMT)
commit6826490774d66e0470fc1e5848ab89b3a0d0bb86 (patch)
tree553656766c1625ca837e3d07f59f77e6f3461ace /src
parent47f58dfad1eb7fe61a523597023df33f3d320377 (diff)
downloadQt-6826490774d66e0470fc1e5848ab89b3a0d0bb86.zip
Qt-6826490774d66e0470fc1e5848ab89b3a0d0bb86.tar.gz
Qt-6826490774d66e0470fc1e5848ab89b3a0d0bb86.tar.bz2
Implemented QPinchGesture.
Added a new standard gesture, which is implemented using a native zoom and rotate gestures on Windows and with a direct touch event handling on other platforms. Improved pan support - we subscribe to native pan gesture only when it's really needed, and we pass proper flags for single finger horizontal/vertical panning. Reviewed-by: Richard Moe Gustavsen
Diffstat (limited to 'src')
-rw-r--r--src/gui/kernel/qapplication_p.h3
-rw-r--r--src/gui/kernel/qapplication_win.cpp21
-rw-r--r--src/gui/kernel/qevent_p.h5
-rw-r--r--src/gui/kernel/qstandardgestures.cpp210
-rw-r--r--src/gui/kernel/qstandardgestures.h39
-rw-r--r--src/gui/kernel/qstandardgestures_p.h25
-rw-r--r--src/gui/kernel/qwidget_win.cpp40
7 files changed, 316 insertions, 27 deletions
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index c4ce2ea..9953907 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -235,6 +235,7 @@ typedef struct tagGESTUREINFO
# define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004
# define GC_ZOOM 0x00000001
+# define GC_ROTATE 0x00000001
typedef struct tagGESTURECONFIG
{
@@ -243,6 +244,8 @@ typedef struct tagGESTURECONFIG
DWORD dwBlock;
} GESTURECONFIG;
+# define GID_ROTATE_ANGLE_FROM_ARGUMENT(arg) ((((double)(arg) / 65535.0) * 4.0 * 3.14159265) - 2.0*3.14159265)
+
#endif // WM_GESTURE
#endif // Q_WS_WIN
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index bdee6ec..cb67409 100644
--- a/src/gui/kernel/qapplication_win.cpp
+++ b/src/gui/kernel/qapplication_win.cpp
@@ -3721,17 +3721,18 @@ bool QETWidget::translateGestureEvent(const MSG &msg)
QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal();
BOOL bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi);
+ if (bResult) {
+ const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
+ QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
+ if (alienWidget && alienWidget->internalWinId())
+ alienWidget = 0;
+ QWidget *widget = alienWidget ? alienWidget : this;
- const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
- QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos);
- if (alienWidget && alienWidget->internalWinId())
- alienWidget = 0;
- QWidget *widget = alienWidget ? alienWidget : this;
+ QNativeGestureEvent event;
+ event.sequenceId = gi.dwSequenceID;
+ event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
+ event.argument = gi.ullArguments;
- QNativeGestureEvent event;
- event.sequenceId = gi.dwSequenceID;
- event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
- if (bResult) {
switch (gi.dwID) {
case GID_BEGIN:
event.gestureType = QNativeGestureEvent::GestureBegin;
@@ -3746,6 +3747,8 @@ bool QETWidget::translateGestureEvent(const MSG &msg)
event.gestureType = QNativeGestureEvent::Pan;
break;
case GID_ROTATE:
+ event.gestureType = QNativeGestureEvent::Rotate;
+ break;
case GID_TWOFINGERTAP:
case GID_ROLLOVER:
default:
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index b21b35c..2ff672b 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -133,9 +133,9 @@ public:
};
QNativeGestureEvent()
- : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0), direction(0, 0)
+ : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0)
#ifdef Q_WS_WIN
- , sequenceId(0)
+ , sequenceId(0), argument(0)
#endif
{
}
@@ -146,6 +146,7 @@ public:
QSize direction;
#ifdef Q_WS_WIN
ulong sequenceId;
+ quint64 argument;
#endif
};
diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp
index 7078dbf..ac03cd2 100644
--- a/src/gui/kernel/qstandardgestures.cpp
+++ b/src/gui/kernel/qstandardgestures.cpp
@@ -132,8 +132,7 @@ bool QPanGesture::eventFilter(QObject *receiver, QEvent *event)
it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver));
if (it == qAppPriv->widgetGestures.end())
return false;
- QPanGesture *gesture = it.value().pan;
- if (this != gesture)
+ if (this != it.value().pan)
return false;
Qt::GestureState nextState = Qt::NoGesture;
switch(ev->gestureType) {
@@ -162,7 +161,7 @@ bool QPanGesture::eventFilter(QObject *receiver, QEvent *event)
d->totalOffset += d->lastOffset;
}
d->lastPosition = ev->position;
- gesture->updateState(nextState);
+ updateState(nextState);
return true;
}
#endif
@@ -248,6 +247,7 @@ void QPanGesture::reset()
d->panFinishedTimer = 0;
}
#endif
+ QGesture::reset();
}
/*!
@@ -273,6 +273,210 @@ QSize QPanGesture::lastOffset() const
return d->lastOffset;
}
+
+/*!
+ \class QPinchGesture
+ \since 4.6
+
+ \brief The QPinchGesture class represents a Pinch gesture,
+ providing additional information related to zooming and/or rotation.
+*/
+
+/*!
+ Creates a new Pinch gesture handler object and marks it as a child of \a
+ parent.
+
+ On some platform like Windows it's necessary to provide a non-null widget
+ as \a parent to get native gesture support.
+*/
+QPinchGesture::QPinchGesture(QWidget *parent)
+ : QGesture(*new QPinchGesturePrivate, parent)
+{
+ if (parent) {
+ QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal();
+ qAppPriv->widgetGestures[parent].pinch = this;
+#ifdef Q_WS_WIN
+ qt_widget_private(parent)->winSetupGestures();
+#endif
+ }
+}
+
+/*! \internal */
+bool QPinchGesture::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::ParentAboutToChange:
+ if (QWidget *w = qobject_cast<QWidget*>(parent())) {
+ getQApplicationPrivateInternal()->widgetGestures[w].pinch = 0;
+#ifdef Q_WS_WIN
+ qt_widget_private(w)->winSetupGestures();
+#endif
+ }
+ break;
+ case QEvent::ParentChange:
+ if (QWidget *w = qobject_cast<QWidget*>(parent())) {
+ getQApplicationPrivateInternal()->widgetGestures[w].pinch = this;
+#ifdef Q_WS_WIN
+ qt_widget_private(w)->winSetupGestures();
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+ return QObject::event(event);
+}
+
+bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event)
+{
+#ifdef Q_WS_WIN
+ Q_D(QPinchGesture);
+ if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) {
+ QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
+ QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal();
+ QApplicationPrivate::WidgetStandardGesturesMap::iterator it;
+ it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver));
+ if (it == qAppPriv->widgetGestures.end())
+ return false;
+ if (this != it.value().pinch)
+ return false;
+ Qt::GestureState nextState = Qt::NoGesture;
+ switch(ev->gestureType) {
+ case QNativeGestureEvent::GestureBegin:
+ // next we might receive the first gesture update event, so we
+ // prepare for it.
+ d->state = Qt::NoGesture;
+ d->scaleFactor = d->lastScaleFactor = 1;
+ d->rotationAngle = d->lastRotationAngle = 0;
+ d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPoint();
+ d->initialDistance = 0;
+ return false;
+ case QNativeGestureEvent::Rotate:
+ d->lastRotationAngle = d->rotationAngle;
+ d->rotationAngle = -1 * GID_ROTATE_ANGLE_FROM_ARGUMENT(ev->argument);
+ nextState = Qt::GestureUpdated;
+ event->accept();
+ break;
+ case QNativeGestureEvent::Zoom:
+ if (d->initialDistance != 0) {
+ d->lastScaleFactor = d->scaleFactor;
+ int distance = int(qint64(ev->argument));
+ d->scaleFactor = (qreal) distance / d->initialDistance;
+ } else {
+ d->initialDistance = int(qint64(ev->argument));
+ }
+ nextState = Qt::GestureUpdated;
+ event->accept();
+ break;
+ case QNativeGestureEvent::GestureEnd:
+ if (state() == Qt::NoGesture)
+ return false; // some other gesture has ended
+ nextState = Qt::GestureFinished;
+ break;
+ default:
+ return false;
+ }
+ if (d->startCenterPoint.isNull())
+ d->startCenterPoint = d->centerPoint;
+ d->lastCenterPoint = d->centerPoint;
+ d->centerPoint = static_cast<QWidget*>(receiver)->mapFromGlobal(ev->position);
+ updateState(nextState);
+ return true;
+ }
+#endif
+ return QGesture::eventFilter(receiver, event);
+}
+
+/*! \internal */
+bool QPinchGesture::filterEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+ return false;
+}
+
+/*! \internal */
+void QPinchGesture::reset()
+{
+ Q_D(QPinchGesture);
+ d->scaleFactor = d->lastScaleFactor = 0;
+ d->rotationAngle = d->lastRotationAngle = 0;
+ d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPoint();
+ QGesture::reset();
+}
+
+/*!
+ \property QPinchGesture::scaleFactor
+
+ Specifies a scale factor of the pinch gesture.
+*/
+qreal QPinchGesture::scaleFactor() const
+{
+ return d_func()->scaleFactor;
+}
+
+/*!
+ \property QPinchGesture::lastScaleFactor
+
+ Specifies a previous scale factor of the pinch gesture.
+*/
+qreal QPinchGesture::lastScaleFactor() const
+{
+ return d_func()->lastScaleFactor;
+}
+
+/*!
+ \property QPinchGesture::rotationAngle
+
+ Specifies a rotation angle of the gesture.
+*/
+qreal QPinchGesture::rotationAngle() const
+{
+ return d_func()->rotationAngle;
+}
+
+/*!
+ \property QPinchGesture::lastRotationAngle
+
+ Specifies a previous rotation angle of the gesture.
+*/
+qreal QPinchGesture::lastRotationAngle() const
+{
+ return d_func()->lastRotationAngle;
+}
+
+/*!
+ \property QPinchGesture::centerPoint
+
+ Specifies a center point of the gesture. The point can be used as a center
+ point that the object is rotated around.
+*/
+QPoint QPinchGesture::centerPoint() const
+{
+ return d_func()->centerPoint;
+}
+
+/*!
+ \property QPinchGesture::lastCenterPoint
+
+ Specifies a previous center point of the gesture.
+*/
+QPoint QPinchGesture::lastCenterPoint() const
+{
+ return d_func()->lastCenterPoint;
+}
+
+/*!
+ \property QPinchGesture::startCenterPoint
+
+ Specifies an initial center point of the gesture. Difference between the
+ startCenterPoint and the centerPoint is the distance at which pinching
+ fingers has shifted.
+*/
+QPoint QPinchGesture::startCenterPoint() const
+{
+ return d_func()->startCenterPoint;
+}
+
QT_END_NAMESPACE
#include "moc_qstandardgestures.cpp"
diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h
index 03a1374..adee740 100644
--- a/src/gui/kernel/qstandardgestures.h
+++ b/src/gui/kernel/qstandardgestures.h
@@ -80,6 +80,45 @@ private:
friend class QWidget;
};
+class QPinchGesturePrivate;
+class Q_GUI_EXPORT QPinchGesture : public QGesture
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPinchGesture)
+
+ Q_PROPERTY(qreal scaleFactor READ scaleFactor)
+ Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor)
+
+ Q_PROPERTY(qreal rotationAngle READ rotationAngle)
+ Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle)
+
+ Q_PROPERTY(QPoint startCenterPoint READ startCenterPoint)
+ Q_PROPERTY(QPoint lastCenterPoint READ lastCenterPoint)
+ Q_PROPERTY(QPoint centerPoint READ centerPoint)
+
+public:
+ QPinchGesture(QWidget *parent);
+
+ bool filterEvent(QEvent *event);
+ void reset();
+
+ QPoint startCenterPoint() const;
+ QPoint lastCenterPoint() const;
+ QPoint centerPoint() const;
+
+ qreal scaleFactor() const;
+ qreal lastScaleFactor() const;
+
+ qreal rotationAngle() const;
+ qreal lastRotationAngle() const;
+
+private:
+ bool event(QEvent *event);
+ bool eventFilter(QObject *receiver, QEvent *event);
+
+ friend class QWidget;
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h
index 0fe24ee..43636d0 100644
--- a/src/gui/kernel/qstandardgestures_p.h
+++ b/src/gui/kernel/qstandardgestures_p.h
@@ -85,6 +85,31 @@ public:
#endif
};
+class QPinchGesturePrivate : public QGesturePrivate
+{
+ Q_DECLARE_PUBLIC(QPinchGesture)
+
+public:
+ QPinchGesturePrivate()
+ : scaleFactor(0), lastScaleFactor(0),
+ rotationAngle(0), lastRotationAngle(0)
+#ifdef Q_WS_WIN
+ ,initialDistance(0)
+#endif
+ {
+ }
+ qreal scaleFactor;
+ qreal lastScaleFactor;
+ qreal rotationAngle;
+ qreal lastRotationAngle;
+ QPoint startCenterPoint;
+ QPoint lastCenterPoint;
+ QPoint centerPoint;
+#ifdef Q_WS_WIN
+ int initialDistance;
+#endif
+};
+
QT_END_NAMESPACE
#endif // QSTANDARDGESTURES_P_H
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 7cfa111..510df7f 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -1160,6 +1160,8 @@ void QWidgetPrivate::show_sys()
data.window_state |= Qt::WindowMaximized;
}
+ winSetupGestures();
+
invalidateBuffer(q->rect());
}
#endif //Q_WS_WINCE
@@ -2058,8 +2060,11 @@ void QWidgetPrivate::winSetupGestures()
Q_Q(QWidget);
if (!q)
return;
- extern QApplicationPrivate* getQApplicationPrivateInternal();
- QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal();
+ q->setAttribute(Qt::WA_DontCreateNativeAncestors);
+ q->setAttribute(Qt::WA_NativeWindow);
+ if (!q->isVisible())
+ return;
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
bool needh = false;
bool needv = false;
bool singleFingerPanEnabled = false;
@@ -2072,34 +2077,43 @@ void QWidgetPrivate::winSetupGestures()
QScrollBar *vbar = asa->verticalScrollBar();
Qt::ScrollBarPolicy hbarpolicy = asa->horizontalScrollBarPolicy();
Qt::ScrollBarPolicy vbarpolicy = asa->verticalScrollBarPolicy();
- needh = (hbarpolicy == Qt::ScrollBarAlwaysOn
- || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum()));
- needv = (vbarpolicy == Qt::ScrollBarAlwaysOn
- || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum()));
+ needh = (hbarpolicy == Qt::ScrollBarAlwaysOn ||
+ (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum()));
+ needv = (vbarpolicy == Qt::ScrollBarAlwaysOn ||
+ (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum()));
singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled;
} else {
winid = q->winId();
}
if (qAppPriv->SetGestureConfig) {
- GESTURECONFIG gc[2];
+ GESTURECONFIG gc[3];
+ memset(gc, 0, sizeof(gc));
gc[0].dwID = GID_PAN;
- if (gestures.pan || needh || needv) {
+ if (gestures.pan) {
gc[0].dwWant = GC_PAN;
- gc[0].dwBlock = 0;
if (needv && singleFingerPanEnabled)
gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
+ else
+ gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
if (needh && singleFingerPanEnabled)
gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
+ else
+ gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
} else {
- gc[0].dwWant = 0;
gc[0].dwBlock = GC_PAN;
}
gc[1].dwID = GID_ZOOM;
- if (gestures.pinch) {
+ if (gestures.pinch)
gc[1].dwWant = GC_ZOOM;
- gc[1].dwBlock = 0;
- }
+ else
+ gc[1].dwBlock = GC_ZOOM;
+ gc[2].dwID = GID_ROTATE;
+ if (gestures.pinch)
+ gc[2].dwWant = GC_ROTATE;
+ else
+ gc[2].dwBlock = GC_ROTATE;
+
Q_ASSERT(winid);
qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0]));
}