diff options
author | Michael Hasselmann <michaelh@openismus.com> | 2011-02-10 18:14:45 (GMT) |
---|---|---|
committer | Jan-Arve Sæther <jan-arve.saether@nokia.com> | 2011-03-16 08:37:52 (GMT) |
commit | 517290f73be74d1cf08fbd603870d3dacc379ff3 (patch) | |
tree | 8354ffe3c15c37544fae1e284bfa6bb0ec18e3f2 | |
parent | 5949c215bd53582d0c6481f606a9ec015f067b37 (diff) | |
download | Qt-517290f73be74d1cf08fbd603870d3dacc379ff3.zip Qt-517290f73be74d1cf08fbd603870d3dacc379ff3.tar.gz Qt-517290f73be74d1cf08fbd603870d3dacc379ff3.tar.bz2 |
Introduce QGraphicsItem::ItemStopsFocusHandling flag
When set for an item, QGraphicsScene will skip focus handling for this item and
everything underneath it (including focus-out). Allows users to reimplement
custom focus handling.
Use case: touch devices that implement panning. Here, focus-in has to happen
only if no panning was triggered. Analogous, no focus-out should happen when
panning was detected.
Fixes the alternative proposal ("black holes for focus changes") of
QTBUG-16343: QGraphicsView doesn't support focus change on mouse release.
The previous test was only testing one scenario, which didn't give a good idea
whether the flag was actually working as intended.
Task-number: QTBUG-17505
Reviewed-by: Yoann Lopes
Reviewed-by: Jan-Arve Sæther
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 8 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 3 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 6 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 17 | ||||
-rw-r--r-- | tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 69 |
5 files changed, 84 insertions, 19 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index f463887..4e2d4e2 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -417,6 +417,11 @@ click focus to items underneath when being clicked on. This flag allows you create a non-focusable item that can be clicked on without changing the focus. \endomit + + \omitvalue ItemStopsFocusHandling \omit Same as + ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag + allows you to completely take over focus handling. + This flag was introduced in Qt 4.7. */ /*! @@ -11549,6 +11554,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemStopsClickFocusPropagation: str = "ItemStopsClickFocusPropagation"; break; + case QGraphicsItem::ItemStopsFocusHandling: + str = "ItemStopsFocusHandling"; + break; } debug << str; return debug; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index e59a7c9..67c9cd3 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -107,7 +107,8 @@ public: ItemIsPanel = 0x4000, ItemIsFocusScope = 0x8000, // internal ItemSendsScenePositionChanges = 0x10000, - ItemStopsClickFocusPropagation = 0x20000 + ItemStopsClickFocusPropagation = 0x20000, + ItemStopsFocusHandling = 0x40000 // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 5c82116..90ff43f 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -559,7 +559,7 @@ public: quint32 dirtyChildrenBoundingRect : 1; // Packed 32 bits - quint32 flags : 18; + quint32 flags : 19; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; quint32 geometryChanged : 1; @@ -573,9 +573,9 @@ public: quint32 sceneTransformTranslateOnly : 1; quint32 notifyBoundingRectChanged : 1; quint32 notifyInvalidated : 1; - quint32 mouseSetsFocus : 1; // New 32 bits + quint32 mouseSetsFocus : 1; quint32 explicitActivate : 1; quint32 wantsActive : 1; quint32 holesInSiblingIndex : 1; @@ -586,7 +586,7 @@ public: quint32 mayHaveChildWithGraphicsEffect : 1; quint32 isDeclarativeItem : 1; quint32 sendParentChangeNotification : 1; - quint32 padding : 22; + quint32 padding : 21; // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index f997fc2..2d85de6 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1317,8 +1317,10 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // Set focus on the topmost enabled item that can take focus. bool setFocus = false; + foreach (QGraphicsItem *item, cachedItemsUnderMouse) { - if (item->isBlockedByModalPanel()) { + if (item->isBlockedByModalPanel() + || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) { // Make sure we don't clear focus. setFocus = true; break; @@ -1331,10 +1333,10 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou break; } } - if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation) - break; if (item->isPanel()) break; + if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation) + break; } // Check for scene modality. @@ -5925,6 +5927,7 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve // Set focus on the topmost enabled item that can take focus. bool setFocus = false; + foreach (QGraphicsItem *item, cachedItemsUnderMouse) { if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) { if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { @@ -5938,6 +5941,11 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve break; if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation) break; + if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) { + // Make sure we don't clear focus. + setFocus = true; + break; + } } // If nobody could take focus, clear it. @@ -5970,7 +5978,8 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve } if (item && item->isPanel()) break; - if (item && (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)) + if (item && (item->d_ptr->flags + & (QGraphicsItem::ItemStopsClickFocusPropagation | QGraphicsItem::ItemStopsFocusHandling))) break; } diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index dacb61e..168f75e 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -447,7 +447,8 @@ private slots: void updateMicroFocus(); void textItem_shortcuts(); void scroll(); - void stopClickFocusPropagation(); + void focusHandling_data(); + void focusHandling(); void deviceCoordinateCache_simpleRotations(); // task specific tests below me @@ -10537,8 +10538,39 @@ void tst_QGraphicsItem::scroll() QCOMPARE(item2->lastExposedRect, expectedItem2Expose); } -void tst_QGraphicsItem::stopClickFocusPropagation() +Q_DECLARE_METATYPE(QGraphicsItem::GraphicsItemFlag); + +void tst_QGraphicsItem::focusHandling_data() { + QTest::addColumn<QGraphicsItem::GraphicsItemFlag>("focusFlag"); + QTest::addColumn<bool>("useStickyFocus"); + QTest::addColumn<int>("expectedFocusItem"); // 0: none, 1: focusableUnder, 2: itemWithFocus + + QTest::newRow("Focus goes through.") + << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << false << 1; + + QTest::newRow("Focus goes through, even with sticky scene.") + << static_cast<QGraphicsItem::GraphicsItemFlag>(0x0) << true << 1; + + QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (but can still focus-out).") + << QGraphicsItem::ItemStopsClickFocusPropagation << false << 0; + + QTest::newRow("With ItemStopsClickFocusPropagation, we cannot focus the item beneath the flagged one (and cannot focus-out if scene is sticky).") + << QGraphicsItem::ItemStopsClickFocusPropagation << true << 2; + + QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses.") + << QGraphicsItem::ItemStopsFocusHandling << false << 2; + + QTest::newRow("With ItemStopsFocusHandling, focus cannot be changed by presses (even if scene is sticky).") + << QGraphicsItem::ItemStopsFocusHandling << true << 2; +} + +void tst_QGraphicsItem::focusHandling() +{ + QFETCH(QGraphicsItem::GraphicsItemFlag, focusFlag); + QFETCH(bool, useStickyFocus); + QFETCH(int, expectedFocusItem); + class MyItem : public QGraphicsRectItem { public: @@ -10549,12 +10581,9 @@ void tst_QGraphicsItem::stopClickFocusPropagation() } }; - QGraphicsScene scene(-50, -50, 400, 400); - scene.setStickyFocus(true); - QGraphicsRectItem *noFocusOnTop = new MyItem; + noFocusOnTop->setFlag(QGraphicsItem::ItemIsFocusable, false); noFocusOnTop->setBrush(Qt::yellow); - noFocusOnTop->setFlag(QGraphicsItem::ItemStopsClickFocusPropagation); QGraphicsRectItem *focusableUnder = new MyItem; focusableUnder->setBrush(Qt::blue); @@ -10566,9 +10595,13 @@ void tst_QGraphicsItem::stopClickFocusPropagation() itemWithFocus->setFlag(QGraphicsItem::ItemIsFocusable); itemWithFocus->setPos(250, 10); + QGraphicsScene scene(-50, -50, 400, 400); scene.addItem(noFocusOnTop); scene.addItem(focusableUnder); scene.addItem(itemWithFocus); + scene.setStickyFocus(useStickyFocus); + + noFocusOnTop->setFlag(focusFlag); focusableUnder->stackBefore(noFocusOnTop); itemWithFocus->setFocus(); @@ -10580,14 +10613,28 @@ void tst_QGraphicsItem::stopClickFocusPropagation() QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); QVERIFY(itemWithFocus->hasFocus()); - QPointF mousePressPoint = noFocusOnTop->mapToScene(QPointF()); - mousePressPoint.rx() += 60; - mousePressPoint.ry() += 60; + const QPointF mousePressPoint = noFocusOnTop->mapToScene(noFocusOnTop->boundingRect().center()); const QList<QGraphicsItem *> itemsAtMousePressPosition = scene.items(mousePressPoint); - QVERIFY(itemsAtMousePressPosition.contains(focusableUnder)); + QVERIFY(itemsAtMousePressPosition.contains(noFocusOnTop)); sendMousePress(&scene, mousePressPoint); - QVERIFY(itemWithFocus->hasFocus()); + + switch (expectedFocusItem) { + case 0: + QCOMPARE(scene.focusItem(), static_cast<QGraphicsRectItem *>(0)); + break; + case 1: + QCOMPARE(scene.focusItem(), focusableUnder); + break; + case 2: + QCOMPARE(scene.focusItem(), itemWithFocus); + break; + } + + // Sanity check - manually setting the focus must work regardless of our + // focus handling flags: + focusableUnder->setFocus(); + QCOMPARE(scene.focusItem(), focusableUnder); } void tst_QGraphicsItem::deviceCoordinateCache_simpleRotations() |