QWheelEvent high-resolution delta support.
authorMorten Johan Sorvig <morten.sorvig@nokia.com>
Mon, 9 Jan 2012 10:25:40 +0000 (11:25 +0100)
committerQt by Nokia <qt-info@nokia.com>
Fri, 24 Feb 2012 13:55:06 +0000 (14:55 +0100)
Support pixel-based deltas as well as sending
dx and dy values in the same event. Keep source and
behavior compatibility with Qt 4.

New API:
QPoint pixelDelta() const
QPoint angleDelta() const

Deprecate delta() and orientation().

Both pixel-based deltas and combined updates are
necessary for smooth trackpad-based scrolling on
OS X.

Qt 4 compatible behavior is achieved by sending an
extra wheel event in cases where the initial event
has a combined dx and dy update. This extra event
sends dx in delta() and orientation(), with pixelDelta()
and angleDelta() set to null.

Modify the Cocoa implementation to provide pixel
deltas. It is expected that not all platforms can
provide these. Angle deltas will always be available.

Change-Id: I20c10f0df338ddcd6a3f7a4d40949ed5ae3b4795
Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
14 files changed:
doc/src/snippets/code/src_gui_kernel_qevent.cpp
src/gui/kernel/qevent.cpp
src/gui/kernel/qevent.h
src/gui/kernel/qguiapplication.cpp
src/gui/kernel/qwindowsysteminterface_qpa.cpp
src/gui/kernel/qwindowsysteminterface_qpa.h
src/gui/kernel/qwindowsysteminterface_qpa_p.h
src/plugins/platforms/cocoa/qnsview.mm
src/widgets/kernel/qapplication.cpp
src/widgets/kernel/qwidgetwindow_qpa.cpp
tests/manual/cocoa/wheelevent/main.cpp [new file with mode: 0644]
tests/manual/cocoa/wheelevent/wheelevent.pro [new file with mode: 0644]
tests/manual/cocoa/wheelevent/window.cpp [new file with mode: 0644]
tests/manual/cocoa/wheelevent/window.h [new file with mode: 0644]

index 35c5333..d8bdeeb 100644 (file)
 //! [0]
 void MyWidget::wheelEvent(QWheelEvent *event)
 {
-    int numDegrees = event->delta() / 8;
-    int numSteps = numDegrees / 15;
+    QPoint numPixels = envent->pixelDelta();
+    QPoint numDegrees = envent->angleDelta() / 8;
 
-    if (event->orientation() == Qt::Horizontal) {
-        scrollHorizontally(numSteps);
-    } else {
-        scrollVertically(numSteps);
+    if (!numPixels.isNull()) {
+        scrollWithPixels(numpixels);
+    } else if (!numDegrees.isNull()) {
+        QPoint numSteps = numDegrees / 15;
+        scrollWithDegrees(numSteps);
     }
+
     event->accept();
 }
 //! [0]
index f99f3dd..281d4f6 100644 (file)
@@ -453,7 +453,13 @@ QHoverEvent::~QHoverEvent()
 
     Wheel events are sent to the widget under the mouse cursor, but
     if that widget does not handle the event they are sent to the
-    focus widget. The rotation distance is provided by delta().
+    focus widget. Wheel events are generated for both mouse wheels
+    and trackpad scroll gestures. There are two ways to read the
+    wheel event delta: angleDelta() returns the delta in wheel
+    degrees. This value is always provided. pixelDelta() returns
+    the delta in screen pixels and is available on platforms that
+    have high-resolution trackpads, such as Mac OS X.
+
     The functions pos() and globalPos() return the mouse cursor's
     location at the time of the event.
 
@@ -483,8 +489,11 @@ QHoverEvent::~QHoverEvent()
 */
 
 /*!
+    \obsolete
     Constructs a wheel event object.
 
+    Use the QPoint-based constructor instead.
+
     The position, \a pos, is the location of the mouse cursor within
     the widget. The globalPos() is initialized to QCursor::pos()
     which is usually, but not always, correct.
@@ -496,13 +505,13 @@ QHoverEvent::~QHoverEvent()
     \a modifiers holds the keyboard modifier flags at the time of the
     event, and \a orient holds the wheel's orientation.
 
-    \sa pos() delta() state()
+    \sa pos() pixelDelta() angleDelta() state()
 */
 #ifndef QT_NO_WHEELEVENT
 QWheelEvent::QWheelEvent(const QPointF &pos, int delta,
                          Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
                          Qt::Orientation orient)
-    : QInputEvent(Wheel, modifiers), p(pos), d(delta), mouseState(buttons), o(orient)
+    : QInputEvent(Wheel, modifiers), p(pos), qt4D(delta), qt4O(orient), mouseState(buttons)
 {
     g = QCursor::pos();
 }
@@ -515,26 +524,69 @@ QWheelEvent::~QWheelEvent()
 }
 
 /*!
+    \obsolete
     Constructs a wheel event object.
 
+    Use the QPoint-based constructor instead.
+
     The \a pos provides the location of the mouse cursor
     within the widget. The position in global coordinates is specified
     by \a globalPos. \a delta contains the rotation distance, \a modifiers
     holds the keyboard modifier flags at the time of the event, and
     \a orient holds the wheel's orientation.
 
-    \sa pos() globalPos() delta() state()
+
+    \sa pos() pixelDelta() angleDelta() state()
 */
 QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta,
                          Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
                          Qt::Orientation orient)
