diff options
-rw-r--r-- | doc/src/declarative/whatsnew.qdoc | 5 | ||||
-rw-r--r-- | src/declarative/items/qsggridview.cpp | 77 | ||||
-rw-r--r-- | src/declarative/items/qsgitemview.cpp | 42 | ||||
-rw-r--r-- | src/declarative/items/qsglistview.cpp | 70 | ||||
-rw-r--r-- | src/qtquick1/graphicsitems/qdeclarativegridview.cpp | 23 | ||||
-rw-r--r-- | src/qtquick1/graphicsitems/qdeclarativelistview.cpp | 2 | ||||
-rw-r--r-- | tests/auto/declarative/qsggridview/data/snapToRow.qml | 49 | ||||
-rw-r--r-- | tests/auto/declarative/qsggridview/tst_qsggridview.cpp | 116 | ||||
-rw-r--r-- | tests/auto/declarative/qsglistview/data/snapToItem.qml | 49 | ||||
-rw-r--r-- | tests/auto/declarative/qsglistview/tst_qsglistview.cpp | 117 |
10 files changed, 406 insertions, 144 deletions
diff --git a/doc/src/declarative/whatsnew.qdoc b/doc/src/declarative/whatsnew.qdoc index 84245a565f..4c44166472 100644 --- a/doc/src/declarative/whatsnew.qdoc +++ b/doc/src/declarative/whatsnew.qdoc @@ -117,8 +117,9 @@ Text improvements: PathView now has a \c currentItem property -ListView and GridView now have headerItem and footerItem properties (the instantiated -header and footer items). +ListView and GridView: + - now have headerItem and footerItem properties (the instantiated header and footer items). + - In RightToLeft layout the preferredHighlightBegin/End are now also reversed. ListView section.labelPositioning property added to allow keeping the current section label at the start and/or next section label at the end of the view. diff --git a/src/declarative/items/qsggridview.cpp b/src/declarative/items/qsggridview.cpp index fd2742c2f3..6b01583497 100644 --- a/src/declarative/items/qsggridview.cpp +++ b/src/declarative/items/qsggridview.cpp @@ -334,7 +334,10 @@ qreal QSGGridViewPrivate::snapPosAt(qreal pos) const Q_Q(const QSGGridView); qreal snapPos = 0; if (!visibleItems.isEmpty()) { - qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart; + qreal highlightStart = highlightRangeStart; + if (isRightToLeftTopToBottom()) + highlightStart = highlightRangeEndValid ? -size() + highlightRangeEnd : -size(); + pos += highlightStart; pos += rowSize()/2; snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize(); @@ -807,19 +810,7 @@ void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) fixupMode = moveReason == Mouse ? fixupMode : Immediate; - qreal highlightStart; - qreal highlightEnd; - qreal viewPos; - if (isRightToLeftTopToBottom()) { - // Handle Right-To-Left exceptions - viewPos = -position()-size(); - highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart; - highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd; - } else { - viewPos = position(); - highlightStart = highlightRangeStart; - highlightEnd = highlightRangeEnd; - } + qreal viewPos = isRightToLeftTopToBottom() ? -position()-size() : position(); bool strictHighlightRange = haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange; if (snapMode != QSGGridView::NoSnap) { @@ -836,40 +827,35 @@ void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) bias = -bias; tempPosition -= bias; } - FxViewItem *topItem = snapItemAt(tempPosition+highlightStart); + FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart); if (!topItem && strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); topItem = currentItem; } - FxViewItem *bottomItem = snapItemAt(tempPosition+highlightEnd); + FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd); if (!bottomItem && strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); bottomItem = currentItem; } qreal pos; - if (topItem && bottomItem && strictHighlightRange) { - qreal topPos = qMin(topItem->position() - highlightStart, -maxExtent); - qreal bottomPos = qMax(bottomItem->position() - highlightEnd, -minExtent); - pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos; - } else if (topItem) { - qreal headerPos = 0; - if (header) - headerPos = isRightToLeftTopToBottom() ? static_cast<FxGridItemSG*>(header)->rowPos() + cellWidth - headerSize() : static_cast<FxGridItemSG*>(header)->rowPos(); - if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2 && !strictHighlightRange) { - pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart; + bool isInBounds = -position() > maxExtent && -position() <= minExtent; + if (topItem && (isInBounds || strictHighlightRange)) { + qreal headerPos = header ? static_cast<FxGridItemSG*>(header)->rowPos() : 0; + if (topItem->index == 0 && header && tempPosition+highlightRangeStart < headerPos+headerSize()/2 && !strictHighlightRange) { + pos = isRightToLeftTopToBottom() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart; } else { if (isRightToLeftTopToBottom()) - pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent); + pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent); else - pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent); + pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); } - } else if (bottomItem) { + } else if (bottomItem && isInBounds) { if (isRightToLeftTopToBottom()) - pos = qMax(qMin(-bottomItem->position() + highlightEnd - size(), -maxExtent), -minExtent); + pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent); else - pos = qMax(qMin(bottomItem->position() - highlightEnd, -maxExtent), -minExtent); + pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent); } else { QSGItemViewPrivate::fixup(data, minExtent, maxExtent); return; @@ -890,10 +876,10 @@ void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) if (currentItem) { updateHighlight(); qreal pos = static_cast<FxGridItemSG*>(currentItem)->rowPos(); - if (viewPos < pos + rowSize() - highlightEnd) - viewPos = pos + rowSize() - highlightEnd; - if (viewPos > pos - highlightStart) - viewPos = pos - highlightStart; + if (viewPos < pos + rowSize() - highlightRangeEnd) + viewPos = pos + rowSize() - highlightRangeEnd; + if (viewPos > pos - highlightRangeStart) + viewPos = pos - highlightRangeStart; if (isRightToLeftTopToBottom()) viewPos = -viewPos-size(); timeline.reset(data.move); @@ -1543,22 +1529,11 @@ void QSGGridView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos; - qreal highlightStart; - qreal highlightEnd; - if (d->isRightToLeftTopToBottom()) { - viewPos = -d->position()-d->size(); - highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; - highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; - } else { - viewPos = d->position(); - highlightStart = d->highlightRangeStart; - highlightEnd = d->highlightRangeEnd; - } - if (pos > viewPos + highlightEnd - d->highlight->size()) - pos = viewPos + highlightEnd - d->highlight->size(); - if (pos < viewPos + highlightStart) - pos = viewPos + highlightStart; + qreal viewPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size() : d->position(); + if (pos > viewPos + d->highlightRangeEnd - d->highlight->size()) + pos = viewPos + d->highlightRangeEnd - d->highlight->size(); + if (pos < viewPos + d->highlightRangeStart) + pos = viewPos + d->highlightRangeStart; if (pos != d->highlight->position()) { d->highlightXAnimator->stop(); diff --git a/src/declarative/items/qsgitemview.cpp b/src/declarative/items/qsgitemview.cpp index 075024db0f..5b95097dcc 100644 --- a/src/declarative/items/qsgitemview.cpp +++ b/src/declarative/items/qsgitemview.cpp @@ -821,30 +821,14 @@ void QSGItemView::trackedPositionChanged() if (d->trackedItem != d->currentItem) { trackedSize += d->currentItem->sectionSize(); } - qreal viewPos; - qreal highlightStart; - qreal highlightEnd; - if (d->isContentFlowReversed()) { - viewPos = -d->position()-d->size(); - highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; - highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; - } else { - viewPos = d->position(); - highlightStart = d->highlightRangeStart; - highlightEnd = d->highlightRangeEnd; - } + qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position(); qreal pos = viewPos; if (d->haveHighlightRange) { - if (d->highlightRange == StrictlyEnforceRange) { - if (trackedPos > pos + highlightEnd - d->trackedItem->size()) - pos = trackedPos - highlightEnd + d->trackedItem->size(); - if (trackedPos < pos + highlightStart) - pos = trackedPos - highlightStart; - } else { - if (trackedPos > pos + highlightEnd - trackedSize) - pos = trackedPos - highlightEnd + trackedSize; - if (trackedPos < pos + highlightStart) - pos = trackedPos - highlightStart; + if (trackedPos > pos + d->highlightRangeEnd - trackedSize) + pos = trackedPos - d->highlightRangeEnd + trackedSize; + if (trackedPos < pos + d->highlightRangeStart) + pos = trackedPos - d->highlightRangeStart; + if (d->highlightRange != StrictlyEnforceRange) { if (pos > d->endPosition() - d->size()) pos = d->endPosition() - d->size(); if (pos < d->startPosition()) @@ -967,10 +951,8 @@ qreal QSGItemView::minXExtent() const endPositionFirstItem = d->positionAt(d->model->count()-1); else if (d->header) d->minExtent += d->headerSize(); - highlightStart = d->highlightRangeStartValid - ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem) - : d->size() - (d->lastPosition()-endPositionFirstItem); - highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size(); + highlightStart = d->highlightRangeEndValid ? d->size() - d->highlightRangeEnd : d->size(); + highlightEnd = d->highlightRangeStartValid ? d->size() - d->highlightRangeStart : d->size(); if (d->footer) d->minExtent += d->footerSize(); qreal maxX = maxXExtent(); @@ -986,7 +968,9 @@ qreal QSGItemView::minXExtent() const } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { d->minExtent += highlightStart; - d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd)); + d->minExtent = d->isContentFlowReversed() + ? qMin(d->minExtent, endPositionFirstItem + highlightEnd) + : qMax(d->minExtent, -(endPositionFirstItem - highlightEnd)); } d->hData.minExtentDirty = false; } @@ -1006,8 +990,8 @@ qreal QSGItemView::maxXExtent() const qreal lastItemPosition = 0; d->maxExtent = 0; if (d->isContentFlowReversed()) { - highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size(); - highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size(); + highlightStart = d->highlightRangeEndValid ? d->size() - d->highlightRangeEnd : d->size(); + highlightEnd = d->highlightRangeStartValid ? d->size() - d->highlightRangeStart : d->size(); lastItemPosition = d->endPosition(); } else { highlightStart = d->highlightRangeStart; diff --git a/src/declarative/items/qsglistview.cpp b/src/declarative/items/qsglistview.cpp index 75472c2a79..5ea9efe274 100644 --- a/src/declarative/items/qsglistview.cpp +++ b/src/declarative/items/qsglistview.cpp @@ -1251,19 +1251,7 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) fixupMode = moveReason == Mouse ? fixupMode : Immediate; bool strictHighlightRange = haveHighlightRange && highlightRange == QSGListView::StrictlyEnforceRange; - qreal highlightStart; - qreal highlightEnd; - qreal viewPos; - if (isRightToLeft()) { - // Handle Right-To-Left exceptions - viewPos = -position()-size(); - highlightStart = highlightRangeStartValid ? size() - highlightRangeEnd : highlightRangeStart; - highlightEnd = highlightRangeEndValid ? size() - highlightRangeStart : highlightRangeEnd; - } else { - viewPos = position(); - highlightStart = highlightRangeStart; - highlightEnd = highlightRangeEnd; - } + qreal viewPos = isRightToLeft() ? -position()-size() : position(); if (snapMode != QSGListView::NoSnap && moveReason != QSGListViewPrivate::SetIndex) { qreal tempPosition = isRightToLeft() ? -position()-size() : position(); @@ -1279,13 +1267,13 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) bias = -bias; tempPosition -= bias; } - FxViewItem *topItem = snapItemAt(tempPosition+highlightStart); + FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart); if (!topItem && strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); topItem = currentItem; } - FxViewItem *bottomItem = snapItemAt(tempPosition+highlightEnd); + FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd); if (!bottomItem && strictHighlightRange && currentItem) { // StrictlyEnforceRange always keeps an item in range updateHighlight(); @@ -1294,19 +1282,19 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) qreal pos; bool isInBounds = -position() > maxExtent && -position() <= minExtent; if (topItem && (isInBounds || strictHighlightRange)) { - if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2 && !strictHighlightRange) { - pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart; + if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) { + pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart; } else { if (isRightToLeft()) - pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent); + pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent); else - pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent); + pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); } } else if (bottomItem && isInBounds) { if (isRightToLeft()) - pos = qMax(qMin(-bottomItem->position() + highlightEnd - size(), -maxExtent), -minExtent); + pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent); else - pos = qMax(qMin(bottomItem->position() - highlightEnd, -maxExtent), -minExtent); + pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent); } else { QSGItemViewPrivate::fixup(data, minExtent, maxExtent); return; @@ -1326,10 +1314,10 @@ void QSGListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) } else if (currentItem && strictHighlightRange && moveReason != QSGListViewPrivate::SetIndex) { updateHighlight(); qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition(); - if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightEnd) - viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightEnd; - if (viewPos > pos - highlightStart) - viewPos = pos - highlightStart; + if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd) + viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd; + if (viewPos > pos - highlightRangeStart) + viewPos = pos - highlightRangeStart; if (isRightToLeft()) viewPos = -viewPos-size(); @@ -1364,7 +1352,7 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, } qreal maxDistance = 0; qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value(); - qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart; + // -ve velocity means list is moving up/left if (velocity > 0) { if (data.move.value() < minExtent) { @@ -1374,7 +1362,7 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal bias = dist < averageSize/2 ? averageSize/2 : 0; if (isRightToLeft()) bias = -bias; - data.flickTarget = -snapPosAt(-(dataValue - highlightStart) - bias) + highlightStart; + data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart; maxDistance = qAbs(data.flickTarget - data.move.value()); velocity = maxVelocity; } else { @@ -1391,7 +1379,7 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal bias = -dist < averageSize/2 ? averageSize/2 : 0; if (isRightToLeft()) bias = -bias; - data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + bias) + highlightStart; + data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart; maxDistance = qAbs(data.flickTarget - data.move.value()); velocity = -maxVelocity; } else { @@ -1428,7 +1416,7 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGListView::SnapOneItem) { if (snapMode != QSGListView::SnapOneItem) { qreal distTemp = isRightToLeft() ? -dist : dist; - data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart; + data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart; } data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; if (overShoot) { @@ -1484,7 +1472,7 @@ void QSGListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal newtarget = data.flickTarget; if (snapMode != QSGListView::NoSnap || highlightRange == QSGListView::StrictlyEnforceRange) { qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; - newtarget = -snapPosAt(-(tempFlickTarget - highlightStart)) + highlightStart; + newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart; newtarget = isRightToLeft() ? -newtarget+size() : newtarget; } if (velocity < 0 && newtarget <= maxExtent) @@ -2167,23 +2155,11 @@ void QSGListView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos; - qreal highlightStart; - qreal highlightEnd; - if (d->isRightToLeft()) { - // Handle Right-To-Left exceptions - viewPos = -d->position()-d->size(); - highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; - highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; - } else { - viewPos = d->position(); - highlightStart = d->highlightRangeStart; - highlightEnd = d->highlightRangeEnd; - } - if (pos > viewPos + highlightEnd - d->highlight->size()) - pos = viewPos + highlightEnd - d->highlight->size(); - if (pos < viewPos + highlightStart) - pos = viewPos + highlightStart; + qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position(); + if (pos > viewPos + d->highlightRangeEnd - d->highlight->size()) + pos = viewPos + d->highlightRangeEnd - d->highlight->size(); + if (pos < viewPos + d->highlightRangeStart) + pos = viewPos + d->highlightRangeStart; if (pos != d->highlight->position()) { d->highlightPosAnimator->stop(); static_cast<FxListItemSG*>(d->highlight)->setPosition(pos); diff --git a/src/qtquick1/graphicsitems/qdeclarativegridview.cpp b/src/qtquick1/graphicsitems/qdeclarativegridview.cpp index feabbf0387..2ed1ca1782 100644 --- a/src/qtquick1/graphicsitems/qdeclarativegridview.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativegridview.cpp @@ -1095,23 +1095,17 @@ void QDeclarative1GridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal bottomItem = currentItem; } qreal pos; - if (topItem && bottomItem && strictHighlightRange) { - qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent); - qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent); - pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos; - } else if (topItem) { - qreal headerPos = 0; - if (header) - headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos(); - if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2 && !strictHighlightRange) { - pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart; + bool isInBounds = -position() > maxExtent && -position() <= minExtent; + if (topItem && (isInBounds || strictHighlightRange)) { + if (topItem->index == 0 && header && tempPosition+highlightStart < header->rowPos()+headerSize()/2 && !strictHighlightRange) { + pos = isRightToLeftTopToBottom() ? - header->rowPos() + highlightStart - size() : header->rowPos() - highlightStart; } else { if (isRightToLeftTopToBottom()) pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent); else pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent); } - } else if (bottomItem) { + } else if (bottomItem && isInBounds) { if (isRightToLeftTopToBottom()) pos = qMax(qMin(-bottomItem->rowPos() + highlightEnd - size(), -maxExtent), -minExtent); else @@ -2267,9 +2261,10 @@ qreal QDeclarative1GridView::minXExtent() const qreal extent = -d->startPosition(); qreal highlightStart; qreal highlightEnd; - qreal endPositionFirstItem; + qreal endPositionFirstItem = 0; if (d->isRightToLeftTopToBottom()) { - endPositionFirstItem = d->rowPosAt(d->model->count()-1); + if (d->model && d->model->count()) + endPositionFirstItem = d->rowPosAt(d->model->count()-1); highlightStart = d->highlightRangeStartValid ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem) : d->size() - (d->lastPosition()-endPositionFirstItem); @@ -2284,7 +2279,7 @@ qreal QDeclarative1GridView::minXExtent() const extent += d->header->item->width(); } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - extent += highlightStart; + extent += d->isRightToLeftTopToBottom() ? -highlightStart : highlightStart; extent = qMax(extent, -(endPositionFirstItem - highlightEnd)); } return extent; diff --git a/src/qtquick1/graphicsitems/qdeclarativelistview.cpp b/src/qtquick1/graphicsitems/qdeclarativelistview.cpp index 7b9cb12e90..6430f6a071 100644 --- a/src/qtquick1/graphicsitems/qdeclarativelistview.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativelistview.cpp @@ -2773,7 +2773,7 @@ qreal QDeclarative1ListView::minXExtent() const d->minExtent += d->header->size(); } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->minExtent += highlightStart; + d->minExtent += d->isRightToLeft() ? -highlightStart : highlightStart; d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd + 1)); } d->minExtentDirty = false; diff --git a/tests/auto/declarative/qsggridview/data/snapToRow.qml b/tests/auto/declarative/qsggridview/data/snapToRow.qml new file mode 100644 index 0000000000..f079a048f0 --- /dev/null +++ b/tests/auto/declarative/qsggridview/data/snapToRow.qml @@ -0,0 +1,49 @@ +import QtQuick 2.0 + +Rectangle { + id: root + width: 240 + height: 240 + color: "#ffffff" + + Component { + id: myDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + height: 80 + width: 80 + Column { + Text { + text: index + } + Text { + text: wrapper.x + ", " + wrapper.y + } + } + color: GridView.isCurrentItem ? "lightsteelblue" : "transparent" + } + } + GridView { + id: grid + objectName: "grid" + anchors.fill: parent + cellWidth: 80 + cellHeight: 80 + preferredHighlightBegin: 20 + preferredHighlightEnd: 100 + snapMode: GridView.SnapToRow + layoutDirection: Qt.RightToLeft + flow: GridView.TopToBottom + highlightRangeMode: GridView.StrictlyEnforceRange + highlight: Rectangle { width: 80; height: 80; color: "yellow" } + model: 54 + delegate: myDelegate + } + + Text { + anchors.right: parent.right + anchors.bottom: parent.bottom + text: grid.contentX + ", " + grid.contentY + } +} diff --git a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp index 03975e295d..b6a601d8d7 100644 --- a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp +++ b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp @@ -110,9 +110,12 @@ private slots: void columnCount(); void margins(); void creationContext(); + void snapToRow_data(); + void snapToRow(); private: QSGView *createView(); + void flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration); template<typename T> T *findItem(QSGItem *parent, const QString &id, int index=-1); template<typename T> @@ -3121,6 +3124,101 @@ void tst_QSGGridView::creationContext() QCOMPARE(item->property("text").toString(), QString("Hello!")); } +void tst_QSGGridView::snapToRow_data() +{ + QTest::addColumn<QSGGridView::Flow>("flow"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<int>("highlightRangeMode"); + QTest::addColumn<QPoint>("flickStart"); + QTest::addColumn<QPoint>("flickEnd"); + QTest::addColumn<qreal>("snapAlignment"); + QTest::addColumn<qreal>("endExtent"); + QTest::addColumn<qreal>("startExtent"); + + QTest::newRow("vertical, left to right") << QSGGridView::LeftToRight << Qt::LeftToRight << int(QSGItemView::NoHighlightRange) + << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0; + + QTest::newRow("horizontal, left to right") << QSGGridView::TopToBottom << Qt::LeftToRight << int(QSGItemView::NoHighlightRange) + << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0; + + QTest::newRow("horizontal, right to left") << QSGGridView::TopToBottom << Qt::RightToLeft << int(QSGItemView::NoHighlightRange) + << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 << -240.0; + + QTest::newRow("vertical, left to right, enforce range") << QSGGridView::LeftToRight << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange) + << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0; + + QTest::newRow("horizontal, left to right, enforce range") << QSGGridView::TopToBottom << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange) + << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0; + + QTest::newRow("horizontal, right to left, enforce range") << QSGGridView::TopToBottom << Qt::RightToLeft << int(QSGItemView::StrictlyEnforceRange) + << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 - 140.0 << -220.0; +} + +void tst_QSGGridView::snapToRow() +{ + QFETCH(QSGGridView::Flow, flow); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(int, highlightRangeMode); + QFETCH(QPoint, flickStart); + QFETCH(QPoint, flickEnd); + QFETCH(qreal, snapAlignment); + QFETCH(qreal, endExtent); + QFETCH(qreal, startExtent); + + QSGView *canvas = createView(); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("snapToRow.qml"))); + canvas->show(); + qApp->processEvents(); + + QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + + gridview->setFlow(flow); + gridview->setLayoutDirection(layoutDirection); + gridview->setHighlightRangeMode(QSGItemView::HighlightRangeMode(highlightRangeMode)); + + QSGItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + // confirm that a flick hits an item boundary + flick(canvas, flickStart, flickEnd, 180); + QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops + if (flow == QSGGridView::LeftToRight) + QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment); + else + QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment); + + // flick to end + do { + flick(canvas, flickStart, flickEnd, 180); + QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops + } while (flow == QSGGridView::LeftToRight + ? !gridview->isAtYEnd() + : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning()); + + if (flow == QSGGridView::LeftToRight) + QCOMPARE(gridview->contentY(), endExtent); + else + QCOMPARE(gridview->contentX(), endExtent); + + // flick to start + do { + flick(canvas, flickEnd, flickStart, 180); + QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops + } while (flow == QSGGridView::LeftToRight + ? !gridview->isAtYBeginning() + : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd()); + + if (flow == QSGGridView::LeftToRight) + QCOMPARE(gridview->contentY(), startExtent); + else + QCOMPARE(gridview->contentX(), startExtent); + + delete canvas; +} + + QSGView *tst_QSGGridView::createView() { QSGView *canvas = new QSGView(0); @@ -3129,6 +3227,24 @@ QSGView *tst_QSGGridView::createView() return canvas; } +void tst_QSGGridView::flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration) +{ + const int pointCount = 5; + QPoint diff = to - from; + + // send press, five equally spaced moves, and release. + QTest::mousePress(canvas, Qt::LeftButton, 0, from); + + for (int i = 0; i < pointCount; ++i) { + QMouseEvent mv(QEvent::MouseMove, from + (i+1)*diff/pointCount, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas, &mv); + QTest::qWait(duration/pointCount); + QCoreApplication::processEvents(); + } + + QTest::mouseRelease(canvas, Qt::LeftButton, 0, to); +} + /* Find an item with the specified objectName. If index is supplied then the item must also evaluate the {index} expression equal to index diff --git a/tests/auto/declarative/qsglistview/data/snapToItem.qml b/tests/auto/declarative/qsglistview/data/snapToItem.qml new file mode 100644 index 0000000000..6f201072f0 --- /dev/null +++ b/tests/auto/declarative/qsglistview/data/snapToItem.qml @@ -0,0 +1,49 @@ +import QtQuick 2.0 + +Rectangle { + id: root + width: 240 + height: 240 + color: "#ffffff" + + Component { + id: myDelegate + Rectangle { + id: wrapper + objectName: "wrapper" + height: 80 + width: 80 + Column { + Text { + text: index + } + Text { + text: wrapper.x + ", " + wrapper.y + } + } + color: ListView.isCurrentItem ? "lightsteelblue" : "transparent" + } + } + ListView { + id: list + objectName: "list" + anchors.fill: parent +// preferredHighlightBegin: 20 +// preferredHighlightEnd: 100 + preferredHighlightBegin: 20 + preferredHighlightEnd: 100 + snapMode: ListView.SnapToItem + orientation: ListView.Horizontal + layoutDirection: Qt.RightToLeft + highlightRangeMode: ListView.StrictlyEnforceRange + highlight: Rectangle { width: 80; height: 80; color: "yellow" } + model: 18 + delegate: myDelegate + } + + Text { + anchors.right: parent.right + anchors.bottom: parent.bottom + text: list.contentX + ", " + list.contentY + } +} diff --git a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp index 386a03b81a..be297122ba 100644 --- a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp +++ b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp @@ -55,6 +55,7 @@ #include "../shared/util.h" #include "../../../shared/util.h" #include "incrementalmodel.h" +#include <math.h> Q_DECLARE_METATYPE(Qt::LayoutDirection) Q_DECLARE_METATYPE(QSGListView::Orientation) @@ -139,6 +140,8 @@ private slots: void test_mirroring(); void margins(); void creationContext(); + void snapToItem_data(); + void snapToItem(); private: template <class T> void items(); @@ -149,6 +152,7 @@ private: template <class T> void moved(); template <class T> void clear(); QSGView *createView(); + void flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration); QSGItem *findVisibleChild(QSGItem *parent, const QString &objectName); template<typename T> T *findItem(QSGItem *parent, const QString &id, int index=-1); @@ -3800,6 +3804,100 @@ void tst_QSGListView::margins() delete canvas; } +void tst_QSGListView::snapToItem_data() +{ + QTest::addColumn<QSGListView::Orientation>("orientation"); + QTest::addColumn<Qt::LayoutDirection>("layoutDirection"); + QTest::addColumn<int>("highlightRangeMode"); + QTest::addColumn<QPoint>("flickStart"); + QTest::addColumn<QPoint>("flickEnd"); + QTest::addColumn<qreal>("snapAlignment"); + QTest::addColumn<qreal>("endExtent"); + QTest::addColumn<qreal>("startExtent"); + + QTest::newRow("vertical, left to right") << QSGListView::Vertical << Qt::LeftToRight << int(QSGItemView::NoHighlightRange) + << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0; + + QTest::newRow("horizontal, left to right") << QSGListView::Horizontal << Qt::LeftToRight << int(QSGItemView::NoHighlightRange) + << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1200.0 << 0.0; + + QTest::newRow("horizontal, right to left") << QSGListView::Horizontal << Qt::RightToLeft << int(QSGItemView::NoHighlightRange) + << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 << -240.0; + + QTest::newRow("vertical, left to right, enforce range") << QSGListView::Vertical << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange) + << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0; + + QTest::newRow("horizontal, left to right, enforce range") << QSGListView::Horizontal << Qt::LeftToRight << int(QSGItemView::StrictlyEnforceRange) + << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 1340.0 << -20.0; + + QTest::newRow("horizontal, right to left, enforce range") << QSGListView::Horizontal << Qt::RightToLeft << int(QSGItemView::StrictlyEnforceRange) + << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -1200.0 - 240.0 - 140.0 << -220.0; +} + +void tst_QSGListView::snapToItem() +{ + QFETCH(QSGListView::Orientation, orientation); + QFETCH(Qt::LayoutDirection, layoutDirection); + QFETCH(int, highlightRangeMode); + QFETCH(QPoint, flickStart); + QFETCH(QPoint, flickEnd); + QFETCH(qreal, snapAlignment); + QFETCH(qreal, endExtent); + QFETCH(qreal, startExtent); + + QSGView *canvas = createView(); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("snapToItem.qml"))); + canvas->show(); + qApp->processEvents(); + + QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + + listview->setOrientation(orientation); + listview->setLayoutDirection(layoutDirection); + listview->setHighlightRangeMode(QSGItemView::HighlightRangeMode(highlightRangeMode)); + + QSGItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + // confirm that a flick hits an item boundary + flick(canvas, flickStart, flickEnd, 180); + QTRY_VERIFY(listview->isMoving() == false); // wait until it stops + if (orientation == QSGListView::Vertical) + QCOMPARE(qreal(fmod(listview->contentY(),80.0)), snapAlignment); + else + QCOMPARE(qreal(fmod(listview->contentX(),80.0)), snapAlignment); + + // flick to end + do { + flick(canvas, flickStart, flickEnd, 180); + QTRY_VERIFY(listview->isMoving() == false); // wait until it stops + } while (orientation == QSGListView::Vertical + ? !listview->isAtYEnd() + : layoutDirection == Qt::LeftToRight ? !listview->isAtXEnd() : !listview->isAtXBeginning()); + + if (orientation == QSGListView::Vertical) + QCOMPARE(listview->contentY(), endExtent); + else + QCOMPARE(listview->contentX(), endExtent); + + // flick to start + do { + flick(canvas, flickEnd, flickStart, 180); + QTRY_VERIFY(listview->isMoving() == false); // wait until it stops + } while (orientation == QSGListView::Vertical + ? !listview->isAtYBeginning() + : layoutDirection == Qt::LeftToRight ? !listview->isAtXBeginning() : !listview->isAtXEnd()); + + if (orientation == QSGListView::Vertical) + QCOMPARE(listview->contentY(), startExtent); + else + QCOMPARE(listview->contentX(), startExtent); + + delete canvas; +} + void tst_QSGListView::qListModelInterface_items() { items<TestModel>(); @@ -3922,6 +4020,25 @@ QSGView *tst_QSGListView::createView() return canvas; } +void tst_QSGListView::flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration) +{ + const int pointCount = 5; + QPoint diff = to - from; + + // send press, five equally spaced moves, and release. + QTest::mousePress(canvas, Qt::LeftButton, 0, from); + + for (int i = 0; i < pointCount; ++i) { + QMouseEvent mv(QEvent::MouseMove, from + (i+1)*diff/pointCount, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas, &mv); + QTest::qWait(duration/pointCount); + QCoreApplication::processEvents(); + } + + QTest::mouseRelease(canvas, Qt::LeftButton, 0, to); +} + + QSGItem *tst_QSGListView::findVisibleChild(QSGItem *parent, const QString &objectName) { QSGItem *item = 0; |