summaryrefslogtreecommitdiffstats
path: root/src/declarative/fx/qfxmouseregion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/fx/qfxmouseregion.cpp')
-rw-r--r--src/declarative/fx/qfxmouseregion.cpp589
1 files changed, 589 insertions, 0 deletions
diff --git a/src/declarative/fx/qfxmouseregion.cpp b/src/declarative/fx/qfxmouseregion.cpp
new file mode 100644
index 0000000..2bf7aa7
--- /dev/null
+++ b/src/declarative/fx/qfxmouseregion.cpp
@@ -0,0 +1,589 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxmouseregion.h"
+#include "qfxmouseregion_p.h"
+#include <QGraphicsSceneMouseEvent>
+
+
+QT_BEGIN_NAMESPACE
+static const int DragThreshold = 5;
+static const int PressAndHoldDelay = 800;
+
+QML_DEFINE_TYPE(QFxDrag,Drag);
+QFxDrag::QFxDrag(QObject *parent)
+: QObject(parent), _target(0), _xmin(0), _xmax(0), _ymin(0), _ymax(0)
+{
+}
+
+QFxDrag::~QFxDrag()
+{
+}
+
+QFxItem *QFxDrag::target() const
+{
+ return _target;
+}
+
+void QFxDrag::setTarget(QFxItem *t)
+{
+ _target = t;
+}
+
+QString QFxDrag::axis() const
+{
+ return _axis;
+}
+
+void QFxDrag::setAxis(const QString &a)
+{
+ _axis = a;
+}
+
+/*!
+ \property QFxDrag::xmin
+ \brief the minimum x position for the target
+
+ If x-axis dragging is enabled, xmin limits how far to the left the target can be dragged. If x-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::xmin() const
+{
+ return _xmin;
+}
+
+void QFxDrag::setXmin(int m)
+{
+ _xmin = m;
+}
+
+/*!
+ \property QFxDrag::xmax
+ \brief the maximum x position for the target
+
+ If x-axis dragging is enabled, xmax limits how far to the right the target can be dragged. If x-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::xmax() const
+{
+ return _xmax;
+}
+
+void QFxDrag::setXmax(int m)
+{
+ _xmax = m;
+}
+
+/*!
+ \property QFxDrag::ymin
+ \brief the minimum y position for the target
+
+ If y-axis dragging is enabled, ymin limits how far up the target can be dragged. If y-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::ymin() const
+{
+ return _ymin;
+}
+
+void QFxDrag::setYmin(int m)
+{
+ _ymin = m;
+}
+
+/*!
+ \property QFxDrag::ymax
+ \brief the maximum y position for the target
+
+ If y-axis dragging is enabled, ymax limits how far down the target can be dragged. If y-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::ymax() const
+{
+ return _ymax;
+}
+
+void QFxDrag::setYmax(int m)
+{
+ _ymax = m;
+}
+
+/*!
+ \qmlclass MouseRegion
+ \brief The MouseRegion element enables simple mouse handling.
+ \inherits Item
+
+ A MouseRegion is typically used in conjunction with a visible element, where the MouseRegion effectively 'proxies' mouse handling for that element. For example, we can put a MouseRegion in a Rect that changes the Rect color to red when clicked:
+ \code
+ <Rect width="100" height="100">
+ <MouseRegion anchors.fill="{parent}" onClick="parent.color = 'red';"/>
+ </Rect>
+ \endcode
+
+ For the mouse handlers the variable mouseButton is set to be one of 'Left', 'Right', 'Middle',
+ or 'None'. This allows you to distinguish left and right clicking. Below we have the previous
+ example extended so as to give a different color when you right click.
+ \code
+ <Rect width="100" height="100">
+ <MouseRegion anchors.fill="{parent}" onClick="if(mouseButton=='Right') { parent.color='blue';} else { parent.color = 'red';}"/>
+ </Rect>
+ \endcode
+
+ For basic key handling, see \l KeyActions.
+
+ MouseRegion is an invisible element: it is never painted.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onEntered
+
+ This handler is called when the mouse enters the mouse region.
+
+ \warning This handler is not yet implemented.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onExited
+
+ This handler is called when the mouse exists the mouse region.
+
+ \warning This handler is not yet implemented.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onReenteredWhilePressed
+
+ This handler is called when the mouse reenters the mouse region while pressed.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onExitedWhilePressed
+
+ This handler is called when the mouse exists the mouse region while pressed.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onClicked
+
+ This handler is called when there is a click. A click is defined as a press followed by a release,
+ both inside the MouseRegion (pressing, moving outside the MouseRegion, and then moving back inside and
+ releasing is also considered a click).
+ The x and y parameters tell you the position of the release of the click. The followsPressAndHold parameter tells
+ you whether or not the release portion of the click followed a long press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onPressed
+
+ This handler is called when there is a press.
+ The x and y parameters tell you the position of the press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onReleased
+
+ This handler is called when there is a release.
+ The x and y parameters tell you the position of the release. The isClick parameter tells you whether
+ or not the release is part of a click. The followsPressAndHold parameter tells you whether or not the
+ release followed a long press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onPressAndHold
+
+ This handler is called when there is a long press (currently 800ms).
+ The x and y parameters tell you the position of the long press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onDoubleClicked
+
+ This handler is called when there is a double-click (a press followed by a release followed by a press).
+ The x and y parameters tell you the position of the double-click.
+*/
+
+QML_DEFINE_TYPE(QFxMouseRegion,MouseRegion);
+/*!
+ \internal
+ \class QFxMouseRegion
+ \brief The QFxMouseRegion class provides a simple mouse handling abstraction for use within Qml.
+
+ \ingroup coreitems
+
+ All QFxItem derived classes can do mouse handling but the QFxMouseRegion class exposes mouse
+ handling data as properties and tracks flicking and dragging of the mouse.
+
+ A QFxMouseRegion object can be instantiated in Qml using the tag \l MouseRegion.
+ */
+QFxMouseRegion::QFxMouseRegion(QFxItem *parent)
+ : QFxItem(*(new QFxMouseRegionPrivate), parent)
+{
+ Q_D(QFxMouseRegion);
+ d->init();
+}
+
+QFxMouseRegion::QFxMouseRegion(QFxMouseRegionPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxMouseRegion);
+ d->init();
+}
+
+QFxMouseRegion::~QFxMouseRegion()
+{
+}
+
+/*!
+ \qmlproperty int MouseRegion::mouseX
+ \qmlproperty int MouseRegion::mouseY
+
+ The coordinates of the mouse while pressed. The coordinates are relative to the item that was pressed.
+*/
+int QFxMouseRegion::mouseX() const
+{
+ Q_D(const QFxMouseRegion);
+ return int(d->lastPos.x());
+}
+
+int QFxMouseRegion::mouseY() const
+{
+ Q_D(const QFxMouseRegion);
+ return int(d->lastPos.y());
+}
+
+/*!
+ \qmlproperty bool MouseRegion::enabled
+ This property holds whether the item accepts mouse events.
+*/
+bool QFxMouseRegion::isEnabled() const
+{
+ Q_D(const QFxMouseRegion);
+ return d->absorb;
+}
+
+void QFxMouseRegion::setEnabled(bool a)
+{
+ Q_D(QFxMouseRegion);
+ d->absorb = a;
+}
+
+void QFxMouseRegionPrivate::bindButtonValue(Qt::MouseButton b)
+{
+ Q_Q(QFxMouseRegion);
+ QString bString;
+ switch(b){
+ case Qt::LeftButton:
+ bString = QLatin1String("Left"); break;
+ case Qt::RightButton:
+ bString = QLatin1String("Right"); break;
+ case Qt::MidButton:
+ bString = QLatin1String("Middle"); break;
+ default:
+ bString = QLatin1String("None"); break;
+ }
+ q->itemContext()->setContextProperty(QLatin1String("mouseButton"), bString);
+}
+
+void QFxMouseRegion::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ d->moved = false;
+ if(!d->absorb)
+ QFxItem::mousePressEvent(event);
+ else {
+ if (!d->inside) {
+ d->inside = true;
+ emit hoveredChanged();
+ }
+ d->longPress = false;
+ d->lastPos = event->pos();
+ d->dragX = drag()->axis().contains(QLatin1String("x"));
+ d->dragY = drag()->axis().contains(QLatin1String("y"));
+ d->dragged = false;
+ d->start = event->pos();
+ d->startScene = event->scenePos();
+ // ### we should only start timer if pressAndHold is connected to (but connectNotify doesn't work)
+ d->pressAndHoldTimer.start(PressAndHoldDelay, this);
+ setKeepMouseGrab(false);
+ d->bindButtonValue(event->button());
+ setPressed(true);
+ emit positionChanged();
+ event->accept();
+ }
+}
+
+void QFxMouseRegion::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb) {
+ QFxItem::mouseMoveEvent(event);
+ return;
+ }
+
+ d->lastPos = event->pos();
+
+ // ### we should skip this if these signals aren't used
+ const QRect &bounds = itemBoundingRect();
+ bool contains = bounds.contains(d->lastPos.toPoint());
+ if (d->inside && !contains) {
+ d->inside = false;
+ emit hoveredChanged();
+ emit exitedWhilePressed();
+ } else if (!d->inside && contains) {
+ d->inside = true;
+ emit hoveredChanged();
+ emit reenteredWhilePressed();
+ }
+
+ if(drag()->target()) {
+ if(!d->moved) {
+ if(d->dragX) d->startX = int(drag()->target()->x()); //### change startX and startY to qreal?
+ if(d->dragY) d->startY = int(drag()->target()->y());
+ }
+
+ QPointF startLocalPos;
+ QPointF curLocalPos;
+ if (drag()->target()->parent()) {
+ startLocalPos = drag()->target()->parent()->mapFromScene(d->startScene);
+ curLocalPos = drag()->target()->parent()->mapFromScene(event->scenePos());
+ } else {
+ startLocalPos = d->startScene;
+ curLocalPos = event->scenePos();
+ }
+
+ int dx = int(qAbs(curLocalPos.x() - startLocalPos.x()));
+ int dy = int(qAbs(curLocalPos.y() - startLocalPos.y()));
+ if ((d->dragX && !(dx < DragThreshold)) || (d->dragY && !(dy < DragThreshold)))
+ d->dragged = true;
+ if (!keepMouseGrab()) {
+ if ((!d->dragY && dy < DragThreshold && d->dragX && dx > DragThreshold)
+ || (!d->dragX && dx < DragThreshold && d->dragY && dy > DragThreshold)
+ || (d->dragX && d->dragY)) {
+ setKeepMouseGrab(true);
+ }
+ }
+
+ if(d->dragX) {
+ qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
+ if (x < drag()->xmin())
+ x = drag()->xmin();
+ else if (x > drag()->xmax())
+ x = drag()->xmax();
+ drag()->target()->setX(x);
+ }
+ if(d->dragY) {
+ qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY;
+ if (y < drag()->ymin())
+ y = drag()->ymin();
+ else if (y > drag()->ymax())
+ y = drag()->ymax();
+ drag()->target()->setY(y);
+ }
+ }
+ d->moved = true;
+ emit positionChanged();
+ event->accept();
+}
+
+
+void QFxMouseRegion::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::mouseReleaseEvent(event);
+ else {
+ setPressed(false);
+ //d->inside = false;
+ //emit hoveredChanged();
+ event->accept();
+ }
+}
+
+void QFxMouseRegion::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::mouseDoubleClickEvent(event);
+ else {
+ //d->inside = true;
+ //emit hoveredChanged();
+ setPressed(true);
+ emit this->doubleClicked(d->lastPos.x(), d->lastPos.y());
+ event->accept();
+ }
+}
+
+void QFxMouseRegion::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::hoverEnterEvent(event);
+ else {
+ setHovered(true);
+ emit entered();
+ }
+}
+
+void QFxMouseRegion::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::hoverLeaveEvent(event);
+ else {
+ setHovered(false);
+ emit exited();
+ }
+}
+
+void QFxMouseRegion::mouseUngrabEvent()
+{
+ Q_D(QFxMouseRegion);
+ if (d->pressed) {
+ // if our mouse grab has been removed (probably by Flickable), fix our
+ // state
+ d->pressed = false;
+ //d->inside = false;
+ setKeepMouseGrab(false);
+ emit pressedChanged();
+ //emit hoveredChanged();
+ }
+}
+
+void QFxMouseRegion::timerEvent(QTimerEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if (event->timerId() == d->pressAndHoldTimer.timerId()) {
+ d->pressAndHoldTimer.stop();
+ if (d->pressed && d->dragged == false && d->inside == true) {
+ d->longPress = true;
+ emit pressAndHold(d->lastPos.x(), d->lastPos.y());
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool MouseRegion::containsMouse
+ This property holds whether the mouse is currently inside the mouse region.
+
+ \warning This property is only partially implemented -- it is only valid when the mouse is pressed, and not for hover events.
+*/
+bool QFxMouseRegion::hovered()
+{
+ Q_D(QFxMouseRegion);
+ return d->hovered || d->inside;
+}
+
+/*!
+ \qmlproperty bool MouseRegion::pressed
+ This property holds whether the mouse region is currently pressed.
+*/
+bool QFxMouseRegion::pressed()
+{
+ Q_D(QFxMouseRegion);
+ return d->pressed;
+}
+
+void QFxMouseRegion::setHovered(bool h)
+{
+ Q_D(QFxMouseRegion);
+ if(d->hovered != h) {
+ d->hovered = h;
+ emit hoveredChanged();
+ }
+}
+
+void QFxMouseRegion::setPressed(bool p)
+{
+ Q_D(QFxMouseRegion);
+ bool isclick = d->pressed == true && p == false && d->dragged == false && d->inside == true;
+
+ if(d->pressed != p) {
+ d->pressed = p;
+ if(d->pressed)
+ emit pressed(d->lastPos.x(), d->lastPos.y());
+ else {
+ emit released(d->lastPos.x(), d->lastPos.y(), isclick, d->longPress);
+ if (isclick)
+ emit clicked(d->lastPos.x(), d->lastPos.y(), d->longPress);
+ }
+
+ emit pressedChanged();
+ }
+}
+
+/*!
+ \property QFxMouseRegion::drag
+ \brief The current drag being performed on the Mouse Region.
+*/
+QFxDrag *QFxMouseRegion::drag()
+{
+ Q_D(QFxMouseRegion);
+ return &(d->drag);
+}
+
+/*!
+ \qmlproperty Item MouseRegion::drag.target
+ \qmlproperty string MouseRegion::drag.axis
+ \qmlproperty int MouseRegion::drag.xmin
+ \qmlproperty int MouseRegion::drag.xmax
+ \qmlproperty int MouseRegion::drag.ymin
+ \qmlproperty int MouseRegion::drag.ymax
+
+ drag provides a convenient way to make an item draggable.
+
+ \list
+ \i \c target specifies the item to drag.
+ \i \c axis specifies whether dragging can be done horizontally (x), vertically (y), or both (x,y)
+ \i the min and max properties limit how far the target can be dragged along the corresponding axes.
+ \endlist
+
+ The following example uses drag to blur an image as it moves to the right:
+ \code
+ <Item id="blurtest" width="600" height="200">
+ <Image id="pic" file="pic.png" anchors.verticalCenter="{parent.verticalCenter}" >
+ <filter><Blur radius="{pic.x/10}"/></filter>
+ <MouseRegion anchors.fill="{parent}"
+ drag.target="{pic}"
+ drag.axis="x"
+ drag.xmin="0"
+ drag.xmax="{blurtest.width-pic.width}" />
+ </Image>
+ </Item>
+ \endcode
+*/
+
+QT_END_NAMESPACE