aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2012-07-25 14:04:47 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-26 05:54:37 +0200
commit419296133aa68a317838e047b22513f1e5508b47 (patch)
treee3a0597f6d9c83cc2ac06eba385decd3ec12ff62 /src/quick/items
parent57485805057eda17008d14ca618e9c1f69a5a35d (diff)
Fix resolution of cursor when items are overlapping.
If MouseArea with cursorShapes are overlapping then cursor shape of the foremost item under the mouse cursor should be shown, but because the hover events are delivered to the foremost items first the opposite is occuring. This makes QQuickWindow responsible for correctly setting its own cursor instead of relying on items to work it out amongst themselves. Change-Id: Iedf144c583dfa3d1ff441e19db9601b5e171902a Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/qquickitem.cpp91
-rw-r--r--src/quick/items/qquickitem.h7
-rw-r--r--src/quick/items/qquickitem_p.h6
-rw-r--r--src/quick/items/qquickmousearea.cpp25
-rw-r--r--src/quick/items/qquickmousearea_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp50
-rw-r--r--src/quick/items/qquickwindow_p.h7
7 files changed, 169 insertions, 19 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index fefddad4b6..5930b5fb0b 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -68,6 +68,10 @@
#include <private/qqmlaccessors_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
+#ifndef QT_NO_CURSOR
+# include <QtGui/qcursor.h>
+#endif
+
#include <float.h>
// XXX todo Check that elements that create items handle memory correctly after visual ownership change
@@ -2266,6 +2270,10 @@ void QQuickItemPrivate::derefWindow()
}
if (c->mouseGrabberItem == q)
c->mouseGrabberItem = 0;
+#ifndef QT_NO_CURSOR
+ if (c->cursorItem == q)
+ c->cursorItem = 0;
+#endif
if ( hoverEnabled )
c->hoverItems.removeAll(q);
if (itemNodeInstance)
@@ -2429,6 +2437,7 @@ QQuickItemPrivate::QQuickItemPrivate()
, inheritMirrorFromItem(false)
, isAccessible(false)
, culled(false)
+ , hasCursor(false)
, dirtyAttributes(0)
, nextDirtyItem(0)
, prevDirtyItem(0)
@@ -5113,6 +5122,88 @@ void QQuickItem::setAcceptHoverEvents(bool enabled)
d->hoverEnabled = enabled;
}
+#ifndef QT_NO_CURSOR
+
+
+/*!
+ Returns the cursor shape for this item.
+
+ The mouse cursor will assume this shape when it is over this
+ item, unless an override cursor is set.
+ See the \l{Qt::CursorShape}{list of predefined cursor objects} for a
+ range of useful shapes.
+
+ If no cursor shape has been set this returns a cursor with the Qt::ArrowCursor shape, however
+ another cursor shape may be displayed if an overlapping item has a valid cursor.
+
+ \sa setCursor(), unsetCursor()
+*/
+
+QCursor QQuickItem::cursor() const
+{
+ Q_D(const QQuickItem);
+ return d->extra.isAllocated()
+ ? d->extra->cursor
+ : QCursor();
+}
+
+/*!
+ Sets the \a cursor shape for this item.
+
+ \sa cursor(), unsetCursor()
+*/
+
+void QQuickItem::setCursor(const QCursor &cursor)
+{
+ Q_D(QQuickItem);
+
+ Qt::CursorShape oldShape = d->extra.isAllocated() ? d->extra->cursor.shape() : Qt::ArrowCursor;
+
+ if (oldShape != cursor.shape() || oldShape >= Qt::LastCursor || cursor.shape() >= Qt::LastCursor) {
+ d->extra.value().cursor = cursor;
+ if (d->window) {
+ QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(d->window);
+ if (windowPrivate->cursorItem == this)
+ d->window->setCursor(cursor);
+ }
+ }
+
+ if (!d->hasCursor) {
+ d->hasCursor = true;
+ if (d->window) {
+ QPointF pos = d->window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
+ if (contains(mapFromScene(pos)))
+ QQuickWindowPrivate::get(d->window)->updateCursor(pos);
+ }
+ }
+}
+
+/*!
+ Clears the cursor shape for this item.
+
+ \sa cursor(), setCursor()
+*/
+
+void QQuickItem::unsetCursor()
+{
+ Q_D(QQuickItem);
+ if (!d->hasCursor)
+ return;
+ d->hasCursor = false;
+ if (d->extra.isAllocated())
+ d->extra->cursor = QCursor();
+
+ if (d->window) {
+ QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(d->window);
+ if (windowPrivate->cursorItem == this) {
+ QPointF pos = d->window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
+ windowPrivate->updateCursor(pos);
+ }
+ }
+}
+
+#endif
+
void QQuickItem::grabMouse()
{
Q_D(QQuickItem);
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 61bb3250ea..8854449d2b 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -80,6 +80,7 @@ private:
Q_DECLARE_PRIVATE(QQuickTransform)
};
+class QCursor;
class QQuickItemLayer;
class QQmlV8Function;
class QQuickState;
@@ -282,6 +283,12 @@ public:
bool acceptHoverEvents() const;
void setAcceptHoverEvents(bool enabled);
+#ifndef QT_NO_CURSOR
+ QCursor cursor() const;
+ void setCursor(const QCursor &cursor);
+ void unsetCursor();
+#endif
+
bool isUnderMouse() const;
void grabMouse();
void ungrabMouse();
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index adfe384b25..9dc7344b89 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -342,6 +342,9 @@ public:
QQuickLayoutMirroringAttached* layoutDirectionAttached;
QQuickItemKeyFilter *keyHandler;
mutable QQuickItemLayer *layer;
+#ifndef QT_NO_CURSOR
+ QCursor cursor;
+#endif
QPointF userTransformOriginPoint;
int effectRefCount;
@@ -408,7 +411,8 @@ public:
bool inheritMirrorFromItem:1;
bool isAccessible:1;
bool culled:1;
- // bool dummy:2
+ bool hasCursor:1;
+ // bool dummy:1
// Bit 32
enum DirtyType {
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 5cfd62ff8f..85a224fc93 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -1136,15 +1136,6 @@ void QQuickMouseArea::setHovered(bool h)
d->hovered = h;
emit hoveredChanged();
d->hovered ? emit entered() : emit exited();
-#ifndef QT_NO_CURSOR
- if (d->cursor) {
- if (d->hovered) {
- window()->setCursor(QCursor(*d->cursor));
- } else {
- window()->unsetCursor();
- }
- }
-#endif
}
}
@@ -1274,19 +1265,19 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p)
#ifndef QT_NO_CURSOR
Qt::CursorShape QQuickMouseArea::cursorShape() const
{
- Q_D(const QQuickMouseArea);
- if (d->cursor)
- return d->cursor->shape();
- return Qt::ArrowCursor;
+ return cursor().shape();
}
void QQuickMouseArea::setCursorShape(Qt::CursorShape shape)
{
- Q_D(QQuickMouseArea);
- setHoverEnabled(true);
- delete d->cursor;
- d->cursor = new QCursor(shape);
+ if (cursor().shape() == shape)
+ return;
+
+ setCursor(shape);
+
+ emit cursorShapeChanged();
}
+
#endif
/*!
diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h
index 8a8de3bdc3..3385485cac 100644
--- a/src/quick/items/qquickmousearea_p.h
+++ b/src/quick/items/qquickmousearea_p.h
@@ -144,7 +144,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseArea : public QQuickItem
Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged)
Q_PROPERTY(bool propagateComposedEvents READ propagateComposedEvents WRITE setPropagateComposedEvents NOTIFY propagateComposedEventsChanged)
#ifndef QT_NO_CURSOR
- Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged)
+ Q_PROPERTY(Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape RESET unsetCursor NOTIFY cursorShapeChanged)
#endif
public:
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 1d3adea5cb..4cfe1a101c 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -326,6 +326,9 @@ QQuickWindowPrivate::QQuickWindowPrivate()
: rootItem(0)
, activeFocusItem(0)
, mouseGrabberItem(0)
+#ifndef QT_NO_CURSOR
+ , cursorItem(0)
+#endif
, touchMouseId(-1)
, touchMousePressTimestamp(0)
, renderWithoutShowing(false)
@@ -1301,6 +1304,10 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
qWarning() << "QQuickWindow::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
#endif
+#ifndef QT_NO_CURSOR
+ d->updateCursor(event->windowPos());
+#endif
+
if (!d->mouseGrabberItem) {
if (d->lastMousePosition.isNull())
d->lastMousePosition = event->windowPos();
@@ -1832,6 +1839,49 @@ bool QQuickWindowPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
}
#endif // QT_NO_DRAGANDDROP
+#ifndef QT_NO_CURSOR
+void QQuickWindowPrivate::updateCursor(const QPointF &scenePos)
+{
+ Q_Q(QQuickWindow);
+
+ QQuickItem *oldCursorItem = cursorItem;
+ cursorItem = findCursorItem(rootItem, scenePos);
+
+ if (cursorItem != oldCursorItem) {
+ if (cursorItem)
+ q->setCursor(cursorItem->cursor());
+ else
+ q->unsetCursor();
+ }
+}
+
+QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF &scenePos)
+{
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(scenePos);
+ if (!item->contains(p))
+ return 0;
+ }
+
+ QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QQuickItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled())
+ continue;
+ if (QQuickItem *cursorItem = findCursorItem(child, scenePos))
+ return cursorItem;
+ }
+
+ if (itemPrivate->hasCursor) {
+ QPointF p = item->mapFromScene(scenePos);
+ if (item->contains(p))
+ return item;
+ }
+ return 0;
+}
+#endif
+
bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event)
{
if (!target)
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 52e46ca6a8..267c8d3104 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -113,6 +113,9 @@ public:
// Keeps track of the item currently receiving mouse events
QQuickItem *mouseGrabberItem;
+#ifndef QT_NO_CURSOR
+ QQuickItem *cursorItem;
+#endif
#ifndef QT_NO_DRAGANDDROP
QQuickDragGrabber dragGrabber;
#endif
@@ -145,6 +148,10 @@ public:
void deliverDragEvent(QQuickDragGrabber *, QEvent *);
bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *);
#endif
+#ifndef QT_NO_CURSOR
+ void updateCursor(const QPointF &scenePos);
+ QQuickItem *findCursorItem(QQuickItem *item, const QPointF &scenePos);
+#endif
QList<QQuickItem*> hoverItems;
enum FocusOption {