Skip to content

Commit

Permalink
Add mouse wheel events handler to MouseArea
Browse files Browse the repository at this point in the history
This patch was based on the attached patch in QTBUG-7369. It basically
exposes the wheel events to MouseArea via the onWheel signal.

The current API is based on the new QWheelEvent API introduced by this
patch: http://codereview.qt-project.org/#change,12532

Task-number: QTBUG-7369
Change-Id: Id58513715c2d0ae81e3a69e9e1ed400bbae07507
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
  • Loading branch information
Luis Gabriel Lima authored and Qt by Nokia committed Mar 10, 2012
1 parent 78356f6 commit f2e1be9
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 2 deletions.
84 changes: 84 additions & 0 deletions examples/qtquick/mousearea/mousearea-wheel-example.qml
@@ -0,0 +1,84 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

import QtQuick 2.0

Rectangle {
height: 700
width: 485
color: "#333333"

Column {
anchors.centerIn: parent
spacing: 2

Repeater {
model: ["#9ACD32", "#EEEEEE", "#FFD700", "#87CEEB"]

Rectangle {
property real scaleFactor: 1

height: 40 * scaleFactor
width: 60 * scaleFactor
color: modelData
anchors.horizontalCenter: parent.horizontalCenter

MouseArea {
anchors.fill: parent
onWheel: {
if (wheel.modifiers & Qt.ControlModifier) {
if (wheel.angleDelta.y > 0)
parent.scaleFactor += 0.2;
else if (parent.scaleFactor - 0.2 >= 0.2)
parent.scaleFactor -= 0.2;
}
}
}
}
}
}

Text {
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
color: "#FFD700"
text: "Rotate the mouse wheel pressing <Control> to resize the squares."
}
}
3 changes: 2 additions & 1 deletion src/quick/items/qquickcanvas.cpp
Expand Up @@ -1185,7 +1185,8 @@ bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event

QPointF p = item->mapFromScene(event->posF());
if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
event->orientation(), event->buttons(), event->modifiers());
wheel.accept();
q->sendEvent(item, &wheel);
if (wheel.isAccepted()) {
Expand Down
104 changes: 104 additions & 0 deletions src/quick/items/qquickevents.cpp
Expand Up @@ -236,4 +236,108 @@ Item {
*/


/*!
\qmlclass WheelEvent QQuickWheelEvent
\inqmlmodule QtQuick 2
\ingroup qml-event-elements
\brief The WheelEvent object provides information about a mouse wheel event.
The position of the mouse can be found via the \l x and \l y properties.
\sa MouseArea
*/

/*!
\internal
\class QQuickWheelEvent
*/

/*!
\qmlproperty int QtQuick2::WheelEvent::x
\qmlproperty int QtQuick2::WheelEvent::y
These properties hold the coordinates of the position supplied by the wheel event.
*/

/*!
\qmlproperty bool QtQuick2::WheelEvent::accepted
Setting \a accepted to true prevents the wheel event from being
propagated to items below this item.
Generally, if the item acts on the wheel event then it should be accepted
so that items lower in the stacking order do not also respond to the same event.
*/

/*!
\qmlproperty int QtQuick2::WheelEvent::buttons
This property holds the mouse buttons pressed when the wheel event was generated.
It contains a bitwise combination of:
\list
\o Qt.LeftButton
\o Qt.RightButton
\o Qt.MiddleButton
\endlist
*/

/*!
\qmlproperty point QtQuick2::WheelEvent::angleDelta
This property holds the distance that the wheel is rotated in wheel degrees.
The x and y cordinate of this property holds the delta in horizontal and
vertical orientation.
A positive value indicates that the wheel was rotated up/right;
a negative value indicates that the wheel was rotated down/left.
Most mouse types work in steps of 15 degrees, in which case the delta value is a
multiple of 120; i.e., 120 units * 1/8 = 15 degrees.
*/

/*!
\qmlproperty point QtQuick2::WheelEvent::pixelDelta
This property holds the delta in screen pixels and is available in plataforms that
have high-resolution trackpads, such as Mac OS X.
The x and y cordinate of this property holds the delta in horizontal and
vertical orientation. The value should be used directly to scroll content on screen.
For platforms without high-resolution trackpad support, pixelDelta will always be (0,0),
and angleDelta should be used instead.
*/

/*!
\qmlproperty int QtQuick2::WheelEvent::modifiers
This property holds the keyboard modifier flags that existed immediately
before the event occurred.
It contains a bitwise combination of:
\list
\o Qt.NoModifier - No modifier key is pressed.
\o Qt.ShiftModifier - A Shift key on the keyboard is pressed.
\o Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
\o Qt.AltModifier - An Alt key on the keyboard is pressed.
\o Qt.MetaModifier - A Meta key on the keyboard is pressed.
\o Qt.KeypadModifier - A keypad button is pressed.
\endlist
For example, to react to a Control key pressed during the wheel event:
\qml
MouseArea {
onWheel: {
if (wheel.modifiers & Qt.ControlModifier) {
if (wheel.angleDelta.y > 0)
zoomIn();
else
zoomOut();
}
}
}
\endqml
*/

QT_END_NAMESPACE
38 changes: 38 additions & 0 deletions src/quick/items/qquickevents_p_p.h
Expand Up @@ -201,9 +201,47 @@ class QQuickMouseEventEx : public QMouseEvent
};


class QQuickWheelEvent : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal x READ x)
Q_PROPERTY(qreal y READ y)
Q_PROPERTY(QPoint angleDelta READ angleDelta)
Q_PROPERTY(QPoint pixelDelta READ pixelDelta)
Q_PROPERTY(int buttons READ buttons)
Q_PROPERTY(int modifiers READ modifiers)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)

