Allow descendant chains to simultaneously be hovered.

Matches GV behaviour. Also fixes a bug in QSGMouseArea,
which we aren't fixing for QtQuick 1.

Task-number: QTBUG-18175
Change-Id: I4ecac7b908504f28de830732c731281407d7b0bc
Reviewed-on: http://codereview.qt.nokia.com/2422
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
This commit is contained in:
Alan Alpert 2011-08-01 16:20:26 +10:00 committed by Qt by Nokia
parent 9dfd621aec
commit 1b65161042
6 changed files with 140 additions and 27 deletions

View File

@ -422,7 +422,6 @@ QSGCanvasPrivate::QSGCanvasPrivate()
: rootItem(0)
, activeFocusItem(0)
, mouseGrabberItem(0)
, hoverItem(0)
, dirtyItemList(0)
, context(0)
, contextFailed(false)
@ -955,17 +954,19 @@ QSGItem *QSGCanvas::mouseGrabberItem() const
}
void QSGCanvasPrivate::clearHover()
bool QSGCanvasPrivate::clearHover()
{
Q_Q(QSGCanvas);
if (!hoverItem)
return;
if (hoverItems.isEmpty())
return false;
QPointF pos = q->mapFromGlobal(QCursor::pos());
QSGItem *item = hoverItem;
hoverItem = 0;
sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QApplication::keyboardModifiers(), true);
bool accepted = false;
foreach (QSGItem* item, hoverItems)
accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QApplication::keyboardModifiers(), true) || accepted;
hoverItems.clear();
return accepted;
}
@ -1205,11 +1206,7 @@ void QSGCanvas::mouseMoveEvent(QMouseEvent *event)
bool delivered = d->deliverHoverEvent(d->rootItem, event->pos(), last, event->modifiers(), accepted);
if (!delivered) {
//take care of any exits
if (d->hoverItem) {
QSGItem *item = d->hoverItem;
d->hoverItem = 0;
accepted = d->sendHoverEvent(QEvent::HoverLeave, item, event->pos(), last, event->modifiers(), accepted);
}
accepted = d->clearHover();
}
event->setAccepted(accepted);
return;
@ -1247,20 +1244,43 @@ bool QSGCanvasPrivate::deliverHoverEvent(QSGItem *item, const QPointF &scenePos,
if (itemPrivate->hoverEnabled) {
QPointF p = item->mapFromScene(scenePos);
if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
if (hoverItem == item) {
if (!hoverItems.isEmpty() && hoverItems[0] == item) {
//move
accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
} else {
//exit from previous
if (hoverItem) {
QSGItem *item = hoverItem;
hoverItem = 0;
accepted = sendHoverEvent(QEvent::HoverLeave, item, scenePos, lastScenePos, modifiers, accepted);
QList<QSGItem*> parents;
QSGItem* parent = item;
parents << item;
while ((parent = parent->parentItem()))
parents << parent;
//exit from previous (excepting ancestors)
while (!hoverItems.isEmpty() && !parents.contains(hoverItems[0])){
sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
hoverItems.removeFirst();
}
//enter new item
hoverItem = item;
accepted = sendHoverEvent(QEvent::HoverEnter, item, scenePos, lastScenePos, modifiers, accepted);
if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
} else {
//enter any ancestors that also wish to be hovered and aren't
int startIdx = -1;
if (!hoverItems.isEmpty())
startIdx = parents.indexOf(hoverItems[0]);
if (startIdx == -1)
startIdx = parents.count() - 1;
for (int i = startIdx; i >= 0; i--) {
if (QSGItemPrivate::get(parents[i])->hoverEnabled) {
hoverItems.prepend(parents[i]);
sendHoverEvent(QEvent::HoverEnter, parents[i], scenePos, lastScenePos, modifiers, accepted);
}
}
//enter new item
hoverItems.prepend(item);
accepted = sendHoverEvent(QEvent::HoverEnter, item, scenePos, lastScenePos, modifiers, accepted);
}
}
return true;
}

View File

@ -117,11 +117,11 @@ public:
bool deliverHoverEvent(QSGItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
bool sendHoverEvent(QEvent::Type, QSGItem *, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, bool accepted);
void clearHover();
bool clearHover();
void deliverDragEvent(QSGDragEvent *);
bool deliverDragEvent(QSGItem *item, QSGDragEvent *);
QDeclarativeGuard<QSGItem> hoverItem;
QList<QSGItem*> hoverItems;
enum FocusOption {
DontChangeFocusProperty = 0x01,
};

View File

@ -1161,6 +1161,8 @@ void QSGItemPrivate::initCanvas(InitializationState *state, QSGCanvas *c)
c->itemsToPolish.remove(q);
if (c->mouseGrabberItem == q)
c->mouseGrabberItem = 0;
if ( hoverEnabled )
c->hoverItems.removeAll(q);
}
canvas = c;
@ -3021,8 +3023,21 @@ void QSGItem::setAcceptHoverEvents(bool enabled)
Q_D(QSGItem);
d->hoverEnabled = enabled;
if (d->canvas && d->hoverEnabled && !d->canvas->hasMouseTracking())
d->canvas->setMouseTracking(true);
if (d->canvas){
QSGCanvasPrivate *c = QSGCanvasPrivate::get(d->canvas);
if (d->hoverEnabled){
if (!d->canvas->hasMouseTracking())
d->canvas->setMouseTracking(true);
if (isUnderMouse())
c->hoverItems.prepend(this);
c->sendHoverEvent(QEvent::HoverEnter, this, c->lastMousePosition, c->lastMousePosition,
QApplication::keyboardModifiers(), true);
} else {
c->hoverItems.removeAll(this);
c->sendHoverEvent(QEvent::HoverLeave, this, c->lastMousePosition, c->lastMousePosition,
QApplication::keyboardModifiers(), true);
}
}
}
void QSGItem::grabMouse()

View File

@ -834,8 +834,6 @@ void QSGMouseArea::setHoverEnabled(bool h)
setAcceptHoverEvents(h);
emit hoverEnabledChanged();
if (d->hovered != isUnderMouse())
setHovered(!d->hovered);
}
bool QSGMouseArea::hovered() const

