aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdriano Rezende <atdrez@gmail.com>2012-02-26 17:26:53 +0100
committerQt by Nokia <qt-info@nokia.com>2012-04-19 06:16:28 +0200
commitadb0848513198db72c6066b9a97077c7083df9fe (patch)
treebe96156388b1e348cad79ec98bd30a87ac364f7a
parent7bd68f6447c79aa58a9854bb6c44db00ea36a06a (diff)
Add contains method to QQuickItem public API
This method can be overwritten in order to provide fine grained control over the mouse events handled by the item. Change-Id: I23cb61958d3ac0b2f5091c47fa9e0ed07dc5e5d0 Reviewed-by: Martin Jones <martin.jones@nokia.com>
-rw-r--r--examples/quick/maskedmousearea/images/cloud_1.pngbin0 -> 49524 bytes
-rw-r--r--examples/quick/maskedmousearea/images/cloud_2.pngbin0 -> 32288 bytes
-rw-r--r--examples/quick/maskedmousearea/images/moon.pngbin0 -> 13263 bytes
-rw-r--r--examples/quick/maskedmousearea/main.cpp57
-rw-r--r--examples/quick/maskedmousearea/maskedmousearea.cpp141
-rw-r--r--examples/quick/maskedmousearea/maskedmousearea.h98
-rw-r--r--examples/quick/maskedmousearea/maskedmousearea.pro14
-rw-r--r--examples/quick/maskedmousearea/maskedmousearea.qml135
-rw-r--r--examples/quick/maskedmousearea/maskedmousearea.qmlproject16
-rw-r--r--src/quick/items/qquickcanvas.cpp23
-rw-r--r--src/quick/items/qquickflickable.cpp6
-rw-r--r--src/quick/items/qquickitem.cpp22
-rw-r--r--src/quick/items/qquickitem.h2
-rw-r--r--src/quick/items/qquickmousearea.cpp16
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp18
-rw-r--r--src/quick/items/qquickpathview.cpp13
-rw-r--r--src/quick/items/qquickpincharea.cpp6
-rw-r--r--tests/auto/quick/qquickitem2/data/hollowTestItem.qml38
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp171
19 files changed, 730 insertions, 46 deletions
diff --git a/examples/quick/maskedmousearea/images/cloud_1.png b/examples/quick/maskedmousearea/images/cloud_1.png
new file mode 100644
index 0000000000..87c54af253
--- /dev/null
+++ b/examples/quick/maskedmousearea/images/cloud_1.png
Binary files differ
diff --git a/examples/quick/maskedmousearea/images/cloud_2.png b/examples/quick/maskedmousearea/images/cloud_2.png
new file mode 100644
index 0000000000..981bbd2630
--- /dev/null
+++ b/examples/quick/maskedmousearea/images/cloud_2.png
Binary files differ
diff --git a/examples/quick/maskedmousearea/images/moon.png b/examples/quick/maskedmousearea/images/moon.png
new file mode 100644
index 0000000000..0a8037dd85
--- /dev/null
+++ b/examples/quick/maskedmousearea/images/moon.png
Binary files differ
diff --git a/examples/quick/maskedmousearea/main.cpp b/examples/quick/maskedmousearea/main.cpp
new file mode 100644
index 0000000000..407497e640
--- /dev/null
+++ b/examples/quick/maskedmousearea/main.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQuickView>
+
+#include "maskedmousearea.h"
+
+
+int main(int argc, char* argv[])
+{
+ QGuiApplication app(argc,argv);
+ QQuickView view;
+
+ qmlRegisterType<MaskedMouseArea>("Example", 1, 0, "MaskedMouseArea");
+
+ view.setSource(QUrl::fromLocalFile("maskedmousearea.qml"));
+ view.show();
+ return app.exec();
+}
diff --git a/examples/quick/maskedmousearea/maskedmousearea.cpp b/examples/quick/maskedmousearea/maskedmousearea.cpp
new file mode 100644
index 0000000000..3f872a66f6
--- /dev/null
+++ b/examples/quick/maskedmousearea/maskedmousearea.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "maskedmousearea.h"
+
+#include <QStyleHints>
+#include <QGuiApplication>
+
+
+MaskedMouseArea::MaskedMouseArea(QQuickItem *parent)
+ : QQuickItem(parent),
+ m_pressed(false),
+ m_alphaThreshold(0.0),
+ m_containsMouse(false)
+{
+ setAcceptHoverEvents(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+}
+
+void MaskedMouseArea::setPressed(bool pressed)
+{
+ if (m_pressed != pressed) {
+ m_pressed = pressed;
+ emit pressedChanged();
+ }
+}
+
+void MaskedMouseArea::setContainsMouse(bool containsMouse)
+{
+ if (m_containsMouse != containsMouse) {
+ m_containsMouse = containsMouse;
+ emit containsMouseChanged();
+ }
+}
+
+void MaskedMouseArea::setMaskSource(const QUrl &source)
+{
+ if (m_maskSource != source) {
+ m_maskSource = source;
+ m_maskImage = QImage(source.toLocalFile());
+ emit maskSourceChanged();
+ }
+}
+
+void MaskedMouseArea::setAlphaThreshold(qreal threshold)
+{
+ if (m_alphaThreshold != threshold) {
+ m_alphaThreshold = threshold;
+ emit alphaThresholdChanged();
+ }
+}
+
+bool MaskedMouseArea::contains(const QPointF &point) const
+{
+ if (!QQuickItem::contains(point) || m_maskImage.isNull())
+ return false;
+
+ QPoint p = point.toPoint();
+
+ if (p.x() < 0 || p.x() >= m_maskImage.width() ||
+ p.y() < 0 || p.y() >= m_maskImage.height())
+ return false;
+
+ qreal r = qBound<int>(0, m_alphaThreshold * 255, 255);
+ return qAlpha(m_maskImage.pixel(p)) > r;
+}
+
+void MaskedMouseArea::mousePressEvent(QMouseEvent *event)
+{
+ setPressed(true);
+ m_pressPoint = event->pos();
+ emit pressed();
+}
+
+void MaskedMouseArea::mouseReleaseEvent(QMouseEvent *event)
+{
+ setPressed(false);
+ emit released();
+
+ const int threshold = qApp->styleHints()->startDragDistance();
+ const bool isClick = (threshold >= qAbs(event->x() - m_pressPoint.x()) &&
+ threshold >= qAbs(event->y() - m_pressPoint.y()));
+
+ if (isClick)
+ emit clicked();
+}
+
+void MaskedMouseArea::mouseUngrabEvent()
+{
+ setPressed(false);
+ emit canceled();
+}
+
+void MaskedMouseArea::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_UNUSED(event);
+ setContainsMouse(true);
+}
+
+void MaskedMouseArea::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_UNUSED(event);
+ setContainsMouse(false);
+}
diff --git a/examples/quick/maskedmousearea/maskedmousearea.h b/examples/quick/maskedmousearea/maskedmousearea.h
new file mode 100644
index 0000000000..045d02d6f0
--- /dev/null
+++ b/examples/quick/maskedmousearea/maskedmousearea.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef MASKEDMOUSEAREA_H
+#define MASKEDMOUSEAREA_H
+
+#include <QImage>
+#include <QQuickItem>
+
+
+class MaskedMouseArea : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged)
+ Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged)
+ Q_PROPERTY(QUrl maskSource READ maskSource WRITE setMaskSource NOTIFY maskSourceChanged)
+ Q_PROPERTY(qreal alphaThreshold READ alphaThreshold WRITE setAlphaThreshold NOTIFY alphaThresholdChanged)
+
+public:
+ MaskedMouseArea(QQuickItem *parent = 0);
+
+ bool contains(const QPointF &point) const;
+
+ bool isPressed() const { return m_pressed; }
+ bool containsMouse() const { return m_containsMouse; }
+
+ QUrl maskSource() const { return m_maskSource; }
+ void setMaskSource(const QUrl &source);
+
+ qreal alphaThreshold() const { return m_alphaThreshold; }
+ void setAlphaThreshold(qreal threshold);
+
+signals:
+ void pressed();
+ void released();
+ void clicked();
+ void canceled();
+ void pressedChanged();
+ void maskSourceChanged();
+ void containsMouseChanged();
+ void alphaThresholdChanged();
+
+protected:
+ void setPressed(bool pressed);
+ void setContainsMouse(bool containsMouse);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void hoverEnterEvent(QHoverEvent *event);
+ void hoverLeaveEvent(QHoverEvent *event);
+ void mouseUngrabEvent();
+
+private:
+ bool m_pressed;
+ QUrl m_maskSource;
+ QImage m_maskImage;
+ QPointF m_pressPoint;
+ qreal m_alphaThreshold;
+ bool m_containsMouse;
+};
+
+#endif
diff --git a/examples/quick/maskedmousearea/maskedmousearea.pro b/examples/quick/maskedmousearea/maskedmousearea.pro
new file mode 100644
index 0000000000..53e14aaa4b
--- /dev/null
+++ b/examples/quick/maskedmousearea/maskedmousearea.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+
+QT += quick qml
+
+HEADERS += maskedmousearea.h
+
+SOURCES += main.cpp \
+ maskedmousearea.cpp
+
+target.path = $$[QT_INSTALL_EXAMPLES]/qtdeclarative/qtquick/maskedmousearea
+qml.files = maskedmousearea.qml images
+qml.path = $$[QT_INSTALL_EXAMPLES]/qtdeclarative/qtquick/maskedmousearea
+INSTALLS += target qml
+
diff --git a/examples/quick/maskedmousearea/maskedmousearea.qml b/examples/quick/maskedmousearea/maskedmousearea.qml
new file mode 100644
index 0000000000..82d351b04f
--- /dev/null
+++ b/examples/quick/maskedmousearea/maskedmousearea.qml
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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
+import Example 1.0
+
+Rectangle {
+ height: 480
+ width: 320
+ color: "black"
+
+ Text {
+ text: qsTr("CLICK AND HOVER")
+ opacity: 0.6
+ color: "white"
+ font.pixelSize: 20
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.topMargin: 50
+ }
+
+ Image {
+ id: moon
+ smooth: true
+ anchors.centerIn: parent
+ scale: moonArea.pressed ? 1.1 : 1.0
+ opacity: moonArea.containsMouse ? 1.0 : 0.7
+ source: Qt.resolvedUrl("images/moon.png")
+
+ MaskedMouseArea {
+ id: moonArea
+ anchors.fill: parent
+ alphaThreshold: 0.4
+ maskSource: moon.source
+ }
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+ Behavior on scale {
+ NumberAnimation { duration: 100 }
+ }
+ }
+
+ Image {
+ id: rightCloud
+ anchors {
+ centerIn: moon
+ verticalCenterOffset: 30
+ horizontalCenterOffset: 80
+ }
+ smooth: true
+ scale: rightCloudArea.pressed ? 1.1 : 1.0
+ opacity: rightCloudArea.containsMouse ? 1.0 : 0.7
+ source: Qt.resolvedUrl("images/cloud_2.png")
+
+ MaskedMouseArea {
+ id: rightCloudArea
+ anchors.fill: parent
+ alphaThreshold: 0.4
+ maskSource: rightCloud.source
+ }
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+ Behavior on scale {
+ NumberAnimation { duration: 100 }
+ }
+ }
+
+ Image {
+ id: leftCloud
+ anchors {
+ centerIn: moon
+ verticalCenterOffset: 40
+ horizontalCenterOffset: -80
+ }
+ smooth: true
+ scale: leftCloudArea.pressed ? 1.1 : 1.0
+ opacity: leftCloudArea.containsMouse ? 1.0 : 0.7
+ source: Qt.resolvedUrl("images/cloud_1.png")
+
+ MaskedMouseArea {
+ id: leftCloudArea
+ anchors.fill: parent
+ alphaThreshold: 0.4
+ maskSource: leftCloud.source
+ }
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+ Behavior on scale {
+ NumberAnimation { duration: 100 }
+ }
+ }
+}
diff --git a/examples/quick/maskedmousearea/maskedmousearea.qmlproject b/examples/quick/maskedmousearea/maskedmousearea.qmlproject
new file mode 100644
index 0000000000..709c19866f
--- /dev/null
+++ b/examples/quick/maskedmousearea/maskedmousearea.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.1
+
+Project {
+ mainFile: "maskedmousearea.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+}
diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp
index a288531beb..91102331a6 100644
--- a/src/quick/items/qquickcanvas.cpp
+++ b/src/quick/items/qquickcanvas.cpp
@@ -1039,7 +1039,7 @@ bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouse
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
QPointF p = item->mapFromScene(event->windowPos());
- if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ if (!item->contains(p))
return false;
}
@@ -1054,7 +1054,7 @@ bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouse
if (itemPrivate->acceptedMouseButtons() & event->button()) {
QPointF p = item->mapFromScene(event->windowPos());
- if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ if (item->contains(p)) {
QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers());
me.accept();
@@ -1218,7 +1218,7 @@ bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
QPointF p = item->mapFromScene(scenePos);
- if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ if (!item->contains(p))
return false;
}
@@ -1233,7 +1233,7 @@ bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
if (itemPrivate->hoverEnabled) {
QPointF p = item->mapFromScene(scenePos);
- if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ if (item->contains(p)) {
if (!hoverItems.isEmpty() && hoverItems[0] == item) {
//move
accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
@@ -1286,7 +1286,7 @@ bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
QPointF p = item->mapFromScene(event->posF());
- if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ if (!item->contains(p))
return false;
}
@@ -1300,7 +1300,8 @@ bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event
}
QPointF p = item->mapFromScene(event->posF());
- if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+
+ if (item->contains(p)) {
QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(),
event->orientation(), event->buttons(), event->modifiers());
wheel.accept();
@@ -1422,10 +1423,9 @@ bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
return false;
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- QRectF bounds(0, 0, item->width(), item->height());
for (int i=0; i<newPoints.count(); i++) {
QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (!bounds.contains(p))
+ if (!item->contains(p))
return false;
}
}
@@ -1441,12 +1441,11 @@ bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
QList<QTouchEvent::TouchPoint> matchingPoints;
if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
- QRectF bounds(0, 0, item->width(), item->height());
for (int i=0; i<newPoints.count(); i++) {
if (acceptedNewPoints->contains(newPoints[i].id()))
continue;
QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (bounds.contains(p))
+ if (item->contains(p))
matchingPoints << newPoints[i];
}
}
@@ -1537,7 +1536,7 @@ void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *e
moveEvent->setAccepted(true);
for (++grabItem; grabItem != grabber->end();) {
QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
- if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
+ if ((**grabItem)->contains(p)) {
QDragMoveEvent translatedEvent(
p.toPoint(),
moveEvent->possibleActions(),
@@ -1582,7 +1581,7 @@ bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
return false;
QPointF p = item->mapFromScene(event->pos());
- if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ if (item->contains(p)) {
if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
QDragMoveEvent translatedEvent(
p.toPoint(),
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 75c9919e34..76d36987dd 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1772,14 +1772,14 @@ void QQuickFlickable::mouseUngrabEvent()
bool QQuickFlickable::sendMouseEvent(QMouseEvent *event)
{
Q_D(QQuickFlickable);
- QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+ QPointF localPos = mapFromScene(event->windowPos());
QQuickCanvas *c = canvas();
QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
bool disabledItem = grabber && !grabber->isEnabled();
bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
- QQuickMouseEventEx mouseEvent(event->type(), mapFromScene(event->windowPos()),
+ if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
+ QQuickMouseEventEx mouseEvent(event->type(), localPos,
event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers());
QQuickMouseEventEx *eventEx = QQuickMouseEventEx::extended(event);
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index ffaec540a2..628e19dbec 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -4886,9 +4886,7 @@ bool QQuickItem::isUnderMouse() const
return false;
QPointF cursorPos = QGuiApplicationPrivate::lastCursorPosition;
- if (QRectF(0, 0, width(), height()).contains(mapFromScene(cursorPos))) // ### refactor: d->canvas->mapFromGlobal(cursorPos))))
- return true;
- return false;
+ return contains(mapFromScene(cursorPos)); // ### refactor: d->canvas->mapFromGlobal(cursorPos))))
}
bool QQuickItem::acceptHoverEvents() const
@@ -5056,6 +5054,24 @@ void QQuickItem::setKeepTouchGrab(bool keep)
}
/*!
+ Returns true if this item contains \a point, which is in local coordinates;
+ returns false otherwise.
+
+ This function can be overwritten in order to handle point collisions in items
+ with custom shapes. The default implementation checks if the point is inside
+ the item's bounding rect.
+
+ Note that it's normally used to check if the item is under the mouse cursor,
+ and for that reason, the implementation of this function should be as light-weight
+ as possible.
+*/
+bool QQuickItem::contains(const QPointF &point) const
+{
+ Q_D(const QQuickItem);
+ return QRectF(0, 0, d->width, d->height).contains(point);
+}
+
+/*!
\qmlmethod object QtQuick2::Item::mapFromItem(Item item, real x, real y)
Maps the point (\a x, \a y), which is in \a item's coordinate system, to
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 16dee80380..0d74cc0c4d 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -292,6 +292,8 @@ public:
bool keepTouchGrab() const;
void setKeepTouchGrab(bool);
+ Q_INVOKABLE virtual bool contains(const QPointF &point) const;
+
QTransform itemTransform(QQuickItem *, bool *) const;
QPointF mapToItem(const QQuickItem *item, const QPointF &point) const;
QPointF mapToScene(const QPointF &point) const;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index b8555124eb..956ca09aac 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -263,7 +263,7 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
QPointF p = item->mapFromScene(sp);
- if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ if (!item->contains(p))
return false;
}
@@ -293,7 +293,7 @@ bool QQuickMouseAreaPrivate::propagateHelper(QQuickMouseEvent *ev, QQuickItem *i
break;
}
QPointF p = item->mapFromScene(sp);
- if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ if (item->contains(p)) {
ev->setX(p.x());
ev->setY(p.y());
ev->setAccepted(true);//It is connected, they have to explicitly ignore to let it slide
@@ -725,10 +725,10 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
// ### we should skip this if these signals aren't used
// ### can GV handle this for us?
- bool contains = boundingRect().contains(d->lastPos);
- if (d->hovered && !contains)
+ const bool isInside = contains(d->lastPos);
+ if (d->hovered && !isInside)
setHovered(false);
- else if (!d->hovered && contains)
+ else if (!d->hovered && isInside)
setHovered(true);
if (d->drag && d->drag->target()) {
@@ -921,13 +921,13 @@ void QQuickMouseArea::mouseUngrabEvent()
bool QQuickMouseArea::sendMouseEvent(QMouseEvent *event)
{
Q_D(QQuickMouseArea);
- QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+ QPointF localPos = mapFromScene(event->windowPos());
QQuickCanvas *c = canvas();
QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
- QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
+ if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
+ QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers());
mouseEvent.setAccepted(false);
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 2ba7b80748..df5edfb00d 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -644,13 +644,13 @@ void QQuickMultiPointTouchArea::touchUngrabEvent()
bool QQuickMultiPointTouchArea::sendMouseEvent(QMouseEvent *event)
{
- QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+ QPointF localPos = mapFromScene(event->windowPos());
QQuickCanvas *c = canvas();
QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
bool stealThisEvent = _stealMouse;
- if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
- QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
+ if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
+ QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers());
mouseEvent.setAccepted(false);
@@ -724,25 +724,23 @@ bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event)
QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
bool disabledItem = grabber && !grabber->isEnabled();
bool stealThisEvent = _stealMouse;
- bool contains = false;
+ bool containsPoint = false;
if (!stealThisEvent) {
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseMove:
case QEvent::MouseButtonRelease: {
QMouseEvent *me = static_cast<QMouseEvent*>(event);
- QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
- contains = myRect.contains(me->windowPos());
+ containsPoint = contains(mapFromScene(me->windowPos()));
}
break;
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd: {
QTouchEvent *te = static_cast<QTouchEvent*>(event);
- QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
foreach (const QTouchEvent::TouchPoint &point, te->touchPoints()) {
- if (myRect.contains(point.scenePos())) {
- contains = true;
+ if (contains(mapFromScene(point.scenePos()))) {
+ containsPoint = true;
break;
}
}
@@ -752,7 +750,7 @@ bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event)
break;
}
}
- if ((stealThisEvent || contains) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
+ if ((stealThisEvent || containsPoint) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
return true;
}
ungrab();
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 836943c478..ba5b237596 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -1300,12 +1300,10 @@ void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event)
if (!interactive || !items.count() || !model || !modelCount)
return;
velocityBuffer.clear();
- QPointF scenePoint = q->mapToScene(event->localPos());
int idx = 0;
for (; idx < items.count(); ++idx) {
- QRectF rect = items.at(idx)->boundingRect();
- rect = items.at(idx)->mapRectToScene(rect);
- if (rect.contains(scenePoint))
+ QQuickItem *item = items.at(idx);
+ if (item->contains(item->mapFromScene(event->windowPos())))
break;
}
if (idx == items.count() && dragMargin == 0.) // didn't click on an item
@@ -1470,12 +1468,13 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
bool QQuickPathView::sendMouseEvent(QMouseEvent *event)
{
Q_D(QQuickPathView);
- QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+ QPointF localPos = mapFromScene(event->windowPos());
+
QQuickCanvas *c = canvas();
QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
- QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
+ if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
+ QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers());
mouseEvent.setAccepted(false);
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 6f79385d96..eba9d098ff 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -503,13 +503,13 @@ void QQuickPinchArea::mouseUngrabEvent()
bool QQuickPinchArea::sendMouseEvent(QMouseEvent *event)
{
Q_D(QQuickPinchArea);
- QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+ QPointF localPos = mapFromScene(event->windowPos());
QQuickCanvas *c = canvas();
QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
- QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
+ if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
+ QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers());
mouseEvent.setAccepted(false);
diff --git a/tests/auto/quick/qquickitem2/data/hollowTestItem.qml b/tests/auto/quick/qquickitem2/data/hollowTestItem.qml
new file mode 100644
index 0000000000..d07d89c4f4
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/hollowTestItem.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+import Test 1.0
+
+Rectangle {
+ width: 400
+ height: 400
+
+ Rectangle {
+ x: 100
+ y: 100
+ width: 200
+ height: 200
+ rotation: 45
+
+ Rectangle {
+ scale: 0.5
+ color: "black"
+ anchors.fill: parent
+ radius: hollowItem.circle ? 100 : 0
+
+ Rectangle {
+ color: "white"
+ anchors.centerIn: parent
+ width: hollowItem.holeRadius * 2
+ height: hollowItem.holeRadius * 2
+ radius: hollowItem.circle ? 100 : 0
+ }
+
+ HollowTestItem {
+ id: hollowItem
+ anchors.fill: parent
+ objectName: "hollowItem"
+ holeRadius: 50
+ circle: circleShapeTest
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index c2390c4525..34f51875c9 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -93,6 +93,9 @@ private slots:
void qtbug_16871();
void visibleChildren();
void parentLoop();
+ void contains_data();
+ void contains();
+
private:
QQmlEngine engine;
};
@@ -178,6 +181,69 @@ public:
QML_DECLARE_TYPE(KeyTestItem);
+class HollowTestItem : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool circle READ isCircle WRITE setCircle)
+ Q_PROPERTY(qreal holeRadius READ holeRadius WRITE setHoleRadius)
+
+public:
+ HollowTestItem(QQuickItem *parent = 0)
+ : QQuickItem(parent),
+ m_isPressed(false),
+ m_isHovered(false),
+ m_isCircle(false),
+ m_holeRadius(50)
+ {
+ setAcceptHoverEvents(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+ }
+
+ bool isPressed() const { return m_isPressed; }
+ bool isHovered() const { return m_isHovered; }
+
+ bool isCircle() const { return m_isCircle; }
+ void setCircle(bool circle) { m_isCircle = circle; }
+
+ qreal holeRadius() const { return m_holeRadius; }
+ void setHoleRadius(qreal radius) { m_holeRadius = radius; }
+
+ bool contains(const QPointF &point) const {
+ const qreal w = width();
+ const qreal h = height();
+ const qreal r = m_holeRadius;
+
+ // check boundaries
+ if (!QRectF(0, 0, w, h).contains(point))
+ return false;
+
+ // square shape
+ if (!m_isCircle)
+ return !QRectF(w / 2 - r, h / 2 - r, r * 2, r * 2).contains(point);
+
+ // circle shape
+ const qreal dx = point.x() - (w / 2);
+ const qreal dy = point.y() - (h / 2);
+ const qreal dd = (dx * dx) + (dy * dy);
+ const qreal outerRadius = qMin<qreal>(w / 2, h / 2);
+ return dd > (r * r) && dd <= outerRadius * outerRadius;
+ }
+
+protected:
+ void hoverEnterEvent(QHoverEvent *) { m_isHovered = true; }
+ void hoverLeaveEvent(QHoverEvent *) { m_isHovered = false; }
+ void mousePressEvent(QMouseEvent *) { m_isPressed = true; }
+ void mouseReleaseEvent(QMouseEvent *) { m_isPressed = false; }
+
+private:
+ bool m_isPressed;
+ bool m_isHovered;
+ bool m_isCircle;
+ qreal m_holeRadius;
+};
+
+QML_DECLARE_TYPE(HollowTestItem);
+
tst_QQuickItem::tst_QQuickItem()
{
@@ -187,6 +253,7 @@ void tst_QQuickItem::initTestCase()
{
QQmlDataTest::initTestCase();
qmlRegisterType<KeyTestItem>("Test",1,0,"KeyTestItem");
+ qmlRegisterType<HollowTestItem>("Test", 1, 0, "HollowTestItem");
}
void tst_QQuickItem::cleanup()
@@ -1375,6 +1442,110 @@ void tst_QQuickItem::parentLoop()
delete canvas;
}
+void tst_QQuickItem::contains_data()
+{
+ QTest::addColumn<bool>("circleTest");
+ QTest::addColumn<bool>("insideTarget");
+ QTest::addColumn<QList<QPoint> >("points");
+
+ QList<QPoint> points;
+
+ points << QPoint(176, 176)
+ << QPoint(176, 226)
+ << QPoint(226, 176)
+ << QPoint(226, 226)
+ << QPoint(150, 200)
+ << QPoint(200, 150)
+ << QPoint(200, 250)
+ << QPoint(250, 200);
+ QTest::newRow("hollow square: testing points inside") << false << true << points;
+
+ points.clear();
+ points << QPoint(162, 162)
+ << QPoint(162, 242)
+ << QPoint(242, 162)
+ << QPoint(242, 242)
+ << QPoint(200, 200)
+ << QPoint(175, 200)
+ << QPoint(200, 175)
+ << QPoint(200, 228)
+ << QPoint(228, 200)
+ << QPoint(200, 122)
+ << QPoint(122, 200)
+ << QPoint(200, 280)
+ << QPoint(280, 200);
+ QTest::newRow("hollow square: testing points outside") << false << false << points;
+
+ points.clear();
+ points << QPoint(174, 174)
+ << QPoint(174, 225)
+ << QPoint(225, 174)
+ << QPoint(225, 225)
+ << QPoint(165, 200)
+ << QPoint(200, 165)
+ << QPoint(200, 235)
+ << QPoint(235, 200);
+ QTest::newRow("hollow circle: testing points inside") << true << true << points;
+
+ points.clear();
+ points << QPoint(160, 160)
+ << QPoint(160, 240)
+ << QPoint(240, 160)
+ << QPoint(240, 240)
+ << QPoint(200, 200)
+ << QPoint(185, 185)
+ << QPoint(185, 216)
+ << QPoint(216, 185)
+ << QPoint(216, 216)
+ << QPoint(145, 200)
+ << QPoint(200, 145)
+ << QPoint(255, 200)
+ << QPoint(200, 255);
+ QTest::newRow("hollow circle: testing points outside") << true << false << points;
+}
+
+void tst_QQuickItem::contains()
+{
+ QFETCH(bool, circleTest);
+ QFETCH(bool, insideTarget);
+ QFETCH(QList<QPoint>, points);
+
+ QQuickView *canvas = new QQuickView(0);
+ canvas->rootContext()->setContextProperty("circleShapeTest", circleTest);
+ canvas->setBaseSize(QSize(400, 400));
+ canvas->setSource(testFileUrl("hollowTestItem.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QTest::qWaitForWindowShown(canvas);
+ QTRY_VERIFY(QGuiApplication::focusWindow() == canvas);
+
+ QQuickItem *root = qobject_cast<QQuickItem *>(canvas->rootObject());
+ QVERIFY(root);
+
+ HollowTestItem *hollowItem = root->findChild<HollowTestItem *>("hollowItem");
+ QVERIFY(hollowItem);
+
+ foreach (const QPoint &point, points) {
+ // check mouse hover
+ QTest::mouseMove(canvas, point);
+ QTest::qWait(10);
+ QCOMPARE(hollowItem->isHovered(), insideTarget);
+
+ // check mouse press
+ QTest::mousePress(canvas, Qt::LeftButton, 0, point);
+ QTest::qWait(10);
+ QCOMPARE(hollowItem->isPressed(), insideTarget);
+
+ // check mouse release
+ QTest::mouseRelease(canvas, Qt::LeftButton, 0, point);
+ QTest::qWait(10);
+ QCOMPARE(hollowItem->isPressed(), false);
+ }
+
+ delete canvas;
+}
+
+
QTEST_MAIN(tst_QQuickItem)
#include "tst_qquickitem.moc"