diff options
author | Christopher Ham <christopher.ham@nokia.com> | 2011-02-15 06:22:46 (GMT) |
---|---|---|
committer | Christopher Ham <christopher.ham@nokia.com> | 2011-02-15 06:22:46 (GMT) |
commit | 0b0358732cafc34d4b6794200752ac9cb99de569 (patch) | |
tree | e302c95daf4dceec6946034b419e4609fc130a53 /src/declarative/graphicsitems/qdeclarativelistview.cpp | |
parent | 5eb9edbd51df63fe3329e8ddc1325ed3024211ad (diff) | |
download | Qt-0b0358732cafc34d4b6794200752ac9cb99de569.zip Qt-0b0358732cafc34d4b6794200752ac9cb99de569.tar.gz Qt-0b0358732cafc34d4b6794200752ac9cb99de569.tar.bz2 |
Righ-to-left support for GridView and ListView
GridView and ListView can now be laid out right-to-left. The
behaviour should be identical and mirrored to the oridinary behaviour.
Change-Id: I8e55c5f88358042caa5201712ef239cd67628172
Task-number: QTBUG-15877
Reviewed-by: Joona Petrell
Diffstat (limited to 'src/declarative/graphicsitems/qdeclarativelistview.cpp')
-rw-r--r-- | src/declarative/graphicsitems/qdeclarativelistview.cpp | 385 |
1 files changed, 296 insertions, 89 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index a60a4aa..6749657 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -100,13 +100,20 @@ public: } ~FxListItem() {} qreal position() const { - if (section) - return (view->orientation() == QDeclarativeListView::Vertical ? section->y() : section->x()); - else - return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x()); + if (section) { + if (view->orientation() == QDeclarativeListView::Vertical) + return section->y(); + else + return (view->layoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x()); + } else { + return itemPosition(); + } } qreal itemPosition() const { - return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x()); + if (view->orientation() == QDeclarativeListView::Vertical) + return item->y(); + else + return (view->layoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x()); } qreal size() const { if (section) @@ -123,9 +130,13 @@ public: return 0.0; } qreal endPosition() const { - return (view->orientation() == QDeclarativeListView::Vertical - ? item->y() + (item->height() >= 1.0 ? item->height() : 1) - : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1; + if (view->orientation() == QDeclarativeListView::Vertical) { + return item->y() + (item->height() >= 1.0 ? item->height() : 1) - 1; + } else { + return (view->layoutDirection() == Qt::RightToLeft + ? -item->width()-item->x() + (item->width() >= 1.0 ? item->width() : 1) + : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1; + } } void setPosition(qreal pos) { if (view->orientation() == QDeclarativeListView::Vertical) { @@ -135,11 +146,19 @@ public: } item->setY(pos); } else { - if (section) { - section->setX(pos); - pos += section->width(); + if (view->layoutDirection() == Qt::RightToLeft) { + if (section) { + section->setX(-section->width()-pos); + pos += section->width(); + } + item->setX(-item->width()-pos); + } else { + if (section) { + section->setX(pos); + pos += section->width(); + } + item->setX(pos); } - item->setX(pos); } } void setSize(qreal size) { @@ -168,10 +187,11 @@ class QDeclarativeListViewPrivate : public QDeclarativeFlickablePrivate public: QDeclarativeListViewPrivate() - : currentItem(0), orient(QDeclarativeListView::Vertical) + : currentItem(0), orient(QDeclarativeListView::Vertical), layoutDirection(Qt::LeftToRight) , visiblePos(0), visibleIndex(0) , averageSize(100.0), currentIndex(-1), requestedIndex(-1) , itemCount(0), highlightRangeStart(0), highlightRangeEnd(0) + , highlightRangeStartValid(false), highlightRangeEndValid(false) , highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0) , sectionCriteria(0), spacing(0.0) @@ -204,7 +224,7 @@ public: } FxListItem *firstVisibleItem() const { - const qreal pos = position(); + const qreal pos = isRightToLeft() ? -position()-size() : position(); for (int i = 0; i < visibleItems.count(); ++i) { FxListItem *item = visibleItems.at(i); if (item->index != -1 && item->endPosition() > pos) @@ -214,7 +234,7 @@ public: } FxListItem *nextVisibleItem() const { - const qreal pos = position(); + const qreal pos = isRightToLeft() ? -position()-size() : position(); bool foundFirst = false; for (int i = 0; i < visibleItems.count(); ++i) { FxListItem *item = visibleItems.at(i); @@ -228,23 +248,32 @@ public: return 0; } + bool isRightToLeft() const { + return (layoutDirection == Qt::RightToLeft && orient == QDeclarativeListView::Horizontal); + } + qreal position() const { Q_Q(const QDeclarativeListView); return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX(); } + void setPosition(qreal pos) { Q_Q(QDeclarativeListView); - if (orient == QDeclarativeListView::Vertical) + if (orient == QDeclarativeListView::Vertical) { q->QDeclarativeFlickable::setContentY(pos); - else - q->QDeclarativeFlickable::setContentX(pos); + } else { + if (layoutDirection == Qt::RightToLeft) + q->QDeclarativeFlickable::setContentX(-pos-size()); + else + q->QDeclarativeFlickable::setContentX(pos); + } } qreal size() const { Q_Q(const QDeclarativeListView); return orient == QDeclarativeListView::Vertical ? q->height() : q->width(); } - qreal startPosition() const { + qreal originPosition() const { qreal pos = 0; if (!visibleItems.isEmpty()) { pos = (*visibleItems.constBegin())->position(); @@ -254,7 +283,7 @@ public: return pos; } - qreal endPosition() const { + qreal lastPosition() const { qreal pos = 0; if (!visibleItems.isEmpty()) { int invisibleCount = visibleItems.count() - visibleIndex; @@ -271,6 +300,14 @@ public: return pos; } + qreal startPosition() const { + return isRightToLeft() ? -lastPosition()-1 : originPosition(); + } + + qreal endPosition() const { + return isRightToLeft() ? -originPosition()-1 : lastPosition(); + } + qreal positionAt(int modelIndex) const { if (FxListItem *item = visibleItem(modelIndex)) return item->position(); @@ -348,7 +385,7 @@ public: } else if (pos > endPos) return endPos + qRound((pos - endPos) / averageSize) * averageSize; } - return qRound((pos - startPosition()) / averageSize) * averageSize + startPosition(); + return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition(); } FxListItem *snapItemAt(qreal pos) { @@ -464,6 +501,7 @@ public: QHash<QDeclarativeItem*,int> unrequestedItems; FxListItem *currentItem; QDeclarativeListView::Orientation orient; + Qt::LayoutDirection layoutDirection; qreal visiblePos; int visibleIndex; qreal averageSize; @@ -472,6 +510,8 @@ public: int itemCount; qreal highlightRangeStart; qreal highlightRangeEnd; + bool highlightRangeStartValid; + bool highlightRangeEndValid; QDeclarativeComponent *highlightComponent; FxListItem *highlight; FxListItem *trackedItem; @@ -649,7 +689,6 @@ void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer) if (visibleItems.at(i)->index != -1) modelIndex = visibleItems.at(i)->index + 1; } - bool changed = false; FxListItem *item = 0; qreal pos = itemEnd + 1; @@ -795,8 +834,12 @@ void QDeclarativeListViewPrivate::updateUnrequestedPositions() if (item->y() + item->height() > pos && item->y() < pos + q->height()) item->setY(positionAt(*it)); } else { - if (item->x() + item->width() > pos && item->x() < pos + q->width()) - item->setX(positionAt(*it)); + if (item->x() + item->width() > pos && item->x() < pos + q->width()) { + if (isRightToLeft()) + item->setX(-positionAt(*it)-item->width()); + else + item->setX(positionAt(*it)); + } } } } @@ -887,7 +930,9 @@ void QDeclarativeListViewPrivate::updateHighlight() createHighlight(); if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) { // auto-update highlight - highlightPosAnimator->to = currentItem->itemPosition(); + highlightPosAnimator->to = isRightToLeft() + ? -currentItem->itemPosition()-currentItem->itemSize() + : currentItem->itemPosition(); highlightSizeAnimator->to = currentItem->itemSize(); if (orient == QDeclarativeListView::Vertical) { if (highlight->item->width() == 0) @@ -1104,7 +1149,7 @@ void QDeclarativeListViewPrivate::updateFooter() } if (footer) { if (visibleItems.count()) { - qreal endPos = endPosition() + 1; + qreal endPos = lastPosition() + 1; if (lastVisibleIndex() == model->count()-1) { footer->setPosition(endPos); } else { @@ -1144,7 +1189,7 @@ void QDeclarativeListViewPrivate::updateHeader() } if (header) { if (visibleItems.count()) { - qreal startPos = startPosition(); + qreal startPos = originPosition(); if (visibleIndex == 0) { header->setPosition(startPos - header->size()); } else { @@ -1180,14 +1225,30 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m int oldDuration = fixupDuration; fixupDuration = moveReason == Mouse ? fixupDuration : 0; - if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) { + qreal highlightStart; + qreal highlightEnd; + qreal viewPos; + if (isRightToLeft()) { + // Handle Right-To-Left exceptions + viewPos = -position()-size(); + highlightStart = highlightRangeStartValid ? size() - highlightRangeEnd : highlightRangeStart; + highlightEnd = highlightRangeEndValid ? size() - highlightRangeStart : highlightRangeEnd; + } else { + viewPos = position(); + highlightStart = highlightRangeStart; + highlightEnd = highlightRangeEnd; + } + + if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange + && moveReason != QDeclarativeListViewPrivate::SetIndex) { updateHighlight(); qreal pos = currentItem->itemPosition(); - qreal viewPos = position(); - if (viewPos < pos + currentItem->itemSize() - highlightRangeEnd) - viewPos = pos + currentItem->itemSize() - highlightRangeEnd; - if (viewPos > pos - highlightRangeStart) - viewPos = pos - highlightRangeStart; + if (viewPos < pos + currentItem->itemSize() - highlightEnd) + viewPos = pos + currentItem->itemSize() - highlightEnd; + if (viewPos > pos - highlightStart) + viewPos = pos - highlightStart; + if (isRightToLeft()) + viewPos = -viewPos-size(); timeline.reset(data.move); if (viewPos != position()) { @@ -1197,17 +1258,26 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m timeline.set(data.move, -viewPos); } vTime = timeline.time(); - } else if (snapMode != QDeclarativeListView::NoSnap) { - FxListItem *topItem = snapItemAt(position()+highlightRangeStart); - FxListItem *bottomItem = snapItemAt(position()+highlightRangeEnd); + } else if (snapMode != QDeclarativeListView::NoSnap && moveReason != QDeclarativeListViewPrivate::SetIndex) { + qreal tempPosition = isRightToLeft() ? -position()-size() : position(); + FxListItem *topItem = snapItemAt(tempPosition+highlightStart); + FxListItem *bottomItem = snapItemAt(tempPosition+highlightEnd); qreal pos; - if (topItem) { - if (topItem->index == 0 && header && position()+highlightRangeStart < header->position()+header->size()/2) - pos = header->position() - highlightRangeStart; + bool isInBounds = -position() > maxExtent && -position() < minExtent; + if (topItem && isInBounds) { + if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2) { + pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart; + } else { + if (isRightToLeft()) + pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent); + else + pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent); + } + } else if (bottomItem && isInBounds) { + if (isRightToLeft()) + pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent); else - pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); - } else if (bottomItem) { - pos = qMax(qMin(bottomItem->position() - highlightRangeStart, -maxExtent), -minExtent); + pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent); } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); fixupDuration = oldDuration; @@ -1241,12 +1311,15 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m return; } qreal maxDistance = 0; + qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value(); // -ve velocity means list is moving up/left if (velocity > 0) { if (data.move.value() < minExtent) { if (snapMode == QDeclarativeListView::SnapOneItem) { - if (FxListItem *item = firstVisibleItem()) - maxDistance = qAbs(item->position() + data.move.value()); + if (FxListItem *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem()) { + maxDistance = qAbs(item->position() + dataValue); +// qDebug() << "maxDist" << maxDistance << item->position() << dataValue; + } } else { maxDistance = qAbs(minExtent - data.move.value()); } @@ -1256,8 +1329,10 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m } else { if (data.move.value() > maxExtent) { if (snapMode == QDeclarativeListView::SnapOneItem) { - if (FxListItem *item = nextVisibleItem()) - maxDistance = qAbs(item->position() + data.move.value()); + if (FxListItem *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem()) { + maxDistance = qAbs(item->position() + dataValue); +// qDebug() << "maxDist2" << maxDistance << item->position() << dataValue; + } } else { maxDistance = qAbs(maxExtent - data.move.value()); } @@ -1265,7 +1340,10 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m if (snapMode == QDeclarativeListView::NoSnap && highlightRange != QDeclarativeListView::StrictlyEnforceRange) data.flickTarget = maxExtent; } + bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds; + qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart; + if (maxDistance > 0 || overShoot) { // These modes require the list to stop exactly on an item boundary. // The initial flick will estimate the boundary to stop on. @@ -1290,7 +1368,9 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m if (v > 0) dist = -dist; if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeListView::SnapOneItem) { - data.flickTarget = -snapPosAt(-(data.move.value() - highlightRangeStart) + dist) + highlightRangeStart; + qreal distTemp = isRightToLeft() ? -dist : dist; + data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart; + data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; if (overShoot) { if (data.flickTarget >= minExtent) { overshootDist = overShootDistance(v, vSize); @@ -1323,6 +1403,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m data.flickTarget -= overshootDist; } } + timeline.reset(data.move); timeline.accel(data.move, v, accel, maxDistance + overshootDist); timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this)); @@ -1342,8 +1423,11 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m } else { // reevaluate the target boundary. qreal newtarget = data.flickTarget; - if (snapMode != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::StrictlyEnforceRange) - newtarget = -snapPosAt(-(data.flickTarget - highlightRangeStart)) + highlightRangeStart; + if (snapMode != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::StrictlyEnforceRange) { + qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; + newtarget = -snapPosAt(-(tempFlickTarget - highlightStart)) + highlightStart; + newtarget = isRightToLeft() ? -newtarget+size() : newtarget; + } if (velocity < 0 && newtarget <= maxExtent) newtarget = maxExtent - overshootDist; else if (velocity > 0 && newtarget >= minExtent) @@ -1361,6 +1445,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m fixup(data, minExtent, maxExtent); return; } + timeline.reset(data.move); timeline.accelDistance(data.move, v, -dist); timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this)); @@ -1859,6 +1944,7 @@ qreal QDeclarativeListView::preferredHighlightBegin() const void QDeclarativeListView::setPreferredHighlightBegin(qreal start) { Q_D(QDeclarativeListView); + d->highlightRangeStartValid = true; if (d->highlightRangeStart == start) return; d->highlightRangeStart = start; @@ -1866,6 +1952,16 @@ void QDeclarativeListView::setPreferredHighlightBegin(qreal start) emit preferredHighlightBeginChanged(); } +void QDeclarativeListView::resetPreferredHighlightBegin() +{ + Q_D(QDeclarativeListView); + d->highlightRangeStartValid = false; + if (d->highlightRangeStart == 0) + return; + d->highlightRangeStart = 0; + emit preferredHighlightBeginChanged(); +} + qreal QDeclarativeListView::preferredHighlightEnd() const { Q_D(const QDeclarativeListView); @@ -1875,6 +1971,7 @@ qreal QDeclarativeListView::preferredHighlightEnd() const void QDeclarativeListView::setPreferredHighlightEnd(qreal end) { Q_D(QDeclarativeListView); + d->highlightRangeEndValid = true; if (d->highlightRangeEnd == end) return; d->highlightRangeEnd = end; @@ -1882,6 +1979,16 @@ void QDeclarativeListView::setPreferredHighlightEnd(qreal end) emit preferredHighlightEndChanged(); } +void QDeclarativeListView::resetPreferredHighlightEnd() +{ + Q_D(QDeclarativeListView); + d->highlightRangeEndValid = false; + if (d->highlightRangeEnd == 0) + return; + d->highlightRangeEnd = 0; + emit preferredHighlightEndChanged(); +} + QDeclarativeListView::HighlightRangeMode QDeclarativeListView::highlightRangeMode() const { Q_D(const QDeclarativeListView); @@ -1968,6 +2075,25 @@ void QDeclarativeListView::setOrientation(QDeclarativeListView::Orientation orie } } +Qt::LayoutDirection QDeclarativeListView::layoutDirection() const +{ + Q_D(const QDeclarativeListView); + return d->layoutDirection; +} + +void QDeclarativeListView::setLayoutDirection(Qt::LayoutDirection layoutDirection) +{ + Q_D(QDeclarativeListView); + if (d->layoutDirection != layoutDirection) { + d->layoutDirection = layoutDirection; + d->clear(); + d->setPosition(0); + refill(); + emit layoutDirectionChanged(); + d->updateCurrent(d->currentIndex); + } +} + /*! \qmlproperty bool ListView::keyNavigationWraps This property holds whether the list wraps key navigation. @@ -2339,11 +2465,23 @@ void QDeclarativeListView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos = d->position(); - if (pos > viewPos + d->highlightRangeEnd - d->highlight->size()) - pos = viewPos + d->highlightRangeEnd - d->highlight->size(); - if (pos < viewPos + d->highlightRangeStart) - pos = viewPos + d->highlightRangeStart; + qreal viewPos; + qreal highlightStart; + qreal highlightEnd; + if (d->isRightToLeft()) { + // Handle Right-To-Left exceptions + viewPos = -d->position()-d->size(); + highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; + highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; + } else { + viewPos = d->position(); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + } + if (pos > viewPos + highlightEnd - d->highlight->size()) + pos = viewPos + highlightEnd - d->highlight->size(); + if (pos < viewPos + highlightStart) + pos = viewPos + highlightStart; d->highlightPosAnimator->stop(); d->highlight->setPosition(qRound(pos)); @@ -2381,13 +2519,15 @@ void QDeclarativeListView::viewportMoved() if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2) && minX != d->hData.flickTarget) d->flickX(-d->hData.smoothVelocity.value()); - d->bufferMode = QDeclarativeListViewPrivate::BufferBefore; + d->bufferMode = d->isRightToLeft() + ? QDeclarativeListViewPrivate::BufferAfter : QDeclarativeListViewPrivate::BufferBefore; } else if (d->hData.velocity < 0) { const qreal maxX = maxXExtent(); if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2) && maxX != d->hData.flickTarget) d->flickX(-d->hData.smoothVelocity.value()); - d->bufferMode = QDeclarativeListViewPrivate::BufferAfter; + d->bufferMode = d->isRightToLeft() + ? QDeclarativeListViewPrivate::BufferBefore : QDeclarativeListViewPrivate::BufferAfter; } } d->inFlickCorrection = false; @@ -2450,11 +2590,28 @@ qreal QDeclarativeListView::minXExtent() const return QDeclarativeFlickable::minXExtent(); if (d->minExtentDirty) { d->minExtent = -d->startPosition(); - if (d->header) - d->minExtent += d->header->size(); + + qreal highlightStart; + qreal highlightEnd; + qreal endPositionFirstItem; + if (d->isRightToLeft()) { + endPositionFirstItem = d->positionAt(d->model->count()-1); + highlightStart = d->highlightRangeStartValid + ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem) + : d->size() - (d->lastPosition()-endPositionFirstItem); + highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size(); + if (d->footer) + d->minExtent += d->footer->size(); + } else { + endPositionFirstItem = d->endPositionAt(0); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + if (d->header) + d->minExtent += d->header->size(); + } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->minExtent += d->highlightRangeStart; - d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd + 1)); + d->minExtent += highlightStart; + d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd + 1)); } d->minExtentDirty = false; } @@ -2468,23 +2625,42 @@ qreal QDeclarativeListView::maxXExtent() const if (d->orient == QDeclarativeListView::Vertical) return width(); if (d->maxExtentDirty) { + qreal highlightStart; + qreal highlightEnd; + qreal lastItemPosition; + if (d->isRightToLeft()) { + highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size(); + highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size(); + lastItemPosition = d->endPosition(); + } else { + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + lastItemPosition = d->positionAt(d->model->count()-1); + } if (!d->model || !d->model->count()) { d->maxExtent = 0; } 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 + 1)); + d->maxExtent = -(lastItemPosition - highlightStart); + if (highlightEnd != highlightStart) { + d->maxExtent = d->isRightToLeft() + ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd + 1)) + : qMin(d->maxExtent, -(d->endPosition() - highlightEnd + 1)); + } } else { d->maxExtent = -(d->endPosition() - width() + 1); } - if (d->footer) - d->maxExtent -= d->footer->size(); + if (d->isRightToLeft()) { + if (d->header) + d->maxExtent -= d->header->size(); + } else { + if (d->footer) + d->maxExtent -= d->footer->size(); + } qreal minX = minXExtent(); if (d->maxExtent > minX) d->maxExtent = minX; d->maxExtentDirty = false; } - return d->maxExtent; } @@ -2496,7 +2672,8 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event) return; if (d->model && d->model->count() && d->interactive) { - if ((d->orient == QDeclarativeListView::Horizontal && event->key() == Qt::Key_Left) + if ((d->orient == QDeclarativeListView::Horizontal && d->layoutDirection == Qt::LeftToRight && event->key() == Qt::Key_Left) + || (d->orient == QDeclarativeListView::Horizontal && d->layoutDirection == Qt::RightToLeft && event->key() == Qt::Key_Right) || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Up)) { if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) { decrementCurrentIndex(); @@ -2506,7 +2683,8 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event) event->accept(); return; } - } else if ((d->orient == QDeclarativeListView::Horizontal && event->key() == Qt::Key_Right) + } else if ((d->orient == QDeclarativeListView::Horizontal && d->layoutDirection == Qt::LeftToRight && event->key() == Qt::Key_Right) + || (d->orient == QDeclarativeListView::Horizontal && d->layoutDirection == Qt::RightToLeft && event->key() == Qt::Key_Left) || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Down)) { if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) { incrementCurrentIndex(); @@ -2583,9 +2761,14 @@ void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode) if (layoutScheduled) layout(); - qreal pos = position(); + qreal pos = isRightToLeft() ? -position() - size() : position(); FxListItem *item = visibleItem(idx); - qreal maxExtent = orient == QDeclarativeListView::Vertical ? -q->maxYExtent() : -q->maxXExtent(); + qreal maxExtent; + if (orient == QDeclarativeListView::Vertical) + maxExtent = -q->maxYExtent(); + else + maxExtent = isRightToLeft() ? q->minXExtent()-size(): -q->maxXExtent(); + if (!item) { int itemPos = positionAt(idx); // save the currently visible items in case any of them end up visible again @@ -2628,7 +2811,12 @@ void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode) pos = itemPos; } pos = qMin(pos, maxExtent); - qreal minExtent = orient == QDeclarativeListView::Vertical ? -q->minYExtent() : -q->minXExtent(); + qreal minExtent; + if (orient == QDeclarativeListView::Vertical) { + minExtent = -q->minYExtent(); + } else { + minExtent = isRightToLeft() ? q->maxXExtent()-size(): -q->minXExtent(); + } pos = qMax(pos, minExtent); moveReason = QDeclarativeListViewPrivate::Other; q->cancelFlick(); @@ -2783,7 +2971,10 @@ void QDeclarativeListView::updateSections() void QDeclarativeListView::refill() { Q_D(QDeclarativeListView); - d->refill(d->position(), d->position()+d->size()-1); + if (layoutDirection() == Qt::RightToLeft && orientation() == QDeclarativeListView::Horizontal) + d->refill(-d->position()-d->size()+1, -d->position()); + else + d->refill(d->position(), d->position()+d->size()-1); } void QDeclarativeListView::trackedPositionChanged() @@ -2798,26 +2989,37 @@ void QDeclarativeListView::trackedPositionChanged() trackedPos -= d->currentItem->sectionSize(); trackedSize += d->currentItem->sectionSize(); } - const qreal viewPos = d->position(); + qreal viewPos; + qreal highlightStart; + qreal highlightEnd; + if (d->isRightToLeft()) { + viewPos = -d->position()-d->size(); + highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; + highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; + } else { + viewPos = d->position(); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + } qreal pos = viewPos; if (d->haveHighlightRange) { if (d->highlightRange == StrictlyEnforceRange) { - if (trackedPos > pos + d->highlightRangeEnd - d->trackedItem->size()) - pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size(); - if (trackedPos < pos + d->highlightRangeStart) - pos = trackedPos - d->highlightRangeStart; + if (trackedPos > pos + highlightEnd - d->trackedItem->size()) + pos = trackedPos - highlightEnd + d->trackedItem->size(); + if (trackedPos < pos + highlightStart) + pos = trackedPos - highlightStart; } else { - if (trackedPos < d->startPosition() + d->highlightRangeStart) { + if (trackedPos < d->startPosition() + highlightStart) { pos = d->startPosition(); - } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) { + } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + highlightEnd) { pos = d->endPosition() - d->size() + 1; if (pos < d->startPosition()) pos = d->startPosition(); } else { - if (trackedPos < viewPos + d->highlightRangeStart) { - pos = trackedPos - d->highlightRangeStart; - } else if (trackedPos > viewPos + d->highlightRangeEnd - trackedSize) { - pos = trackedPos - d->highlightRangeEnd + trackedSize; + if (trackedPos < viewPos + highlightStart) { + pos = trackedPos - highlightStart; + } else if (trackedPos > viewPos + highlightEnd - trackedSize) { + pos = trackedPos - highlightEnd + trackedSize; } } } @@ -2854,6 +3056,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) d->updateUnrequestedIndexes(); d->moveReason = QDeclarativeListViewPrivate::Other; + qreal tempPos = d->isRightToLeft() ? -d->position()-d->size() : d->position(); int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0; if (index < 0) { int i = d->visibleItems.count() - 1; @@ -2863,7 +3066,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) // there are no visible items except items marked for removal index = d->visibleItems.count(); } else if (d->visibleItems.at(i)->index + 1 == modelIndex - && d->visibleItems.at(i)->endPosition() < d->buffer+d->position()+d->size()-1) { + && d->visibleItems.at(i)->endPosition() < d->buffer+tempPos+d->size()-1) { // Special case of appending an item to the model. index = d->visibleItems.count(); } else { @@ -2908,7 +3111,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) // Insert items before the visible item. int insertionIdx = index; int i = 0; - int from = d->position() - d->buffer; + int from = tempPos - d->buffer; for (i = count-1; i >= 0 && pos > from; --i) { if (!addedVisible) { d->scheduleLayout(); @@ -2938,7 +3141,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) } } else { int i = 0; - int to = d->buffer+d->position()+d->size()-1; + int to = d->buffer+tempPos+d->size()-1; for (i = 0; i < count && pos <= to; ++i) { if (!addedVisible) { d->scheduleLayout(); @@ -3233,10 +3436,14 @@ void QDeclarativeListView::createdItem(int index, QDeclarativeItem *item) if (d->requestedIndex != index) { item->setParentItem(contentItem()); d->unrequestedItems.insert(item, index); - if (d->orient == QDeclarativeListView::Vertical) + if (d->orient == QDeclarativeListView::Vertical) { item->setY(d->positionAt(index)); - else - item->setX(d->positionAt(index)); + } else { + if (d->isRightToLeft()) + item->setX(-d->positionAt(index)-item->width()); + else + item->setX(d->positionAt(index)); + } } } |