aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/quick/items/qquickgridview.cpp379
-rw-r--r--src/quick/items/qquickgridview_p.h6
-rw-r--r--src/quick/items/qquickitemview.cpp249
-rw-r--r--src/quick/items/qquickitemview_p.h23
-rw-r--r--src/quick/items/qquickitemview_p_p.h5
-rw-r--r--src/quick/items/qquicklistview.cpp203
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) {