public:
QQuickWheelEvent(qreal x, qreal y, const QPoint& angleDelta, const QPoint& pixelDelta,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
: _x(x), _y(y), _angleDelta(angleDelta), _pixelDelta(pixelDelta), _buttons(buttons),
_modifiers(modifiers), _accepted(true) {}

qreal x() const { return _x; }
qreal y() const { return _y; }
QPoint angleDelta() const { return _angleDelta; }
QPoint pixelDelta() const { return _pixelDelta; }
int buttons() const { return _buttons; }
int modifiers() const { return _modifiers; }

bool isAccepted() { return _accepted; }
void setAccepted(bool accepted) { _accepted = accepted; }

private:
qreal _x;
qreal _y;
QPoint _angleDelta;
QPoint _pixelDelta;
Qt::MouseButtons _buttons;
Qt::KeyboardModifiers _modifiers;
bool _accepted;
};

QT_END_NAMESPACE

QML_DECLARE_TYPE(QQuickKeyEvent)
QML_DECLARE_TYPE(QQuickMouseEvent)
QML_DECLARE_TYPE(QQuickWheelEvent)

#endif // QQUICKEVENTS_P_P_H
1 change: 1 addition & 0 deletions src/quick/items/qquickitemsmodule.cpp
Expand Up @@ -169,6 +169,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickAnchors>();
qmlRegisterType<QQuickKeyEvent>();
qmlRegisterType<QQuickMouseEvent>();
qmlRegisterType<QQuickWheelEvent>();
qmlRegisterType<QQuickTransform>();
qmlRegisterType<QQuickPathElement>();
qmlRegisterType<QQuickCurve>();
Expand Down
37 changes: 36 additions & 1 deletion src/quick/items/qquickmousearea.cpp
Expand Up @@ -236,6 +236,13 @@ bool QQuickMouseAreaPrivate::isClickConnected()
return QObjectPrivate::get(q)->isSignalConnected(idx);
}

bool QQuickMouseAreaPrivate::isWheelConnected()
{
Q_Q(QQuickMouseArea);
static int idx = QObjectPrivate::get(q)->signalIndex("wheel(QQuickWheelEvent*)");
return QObjectPrivate::get(q)->isSignalConnected(idx);
}

