From 9a107f47ea50f40ce6b9695fba0190b99f76642a Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Mon, 30 Apr 2012 12:55:45 +1000 Subject: [PATCH] Fix content pos adjustment when resizing first item If visibleItems.first() changes size in a ListView, the size change should be made in the direction of the content flow. This was not working correctly for layouts other than the default vertical+LTR layout. This patch fixes the issue for other layouts and also fixes resizing of implicitly sized delegates (e.g. positioners) within the default layout. Change-Id: Ib1d84ce000a3a341fe617cf644420dc5d589d577 Reviewed-by: Andrew den Exter --- src/quick/items/qquicklistview.cpp | 20 ++++ .../data/repositionResizedDelegate.qml | 53 ++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 107 +++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index df50d3e..bbfaeb0 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -1336,9 +1336,29 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF & QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry); if (!q->isComponentComplete()) return; + if (item != contentItem && (!highlight || item != highlight->item)) { if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height()) || (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) { + + // if visibleItems.first() has resized, adjust its pos since it is used to + // position all subsequent items + if (visibleItems.count() && item == visibleItems.first()->item) { + FxListItemSG *listItem = static_cast(visibleItems.first()); + if (orient == Qt::Vertical) { + qreal diff = newGeometry.height() - oldGeometry.height(); + if (verticalLayoutDirection == QQuickListView::TopToBottom && listItem->endPosition() < q->contentY()) + listItem->setPosition(listItem->position() - diff, true); + else if (verticalLayoutDirection == QQuickListView::BottomToTop && listItem->endPosition() > q->contentY()) + listItem->setPosition(listItem->position() + diff, true); + } else { + qreal diff = newGeometry.width() - oldGeometry.width(); + if (q->effectiveLayoutDirection() == Qt::LeftToRight && listItem->endPosition() < q->contentX()) + listItem->setPosition(listItem->position() - diff, true); + else if (q->effectiveLayoutDirection() == Qt::RightToLeft && listItem->endPosition() > q->contentX()) + listItem->setPosition(listItem->position() + diff, true); + } + } forceLayout = true; q->polish(); } diff --git a/tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml b/tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml new file mode 100644 index 0000000..d79ca10 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml @@ -0,0 +1,53 @@ +import QtQuick 2.0 + +ListView { + id: root + + width: 200; height: 200 + + orientation: (testHorizontal == true) ? Qt.Horizontal : Qt.Vertical + layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight + verticalLayoutDirection: (testBottomToTop == true) ? ListView.BottomToTop : ListView.TopToBottom + + model: VisualItemModel { + Rectangle { + objectName: "red" + width: 200; height: 200; color: "red" + Text { text: parent.x + ", " + parent.y } + } + Grid { + id: grid + objectName: "positioner" + columns: root.orientation == Qt.Vertical ? 1 : 2 + Repeater { + id: rpt + model: 1 + Rectangle { + width: 120; height: 120; color: "orange"; border.width: 1 + Column { + Text { text: grid.x + ", " + grid.y } + Text { text: index } + } + } + } + } + Rectangle { + objectName: "yellow" + width: 200; height: 200; color: "yellow" + Text { text: parent.x + ", " + parent.y } + } + } + + focus: true + + function incrementRepeater() { + rpt.model += 1 + } + + function decrementRepeater() { + rpt.model -= 1 + } + + Text { anchors.right: parent.right; anchors.bottom: parent.bottom; text: root.contentX + ", " + root.contentY } +} + diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index e4d81d9..b38bb0d 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -163,6 +163,8 @@ private slots: void QTBUG_14821(); void resizeDelegate(); void resizeFirstDelegate(); + void repositionResizedDelegate(); + void repositionResizedDelegate_data(); void QTBUG_16037(); void indexAt_itemAt_data(); void indexAt_itemAt(); @@ -4056,6 +4058,111 @@ void tst_QQuickListView::resizeFirstDelegate() delete canvas; } +void tst_QQuickListView::repositionResizedDelegate() +{ + QFETCH(QQuickListView::Orientation, orientation); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); + QFETCH(QPointF, contentPos_itemFirstHalfVisible); + QFETCH(QPointF, contentPos_itemStart); + QFETCH(QPointF, contentPos_itemSecondHalfVisible); + QFETCH(QRectF, origPositionerRect); + QFETCH(QRectF, resizedPositionerRect); + + QQuickView *canvas = getView(); + QQmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testHorizontal", orientation == QQuickListView::Horizontal); + ctxt->setContextProperty("testRightToLeft", layoutDirection == Qt::RightToLeft); + ctxt->setContextProperty("testBottomToTop", verticalLayoutDirection == QQuickListView::BottomToTop); + canvas->setSource(testFileUrl("repositionResizedDelegate.qml")); + canvas->show(); + qApp->processEvents(); + + QQuickListView *listview = qobject_cast(canvas->rootObject()); + QTRY_VERIFY(listview != 0); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + + QQuickItem *positioner = findItem(canvas->rootObject(), "positioner"); + QVERIFY(positioner); + QTRY_COMPARE(positioner->boundingRect().size(), origPositionerRect.size()); + QTRY_COMPARE(positioner->pos(), origPositionerRect.topLeft()); + QSignalSpy spy(listview, orientation == QQuickListView::Vertical ? SIGNAL(contentYChanged()) : SIGNAL(contentXChanged())); + int prevSpyCount = 0; + + // When an item is resized while it is partially visible, it should resize in the + // direction of the content flow. If a RightToLeft or BottomToTop layout is used, + // the item should also be re-positioned so its end position stays the same. + + listview->setContentX(contentPos_itemFirstHalfVisible.x()); + listview->setContentY(contentPos_itemFirstHalfVisible.y()); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + prevSpyCount = spy.count(); + QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "incrementRepeater")); + QTRY_COMPARE(positioner->boundingRect().size(), resizedPositionerRect.size()); + QTRY_COMPARE(positioner->pos(), resizedPositionerRect.topLeft()); + QCOMPARE(listview->contentX(), contentPos_itemFirstHalfVisible.x()); + QCOMPARE(listview->contentY(), contentPos_itemFirstHalfVisible.y()); + QCOMPARE(spy.count(), prevSpyCount); + + QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "decrementRepeater")); + QTRY_COMPARE(positioner->boundingRect().size(), origPositionerRect.size()); + QTRY_COMPARE(positioner->pos(), origPositionerRect.topLeft()); + QCOMPARE(listview->contentX(), contentPos_itemFirstHalfVisible.x()); + QCOMPARE(listview->contentY(), contentPos_itemFirstHalfVisible.y()); + + listview->setContentX(contentPos_itemSecondHalfVisible.x()); + listview->setContentY(contentPos_itemSecondHalfVisible.y()); + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + prevSpyCount = spy.count(); + + QVERIFY(QMetaObject::invokeMethod(canvas->rootObject(), "incrementRepeater")); + positioner = findItem(canvas->rootObject(), "positioner"); + QTRY_COMPARE(positioner->boundingRect().size(), resizedPositionerRect.size()); + QTRY_COMPARE(positioner->pos(), resizedPositionerRect.topLeft()); + QCOMPARE(listview->contentX(), contentPos_itemSecondHalfVisible.x()); + QCOMPARE(listview->contentY(), contentPos_itemSecondHalfVisible.y()); + qApp->processEvents(); + QCOMPARE(spy.count(), prevSpyCount); + + releaseView(canvas); +} + +void tst_QQuickListView::repositionResizedDelegate_data() +{ + QTest::addColumn("orientation"); + QTest::addColumn("layoutDirection"); + QTest::addColumn("verticalLayoutDirection"); + QTest::addColumn("contentPos_itemFirstHalfVisible"); + QTest::addColumn("contentPos_itemStart"); + QTest::addColumn("contentPos_itemSecondHalfVisible"); + QTest::addColumn("origPositionerRect"); + QTest::addColumn("resizedPositionerRect"); + + QTest::newRow("vertical") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(0, 60) << QPointF(0, 200) << QPointF(0, 200 + 60) + << QRectF(0, 200, 120, 120) + << QRectF(0, 200, 120, 120 * 2); + + QTest::newRow("vertical, BottomToTop") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop + << QPointF(0, -200 - 60) << QPointF(0, -200 - 200) << QPointF(0, -200 - 260) + << QRectF(0, -200 - 120, 120, 120) + << QRectF(0, -200 - 120*2, 120, 120 * 2); + + QTest::newRow("horizontal") + << QQuickListView::Horizontal<< Qt::LeftToRight << QQuickItemView::TopToBottom + << QPointF(60, 0) << QPointF(200, 0) << QPointF(260, 0) + << QRectF(200, 0, 120, 120) + << QRectF(200, 0, 120 * 2, 120); + + QTest::newRow("horizontal, rtl") + << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom + << QPointF(-200 - 60, 0) << QPointF(-200 - 200, 0) << QPointF(-200 - 260, 0) + << QRectF(-200 - 120, 0, 120, 120) + << QRectF(-200 - 120 * 2, 0, 120 * 2, 120); +} + void tst_QQuickListView::QTBUG_16037() { QQuickView *canvas = createView(); -- 2.7.4