diff options
author | Bea Lam <bea.lam@nokia.com> | 2012-03-20 11:37:10 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-04-17 06:09:56 +0200 |
commit | 0d52c081a1650dc6a3a9b02c7fa5345c94ca6597 (patch) | |
tree | c0c887fc56471b28c7e238bb449fe2d14a254f84 /src/quick/items | |
parent | bf55fe91ed0e6a0673f66d1792605c632b1aa99e (diff) |
Vertical layout direction for ListView and GridView
Provide verticalLayoutDirection property with TopToBottom
and BottomToTop values.
Change-Id: If6f0da5dd4735036162868d391852a661854de5b
Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
Diffstat (limited to 'src/quick/items')
-rw-r--r-- | src/quick/items/qquickgridview.cpp | 379 | ||||
-rw-r--r-- | src/quick/items/qquickgridview_p.h | 6 | ||||
-rw-r--r-- | src/quick/items/qquickitemview.cpp | 249 | ||||
-rw-r--r-- | src/quick/items/qquickitemview_p.h | 23 | ||||
-rw-r--r-- | src/quick/items/qquickitemview_p_p.h | 5 | ||||
-rw-r--r-- | src/quick/items/qquicklistview.cpp | 203 |
6 files changed, 596 insertions, 269 deletions
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index 0caf93c98b..0518fccd10 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -92,7 +92,7 @@ public: } qreal size() const { - return view->flow() == QQuickGridView::LeftToRight ? view->cellHeight() : view->cellWidth(); + return view->flow() == QQuickGridView::FlowLeftToRight ? view->cellHeight() : view->cellWidth(); } qreal sectionSize() const { @@ -100,14 +100,14 @@ public: } qreal rowPos() const { - if (view->flow() == QQuickGridView::LeftToRight) - return itemY(); + if (view->flow() == QQuickGridView::FlowLeftToRight) + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -view->cellHeight()-itemY() : itemY()); else return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -view->cellWidth()-itemX() : itemX()); } qreal colPos() const { - if (view->flow() == QQuickGridView::LeftToRight) { + if (view->flow() == QQuickGridView::FlowLeftToRight) { if (view->effectiveLayoutDirection() == Qt::RightToLeft) { qreal colSize = view->cellWidth(); int columns = view->width()/colSize; @@ -116,12 +116,19 @@ public: return itemX(); } } else { - return itemY(); + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) { + return -view->cellHeight() - itemY(); + } else { + return itemY(); + } } } qreal endRowPos() const { - if (view->flow() == QQuickGridView::LeftToRight) { - return itemY() + view->cellHeight(); + if (view->flow() == QQuickGridView::FlowLeftToRight) { + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) + return -itemY(); + else + return itemY() + view->cellHeight(); } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) return -itemX(); @@ -141,19 +148,24 @@ public: private: QPointF pointForPosition(qreal col, qreal row) const { - if (view->effectiveLayoutDirection() == Qt::RightToLeft) { - if (view->flow() == QQuickGridView::LeftToRight) { + qreal x; + qreal y; + if (view->flow() == QQuickGridView::FlowLeftToRight) { + x = col; + y = row; + if (view->effectiveLayoutDirection() == Qt::RightToLeft) { int columns = view->width()/view->cellWidth(); - return QPointF(view->cellWidth() * (columns-1) - col, row); - } else { - return QPointF(-view->cellWidth() - row, col); + x = view->cellWidth() * (columns-1) - col; } } else { - if (view->flow() == QQuickGridView::LeftToRight) - return QPointF(col, row); - else - return QPointF(row, col); + x = row; + y = col; + if (view->effectiveLayoutDirection() == Qt::RightToLeft) + x = -view->cellWidth() - row; } + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) + y = -view->cellHeight() - y; + return QPointF(x, y); } }; @@ -166,7 +178,6 @@ class QQuickGridViewPrivate : public QQuickItemViewPrivate public: virtual Qt::Orientation layoutOrientation() const; virtual bool isContentFlowReversed() const; - bool isRightToLeftTopToBottom() const; virtual qreal positionAt(int index) const; virtual qreal endPositionAt(int index) const; @@ -180,6 +191,8 @@ public: qreal snapPosAt(qreal pos) const; FxViewItem *snapItemAt(qreal pos) const; int snapIndex() const; + qreal contentXForPosition(qreal pos) const; + qreal contentYForPosition(qreal pos) const; void resetColumns(); @@ -229,7 +242,7 @@ public: QSmoothedAnimation *highlightYAnimator; QQuickGridViewPrivate() - : flow(QQuickGridView::LeftToRight) + : flow(QQuickGridView::FlowLeftToRight) , cellWidth(100), cellHeight(100), columns(1) , snapMode(QQuickGridView::NoSnap) , highlightXAnimator(0), highlightYAnimator(0) @@ -243,18 +256,15 @@ public: Qt::Orientation QQuickGridViewPrivate::layoutOrientation() const { - return flow == QQuickGridView::LeftToRight ? Qt::Vertical : Qt::Horizontal; + return flow == QQuickGridView::FlowLeftToRight ? Qt::Vertical : Qt::Horizontal; } bool QQuickGridViewPrivate::isContentFlowReversed() const { - return isRightToLeftTopToBottom(); -} - -bool QQuickGridViewPrivate::isRightToLeftTopToBottom() const -{ Q_Q(const QQuickGridView); - return flow == QQuickGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft; + + return (flow == QQuickGridView::FlowLeftToRight && verticalLayoutDirection == QQuickItemView::BottomToTop) + || (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft); } void QQuickGridViewPrivate::changedVisibleIndex(int newIndex) @@ -265,16 +275,8 @@ void QQuickGridViewPrivate::changedVisibleIndex(int newIndex) void QQuickGridViewPrivate::setPosition(qreal pos) { Q_Q(QQuickGridView); - if (flow == QQuickGridView::LeftToRight) { - q->QQuickFlickable::setContentY(pos); - q->QQuickFlickable::setContentX(0); - } else { - if (q->effectiveLayoutDirection() == Qt::LeftToRight) - q->QQuickFlickable::setContentX(pos); - else - q->QQuickFlickable::setContentX(-pos-size()); - q->QQuickFlickable::setContentY(0); - } + q->QQuickFlickable::setContentX(contentXForPosition(pos)); + q->QQuickFlickable::setContentY(contentYForPosition(pos)); } qreal QQuickGridViewPrivate::originPosition() const @@ -306,10 +308,10 @@ qreal QQuickGridViewPrivate::endPositionAt(int index) const } qreal QQuickGridViewPrivate::rowSize() const { - return flow == QQuickGridView::LeftToRight ? cellHeight : cellWidth; + return flow == QQuickGridView::FlowLeftToRight ? cellHeight : cellWidth; } qreal QQuickGridViewPrivate::colSize() const { - return flow == QQuickGridView::LeftToRight ? cellWidth : cellHeight; + return flow == QQuickGridView::FlowLeftToRight ? cellWidth : cellHeight; } qreal QQuickGridViewPrivate::colPosAt(int modelIndex) const @@ -375,12 +377,12 @@ qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const snapPos -= highlightStart; qreal maxExtent; qreal minExtent; - if (isRightToLeftTopToBottom()) { + if (isContentFlowReversed()) { maxExtent = q->minXExtent()-size(); minExtent = q->maxXExtent()-size(); } else { - maxExtent = flow == QQuickGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); - minExtent = flow == QQuickGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent(); + maxExtent = flow == QQuickGridView::FlowLeftToRight ? -q->maxYExtent() : -q->maxXExtent(); + minExtent = flow == QQuickGridView::FlowLeftToRight ? -q->minYExtent() : -q->minXExtent(); } if (snapPos > maxExtent) snapPos = maxExtent; @@ -421,10 +423,49 @@ int QQuickGridViewPrivate::snapIndex() const return index; } +qreal QQuickGridViewPrivate::contentXForPosition(qreal pos) const +{ + Q_Q(const QQuickGridView); + if (flow == QQuickGridView::FlowLeftToRight) { + // vertical scroll + if (q->effectiveLayoutDirection() == Qt::LeftToRight) { + return 0; + } else { + qreal colSize = cellWidth; + int columns = q->width()/colSize; + return -q->width() + (cellWidth * columns); + } + } else { + // horizontal scroll + if (q->effectiveLayoutDirection() == Qt::LeftToRight) + return pos; + else + return -pos - q->width(); + } +} + +qreal QQuickGridViewPrivate::contentYForPosition(qreal pos) const +{ + Q_Q(const QQuickGridView); + if (flow == QQuickGridView::FlowLeftToRight) { + // vertical scroll + if (verticalLayoutDirection == QQuickItemView::TopToBottom) + return pos; + else + return -pos - q->height(); + } else { + // horizontal scroll + if (verticalLayoutDirection == QQuickItemView::TopToBottom) + return 0; + else + return -q->height(); + } +} + void QQuickGridViewPrivate::resetColumns() { Q_Q(QQuickGridView); - qreal length = flow == QQuickGridView::LeftToRight ? q->width() : q->height(); + qreal length = flow == QQuickGridView::FlowLeftToRight ? q->width() : q->height(); columns = (int)qMax((length + colSize()/2) / colSize(), qreal(1.)); } @@ -641,15 +682,22 @@ void QQuickGridViewPrivate::repositionPackageItemAt(QQuickItem *item, int index) { Q_Q(QQuickGridView); qreal pos = position(); - if (flow == QQuickGridView::LeftToRight) { - if (item->y() + item->height() > pos && item->y() < pos + q->height()) - item->setPos(QPointF(colPosAt(index), rowPosAt(index))); + if (flow == QQuickGridView::FlowLeftToRight) { + if (item->y() + item->height() > pos && item->y() < pos + q->height()) { + qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom) + ? rowPosAt(index) + : -rowPosAt(index) - item->height(); + item->setPos(QPointF(colPosAt(index), y)); + } } else { if (item->x() + item->width() > pos && item->x() < pos + q->width()) { - if (isRightToLeftTopToBottom()) - item->setPos(QPointF(-rowPosAt(index)-item->width(), colPosAt(index))); + qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom) + ? colPosAt(index) + : -colPosAt(index) - item->height(); + if (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft) + item->setPos(QPointF(-rowPosAt(index)-item->width(), y)); else - item->setPos(QPointF(rowPosAt(index), colPosAt(index))); + item->setPos(QPointF(rowPosAt(index), y)); } } } @@ -744,14 +792,14 @@ qreal QQuickGridViewPrivate::headerSize() const { if (!header) return 0.0; - return flow == QQuickGridView::LeftToRight ? header->item->height() : header->item->width(); + return flow == QQuickGridView::FlowLeftToRight ? header->item->height() : header->item->width(); } qreal QQuickGridViewPrivate::footerSize() const { if (!footer) return 0.0; - return flow == QQuickGridView::LeftToRight? footer->item->height() : footer->item->width(); + return flow == QQuickGridView::FlowLeftToRight? footer->item->height() : footer->item->width(); } bool QQuickGridViewPrivate::showHeaderForIndex(int index) const @@ -781,17 +829,23 @@ void QQuickGridViewPrivate::updateFooter() qreal colOffset = 0; qreal rowOffset = 0; if (q->effectiveLayoutDirection() == Qt::RightToLeft) { - if (flow == QQuickGridView::TopToBottom) - rowOffset = gridItem->item->width() - cellWidth; + if (flow == QQuickGridView::FlowTopToBottom) + rowOffset += gridItem->item->width() - cellWidth; + else + colOffset += gridItem->item->width() - cellWidth; + } + if (verticalLayoutDirection == QQuickItemView::BottomToTop) { + if (flow == QQuickGridView::FlowTopToBottom) + colOffset += gridItem->item->height() - cellHeight; else - colOffset = gridItem->item->width() - cellWidth; + rowOffset += gridItem->item->height() - cellHeight; } if (visibleItems.count()) { qreal endPos = lastPosition(); if (findLastVisibleIndex() == model->count()-1) { gridItem->setPosition(colOffset, endPos + rowOffset); } else { - qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size(); + qreal visiblePos = isContentFlowReversed() ? -position() : position() + size(); if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset) gridItem->setPosition(colOffset, endPos + rowOffset); } @@ -820,23 +874,29 @@ void QQuickGridViewPrivate::updateHeader() qreal colOffset = 0; qreal rowOffset = -headerSize(); if (q->effectiveLayoutDirection() == Qt::RightToLeft) { - if (flow == QQuickGridView::TopToBottom) - rowOffset += gridItem->item->width()-cellWidth; + if (flow == QQuickGridView::FlowTopToBottom) + rowOffset += gridItem->item->width() - cellWidth; + else + colOffset += gridItem->item->width() - cellWidth; + } + if (verticalLayoutDirection == QQuickItemView::BottomToTop) { + if (flow == QQuickGridView::FlowTopToBottom) + colOffset += gridItem->item->height() - cellHeight; else - colOffset = gridItem->item->width()-cellWidth; + rowOffset += gridItem->item->height() - cellHeight; } if (visibleItems.count()) { qreal startPos = originPosition(); if (visibleIndex == 0) { gridItem->setPosition(colOffset, startPos + rowOffset); } else { - qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position(); - qreal headerPos = isRightToLeftTopToBottom() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos(); + qreal tempPos = isContentFlowReversed() ? -position()-size() : position(); + qreal headerPos = isContentFlowReversed() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos(); if (tempPos <= startPos || headerPos > startPos + rowOffset) gridItem->setPosition(colOffset, startPos + rowOffset); } } else { - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) gridItem->setPosition(colOffset, rowOffset); else gridItem->setPosition(colOffset, -headerSize()); @@ -861,7 +921,7 @@ void QQuickGridViewPrivate::initializeCurrentItem() void QQuickGridViewPrivate::fixupPosition() { moveReason = Other; - if (flow == QQuickGridView::LeftToRight) + if (flow == QQuickGridView::FlowLeftToRight) fixupY(); else fixupX(); @@ -869,17 +929,17 @@ void QQuickGridViewPrivate::fixupPosition() void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent) { - if ((flow == QQuickGridView::TopToBottom && &data == &vData) - || (flow == QQuickGridView::LeftToRight && &data == &hData)) + if ((flow == QQuickGridView::FlowTopToBottom && &data == &vData) + || (flow == QQuickGridView::FlowLeftToRight && &data == &hData)) return; fixupMode = moveReason == Mouse ? fixupMode : Immediate; - qreal viewPos = isRightToLeftTopToBottom() ? -position()-size() : position(); + qreal viewPos = isContentFlowReversed() ? -position()-size() : position(); bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange; if (snapMode != QQuickGridView::NoSnap) { - qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position(); + qreal tempPosition = isContentFlowReversed() ? -position()-size() : position(); if (snapMode == QQuickGridView::SnapOneRow && moveReason == Mouse) { // if we've been dragged < rowSize()/2 then bias towards the next row qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); @@ -888,7 +948,7 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte bias = rowSize()/2; else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2) bias = -rowSize()/2; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) bias = -bias; tempPosition -= bias; } @@ -909,15 +969,15 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte 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; + pos = isContentFlowReversed() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart; } else { - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent); else pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); } } else if (bottomItem && isInBounds) { - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent); else pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent); @@ -945,7 +1005,7 @@ void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte viewPos = pos + rowSize() - highlightRangeEnd; if (viewPos > pos - highlightRangeStart) viewPos = pos - highlightRangeStart; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) viewPos = -viewPos-size(); timeline.reset(data.move); if (viewPos != position()) { @@ -977,7 +1037,7 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte return; } qreal maxDistance = 0; - qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value(); + qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value(); // -ve velocity means list is moving up/left if (velocity > 0) { if (data.move.value() < minExtent) { @@ -985,7 +1045,7 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-dataValue - bias); maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1002,7 +1062,7 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0; - if (isRightToLeftTopToBottom()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-dataValue + bias); maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1034,10 +1094,10 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte if (v > 0) dist = -dist; if (snapMode != QQuickGridView::SnapOneRow) { - qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist; + qreal distTemp = isContentFlowReversed() ? -dist : dist; data.flickTarget = -snapPosAt(-dataValue + distTemp); } - data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget; + data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget; if (overShoot) { if (data.flickTarget >= minExtent) { overshootDist = overShootDistance(vSize); @@ -1159,6 +1219,60 @@ void QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte to set this property to true in order to clip the items that are partially or fully outside the view. + + \section1 GridView layouts + + The layout of the items in a GridView can be controlled by these properties: + + \list + \li \l flow - controls whether items flow from left to right (as a series of rows) + or from top to bottom (as a series of columns). This value can be either + GridView.LeftToRight or GridView.TopToBottom. + \li \l layoutDirection - controls the horizontal layout direction: that is, whether items + are laid out from the left side of the view to the right, or vice-versa. This value can + be either Qt.LeftToRight or Qt.RightToLeft. + \li \l verticalLayoutDirection - controls the vertical layout direction: that is, whether items + are laid out from the top of the view down towards the bottom of the view, or vice-versa. + This value can be either GridView.TopToBottom or GridView.BottomToTop. + \endlist + + By default, a GridView flows from left to right, and items are laid out from left to right + horizontally, and from top to bottom vertically. + + These properties can be combined to produce a variety of layouts, as shown in the table below. + The GridViews in the first row all have a \l flow value of GridView.LeftToRight, but use + different combinations of horizontal and vertical layout directions (specified by \l layoutDirection + and \l verticalLayoutDirection respectively). Similarly, the GridViews in the second row below + all have a \l flow value of GridView.TopToBottom, but use different combinations of horizontal and + vertical layout directions to lay out their items in different ways. + + \table + \header + \li {4, 1} + \bold GridViews with GridView.LeftToRight flow + \row + \li \bold (H) Left to right \bold (V) Top to bottom + \image gridview-layout-lefttoright-ltr-ttb.png + \li \bold (H) Right to left \bold (V) Top to bottom + \image gridview-layout-lefttoright-rtl-ttb.png + \li \bold (H) Left to right \bold (V) Bottom to top + \image gridview-layout-lefttoright-ltr-btt.png + \li \bold (H) Right to left \bold (V) Bottom to top + \image gridview-layout-lefttoright-rtl-btt.png + \header + \li {4, 1} + \bold GridViews with GridView.TopToBottom flow + \row + \li \bold (H) Left to right \bold (V) Top to bottom + \image gridview-layout-toptobottom-ltr-ttb.png + \li \bold (H) Right to left \bold (V) Top to bottom + \image gridview-layout-toptobottom-rtl-ttb.png + \li \bold (H) Left to right \bold (V) Bottom to top + \image gridview-layout-toptobottom-ltr-btt.png + \li \bold (H) Right to left \bold (V) Bottom to top + \image gridview-layout-toptobottom-rtl-btt.png + \endtable + \sa {declarative/modelviews/gridview}{GridView example} */ @@ -1380,6 +1494,8 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight) \b Note: If GridView::flow is set to GridView.LeftToRight, this is not to be confused if GridView::layoutDirection is set to Qt.RightToLeft. The GridView.LeftToRight flow value simply indicates that the flow is horizontal. + + \sa GridView::effectiveLayoutDirection, GridView::verticalLayoutDirection */ @@ -1393,6 +1509,21 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight) \sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring} */ + +/*! + \qmlproperty enumeration QtQuick2::GridView::verticalLayoutDirection + This property holds the vertical layout direction of the grid. + + Possible values: + + \list + \li GridView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view. + \li GridView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view. + \endlist + + \sa GridView::layoutDirection +*/ + /*! \qmlproperty bool QtQuick2::GridView::keyNavigationWraps This property holds whether the grid wraps key navigation @@ -1461,7 +1592,7 @@ void QQuickGridView::setFlow(Flow flow) Q_D(QQuickGridView); if (d->flow != flow) { d->flow = flow; - if (d->flow == LeftToRight) { + if (d->flow == FlowLeftToRight) { setContentWidth(-1); setFlickableDirection(VerticalFlick); } else { @@ -1877,12 +2008,17 @@ void QQuickGridView::viewportMoved() return; d->inViewportMoved = true; - if (yflick()) - d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; - else if (d->isRightToLeftTopToBottom()) - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore; - else - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; + if (yflick()) { + if (d->isContentFlowReversed()) + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore; + else + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; + } else { + if (d->isContentFlowReversed()) + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore; + else + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter; + } d->refillOrLayout(); @@ -1904,7 +2040,7 @@ void QQuickGridView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size() : d->position(); + qreal viewPos = d->isContentFlowReversed() ? -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) @@ -1923,7 +2059,7 @@ void QQuickGridView::viewportMoved() if (idx >= 0 && idx != d->currentIndex) { d->updateCurrent(idx); if (d->currentItem && static_cast<FxGridItemSG*>(d->currentItem)->colPos() != static_cast<FxGridItemSG*>(d->highlight)->colPos() && d->autoHighlight) { - if (d->flow == LeftToRight) + if (d->flow == FlowLeftToRight) d->highlightXAnimator->to = d->currentItem->itemX(); else d->highlightYAnimator->to = d->currentItem->itemY(); @@ -1970,6 +2106,16 @@ void QQuickGridView::geometryChanged(const QRectF &newGeometry, const QRectF &ol { Q_D(QQuickGridView); d->resetColumns(); + + if (newGeometry.width() != oldGeometry.width() + && newGeometry.height() != oldGeometry.height()) { + d->setPosition(d->position()); + } else if (newGeometry.width() != oldGeometry.width()) { + QQuickFlickable::setContentX(d->contentXForPosition(d->position())); + } else if (newGeometry.height() != oldGeometry.height()) { + QQuickFlickable::setContentY(d->contentYForPosition(d->position())); + } + QQuickItemView::geometryChanged(newGeometry, oldGeometry); } @@ -1990,15 +2136,29 @@ void QQuickGridView::moveCurrentIndexUp() const int count = d->model ? d->model->count() : 0; if (!count) return; - if (d->flow == QQuickGridView::LeftToRight) { - if (currentIndex() >= d->columns || d->wrap) { - int index = currentIndex() - d->columns; - setCurrentIndex((index >= 0 && index < count) ? index : count-1); + if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) { + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() >= d->columns || d->wrap) { + int index = currentIndex() - d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } + } else { + if (currentIndex() > 0 || d->wrap) { + int index = currentIndex() - 1; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } } } else { - if (currentIndex() > 0 || d->wrap) { - int index = currentIndex() - 1; - setCurrentIndex((index >= 0 && index < count) ? index : count-1); + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() < count - d->columns || d->wrap) { + int index = currentIndex()+d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } + } else { + if (currentIndex() < count - 1 || d->wrap) { + int index = currentIndex() + 1; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } } } } @@ -2018,15 +2178,30 @@ void QQuickGridView::moveCurrentIndexDown() const int count = d->model ? d->model->count() : 0; if (!count) return; - if (d->flow == QQuickGridView::LeftToRight) { - if (currentIndex() < count - d->columns || d->wrap) { - int index = currentIndex()+d->columns; - setCurrentIndex((index >= 0 && index < count) ? index : 0); + + if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) { + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() < count - d->columns || d->wrap) { + int index = currentIndex()+d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } + } else { + if (currentIndex() < count - 1 || d->wrap) { + int index = currentIndex() + 1; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } } } else { - if (currentIndex() < count - 1 || d->wrap) { - int index = currentIndex() + 1; - setCurrentIndex((index >= 0 && index < count) ? index : 0); + if (d->flow == QQuickGridView::FlowLeftToRight) { + if (currentIndex() >= d->columns || d->wrap) { + int index = currentIndex() - d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } + } else { + if (currentIndex() > 0 || d->wrap) { + int index = currentIndex() - 1; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } } } } @@ -2047,7 +2222,7 @@ void QQuickGridView::moveCurrentIndexLeft() if (!count) return; if (effectiveLayoutDirection() == Qt::LeftToRight) { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() > 0 || d->wrap) { int index = currentIndex() - 1; setCurrentIndex((index >= 0 && index < count) ? index : count-1); @@ -2059,7 +2234,7 @@ void QQuickGridView::moveCurrentIndexLeft() } } } else { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() < count - 1 || d->wrap) { int index = currentIndex() + 1; setCurrentIndex((index >= 0 && index < count) ? index : 0); @@ -2090,7 +2265,7 @@ void QQuickGridView::moveCurrentIndexRight() if (!count) return; if (effectiveLayoutDirection() == Qt::LeftToRight) { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() < count - 1 || d->wrap) { int index = currentIndex() + 1; setCurrentIndex((index >= 0 && index < count) ? index : 0); @@ -2102,7 +2277,7 @@ void QQuickGridView::moveCurrentIndexRight() } } } else { - if (d->flow == QQuickGridView::LeftToRight) { + if (d->flow == QQuickGridView::FlowLeftToRight) { if (currentIndex() > 0 || d->wrap) { int index = currentIndex() - 1; setCurrentIndex((index >= 0 && index < count) ? index : count-1); @@ -2146,7 +2321,7 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert & } } - qreal tempPos = isRightToLeftTopToBottom() ? -position()-size()+q->width()+1 : position(); + qreal tempPos = isContentFlowReversed() ? -position()-size()+q->width()+1 : position(); qreal colPos = 0; qreal rowPos = 0; int colNum = 0; diff --git a/src/quick/items/qquickgridview_p.h b/src/quick/items/qquickgridview_p.h index ac3c8f097d..789c6411a5 100644 --- a/src/quick/items/qquickgridview_p.h +++ b/src/quick/items/qquickgridview_p.h @@ -69,13 +69,17 @@ class Q_AUTOTEST_EXPORT QQuickGridView : public QQuickItemView Q_CLASSINFO("DefaultProperty", "data") public: + enum Flow { + FlowLeftToRight = LeftToRight, + FlowTopToBottom = TopToBottom + }; + QQuickGridView(QQuickItem *parent=0); ~QQuickGridView(); virtual void setHighlightFollowsCurrentItem(bool); virtual void setHighlightMoveDuration(int); - enum Flow { LeftToRight, TopToBottom }; Flow flow() const; void setFlow(Flow); diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 64c05aab92..e70e923c4d 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -475,6 +475,21 @@ Qt::LayoutDirection QQuickItemView::effectiveLayoutDirection() const return d->layoutDirection; } +QQuickItemView::VerticalLayoutDirection QQuickItemView::verticalLayoutDirection() const +{ + Q_D(const QQuickItemView); + return d->verticalLayoutDirection; +} + +void QQuickItemView::setVerticalLayoutDirection(VerticalLayoutDirection layoutDirection) +{ + Q_D(QQuickItemView); + if (d->verticalLayoutDirection != layoutDirection) { + d->verticalLayoutDirection = layoutDirection; + d->regenerate(); + emit verticalLayoutDirectionChanged(); + } +} QQmlComponent *QQuickItemView::header() const { @@ -818,7 +833,7 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) FxViewItem *item = visibleItem(idx); qreal maxExtent; if (layoutOrientation() == Qt::Vertical) - maxExtent = -q->maxYExtent(); + maxExtent = isContentFlowReversed() ? q->minYExtent()-size(): -q->maxYExtent(); else maxExtent = isContentFlowReversed() ? q->minXExtent()-size(): -q->maxXExtent(); if (!item) { @@ -864,7 +879,7 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) pos = qMin(pos, maxExtent); qreal minExtent; if (layoutOrientation() == Qt::Vertical) - minExtent = -q->minYExtent(); + minExtent = isContentFlowReversed() ? q->maxYExtent()-size(): -q->minYExtent(); else minExtent = isContentFlowReversed() ? q->maxXExtent()-size(): -q->minXExtent(); pos = qMax(pos, minExtent); @@ -948,6 +963,89 @@ int QQuickItemViewPrivate::findMoveKeyIndex(QQuickChangeSet::MoveKey key, const return -1; } +qreal QQuickItemViewPrivate::minExtentForAxis(const AxisData &axisData, bool forXAxis) const +{ + Q_Q(const QQuickItemView); + + qreal highlightStart; + qreal highlightEnd; + qreal endPositionFirstItem = 0; + qreal extent = -startPosition() + axisData.startMargin; + if (isContentFlowReversed()) { + if (model && model->count()) + endPositionFirstItem = positionAt(model->count()-1); + else + extent += headerSize(); + highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size(); + highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size(); + extent += footerSize(); + qreal maxExtentAlongAxis = forXAxis ? q->maxXExtent() : q->maxYExtent(); + if (extent < maxExtentAlongAxis) + extent = maxExtentAlongAxis; + } else { + endPositionFirstItem = endPositionAt(0); + highlightStart = highlightRangeStart; + highlightEnd = highlightRangeEnd; + extent += headerSize(); + } + if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) { + extent += highlightStart; + FxViewItem *firstItem = visibleItem(0); + if (firstItem) + extent -= firstItem->sectionSize(); + extent = isContentFlowReversed() + ? qMin(extent, endPositionFirstItem + highlightEnd) + : qMax(extent, -(endPositionFirstItem - highlightEnd)); + } + return extent; +} + +qreal QQuickItemViewPrivate::maxExtentForAxis(const AxisData &axisData, bool forXAxis) const +{ + Q_Q(const QQuickItemView); + + qreal highlightStart; + qreal highlightEnd; + qreal lastItemPosition = 0; + qreal extent = 0; + if (isContentFlowReversed()) { + highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size(); + highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size(); + lastItemPosition = endPosition(); + } else { + highlightStart = highlightRangeStart; + highlightEnd = highlightRangeEnd; + if (model && model->count()) + lastItemPosition = positionAt(model->count()-1); + } + if (!model || !model->count()) { + if (!isContentFlowReversed()) + maxExtent = header ? -headerSize() : 0; + extent += forXAxis ? q->width() : q->height(); + } else if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) { + extent = -(lastItemPosition - highlightStart); + if (highlightEnd != highlightStart) { + extent = isContentFlowReversed() + ? qMax(extent, -(endPosition() - highlightEnd)) + : qMin(extent, -(endPosition() - highlightEnd)); + } + } else { + extent = -(endPosition() - (forXAxis ? q->width() : q->height())); + } + if (isContentFlowReversed()) { + extent -= headerSize(); + extent -= axisData.endMargin; + } else { + extent -= footerSize(); + extent -= axisData.endMargin; + qreal minExtentAlongAxis = forXAxis ? q->minXExtent() : q->minYExtent(); + if (extent > minExtentAlongAxis) + extent = minExtentAlongAxis; + } + + return extent; +} + // for debugging only void QQuickItemViewPrivate::checkVisible() const { @@ -1119,12 +1217,17 @@ void QQuickItemView::trackedPositionChanged() toItemEndPos -= startOffset; } else if (d->showFooterForIndex(d->currentIndex)) { qreal endOffset = d->footerSize(); - if (d->layoutOrientation() == Qt::Vertical) - endOffset += d->vData.endMargin; - else if (d->isContentFlowReversed()) - endOffset += d->hData.startMargin; - else - endOffset += d->hData.endMargin; + if (d->layoutOrientation() == Qt::Vertical) { + if (d->isContentFlowReversed()) + endOffset += d->vData.startMargin; + else + endOffset += d->vData.endMargin; + } else { + if (d->isContentFlowReversed()) + endOffset += d->hData.startMargin; + else + endOffset += d->hData.endMargin; + } trackedPos += endOffset; trackedEndPos += endOffset; toItemPos += endOffset; @@ -1166,7 +1269,6 @@ void QQuickItemView::geometryChanged(const QRectF &newGeometry, const QRectF &ol QQuickFlickable::geometryChanged(newGeometry, oldGeometry); } - qreal QQuickItemView::minYExtent() const { Q_D(const QQuickItemView); @@ -1174,15 +1276,7 @@ qreal QQuickItemView::minYExtent() const return QQuickFlickable::minYExtent(); if (d->vData.minExtentDirty) { - d->minExtent = d->vData.startMargin-d->startPosition(); - if (d->header) - d->minExtent += d->headerSize(); - if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->minExtent += d->highlightRangeStart; - if (d->visibleItem(0)) - d->minExtent -= d->visibleItem(0)->sectionSize(); - d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd)); - } + d->minExtent = d->minExtentForAxis(d->vData, false); d->vData.minExtentDirty = false; } @@ -1196,25 +1290,10 @@ qreal QQuickItemView::maxYExtent() const return height(); if (d->vData.maxExtentDirty) { - if (!d->model || !d->model->count()) { - d->maxExtent = d->header ? -d->headerSize() : 0; - d->maxExtent += height(); - } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart); - if (d->highlightRangeEnd != d->highlightRangeStart) - d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd)); - } else { - d->maxExtent = -(d->endPosition() - height()); - } - - if (d->footer) - d->maxExtent -= d->footerSize(); - d->maxExtent -= d->vData.endMargin; - qreal minY = minYExtent(); - if (d->maxExtent > minY) - d->maxExtent = minY; + d->maxExtent = d->maxExtentForAxis(d->vData, false); d->vData.maxExtentDirty = false; } + return d->maxExtent; } @@ -1225,35 +1304,7 @@ qreal QQuickItemView::minXExtent() const return QQuickFlickable::minXExtent(); if (d->hData.minExtentDirty) { - d->minExtent = -d->startPosition() + d->hData.startMargin; - qreal highlightStart; - qreal highlightEnd; - qreal endPositionFirstItem = 0; - if (d->isContentFlowReversed()) { - if (d->model && d->model->count()) - endPositionFirstItem = d->positionAt(d->model->count()-1); - else if (d->header) - d->minExtent += d->headerSize(); - 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(); - if (d->minExtent < maxX) - d->minExtent = maxX; - } else { - endPositionFirstItem = d->endPositionAt(0); - highlightStart = d->highlightRangeStart; - highlightEnd = d->highlightRangeEnd; - if (d->header) - d->minExtent += d->headerSize(); - } - if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->minExtent += highlightStart; - d->minExtent = d->isContentFlowReversed() - ? qMin(d->minExtent, endPositionFirstItem + highlightEnd) - : qMax(d->minExtent, -(endPositionFirstItem - highlightEnd)); - } + d->minExtent = d->minExtentForAxis(d->hData, true); d->hData.minExtentDirty = false; } @@ -1267,46 +1318,7 @@ qreal QQuickItemView::maxXExtent() const return width(); if (d->hData.maxExtentDirty) { - qreal highlightStart; - qreal highlightEnd; - qreal lastItemPosition = 0; - d->maxExtent = 0; - if (d->isContentFlowReversed()) { - 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; - highlightEnd = d->highlightRangeEnd; - if (d->model && d->model->count()) - lastItemPosition = d->positionAt(d->model->count()-1); - } - if (!d->model || !d->model->count()) { - if (!d->isContentFlowReversed()) - d->maxExtent = d->header ? -d->headerSize() : 0; - d->maxExtent += width(); - } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->maxExtent = -(lastItemPosition - highlightStart); - if (highlightEnd != highlightStart) { - d->maxExtent = d->isContentFlowReversed() - ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd)) - : qMin(d->maxExtent, -(d->endPosition() - highlightEnd)); - } - } else { - d->maxExtent = -(d->endPosition() - width()); - } - if (d->isContentFlowReversed()) { - if (d->header) - d->maxExtent -= d->headerSize(); - d->maxExtent -= d->hData.endMargin; - } else { - if (d->footer) - d->maxExtent -= d->footerSize(); - d->maxExtent -= d->hData.endMargin; - qreal minX = minXExtent(); - if (d->maxExtent > minX) - d->maxExtent = minX; - } + d->maxExtent = d->maxExtentForAxis(d->hData, true); d->hData.maxExtentDirty = false; } @@ -1338,6 +1350,15 @@ qreal QQuickItemView::xOrigin() const return -minXExtent() + d->hData.startMargin; } +qreal QQuickItemView::yOrigin() const +{ + Q_D(const QQuickItemView); + if (d->isContentFlowReversed()) + return -maxYExtent() + d->size() - d->vData.endMargin; + else + return -minYExtent() + d->vData.startMargin; +} + void QQuickItemView::updatePolish() { Q_D(QQuickItemView); @@ -1385,7 +1406,7 @@ void QQuickItemView::componentComplete() QQuickItemViewPrivate::QQuickItemViewPrivate() : itemCount(0) , buffer(0), bufferMode(BufferBefore | BufferAfter) - , layoutDirection(Qt::LeftToRight) + , layoutDirection(Qt::LeftToRight), verticalLayoutDirection(QQuickItemView::TopToBottom) , moveReason(Other) , visibleIndex(0) , currentIndex(-1), currentItem(0) @@ -1442,13 +1463,17 @@ qreal QQuickItemViewPrivate::endPosition() const qreal QQuickItemViewPrivate::contentStartOffset() const { qreal pos = -headerSize(); - if (layoutOrientation() == Qt::Vertical) - pos -= vData.startMargin; - else if (isContentFlowReversed()) - pos -= hData.endMargin; - else - pos -= hData.startMargin; - + if (layoutOrientation() == Qt::Vertical) { + if (isContentFlowReversed()) + pos -= vData.endMargin; + else + pos -= vData.startMargin; + } else { + if (isContentFlowReversed()) + pos -= hData.endMargin; + else + pos -= hData.startMargin; + } return pos; } diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index f252fb58f1..89e59306f9 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -70,6 +70,7 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged) Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged) + Q_PROPERTY(VerticalLayoutDirection verticalLayoutDirection READ verticalLayoutDirection WRITE setVerticalLayoutDirection NOTIFY verticalLayoutDirectionChanged) Q_PROPERTY(QQmlComponent *header READ header WRITE setHeader NOTIFY headerChanged) Q_PROPERTY(QQuickItem *headerItem READ headerItem NOTIFY headerItemChanged) @@ -95,8 +96,25 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable Q_ENUMS(HighlightRangeMode) Q_ENUMS(PositionMode) + Q_ENUMS(VerticalLayoutDirection) + Q_ENUMS(LayoutDirection) public: + // this holds all layout enum values so they can be referred to by other enums + // to ensure consistent values - e.g. QML references to GridView.TopToBottom flow + // and GridView.TopToBottom vertical layout direction should have same value + enum LayoutDirection { + LeftToRight = Qt::LeftToRight, + RightToLeft = Qt::RightToLeft, + VerticalTopToBottom, + VerticalBottomToTop + }; + + enum VerticalLayoutDirection { + TopToBottom = VerticalTopToBottom, + BottomToTop = VerticalBottomToTop + }; + QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent = 0); ~QQuickItemView(); @@ -123,6 +141,9 @@ public: void setLayoutDirection(Qt::LayoutDirection); Qt::LayoutDirection effectiveLayoutDirection() const; + VerticalLayoutDirection verticalLayoutDirection() const; + void setVerticalLayoutDirection(VerticalLayoutDirection layoutDirection); + QQmlComponent *footer() const; void setFooter(QQmlComponent *); QQuickItem *footerItem() const; @@ -189,6 +210,7 @@ public: virtual void setContentX(qreal pos); virtual void setContentY(qreal pos); virtual qreal xOrigin() const; + virtual qreal yOrigin() const; signals: void modelChanged(); @@ -202,6 +224,7 @@ signals: void layoutDirectionChanged(); void effectiveLayoutDirectionChanged(); + void verticalLayoutDirectionChanged(); void headerChanged(); void footerChanged(); diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 1e29faf10f..8fc83a99e3 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -204,6 +204,10 @@ public: void updateUnrequestedPositions(); void updateVisibleIndex(); void positionViewAtIndex(int index, int mode); + + qreal minExtentForAxis(const AxisData &axisData, bool forXAxis) const; + qreal maxExtentForAxis(const AxisData &axisData, bool forXAxis) const; + void applyPendingChanges(); bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult); bool applyRemovalChange(const QQuickChangeSet::Remove &removal, ChangeResult *changeResult, int *removedCount); @@ -248,6 +252,7 @@ public: int buffer; int bufferMode; Qt::LayoutDirection layoutDirection; + QQuickItemView::VerticalLayoutDirection verticalLayoutDirection; MovementReason moveReason; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index b65cb85465..df50d3eb8c 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -73,6 +73,7 @@ public: virtual Qt::Orientation layoutOrientation() const; virtual bool isContentFlowReversed() const; bool isRightToLeft() const; + bool isBottomToTop() const; virtual qreal positionAt(int index) const; virtual qreal endPositionAt(int index) const; @@ -265,7 +266,7 @@ public: qreal position() const { if (section()) { if (view->orientation() == QQuickListView::Vertical) - return section()->y(); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -section()->height()-section()->y() : section()->y()); else return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x()); } else { @@ -274,7 +275,7 @@ public: } qreal itemPosition() const { if (view->orientation() == QQuickListView::Vertical) - return itemY(); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY()); else return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX()); } @@ -294,7 +295,9 @@ public: } qreal endPosition() const { if (view->orientation() == QQuickListView::Vertical) { - return itemY() + item->height(); + return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop + ? -itemY() + : itemY() + item->height()); } else { return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -itemX() @@ -305,7 +308,10 @@ public: // position the section immediately even if there is a transition if (section()) { if (view->orientation() == QQuickListView::Vertical) { - section()->setY(pos); + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) + section()->setY(-section()->height()-pos); + else + section()->setY(pos); } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) section()->setX(-section()->width()-pos); @@ -331,9 +337,15 @@ public: private: QPointF pointForPosition(qreal pos) const { if (view->orientation() == QQuickListView::Vertical) { - if (section()) - pos += section()->height(); - return QPointF(itemX(), pos); + if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) { + if (section()) + pos += section()->height(); + return QPointF(itemX(), -item->height() - pos); + } else { + if (section()) + pos += section()->height(); + return QPointF(itemX(), pos); + } } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) { if (section()) @@ -352,7 +364,7 @@ private: bool QQuickListViewPrivate::isContentFlowReversed() const { - return isRightToLeft(); + return isRightToLeft() || isBottomToTop(); } Qt::Orientation QQuickListViewPrivate::layoutOrientation() const @@ -366,6 +378,11 @@ bool QQuickListViewPrivate::isRightToLeft() const return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft; } +bool QQuickListViewPrivate::isBottomToTop() const +{ + return orient == QQuickListView::Vertical && verticalLayoutDirection == QQuickItemView::BottomToTop; +} + // Returns the item before modelIndex, if created. // May return an item marked for removal. FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const @@ -391,7 +408,10 @@ void QQuickListViewPrivate::setPosition(qreal pos) { Q_Q(QQuickListView); if (orient == QQuickListView::Vertical) { - q->QQuickFlickable::setContentY(pos); + if (isBottomToTop()) + q->QQuickFlickable::setContentY(-pos-size()); + else + q->QQuickFlickable::setContentY(pos); } else { if (isRightToLeft()) q->QQuickFlickable::setContentX(-pos-size()); @@ -797,8 +817,12 @@ void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index) Q_Q(QQuickListView); qreal pos = position(); if (orient == QQuickListView::Vertical) { - if (item->y() + item->height() > pos && item->y() < pos + q->height()) - item->setY(positionAt(index)); + if (item->y() + item->height() > pos && item->y() < pos + q->height()) { + if (isBottomToTop()) + item->setY(-positionAt(index)-item->height()); + else + item->setY(positionAt(index)); + } } else { if (item->x() + item->width() > pos && item->x() < pos + q->width()) { if (isRightToLeft()) @@ -880,7 +904,7 @@ void QQuickListViewPrivate::updateHighlight() if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) { // auto-update highlight FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem); - highlightPosAnimator->to = isRightToLeft() + highlightPosAnimator->to = isContentFlowReversed() ? -listItem->itemPosition()-listItem->itemSize() : listItem->itemPosition(); highlightSizeAnimator->to = listItem->itemSize(); @@ -987,8 +1011,8 @@ void QQuickListViewPrivate::updateStickySections() || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem)) return; - bool isRtl = isRightToLeft(); - qreal viewPos = isRightToLeft() ? -position()-size() : position(); + bool isFlowReversed = isContentFlowReversed(); + qreal viewPos = isFlowReversed ? -position()-size() : position(); QQuickItem *sectionItem = 0; QQuickItem *lastSectionItem = 0; int index = 0; @@ -1000,14 +1024,14 @@ void QQuickListViewPrivate::updateStickySections() qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width(); bool visTop = true; if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart) - visTop = isRtl ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos; + visTop = isFlowReversed ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos; bool visBot = true; if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) - visBot = isRtl ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size(); + visBot = isFlowReversed ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size(); section->setVisible(visBot && visTop); if (visTop && !sectionItem) sectionItem = section; - if (isRtl) { + if (isFlowReversed) { if (-sectionPos <= viewPos + size()) lastSectionItem = section; } else { @@ -1031,17 +1055,18 @@ void QQuickListViewPrivate::updateStickySections() return; qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width(); - bool atBeginning = orient == QQuickListView::Vertical ? vData.atBeginning : (isRightToLeft() ? hData.atEnd : hData.atBeginning); + bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning); + currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos)); - qreal pos = isRtl ? position() + size() - sectionSize : viewPos; + qreal pos = isFlowReversed ? position() + size() - sectionSize : viewPos; if (sectionItem) { qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x(); - pos = isRtl ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize); + pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize); } if (header) - pos = isRtl ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos); + pos = isFlowReversed ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos); if (footer) - pos = isRtl ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos); + pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos); if (orient == QQuickListView::Vertical) currentSectionItem->setY(pos); else @@ -1065,13 +1090,13 @@ void QQuickListViewPrivate::updateStickySections() qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width(); nextSectionItem->setVisible(!nextSection.isEmpty()); - qreal pos = isRtl ? position() : viewPos + size() - sectionSize; + qreal pos = isFlowReversed ? position() : viewPos + size() - sectionSize; if (lastSectionItem) { qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x(); - pos = isRtl ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize); + pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize); } if (header) - pos = isRtl ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos); + pos = isFlowReversed ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos); if (orient == QQuickListView::Vertical) nextSectionItem->setY(pos); else @@ -1162,7 +1187,7 @@ void QQuickListViewPrivate::updateCurrentSection() // section when that changes. Clearing lastVisibleSection will also // force searching. QString lastSection = currentSection; - qreal endPos = isRightToLeft() ? -position() : position() + size(); + qreal endPos = isContentFlowReversed() ? -position() : position() + size(); if (nextSectionItem && !inlineSections) endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width(); while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) { @@ -1341,10 +1366,10 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte fixupMode = moveReason == Mouse ? fixupMode : Immediate; bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange; - qreal viewPos = isRightToLeft() ? -position()-size() : position(); + qreal viewPos = isContentFlowReversed() ? -position()-size() : position(); if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) { - qreal tempPosition = isRightToLeft() ? -position()-size() : position(); + qreal tempPosition = isContentFlowReversed() ? -position()-size() : position(); if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) { // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); @@ -1353,7 +1378,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte bias = averageSize/2; else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2) bias = -averageSize/2; - if (isRightToLeft()) + if (isContentFlowReversed()) bias = -bias; tempPosition -= bias; } @@ -1373,15 +1398,15 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte bool isInBounds = -position() > maxExtent && -position() <= minExtent; if (topItem && (isInBounds || strictHighlightRange)) { if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) { - pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart; + pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart; } else { - if (isRightToLeft()) + if (isContentFlowReversed()) pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent); else pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); } } else if (bottomItem && isInBounds) { - if (isRightToLeft()) + if (isContentFlowReversed()) pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent); else pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent); @@ -1408,7 +1433,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd; if (viewPos > pos - highlightRangeStart) viewPos = pos - highlightRangeStart; - if (isRightToLeft()) + if (isContentFlowReversed()) viewPos = -viewPos-size(); timeline.reset(data.move); @@ -1441,7 +1466,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte return; } qreal maxDistance = 0; - qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value(); + qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value(); // -ve velocity means list is moving up/left if (velocity > 0) { @@ -1450,7 +1475,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = dist < averageSize/2 ? averageSize/2 : 0; - if (isRightToLeft()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart; maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1467,7 +1492,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // if we've been dragged < averageSize/2 then bias towards the next item qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset); qreal bias = -dist < averageSize/2 ? averageSize/2 : 0; - if (isRightToLeft()) + if (isContentFlowReversed()) bias = -bias; data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart; maxDistance = qAbs(data.flickTarget - data.move.value()); @@ -1505,10 +1530,10 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte dist = -dist; if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) { if (snapMode != QQuickListView::SnapOneItem) { - qreal distTemp = isRightToLeft() ? -dist : dist; + qreal distTemp = isContentFlowReversed() ? -dist : dist; data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart; } - data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; + data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget; if (overShoot) { if (data.flickTarget >= minExtent) { overshootDist = overShootDistance(vSize); @@ -1561,9 +1586,9 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte // reevaluate the target boundary. qreal newtarget = data.flickTarget; if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) { - qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; + qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget; newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart; - newtarget = isRightToLeft() ? -newtarget+size() : newtarget; + newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget; } if (velocity < 0 && newtarget <= maxExtent) newtarget = maxExtent - overshootDist; @@ -1655,6 +1680,45 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte to set \e {clip: true} in order to have the out of view items clipped nicely. + + \section1 ListView layouts + + The layout of the items in a ListView can be controlled by these properties: + + \list + \li \l orientation - controls whether items flow horizontally or vertically. + This value can be either Qt.Horizontal or Qt.Vertical. + \li \l layoutDirection - controls the horizontal layout direction for a + horizontally-oriented view: that is, whether items are laid out from the left side of + the view to the right, or vice-versa. This value can be either Qt.LeftToRight or Qt.RightToLeft. + \li \l verticalLayoutDirection - controls the vertical layout direction for a vertically-oriented + view: that is, whether items are laid out from the top of the view down towards the bottom of + the view, or vice-versa. This value can be either ListView.TopToBottom or ListView.BottomToTop. + \endlist + + By default, a ListView has a vertical orientation, and items are laid out from top to bottom. The + table below shows the different layouts that a ListView can have, depending on the values of + the properties listed above. + + \table + \header + \li {2, 1} + \bold ListViews with Qt.Vertical orientation + \row + \li Top to bottom + \image listview-layout-toptobottom.png + \li Bottom to top + \image listview-layout-bottomtotop.png + \header + \li {2, 1} + \bold ListViews with Qt.Horizontal orientation + \row + \li Left to right + \image listview-layout-lefttoright.png + \li Right to left + \image listview-layout-righttoleft.png + \endtable + \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples} */ QQuickListView::QQuickListView(QQuickItem *parent) @@ -1956,7 +2020,7 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) /*! \qmlproperty enumeration QtQuick2::ListView::layoutDirection - This property holds the layout direction of the horizontal list. + This property holds the layout direction of a horizontally-oriented list. Possible values: @@ -1965,13 +2029,15 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) \li Qt.RightToLeft - Items will be laid out from right to let. \endlist - \sa ListView::effectiveLayoutDirection + Setting this property has no effect if the \l orientation is Qt.Vertical. + + \sa ListView::effectiveLayoutDirection, ListView::verticalLayoutDirection */ /*! \qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection - This property holds the effective layout direction of the horizontal list. + This property holds the effective layout direction of a horizontally-oriented list. When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts, the visual layout direction of the horizontal list will be mirrored. However, the @@ -1980,6 +2046,24 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring} */ + +/*! + \qmlproperty enumeration QtQuick2::ListView::verticalLayoutDirection + This property holds the layout direction of a vertically-oriented list. + + Possible values: + + \list + \li ListView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view. + \li ListView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view. + \endlist + + Setting this property has no effect if the \l orientation is Qt.Horizontal. + + \sa ListView::layoutDirection +*/ + + /*! \qmlproperty bool QtQuick2::ListView::keyNavigationWraps This property holds whether the list wraps key navigation. @@ -2550,12 +2634,17 @@ void QQuickListView::viewportMoved() return; d->inViewportMoved = true; - if (yflick()) - d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; - else if (d->isRightToLeft()) - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore; - else - d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; + if (yflick()) { + if (d->isBottomToTop()) + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore; + else + d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; + } else { + if (d->isRightToLeft()) + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore; + else + d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter; + } d->refillOrLayout(); @@ -2575,7 +2664,7 @@ void QQuickListView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position(); + qreal viewPos = d->isContentFlowReversed() ? -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) @@ -2641,7 +2730,8 @@ void QQuickListView::keyPressEvent(QKeyEvent *event) if (d->model && d->model->count() && d->interactive) { if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left) || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right) - || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Up)) { + || (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Up) + || (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Down)) { if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) { decrementCurrentIndex(); event->accept(); @@ -2652,7 +2742,8 @@ void QQuickListView::keyPressEvent(QKeyEvent *event) } } else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right) || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left) - || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Down)) { + || (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Down) + || (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Up)) { if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) { incrementCurrentIndex(); event->accept(); @@ -2670,10 +2761,14 @@ void QQuickListView::keyPressEvent(QKeyEvent *event) void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { Q_D(QQuickListView); - if (d->isRightToLeft() && d->orient == QQuickListView::Horizontal) { + if (d->isRightToLeft()) { // maintain position relative to the right edge int dx = newGeometry.width() - oldGeometry.width(); setContentX(contentX() - dx); + } else if (d->isBottomToTop()) { + // maintain position relative to the bottom edge + int dy = newGeometry.height() - oldGeometry.height(); + setContentY(contentY() - dy); } QQuickItemView::geometryChanged(newGeometry, oldGeometry); } @@ -2740,7 +2835,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert & int modelIndex = change.index; int count = change.count; - qreal tempPos = isRightToLeft() ? -position()-size() : position(); + qreal tempPos = isContentFlowReversed() ? -position()-size() : position(); int index = visibleItems.count() ? mapFromModel(modelIndex) : 0; if (index < 0) { |