void QQuickMouseAreaPrivate::propagate(QQuickMouseEvent* event, PropagateType t)
{
Q_Q(QQuickMouseArea);
Expand Down Expand Up @@ -331,7 +338,8 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
Information about the mouse position and button clicks are provided via
signals for which event handler properties are defined. The most commonly
used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
onPressed, onReleased and onPressAndHold.
onPressed, onReleased and onPressAndHold. It's also possible to handle mouse
wheel events via the onWheel signal.
By default, MouseArea items only report mouse clicks and not changes to the
position of the mouse cursor. Setting the hoverEnabled property ensures that
Expand Down Expand Up @@ -513,6 +521,17 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
the logic when the MouseArea has lost the mouse handling to the \l Flickable,
\c onCanceled should be used in addition to onReleased.
*/

/*!
\qmlsignal QtQuick2::MouseArea::onWheel(WheelEvent mouse)
This handler is called in response to both mouse wheel and trackpad scroll gestures.
The \l {WheelEvent}{wheel} parameter provides information about the event, including the x and y
position, any buttons currently pressed, and information about the wheel movement, including
angleDelta and pixelDelta.
*/

QQuickMouseArea::QQuickMouseArea(QQuickItem *parent)
: QQuickItem(*(new QQuickMouseAreaPrivate), parent)
{
Expand Down Expand Up @@ -860,6 +879,22 @@ void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
setHovered(false);
}

void QQuickMouseArea::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickMouseArea);
if (!d->absorb) {
QQuickItem::wheelEvent(event);
return;
}

QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(),
event->pixelDelta(), event->buttons(), event->modifiers());
we.setAccepted(d->isWheelConnected());
emit wheel(&we);
if (!we.isAccepted())
QQuickItem::wheelEvent(event);
}

void QQuickMouseArea::ungrabMouse()
{
Q_D(QQuickMouseArea);
Expand Down
3 changes: 3 additions & 0 deletions src/quick/items/qquickmousearea_p.h
Expand Up @@ -119,6 +119,7 @@ class Q_AUTOTEST_EXPORT QQuickDrag : public QObject
};

class QQuickMouseAreaPrivate;
class QQuickWheelEvent;
// used in QtLocation
class Q_QUICK_EXPORT QQuickMouseArea : public QQuickItem
{
Expand Down Expand Up @@ -182,6 +183,7 @@ class Q_QUICK_EXPORT QQuickMouseArea : public QQuickItem
void released(QQuickMouseEvent *mouse);
void clicked(QQuickMouseEvent *mouse);
void doubleClicked(QQuickMouseEvent *mouse);
void wheel(QQuickWheelEvent *wheel);
void entered();
void exited();
void canceled();
Expand All @@ -199,6 +201,7 @@ class Q_QUICK_EXPORT QQuickMouseArea : public QQuickItem
virtual void hoverEnterEvent(QHoverEvent *event);
virtual void hoverMoveEvent(QHoverEvent *event);
virtual void hoverLeaveEvent(QHoverEvent *event);
virtual void wheelEvent(QWheelEvent *event);
virtual bool childMouseEventFilter(QQuickItem *i, QEvent *e);
virtual void timerEvent(QTimerEvent *event);
virtual void windowDeactivateEvent();
Expand Down
1 change: 1 addition & 0 deletions src/quick/items/qquickmousearea_p_p.h
Expand Up @@ -83,6 +83,7 @@ class QQuickMouseAreaPrivate : public QQuickItemPrivate
bool isPressAndHoldConnected();
bool isDoubleClickConnected();
bool isClickConnected();
bool isWheelConnected();

bool absorb : 1;
bool hovered : 1;
Expand Down
24 changes: 24 additions & 0 deletions tests/auto/quick/qquickmousearea/data/wheel.qml
@@ -0,0 +1,24 @@
import QtQuick 2.0

Rectangle {
id: root

property var angleDeltaY
property real mouseX
property real mouseY
property bool controlPressed

width: 400
height: 400

MouseArea {
anchors.fill: parent

onWheel: {
root.angleDeltaY = wheel.angleDelta.y;
root.mouseX = wheel.x;
root.mouseY = wheel.y;
root.controlPressed = wheel.modifiers & Qt.ControlModifier;
}
}
}

0 comments on commit f2e1be9

Please sign in to comment.