Introduce QWheelEvent::Phase (Begin, Changed, Ended)

Some platforms (read: OS X) send wheel events without delta to indicate
that scrolling is about to start or has ended. Currently, Qt simply
ignores wheel events that have no delta. This change introduces a new
QWheelEvent attribute that specifies the phase, and makes it possible
to receive the special wheel events in started/ended phases. These
events are required for implementing correctly behaving transient
scrollbars.

Change-Id: Ib8ce0d9ce9be63b2ad60aa7b0aaa1f12ef6cad09
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
J-P Nurmi 2013-08-05 13:34:33 +02:00 committed by The Qt Project
parent d916ed12b3
commit 9dfe4b0e68
7 changed files with 83 additions and 16 deletions

View File

@ -654,6 +654,9 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta
event data: \a qt4Delta specifies the rotation, and \a qt4Orientation the
direction.
The phase() is initialized to QWheelEvent::Changed. Use the other constructor
to specify the phase explicitly.
\sa posF(), globalPosF(), angleDelta(), pixelDelta()
*/
@ -661,9 +664,38 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
: QInputEvent(Wheel, modifiers), p(pos), g(globalPos), pixelD(pixelDelta),
angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons)
angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons), ph(Changed)
{}
/*!
Constructs a wheel event object.
The \a pos provides the location of the mouse cursor
within the window. The position in global coordinates is specified
by \a globalPos.
\a pixelDelta contains the scrolling distance in pixels on screen, while
\a angleDelta contains the wheel rotation distance. \a pixelDelta is
optional and can be null.
The mouse and keyboard states at the time of the event are specified by
\a buttons and \a modifiers.
For backwards compatibility, the event can also hold monodirectional wheel
event data: \a qt4Delta specifies the rotation, and \a qt4Orientation the
direction.
The phase of the event is specified by \a phase.
\sa posF(), globalPosF(), angleDelta(), pixelDelta(), phase()
*/
QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Phase phase)
: QInputEvent(Wheel, modifiers), p(pos), g(globalPos), pixelD(pixelDelta),
angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons), ph(phase)
{}
#endif // QT_NO_WHEELEVENT
@ -794,6 +826,28 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
\sa posF()
*/
/*!
\enum QWheelEvent::Phase
\since 5.2
This enum describes the phase of a wheel event.
\value Started Scrolling has started, but the scrolling
distance did not yet change.
\value Changed The scrolling distance has changed (default).
\value Ended Scrolling has ended, but the scrolling distance
did not change anymore.
*/
/*!
\fn QWheelEvent::Phase QWheelEvent::phase() const
\since 5.2
Returns the phase of this wheel event.
*/
/*!
\class QKeyEvent

View File

@ -167,6 +167,8 @@ protected:
class Q_GUI_EXPORT QWheelEvent : public QInputEvent
{
public:
enum Phase { Started, Changed, Ended };
QWheelEvent(const QPointF &pos, int delta,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
Qt::Orientation orient = Qt::Vertical);
@ -176,6 +178,9 @@ public:
QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Phase phase);
~QWheelEvent();
@ -198,6 +203,9 @@ public:
inline const QPointF &globalPosF() const { return g; }
inline Qt::MouseButtons buttons() const { return mouseState; }
inline Phase phase() const { return Phase(ph); }
protected:
QPointF p;
QPointF g;
@ -206,7 +214,8 @@ protected:
int qt4D;
Qt::Orientation qt4O;
Qt::MouseButtons mouseState;
int reserved;
uint ph : 2;
int reserved : 30;
};
#endif

View File

@ -1636,7 +1636,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
return;
}
QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers);
QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers, e->phase);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev);
#endif /* ifndef QT_NO_WHEELEVENT */

View File

@ -298,13 +298,13 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
handleWheelEvent(tlw, timestamp, local, global, QPoint(), point, mods);
}
void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods)
void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, QWheelEvent::Phase phase)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
handleWheelEvent(w, time, local, global, pixelDelta, angleDelta, mods);
handleWheelEvent(w, time, local, global, pixelDelta, angleDelta, mods, phase);
}
void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods)
void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, QWheelEvent::Phase phase)
{
// Qt 4 sends two separate wheel events for horizontal and vertical
// deltas. For Qt 5 we want to send the deltas in one event, but at the
@ -315,19 +315,21 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
// Angle deltas must always be sent in addition to pixel deltas.
QWindowSystemInterfacePrivate::WheelEvent *e;
if (angleDelta.isNull())
// Pass QWheelEvent::Started and QWheelEvent::Ended through
// even if the wheel delta is null.
if (angleDelta.isNull() && phase == QWheelEvent::Changed)
return;
// Simple case: vertical deltas only:
if (angleDelta.y() != 0 && angleDelta.x() == 0) {
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods);
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
return;
}
// Simple case: horizontal deltas only:
if (angleDelta.y() == 0 && angleDelta.x() != 0) {
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods);
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
return;
}
@ -335,12 +337,12 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
// Both horizontal and vertical deltas: Send two wheel events.
// The first event contains the Qt 5 pixel and angle delta as points,
// and in addition the Qt 4 compatibility vertical angle delta.
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods);
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
// The second event contains null pixel and angle points and the
// Qt 4 compatibility horizontal angle delta.
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods);
e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}

View File

@ -61,6 +61,7 @@
#include <QtGui/QTouchEvent>
#include <QtCore/QEventLoop>
#include <QtGui/QVector2D>
#include <QtGui/QWheelEvent>
QT_BEGIN_NAMESPACE
@ -103,8 +104,8 @@ public:
quint32 nativeModifiers,
const QString& text = QString(), bool autorep = false,
ushort count = 1);
static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier);
static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier);
static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, QWheelEvent::Phase phase = QWheelEvent::Changed);
static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods = Qt::NoModifier, QWheelEvent::Phase phase = QWheelEvent::Changed);
// Wheel event compatibility functions. Will be removed: do not use.
static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);

View File

@ -217,14 +217,15 @@ public:
class WheelEvent : public InputEvent {
public:
WheelEvent(QWindow *w, ulong time, const QPointF & local, const QPointF & global, QPoint pixelD, QPoint angleD, int qt4D, Qt::Orientation qt4O,
Qt::KeyboardModifiers mods)
: InputEvent(w, time, Wheel, mods), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D), qt4Orientation(qt4O), localPos(local), globalPos(global) { }
Qt::KeyboardModifiers mods, QWheelEvent::Phase phase = QWheelEvent::Changed)
: InputEvent(w, time, Wheel, mods), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D), qt4Orientation(qt4O), localPos(local), globalPos(global), phase(phase) { }
QPoint pixelDelta;
QPoint angleDelta;
int qt4Delta;
Qt::Orientation qt4Orientation;
QPointF localPos;
QPointF globalPos;
QWheelEvent::Phase phase;
};
class KeyEvent : public InputEvent {

View File

@ -558,7 +558,7 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
QPoint mapped = widget->mapFrom(m_widget, event->pos());
QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers());
QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers(), event->phase());
QGuiApplication::sendSpontaneousEvent(widget, &translated);
}