-    : QInputEvent(Wheel, modifiers), p(pos), g(globalPos), d(delta), mouseState(buttons), o(orient)
+    : QInputEvent(Wheel, modifiers), p(pos), g(globalPos), qt4D(delta), qt4O(orient), mouseState(buttons)
 {}
 
+/*!
+    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. \pixelDelta contains the scrolling distance
+    in pixels on screen, \a angleDelta contains the wheel rotation distance.
+    \pixelDelta is optional and can be null.
+
+    \a modifiers holds the keyboard modifier flags at the time of the event.
+
+    \a pixelDelta contains the scrolling delta in pixels,
+    \a angleDelta contains the rotation distance, and
+    \a orient holds the wheel's orientation.
+
+    \sa pos() globalPos() delta() state()
+*/
+
+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)
+{}
+
+
 #endif // QT_NO_WHEELEVENT
 
 /*!
-    \fn int QWheelEvent::delta() const
+    \fn QPoint QWheelEvent::pixelDelta() const
+
+    Returns the scrolling distance in pixels on screen. This value is
+    provided on platforms that support high-resolution pixel-based
+    delta values, such as Mac OS X. The value should be used directly
+    to scroll content on screen.
+
+    Example:
+
+    \snippet doc/src/snippets/code/src_gui_kernel_qevent.cpp 0
+*/
+
+/*!
+    \fn QPoint QWheelEvent::angleDelta() const
 
     Returns the distance that the wheel is rotated, in eighths of a
     degree. A positive value indicates that the wheel was rotated
@@ -556,6 +608,12 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta
 */
 
 /*!
+    \fn int QWheelEvent::delta() const
+
+    This function has been deprecated, use pixelDelta() or angleDelta() instead.
+*/
+
+/*!
     \fn const QPoint &QWheelEvent::pos() const
 
     Returns the position of the mouse cursor relative to the widget
index 93dea41..ca93095 100644 (file)
@@ -148,9 +148,21 @@ public:
     QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta,
                 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
                 Qt::Orientation orient = Qt::Vertical);
+    QWheelEvent(const QPointF &pos, const QPointF& globalPos,
+                QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
+                Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
+
     ~QWheelEvent();
 
-    inline int delta() const { return d; }
+
+    inline QPoint pixelDelta() const { return pixelD; }
+    inline QPoint angleDelta() const { return angleD; }
+
+#if QT_DEPRECATED_SINCE(5, 0)
+    inline QT_DEPRECATED int delta() const  { return qt4D; }
+    inline QT_DEPRECATED Qt::Orientation orientation() const { return qt4O; }
+#endif
+
 #ifndef QT_NO_INTEGER_EVENT_COORDINATES
     inline QPoint pos() const { return p.toPoint(); }
     inline QPoint globalPos()   const { return g.toPoint(); }
@@ -163,15 +175,15 @@ public:
     inline const QPointF &globalPosF()   const { return g; }
 
     inline Qt::MouseButtons buttons() const { return mouseState; }
-    Qt::Orientation orientation() const { return o; }
-
-
 protected:
     QPointF p;
     QPointF g;
-    int d;
+    QPoint pixelD;
+    QPoint angleD;
+    int qt4D;
+    Qt::Orientation qt4O;
     Qt::MouseButtons mouseState;
-    Qt::Orientation o;
+    int reserved;
 };
 #endif
 
index 2e7441d..1cd448a 100644 (file)
@@ -1032,8 +1032,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
     QWindow *window = e->window.data();
 
     if (window) {
-         QWheelEvent ev(e->localPos, e->globalPos, e->delta, buttons, e->modifiers,
-                        e->orient);
+         QWheelEvent ev(e->localPos, e->globalPos, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers);
          ev.setTimestamp(e->timestamp);
          QGuiApplication::sendSpontaneousEvent(window, &ev);
          return;
index e6c4454..40a4ec0 100644 (file)
@@ -189,8 +189,53 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local,
 
 void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods)
 {
-    QWindowSystemInterfacePrivate::WheelEvent *e =
-            new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, d, o, mods);
+    QPoint point = (o == Qt::Vertical) ? QPoint(0, d) : QPoint(d, 0);
+    handleWheelEvent(tlw, timestamp, local, global, point, point, mods);
+}
+
+void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods)
+{
+    unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
+    handleWheelEvent(w, time, local, global, pixelDelta, angleDelta, mods);
+}
+
+void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods)
+{
+    // 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
+    // same time preserve source and behavior compatibility with Qt 4.
+    //
+    // In addition high-resolution pixel-based deltas are also supported.
+    // Platforms that does not support these may pass a null point here.
+    // Angle deltas must always be sent in addition to pixel deltas.
+    QWindowSystemInterfacePrivate::WheelEvent *e;
+
+    if (angleDelta.isNull())
+        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);
+        QWindowSystemInterfacePrivate::queueWindowSystemEvent(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);
+        QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
+        return;
+    }
+
+    // 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);
+    QWindowSystemInterfacePrivate::queueWindowSystemEvent(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);
     QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
 }
 
index 78152a1..836fb40 100644 (file)
@@ -80,7 +80,10 @@ 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);
 
+    // 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);
     static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
 
index 661b39d..f5c141b 100644 (file)
@@ -157,13 +157,15 @@ public:
 
     class WheelEvent : public InputEvent {
     public:
-        WheelEvent(QWindow *w, ulong time, const QPointF & local, const QPointF & global, int d,
-                   Qt::Orientation o, Qt::KeyboardModifiers mods)
-            : InputEvent(w, time, Wheel, mods), delta(d), localPos(local), globalPos(global), orient(o) { }
-        int delta;
+        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) { }
+        QPoint pixelDelta;
+        QPoint angleDelta;
+        int qt4Delta;
+        Qt::Orientation qt4Orientation;
         QPointF localPos;
         QPointF globalPos;
-        Qt::Orientation orient;
     };
 
     class KeyEvent : public InputEvent {
index 577e075..a43b3fe 100644 (file)
@@ -371,14 +371,11 @@ static QTouchDevice *touchDevice = 0;
 #ifndef QT_NO_WHEELEVENT
 - (void)scrollWheel:(NSEvent *)theEvent
 {
-    int deltaX = 0;
-    int deltaY = 0;
-    int deltaZ = 0;
-
     const EventRef carbonEvent = (EventRef)[theEvent eventRef];
     const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0;
     const bool scrollEvent = carbonEventKind == kEventMouseScroll;
 
+    QPoint angleDelta;
     if (scrollEvent) {
         // The mouse device contains pixel scroll wheel support (Mighty Mouse, Trackpad).
         // Since deviceDelta is delivered as pixels rather than degrees, we need to
@@ -389,40 +386,45 @@ static QTouchDevice *touchDevice = 0;
 
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
         if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
-            deltaX = [theEvent scrollingDeltaX] * pixelsToDegrees;
-            deltaY = [theEvent scrollingDeltaY] * pixelsToDegrees;
-            //  scrollingDeltaZ API is missing.
+            angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees);
+            angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees);
         } else
 #endif
         {
-            deltaX = [theEvent deviceDeltaX] * pixelsToDegrees;
-            deltaY = [theEvent deviceDeltaY] * pixelsToDegrees;
-            deltaZ = [theEvent deviceDeltaZ] * pixelsToDegrees;
+            angleDelta.setX([theEvent deviceDeltaX] * pixelsToDegrees);
+            angleDelta.setY([theEvent deviceDeltaY] * pixelsToDegrees);
         }
 
     } else {
         // carbonEventKind == kEventMouseWheelMoved
         // Remove acceleration, and use either -120 or 120 as delta:
-        deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120);
-        deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120);
-        deltaZ = qBound(-120, int([theEvent deltaZ] * 10000), 120);
+        angleDelta.setX(qBound(-120, int([theEvent deltaX] * 10000), 120));
+        angleDelta.setY(qBound(-120, int([theEvent deltaY] * 10000), 120));
     }
 
+    QPoint pixelDelta;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+    if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) {
+        if ([theEvent hasPreciseScrollingDeltas]) {
+            pixelDelta.setX([theEvent scrollingDeltaX]);
+            pixelDelta.setY([theEvent scrollingDeltaY]);
+        } else {
+            // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width."
+            // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels.
+            const CGFloat lineWithEstimate = 20.0;
+            pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate);
+            pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate);
+        }
+    }
+#endif
+
+
     NSPoint windowPoint = [self convertPoint: [theEvent locationInWindow] fromView: nil];
     QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
     NSTimeInterval timestamp = [theEvent timestamp];
     ulong qt_timestamp = timestamp * 1000;
 
-    if (deltaX != 0)
-        QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaX, Qt::Horizontal);
-
-    if (deltaY != 0)
-        QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaY, Qt::Vertical);
-
-    if (deltaZ != 0)
-        // Qt doesn't explicitly support wheels with a Z component. In a misguided attempt to
-        // try to be ahead of the pack, I'm adding this extra value.
-        QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaY, (Qt::Orientation)3);
+    QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, pixelDelta, angleDelta);
 }
 #endif //QT_NO_WHEELEVENT
 
index 650d4af..c350223 100644 (file)
@@ -3357,8 +3357,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
             }
 
             while (w) {
-                QWheelEvent we(relpos, wheel->globalPos(), wheel->delta(), wheel->buttons(),
-                               wheel->modifiers(), wheel->orientation());
+                QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(),
+                               wheel->modifiers());
                 we.spont = wheel->spontaneous();
                 res = d->notify_helper(w, w == receiver ? wheel : &we);
                 eventAccepted = ((w == receiver) ? wheel : &we)->isAccepted();
index c04d8a9..4d5e9d5 100644 (file)
@@ -364,7 +364,7 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
 
     QPoint mapped = widget->mapFrom(m_widget, event->pos());
 
-    QWheelEvent translated(mapped, event->globalPos(), event->delta(), event->buttons(), event->modifiers(), event->orientation());
+    QWheelEvent translated(mapped, event->globalPos(), event->pixelDelta(), event->pixelDelta(), event->delta(), event->orientation(), event->buttons(), event->modifiers());
     QGuiApplication::sendSpontaneousEvent(widget, &translated);
 }
 
diff --git a/tests/manual/cocoa/wheelevent/main.cpp b/tests/manual/cocoa/wheelevent/main.cpp
new file mode 100644 (file)
index 0000000..9794989
--- /dev/null
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtGui>
+
+#include "window.h"
+
+int main(int argc, char *argv[])
+{
+    QGuiApplication app(argc, argv);
+
+    Window window;
+    window.show();
+
+
+    return app.exec();
+}
+
+
+
diff --git a/tests/manual/cocoa/wheelevent/wheelevent.pro b/tests/manual/cocoa/wheelevent/wheelevent.pro
new file mode 100644 (file)
index 0000000..6eca6d4
--- /dev/null
@@ -0,0 +1,6 @@
+TEMPLATE = app
+
+HEADERS += window.h
+SOURCES += window.cpp main.cpp
+
+QT += core gui gui-private core-private
diff --git a/tests/manual/cocoa/wheelevent/window.cpp b/tests/manual/cocoa/wheelevent/window.cpp
new file mode 100644 (file)
index 0000000..b305b05
--- /dev/null
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+
+#include <private/qguiapplication_p.h>
+
+#include <QBackingStore>
+#include <QPainter>
+#include <QtGui>
+
+static int colorIndexId = 0;
+
+QColor colorTable[] =
+{
+    QColor("#f09f8f"),
+    QColor("#a2bff2"),
+    QColor("#c0ef8f")
+};
+
+Window::Window(QScreen *screen)
+    : QWindow(screen)
+    , m_backgroundColorIndex(colorIndexId++)
+{
+    initialize();
+}
+
+Window::Window(QWindow *parent)
+    : QWindow(parent)
+    , m_backgroundColorIndex(colorIndexId++)
+{
+    initialize();
+}
+
+void Window::initialize()
+{
+    if (parent())
+        setGeometry(QRect(160, 120, 320, 240));
+    else {
+        setGeometry(QRect(10, 10, 640, 480));
+
+        setSizeIncrement(QSize(10, 10));
+        setBaseSize(QSize(640, 480));
+        setMinimumSize(QSize(240, 160));
+        setMaximumSize(QSize(800, 600));
+    }
+
+    create();
+    m_backingStore = new QBackingStore(this);
+
+    m_image = QImage(geometry().size(), QImage::Format_RGB32);
+    m_image.fill(colorTable[m_backgroundColorIndex % (sizeof(colorTable) / sizeof(colorTable[0]))].rgba());
+
+    m_lastPos = QPoint(-1, -1);
+    m_renderTimer = 0;
+}
+
+void Window::mousePressEvent(QMouseEvent *event)
+{
+    m_lastPos = event->pos();
+}
+
+void Window::mouseMoveEvent(QMouseEvent *event)
+{
+    if (m_lastPos != QPoint(-1, -1)) {
+        QPainter p(&m_image);
+        p.setRenderHint(QPainter::Antialiasing);
+        p.drawLine(m_lastPos, event->pos());
+        m_lastPos = event->pos();
+    }
+
+    scheduleRender();
+}
+
+void Window::wheelEvent(QWheelEvent *event)
+{
+    qDebug() << "wheelEvent delta" << event->delta() << "orientation" << event->orientation();
+    qDebug() << "wheelEvent pixelDelta" << event->pixelDelta();
+    qDebug() << "wheelEvent angleDelta" << event->angleDelta();
+
+    const bool useQt4API = false;
+
+    if (useQt4API) {
+        if (event->orientation() == Qt::Horizontal)
+            scrollOffset.setX(scrollOffset.x() + event->delta());
+        else
+            scrollOffset.setY(scrollOffset.y() + event->delta());
+        scheduleRender();
+    } else {
+        if (!event->pixelDelta().isNull()) {
+            scrollOffset += event->pixelDelta();
+            scheduleRender();
+        }
+    }
+}
+
+void Window::mouseReleaseEvent(QMouseEvent *event)
+{
+    if (m_lastPos != QPoint(-1, -1)) {
+        QPainter p(&m_image);
+        p.setRenderHint(QPainter::Antialiasing);
+        p.drawLine(m_lastPos, event->pos());
+        m_lastPos = QPoint(-1, -1);
+    }
+
+    scheduleRender();
+}
+
+void Window::exposeEvent(QExposeEvent *)
+{
+    scheduleRender();
+}
+
+void Window::resizeEvent(QResizeEvent *)
+{
+    QImage old = m_image;
+
+    //qDebug() << "Window::resizeEvent" << width << height;
+
+    int width = qMax(geometry().width(), old.width());
+    int height = qMax(geometry().height(), old.height());
+
+    if (width > old.width() || height > old.height()) {
+        m_image = QImage(width, height, QImage::Format_RGB32);
+        m_image.fill(colorTable[(m_backgroundColorIndex) % (sizeof(colorTable) / sizeof(colorTable[0]))].rgba());
+
+        QPainter p(&m_image);
+        p.drawImage(0, 0, old);
+    }
+
+    render();
+}
+
+void Window::keyPressEvent(QKeyEvent *event)
+{
+    switch (event->key()) {
+    case Qt::Key_Backspace:
+        m_text.chop(1);
+        break;
+    case Qt::Key_Enter:
+    case Qt::Key_Return:
+        m_text.append('\n');
+        break;
+    default:
+        m_text.append(event->text());
+        break;
+    }
+    scheduleRender();
+}
+
+void Window::scheduleRender()
+{
+    if (!m_renderTimer)
+        m_renderTimer = startTimer(1);
+}
+
+void Window::timerEvent(QTimerEvent *)
+{
+    render();
+    killTimer(m_renderTimer);
+    m_renderTimer = 0;
+}
+
+void Window::render()
+{
+    QRect rect(QPoint(), geometry().size());
+
+    m_backingStore->resize(rect.size());
+
+    m_backingStore->beginPaint(rect);
+
+    QPaintDevice *device = m_backingStore->paintDevice();
+
+    QPainter p(device);
+    p.drawImage(0, 0, m_image);
+
+    QFont font;
+    font.setPixelSize(32);
+
+    p.setFont(font);
+    p.drawText(rect, 0, m_text);
+
+    // draw grid:
+    int gridSpace = 80;
+
+    for (int y = 0; y < geometry().height() + gridSpace; y+= gridSpace) {
+        int offset = scrollOffset.y() % gridSpace;
+        //int color = ((y + offset) %255);// + scrollOffset.y()) % 255);
+        p.drawLine(0, y + offset, geometry().width(), y + offset);
+        //p.setBrush(QColor(color,0, 0));
+        //p.fillRect(0, y + offset, geometry().width(), gridSpace,QColor(color,0, 0));
+    }
+
+    for (int x = 0; x < geometry().width() + gridSpace; x+= gridSpace) {
+        p.drawLine(x + scrollOffset.x() % gridSpace, 0, x + scrollOffset.x() % gridSpace, geometry().height());
+    }
+
+    m_backingStore->endPaint();
+    m_backingStore->flush(rect);
+}
+
+
diff --git a/tests/manual/cocoa/wheelevent/window.h b/tests/manual/cocoa/wheelevent/window.h
new file mode 100644 (file)
index 0000000..523c9f3
--- /dev/null
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QWindow>
+#include <QImage>
+
+class Window : public QWindow
+{
+public:
+    Window(QWindow *parent = 0);
+    Window(QScreen *screen);
+
+protected:
+    void mousePressEvent(QMouseEvent *);
+    void mouseMoveEvent(QMouseEvent *);
+    void mouseReleaseEvent(QMouseEvent *);
+    void wheelEvent(QWheelEvent *event);
+
+    void keyPressEvent(QKeyEvent *);
+
+    void exposeEvent(QExposeEvent *);
+    void resizeEvent(QResizeEvent *);
+
+    void timerEvent(QTimerEvent *);
+
+private:
+    void render();
+    void scheduleRender();
+    void initialize();
+
+    QString m_text;
+    QImage m_image;
+    QPoint m_lastPos;
+    int m_backgroundColorIndex;
+    QBackingStore *m_backingStore;
+    int m_renderTimer;
+    QPoint scrollOffset;
+};