From 35cad893a9e92cf36794610a6a718f56b64f9018 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 15 Sep 2009 09:06:12 +1000 Subject: ListView currentItemMode API replaced with highlight range API. --- examples/declarative/focusscope/test3.qml | 4 +- examples/declarative/listview/itemlist.qml | 4 +- examples/declarative/listview/listview.qml | 43 +++--- examples/declarative/xmldata/yahoonews.qml | 1 - src/declarative/QmlChanges.txt | 4 + src/declarative/fx/qfxlistview.cpp | 219 +++++++++++++++-------------- src/declarative/fx/qfxlistview.h | 21 ++- 7 files changed, 156 insertions(+), 140 deletions(-) diff --git a/examples/declarative/focusscope/test3.qml b/examples/declarative/focusscope/test3.qml index 51fa35a..8a53c3a 100644 --- a/examples/declarative/focusscope/test3.qml +++ b/examples/declarative/focusscope/test3.qml @@ -39,7 +39,9 @@ Rectangle { focus: true model: Model delegate: VerticalDelegate - currentItemPositioning: "SnapAuto" + preferredHighlightBegin: 100 + preferredHighlightEnd: 101 + strictlyEnforceHighlightRange: true } diff --git a/examples/declarative/listview/itemlist.qml b/examples/declarative/listview/itemlist.qml index 061fab3..01781ec 100644 --- a/examples/declarative/listview/itemlist.qml +++ b/examples/declarative/listview/itemlist.qml @@ -29,7 +29,9 @@ Rectangle { anchors.fill: parent anchors.bottomMargin: 30 model: ItemModel - currentItemPositioning: "SnapAuto" + preferredHighlightBegin: 0 + preferredHighlightEnd: 1 + strictlyEnforceHighlightRange: true orientation: "Horizontal" } diff --git a/examples/declarative/listview/listview.qml b/examples/declarative/listview/listview.qml index 1cca5ad..ac1cef1 100644 --- a/examples/declarative/listview/listview.qml +++ b/examples/declarative/listview/listview.qml @@ -29,21 +29,24 @@ Rectangle { Rectangle { color: "#FFFF88" } } - // Show the model in three lists, with different currentItemPositioning. - // currentItemPositioning determines how the list behaves when the - // current item changes. Note that the second and third ListView + // Show the model in three lists, with different highlight ranges. + // preferredHighlightBegin and preferredHighlightEnd set the + // range in which to attempt to maintain the highlight. + // Note that the second and third ListView // set their currentIndex to be the same as the first, and that // the first ListView is given keyboard focus. - // The default mode, Free, allows the currentItem to move freely + // The default mode allows the currentItem to move freely // within the visible area. If it would move outside the visible // area, the view is scrolled to keep it visible. - // Snap currentItemPositioning attempts to keep the current item - // aligned with the snapPosition by scrolling the view, however the - // items will not scroll beyond the beginning or end of the view. - // SnapAuto currentItemPositioning always keeps the current item on - // the snapPosition by scrolling the view. It also automatically - // sets the current item as is scrolled with the mouse. Note - // that the first ListView sets its currentIndex to be equal to + // The second list sets a highlight range which attempts to keep the + // current item within the the bounds of the range, however + // items will not scroll beyond the beginning or end of the view, + // forcing the highlight to move outside the range at the ends. + // The third list sets strictlyEnforceHighlightRange to true + // and sets a range smaller than the height of an item. This + // forces the current item to change when the view is flicked, + // since the highlight is unable to move. + // Note that the first ListView sets its currentIndex to be equal to // the third ListView's currentIndex. By flicking List3 with // the mouse, the current index of List1 will be changed. ListView { @@ -57,23 +60,17 @@ Rectangle { id: List2 x: 200; width: 200; height: parent.height model: MyPetsModel; delegate: PetDelegate; highlight: PetHighlight - currentItemPositioning: "Snap"; snapPosition: 125 + preferredHighlightBegin: 80 + preferredHighlightEnd: 220 currentIndex: List1.currentIndex } ListView { id: List3 x: 400; width: 200; height: parent.height - model: MyPetsModel; delegate: PetDelegate - currentItemPositioning: "SnapAuto"; snapPosition: 125 + model: MyPetsModel; delegate: PetDelegate; highlight: PetHighlight currentIndex: List1.currentIndex - - // Position a static highlight rather than a normal highlight so that - // when the view is flicked, the highlight does not move. - // By positioning the highlight at the same position as the snapPosition - // the item under the highlight will always be the current item. - Rectangle { - y: 125; width: 200; height: 50 - color: "#FFFF88"; z: -1 - } + preferredHighlightBegin: 125 + preferredHighlightEnd: 126 + strictlyEnforceHighlightRange: true } } diff --git a/examples/declarative/xmldata/yahoonews.qml b/examples/declarative/xmldata/yahoonews.qml index 6395284..7ebc2b2 100644 --- a/examples/declarative/xmldata/yahoonews.qml +++ b/examples/declarative/xmldata/yahoonews.qml @@ -101,6 +101,5 @@ Rectangle { clip: true model: feedModel delegate: feedDelegate - currentItemPositioning: "Snap" } } diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt index fe923a7..4afffd5 100644 --- a/src/declarative/QmlChanges.txt +++ b/src/declarative/QmlChanges.txt @@ -76,6 +76,8 @@ WebView: add newWindowComponent and newWindowParent properties Loader: add status() and progress() properties Loader: add sourceComponent property Loader: add resizeMode property +ListView: preferredHighlightBegin, preferredHighlightEnd +ListView: strictlyEnforceHighlightRange Deletions: Column/VerticalPositioner: lost "margins" property @@ -84,6 +86,8 @@ Grid/Positioner/Layout: lost "margins" property WebView: lost "interactive" property (always true now) Flickable: removed "dragMode" property ComponentInstance: removed. Replaced by Loader.sourceComponent +ListView: removed currentItemMode. Replaced by highligh range. +ListView: removed snapPos. Other Changes: Drag: axis becomes an enum with values "XAxis", "YAxis", "XandYAxis" diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index ac9b6ca..cd47448 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -173,9 +173,11 @@ public: : model(0), currentItem(0), tmpCurrent(0), orient(Qt::Vertical) , visiblePos(0), visibleIndex(0) , averageSize(100.0), currentIndex(-1), requestedIndex(-1) - , currItemMode(QFxListView::Free), snapPos(0), highlightComponent(0), highlight(0), trackedItem(0) + , highlightRangeStart(0), highlightRangeEnd(0) + , highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0), spacing(0.0) , ownModel(false), wrap(false), autoHighlight(true) + , haveHighlightRange(false), strictHighlightRange(false) {} void init(); @@ -272,13 +274,16 @@ public: } int snapIndex() { - qreal pos = position(); + int index = currentIndex; for (int i = 0; i < visibleItems.count(); ++i) { - qreal itemTop = visibleItems[i]->position() - pos; - if (itemTop >= snapPos-averageSize/2 && itemTop < snapPos+averageSize/2) - return visibleItems[i]->index; + FxListItem *item = visibleItems[i]; + if (item->index == -1) + continue; + qreal itemTop = item->position(); + if (itemTop >= highlight->position()-item->size()/2 && itemTop < highlight->position()+item->size()/2) + return item->index; } - return -1; + return index; } int lastVisibleIndex() const { @@ -372,8 +377,8 @@ public: qreal averageSize; int currentIndex; int requestedIndex; - QFxListView::CurrentItemPositioning currItemMode; - int snapPos; + qreal highlightRangeStart; + qreal highlightRangeEnd; QmlComponent *highlightComponent; FxListItem *highlight; FxListItem *trackedItem; @@ -389,6 +394,8 @@ public: bool ownModel : 1; bool wrap : 1; bool autoHighlight : 1; + bool haveHighlightRange : 1; + bool strictHighlightRange : 1; }; void QFxListViewPrivate::init() @@ -681,7 +688,7 @@ void QFxListViewPrivate::updateHighlight() if ((!currentItem && highlight) || (currentItem && !highlight)) createHighlight(); updateTrackedItem(); - if (currentItem && autoHighlight && highlight) { + if (currentItem && autoHighlight && highlight && !pressed && moveReason != QFxListViewPrivate::Mouse) { // auto-update highlight highlightPosAnimator->setSourceValue(currentItem->position()); highlightSizeAnimator->setSourceValue(currentItem->size()); @@ -794,54 +801,30 @@ void QFxListViewPrivate::fixupPosition() void QFxListViewPrivate::fixupY() { - Q_Q(QFxListView); QFxFlickablePrivate::fixupY(); if (orient == Qt::Horizontal) return; - if (currItemMode == QFxListView::SnapAuto) { - if (currentItem) { + + if (haveHighlightRange && strictHighlightRange) { + if (currentItem && highlight && currentItem->position() != highlight->position()) { moveReason = Mouse; timeline.clear(); - timeline.move(_moveY, -(currentItem->position() - snapPos), QEasingCurve(QEasingCurve::InOutQuad), 200); - } - } else if (currItemMode == QFxListView::Snap) { - moveReason = Mouse; - int idx = snapIndex(); - if (FxListItem *snapItem = visibleItem(idx)) { - int pos = snapItem->position() - snapPos; - if (pos > -q->maxYExtent()) - pos = -q->maxYExtent(); - else if (pos < -q->minYExtent()) - pos = -q->minYExtent(); - timeline.clear(); - timeline.move(_moveY, -(pos), QEasingCurve(QEasingCurve::InOutQuad), 200); + timeline.move(_moveY, -(currentItem->position() - highlightRangeStart), QEasingCurve(QEasingCurve::InOutQuad), 200); } } } void QFxListViewPrivate::fixupX() { - Q_Q(QFxListView); QFxFlickablePrivate::fixupX(); if (orient == Qt::Vertical) return; - if (currItemMode == QFxListView::SnapAuto) { - if (currentItem) { + + if (haveHighlightRange && strictHighlightRange) { + if (currentItem && highlight && currentItem->position() != highlight->position()) { moveReason = Mouse; timeline.clear(); - timeline.move(_moveX, -(currentItem->position() - snapPos), QEasingCurve(QEasingCurve::InOutQuad), 200); - } - } else if (currItemMode == QFxListView::Snap) { - moveReason = Mouse; - int idx = snapIndex(); - if (FxListItem *snapItem = visibleItem(idx)) { - int pos = snapItem->position() - snapPos; - if (pos > -q->maxXExtent()) - pos = -q->maxXExtent(); - else if (pos < -q->minXExtent()) - pos = -q->minXExtent(); - timeline.clear(); - timeline.move(_moveX, -(pos), QEasingCurve(QEasingCurve::InOutQuad), 200); + timeline.move(_moveX, -(currentItem->position() - highlightRangeStart), QEasingCurve(QEasingCurve::InOutQuad), 200); } } } @@ -1067,7 +1050,7 @@ void QFxListView::setHighlight(QmlComponent *highlight) to follow the current item. If autoHighlight is false, the highlight will not be moved by the view, and must be implemented by the highlight. The following example creates a highlight with - its motion defined by the spring \l {Follow}: + its motion defined by the spring \l {SpringFollow}: \snippet doc/src/snippets/declarative/listview/highlight.qml 1 @@ -1091,55 +1074,58 @@ void QFxListView::setAutoHighlight(bool autoHighlight) } /*! - \qmlproperty enumeration ListView::currentItemPositioning - This property determines the current item positioning and selection characteristics. - - The modes supported are: - \list - \i Free - For Mouse, the current item may be positioned anywhere, - whether within the visible area, or outside. During Keyboard interaction, - the current item can move within the visible area, and the view will - scroll to keep the highlight visible. - \i Snap - For mouse, the current item may be positioned anywhere, - whether within the visible area, or outside. During keyboard interaction, - the current item will be kept in the visible area and will prefer to be - positioned at the \l snapPosition, however the view will never scroll - beyond the beginning or end of the view. - \i SnapAuto - For both mouse and keyboard, the current item will be - kept at the \l {snapPosition}. Additionally, if the view is dragged or - flicked, the current item will be automatically updated to be the item - currently at the snapPosition. - \endlist + \qmlproperty real preferredHighlightBegin + \qmlproperty real preferredHighlightEnd + \qmlproperty bool strictlyEnforceHighlightRange + + These properties set the preferred range of the highlight (current item) + within the view. + + If the strictlyEnforceHighlightRange property is false (default) + the highlight can move outside of the range at the ends of the list + or due to a mouse interaction. + + If strictlyEnforceHighlightRange is true then the highlight will never + move outside the range. This means that the current item will change + if a keyboard or mouse action would cause the highlight to move + outside of the range. */ -QFxListView::CurrentItemPositioning QFxListView::currentItemPositioning() const +qreal QFxListView::preferredHighlightBegin() const { Q_D(const QFxListView); - return d->currItemMode; + return d->highlightRangeStart; } -void QFxListView::setCurrentItemPositioning(CurrentItemPositioning mode) +void QFxListView::setPreferredHighlightBegin(qreal start) { Q_D(QFxListView); - d->currItemMode = mode; + d->highlightRangeStart = start; + d->haveHighlightRange = d->highlightRangeStart < d->highlightRangeEnd; } -/*! - \qmlproperty int ListView::snapPosition +qreal QFxListView::preferredHighlightEnd() const +{ + Q_D(const QFxListView); + return d->highlightRangeEnd; +} - When currentItemPositioning is set to Snap or SnapAuto, the - \c snapPosition determines where the top of the items will - snap to. -*/ -int QFxListView::snapPosition() const +void QFxListView::setPreferredHighlightEnd(qreal end) +{ + Q_D(QFxListView); + d->highlightRangeEnd = end; + d->haveHighlightRange = d->highlightRangeStart < d->highlightRangeEnd; +} + +bool QFxListView::strictlyEnforceHighlightRange() const { Q_D(const QFxListView); - return d->snapPos; + return d->strictHighlightRange; } -void QFxListView::setSnapPosition(int pos) +void QFxListView::setStrictlyEnforceHighlightRange(bool strict) { Q_D(QFxListView); - d->snapPos = pos; + d->strictHighlightRange = strict; } /*! @@ -1280,11 +1266,19 @@ void QFxListView::viewportMoved() refill(); if (isFlicking() || d->pressed) d->moveReason = QFxListViewPrivate::Mouse; - if (d->currItemMode == SnapAuto && d->moveReason == QFxListViewPrivate::Mouse) { - // Update current index - int idx = d->snapIndex(); - if (idx >= 0 && idx != d->currentIndex) - d->updateCurrent(idx); + if (d->moveReason == QFxListViewPrivate::Mouse) { + if (d->haveHighlightRange && d->strictHighlightRange && d->highlight) { + int idx = d->snapIndex(); + if (idx >= 0 && idx != d->currentIndex) + d->updateCurrent(idx); + + qreal pos = d->currentItem->position(); + if (pos > d->position() + d->highlightRangeEnd - d->highlight->size()) + pos = d->position() + d->highlightRangeEnd - d->highlight->size(); + if (pos < d->position() + d->highlightRangeStart) + pos = d->position() + d->highlightRangeStart; + d->highlight->setPosition(pos); + } } } @@ -1294,8 +1288,8 @@ qreal QFxListView::minYExtent() const if (d->orient == Qt::Horizontal) return QFxFlickable::minYExtent(); qreal extent = -d->startPosition(); - if (d->currItemMode == SnapAuto) - extent += d->snapPos; + if (d->haveHighlightRange && d->strictHighlightRange) + extent += d->highlightRangeStart; return extent; } @@ -1306,8 +1300,8 @@ qreal QFxListView::maxYExtent() const if (d->orient == Qt::Horizontal) return QFxFlickable::maxYExtent(); qreal extent; - if (d->currItemMode == SnapAuto) - extent = -(d->positionAt(count()-1) - d->snapPos); + if (d->haveHighlightRange && d->strictHighlightRange) + extent = -(d->endPosition() - d->highlightRangeEnd); else extent = -(d->endPosition() - height()); qreal minY = minYExtent(); @@ -1322,8 +1316,8 @@ qreal QFxListView::minXExtent() const if (d->orient == Qt::Vertical) return QFxFlickable::minXExtent(); qreal extent = -d->startPosition(); - if (d->currItemMode == SnapAuto) - extent += d->snapPos; + if (d->haveHighlightRange && d->strictHighlightRange) + extent += d->highlightRangeStart; return extent; } @@ -1334,8 +1328,8 @@ qreal QFxListView::maxXExtent() const if (d->orient == Qt::Vertical) return QFxFlickable::maxXExtent(); qreal extent; - if (d->currItemMode == SnapAuto) - extent = -(d->positionAt(count()-1) - d->snapPos); + if (d->haveHighlightRange && d->strictHighlightRange) + extent = -(d->endPosition() - d->highlightRangeEnd); else extent = -(d->endPosition() - width()); qreal minX = minXExtent(); @@ -1350,7 +1344,7 @@ void QFxListView::keyPressEvent(QKeyEvent *event) if (d->model && d->model->count() && d->interactive) { if ((d->orient == Qt::Horizontal && event->key() == Qt::Key_Left) || (d->orient == Qt::Vertical && event->key() == Qt::Key_Up)) { - if (currentIndex() > 0 || d->wrap) { + if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) { d->moveReason = QFxListViewPrivate::Key; int index = currentIndex()-1; d->updateCurrent(index >= 0 ? index : d->model->count()-1); @@ -1359,7 +1353,7 @@ void QFxListView::keyPressEvent(QKeyEvent *event) } } else if ((d->orient == Qt::Horizontal && event->key() == Qt::Key_Right) || (d->orient == Qt::Vertical && event->key() == Qt::Key_Down)) { - if (currentIndex() < d->model->count() - 1 || d->wrap) { + if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) { d->moveReason = QFxListViewPrivate::Key; int index = currentIndex()+1; d->updateCurrent(index < d->model->count() ? index : 0); @@ -1395,30 +1389,41 @@ void QFxListView::trackedPositionChanged() if (!d->trackedItem) return; if (!isFlicking() && !d->pressed && d->moveReason != QFxListViewPrivate::Mouse) { - switch (d->currItemMode) { - case Free: - if (d->trackedItem->position() < d->position()) { - d->setPosition(d->trackedItem->position()); + const qreal trackedPos = d->trackedItem->position(); + if (d->haveHighlightRange) { + if (d->strictHighlightRange) { + qreal pos = d->position(); + if (trackedPos > pos + d->highlightRangeEnd - d->trackedItem->size()) + pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size(); + if (trackedPos < pos + d->highlightRangeStart) + pos = trackedPos - d->highlightRangeStart; + d->setPosition(pos); + } else { + qreal pos = d->position(); + if (trackedPos < d->startPosition() + d->highlightRangeStart) { + pos = d->startPosition(); + } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) { + pos = d->endPosition() - d->size(); + } else { + if (trackedPos < d->position() + d->highlightRangeStart) { + pos = trackedPos - d->highlightRangeStart; + } else if (trackedPos > d->position() + d->highlightRangeEnd - d->trackedItem->size()) { + pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size(); + } + } + d->setPosition(pos); + } + } else { + if (trackedPos < d->position()) { + d->setPosition(trackedPos); d->fixupPosition(); } else if (d->trackedItem->endPosition() > d->position() + d->size()) { qreal pos = d->trackedItem->endPosition() - d->size(); if (d->trackedItem->size() > d->size()) - pos = d->trackedItem->position(); + pos = trackedPos; d->setPosition(pos); d->fixupPosition(); } - break; - case Snap: - if (d->trackedItem->position() < d->startPosition() + d->snapPos) - d->setPosition(d->startPosition()); - else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->snapPos + d->trackedItem->size()) - d->setPosition(d->endPosition() - d->size()); - else - d->setPosition(d->trackedItem->position() - d->snapPos); - break; - case SnapAuto: - d->setPosition(d->trackedItem->position() - d->snapPos); - break; } } } diff --git a/src/declarative/fx/qfxlistview.h b/src/declarative/fx/qfxlistview.h index 095c27b..b122a8a 100644 --- a/src/declarative/fx/qfxlistview.h +++ b/src/declarative/fx/qfxlistview.h @@ -71,8 +71,11 @@ class Q_DECLARATIVE_EXPORT QFxListView : public QFxFlickable Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(QmlComponent *highlight READ highlight WRITE setHighlight) Q_PROPERTY(bool autoHighlight READ autoHighlight WRITE setAutoHighlight) //### highlightFollowsCurrentItem - Q_PROPERTY(CurrentItemPositioning currentItemPositioning READ currentItemPositioning WRITE setCurrentItemPositioning) //### mode - Q_PROPERTY(int snapPosition READ snapPosition WRITE setSnapPosition) + + Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin) + Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd) + Q_PROPERTY(bool strictlyEnforceHighlightRange READ strictlyEnforceHighlightRange WRITE setStrictlyEnforceHighlightRange) + Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) Q_PROPERTY(bool wrap READ isWrapEnabled WRITE setWrapEnabled) //### keyNavigationWraps, stops at end when held @@ -103,11 +106,6 @@ public: bool autoHighlight() const; void setAutoHighlight(bool); - //### QSpan preferredHighlightRange - //### bool strictlyEnforceHighlightRange - - //### don't jump around unnecessarily - //### fix highlight for snapAuto enum CurrentItemPositioning { Free, Snap, SnapAuto }; CurrentItemPositioning currentItemPositioning() const; void setCurrentItemPositioning(CurrentItemPositioning mode); @@ -115,6 +113,15 @@ public: int snapPosition() const; void setSnapPosition(int pos); + bool strictlyEnforceHighlightRange() const; + void setStrictlyEnforceHighlightRange(bool strict); + + qreal preferredHighlightBegin() const; + void setPreferredHighlightBegin(qreal); + + qreal preferredHighlightEnd() const; + void setPreferredHighlightEnd(qreal); + qreal spacing() const; void setSpacing(qreal spacing); -- cgit v0.12