Cannot flick to the end of a horizontal ListView with LayoutMirroring

Forward port of fix for QTBUG-21756.
minXExtent calculated the offset due to highlight range incorrectly
(reversed) when mirroring enabled.  Also us same algorithm for fixup()
in GridView and ListView uses.

For QtQuick 2, this change also reverses the beginning and end highlight
range, as it should be, i.e. the preferredHighlightBegin is from the
right side in RightToLeft mode.  Also added snapping tests.

Task-number: QTBUG-21756
Change-Id: Ica0ba4ab5db0ce9c77f2da75e9f8293550bd37d1
Reviewed-by: Martin Jones <martin.jones@nokia.com>
This commit is contained in:
Martin Jones 2011-10-13 17:41:51 +10:00 committed by Qt by Nokia
parent 063c08ab82
commit 9bd6361400
10 changed files with 406 additions and 144 deletions

View File

@ -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.

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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;