View File

@ -0,0 +1,54 @@
import QtQuick 2.0
Item{
width: 400
height: 200
property bool point1: ma2.containsMouse && !ma1.containsMouse
property bool point2: ma3.containsMouse && ma4.containsMouse
Rectangle{
width: 200
height: 200
color: ma1.containsMouse ? "red" : "white"
MouseArea{
id: ma1
hoverEnabled: true
anchors.fill: parent
}
Rectangle{
width: 100
height: 100
color: ma2.containsMouse ? "blue" : "white"
MouseArea{
id: ma2
hoverEnabled: true
anchors.fill: parent
}
}
}
Item{
x:200
Rectangle{
width: 200
height: 200
color: ma3.containsMouse ? "yellow" : "white"
Rectangle{
width: 100
height: 100
color: ma4.containsMouse ? "green" : "white"
}
}
MouseArea{
id: ma3
hoverEnabled: true
width: 200
height: 200
MouseArea{
id: ma4
width: 100
height: 100
hoverEnabled: true
}
}
}
}

View File

@ -75,6 +75,7 @@ private slots:
void testQtQuick11Attributes();
void testQtQuick11Attributes_data();
void hoverPosition();
void hoverPropagation();
private:
QSGView *createView();
@ -741,6 +742,31 @@ void tst_QSGMouseArea::hoverPosition()
delete canvas;
}
void tst_QSGMouseArea::hoverPropagation()
{
//QTBUG-18175, to behave like GV did.
QSGView *canvas = createView();
canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/hoverPropagation.qml"));
QSGItem *root = canvas->rootObject();
QVERIFY(root != 0);
QCOMPARE(root->property("point1").toBool(), false);
QCOMPARE(root->property("point2").toBool(), false);
QMouseEvent moveEvent(QEvent::MouseMove, QPoint(32, 32), Qt::NoButton, Qt::NoButton, 0);
QApplication::sendEvent(canvas, &moveEvent);
QCOMPARE(root->property("point1").toBool(), true);
QCOMPARE(root->property("point2").toBool(), false);
QMouseEvent moveEvent2(QEvent::MouseMove, QPoint(232, 32), Qt::NoButton, Qt::NoButton, 0);
QApplication::sendEvent(canvas, &moveEvent2);
QCOMPARE(root->property("point1").toBool(), false);
QCOMPARE(root->property("point2").toBool(), true);
delete canvas;
}
QTEST_MAIN(tst_QSGMouseArea)
#include "tst_qsgmousearea.moc"