on xenial help sign in
Rework how we set the ranges so we get some more asynchronousity from item views Fixes: #1384374

Approved by: Andrea Cimitan

commit05c7dcab0e2fd1b44054828e9d119d2cbb1e7fab authorAlbert Astals <albert.astals@canonical.com> dateMon 15 Dec 2014, 22:41 (12 years ago) parent0267639006ecdb
16 files changed+102−35
plugins/Dash/abstractdashview.cpp+24−5 plugins/Dash/abstractdashview.h+6 plugins/Dash/listviewwithpageheader.cpp+7−2 plugins/Dash/listviewwithpageheader.h+4−4 qml/Components/ResponsiveVerticalJournal.qml+1 qml/Dash/CardGrid.qml+1−2 qml/Dash/CardVerticalJournal.qml+1 qml/Dash/DashContent.qml+2 qml/Dash/DashRenderer.qml+2 qml/Dash/GenericScopeView.qml+45−19 qml/Dash/ScopeListView.qml+4−2 tests/plugins/Dash/horizontaljournaltest.qml+1 tests/plugins/Dash/listviewwithpageheadertest.cpp+1−1 tests/plugins/Dash/organicgridtest.qml+1 tests/plugins/Dash/verticaljournaltest.qml+1 tests/qmltests/Dash/tst_GenericScopeView.qml+1
plugins/Dash/abstractdashview.cpp+24−5
@@ -16,13 +16,12 @@
1616
1717#include "abstractdashview.h"
1818
19−static const qreal bufferRatio = 0.5;
20−
2119AbstractDashView::AbstractDashView()
2220 : m_delegateModel(nullptr)
2321 , m_asyncRequestedIndex(-1)
2422 , m_columnSpacing(0)
2523 , m_rowSpacing(0)
24+ , m_buffer(320) // Same value used in qquickitemview.cpp in Qt 5.4
2625 , m_displayMarginBeginning(0)
2726 , m_displayMarginEnd(0)
2827 , m_needsRelayout(false)
@@ -112,6 +111,27 @@ void AbstractDashView::setRowSpacing(qreal rowSpacing)
112111 }
113112}
114113
114+int AbstractDashView::cacheBuffer() const
115+{
116+ return m_buffer;
117+}
118+
119+void AbstractDashView::setCacheBuffer(int buffer)
120+{
121+ if (buffer < 0) {
122+ qmlInfo(this) << "Cannot set a negative cache buffer";
123+ return;
124+ }
125+
126+ if (m_buffer != buffer) {
127+ m_buffer = buffer;
128+ if (isComponentComplete()) {
129+ polish();
130+ }
131+ emit cacheBufferChanged();
132+ }
133+}
134+
115135qreal AbstractDashView::displayMarginBeginning() const
116136{
117137 return m_displayMarginBeginning;
@@ -160,9 +180,8 @@ void AbstractDashView::refill()
160180
161181 const qreal from = -m_displayMarginBeginning;
162182 const qreal to = height() + m_displayMarginEnd;
163− const qreal buffer = (to - from) * bufferRatio;
164− const qreal bufferFrom = from - buffer;
165− const qreal bufferTo = to + buffer;
183+ const qreal bufferFrom = from - m_buffer;
184+ const qreal bufferTo = to + m_buffer;
166185
167186 bool added = addVisibleItems(from, to, false);
168187 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
plugins/Dash/abstractdashview.h+6
@@ -35,6 +35,7 @@ class AbstractDashView : public QQuickItem
3535 Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
3636 Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
3737 Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
38+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
3839 Q_PROPERTY(qreal displayMarginBeginning READ displayMarginBeginning
3940 WRITE setDisplayMarginBeginning
4041 NOTIFY displayMarginBeginningChanged)
@@ -61,6 +62,9 @@ public:
6162 qreal rowSpacing() const;
6263 void setRowSpacing(qreal rowSpacing);
6364
65+ int cacheBuffer() const;
66+ void setCacheBuffer(int);
67+
6468 qreal displayMarginBeginning() const;
6569 void setDisplayMarginBeginning(qreal);
6670
@@ -72,6 +76,7 @@ Q_SIGNALS:
7276 void delegateChanged();
7377 void columnSpacingChanged();
7478 void rowSpacingChanged();
79+ void cacheBufferChanged();
7580 void displayMarginBeginningChanged();
7681 void displayMarginEndChanged();
7782
@@ -117,6 +122,7 @@ private:
117122
118123 int m_columnSpacing;
119124 int m_rowSpacing;
125+ int m_buffer;
120126 qreal m_displayMarginBeginning;
121127 qreal m_displayMarginEnd;
122128 bool m_needsRelayout;
plugins/Dash/listviewwithpageheader.cpp+7−2
@@ -334,13 +334,18 @@ qreal ListViewWithPageHeader::headerItemShownHeight() const
334334 return m_headerItemShownHeight;
335335}
336336
337−qreal ListViewWithPageHeader::cacheBuffer() const
337+int ListViewWithPageHeader::cacheBuffer() const
338338{
339339 return m_cacheBuffer;
340340}
341341
342−void ListViewWithPageHeader::setCacheBuffer(qreal cacheBuffer)
342+void ListViewWithPageHeader::setCacheBuffer(int cacheBuffer)
343343{
344+ if (cacheBuffer < 0) {
345+ qmlInfo(this) << "Cannot set a negative cache buffer";
346+ return;
347+ }
348+
344349 if (cacheBuffer != m_cacheBuffer) {
345350 m_cacheBuffer = cacheBuffer;
346351 Q_EMIT cacheBufferChanged();
plugins/Dash/listviewwithpageheader.h+4−4
@@ -54,7 +54,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
5454 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
5555 Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
5656 Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
57− Q_PROPERTY(qreal cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
57+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
5858
5959 friend class ListViewWithPageHeaderTest;
6060 friend class ListViewWithPageHeaderTestSection;
@@ -85,8 +85,8 @@ public:
8585 int stickyHeaderHeight() const;
8686 qreal headerItemShownHeight() const;
8787
88− qreal cacheBuffer() const;
89− void setCacheBuffer(qreal cacheBuffer);
88+ int cacheBuffer() const;
89+ void setCacheBuffer(int cacheBuffer);
9090
9191 Q_INVOKABLE void positionAtBeginning();
9292 Q_INVOKABLE void showHeader();
@@ -204,7 +204,7 @@ private:
204204 bool m_forceNoClip;
205205 bool m_inLayout;
206206 bool m_inContentHeightKeepHeaderShown;
207− qreal m_cacheBuffer;
207+ int m_cacheBuffer;
208208
209209 // Qt 5.0 doesn't like releasing the items just after itemCreated
210210 // so we delay the releasing until the next updatePolish
qml/Components/ResponsiveVerticalJournal.qml+1
@@ -45,6 +45,7 @@ Item {
4545 property alias rowSpacing: verticalJournalView.rowSpacing
4646 property alias model: verticalJournalView.model
4747 property alias delegate: verticalJournalView.delegate
48+ property alias cacheBuffer: verticalJournalView.cacheBuffer
4849 property alias displayMarginBeginning: verticalJournalView.displayMarginBeginning
4950 property alias displayMarginEnd: verticalJournalView.displayMarginEnd
5051
qml/Dash/CardGrid.qml+1−2
@@ -50,7 +50,7 @@ DashRenderer {
5050 model: root.model
5151 displayMarginBeginning: root.displayMarginBeginning
5252 displayMarginEnd: root.displayMarginEnd
53− cacheBuffer: 0
53+ cacheBuffer: root.cacheBuffer
5454 interactive: false
5555 delegate: Item {
5656 width: grid.cellWidth
@@ -59,7 +59,6 @@ DashRenderer {
5959 id: loader
6060 sourceComponent: cardTool.cardComponent
6161 anchors.horizontalCenter: parent.horizontalCenter
62− asynchronous: true
6362 onLoaded: {
6463 item.objectName = "delegate" + index;
6564 item.width = Qt.binding(function() { return cardTool.cardWidth; });
qml/Dash/CardVerticalJournal.qml+1
@@ -59,6 +59,7 @@ DashRenderer {
5959 rowSpacing: minimumColumnSpacing
6060 columnWidth: cardTool.cardWidth
6161
62+ cacheBuffer: root.cacheBuffer
6263 displayMarginBeginning: root.displayMarginBeginning
6364 displayMarginEnd: root.displayMarginEnd
6465
qml/Dash/DashContent.qml+2
@@ -163,6 +163,7 @@ Item {
163163
164164 delegate:
165165 Loader {
166+ id: loader
166167 width: ListView.view.width
167168 height: ListView.view.height
168169 opacity: { // hide delegate if offscreen
@@ -191,6 +192,7 @@ Item {
191192 dashContent.scopeLoaded(item.scope.id)
192193 item.paginationCount = Qt.binding(function() { return dashContentList.count } )
193194 item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
195+ item.visibleToParent = Qt.binding(function() { return loader.opacity != 0 });
194196 item.holdingList = dashContentList;
195197 item.forceNonInteractive = Qt.binding(function() { return dashContent.forceNonInteractive } )
196198 }
qml/Dash/DashRenderer.qml+2
@@ -23,6 +23,8 @@ Item {
2323
2424 property int collapsedItemCount: -1
2525
26+ property int cacheBuffer: 0
27+
2628 property int displayMarginBeginning: 0
2729
2830 property int displayMarginEnd: 0
qml/Dash/GenericScopeView.qml+45−19
@@ -38,6 +38,7 @@ FocusScope {
3838 readonly property alias subPageShown: subPageLoader.subPageShown
3939 property int paginationCount: 0
4040 property int paginationIndex: 0
41+ property bool visibleToParent: false
4142 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
4243 property var holdingList: null
4344
@@ -357,6 +358,7 @@ FocusScope {
357358 Connections {
358359 target: scopeView
359360 onIsCurrentChanged: rendererLoader.updateRanges();
361+ onVisibleToParentChanged: rendererLoader.updateRanges();
360362 }
361363 Connections {
362364 target: holdingList
@@ -364,7 +366,9 @@ FocusScope {
364366 }
365367
366368 function updateRanges() {
367− if (holdingList && holdingList.moving) {
369+ // Don't want to create stress by requesting more items during scope
370+ // changes so unless you're not part of the visible scopes just return
371+ if (holdingList && holdingList.moving && !scopeView.visibleToParent) {
368372 return;
369373 }
370374
@@ -380,28 +384,50 @@ FocusScope {
380384 }
381385
382386 if (item && item.hasOwnProperty("displayMarginBeginning")) {
383− // A item view is considered visible from
387+ // A item view creates its delegates synchronously from
384388 // -displayMarginBeginning
385389 // to
386− // height + item.displayMarginEnd
390+ // height + displayMarginEnd
391+ // Around that area it adds the cacheBuffer area where delegates are created async
392+ //
387393 // We adjust displayMarginBeginning and displayMarginEnd so
388− // * In non visible scopes only the viewport is considered visible
389− // that way when you switch to it the visible items are there
390− // * For visible scopes we increase the visible range by categoryView.height * 1.5
391− // in both directions to make scrolling nicer by mantaining a higher number of
394+ // * In non visible scopes nothing is considered visible and we set cacheBuffer
395+ // so that creates the items that would be in the viewport asynchronously
396+ // * For the current scope set the visible range to the viewport and then
397+ // use cacheBuffer to create extra items for categoryView.height * 1.5
398+ // to make scrolling nicer by mantaining a higher number of
392399 // cached items
393− // TODO Improvements
394− // - For non visible scopes we should always have a visible range of 0 and
395− // make sure the items in the viewport are created with the cache buffer feature
396− // - For visible scopes we should always the have a visible range be exactly the
397− // viewport and make sure the rest of items are created with the cache buffer feature
398− // To be able to implement that feature VerticalJournal/AbstractDashView needs to
399− // make the cache buffer value setable externally
400− var extraMargins = scopeView.isCurrent ? categoryView.height * 1.5 : 0;
401−
402− item.displayMarginBeginning = Math.round(-Math.max(-baseItem.y - extraMargins, 0));
403− item.displayMarginEnd = -Math.round(Math.max(baseItem.height - extraMargins - seeAll.height -
404− categoryView.height + baseItem.y, 0));
400+ // * For non current but visible scopes (i.e. when the user changes from one scope
401+ // to the next, we set the visible range to the viewport so
402+ // items are not culled (invisible) but still use no cacheBuffer
403+ // (it will be set once the scope is the current one)
404+ var displayMarginBeginning = baseItem.y;
405+ displayMarginBeginning = -Math.max(-displayMarginBeginning, 0);
406+ displayMarginBeginning = -Math.min(-displayMarginBeginning, baseItem.height);
407+ displayMarginBeginning = Math.round(displayMarginBeginning);
408+ var displayMarginEnd = -baseItem.height + seeAll.height + categoryView.height - baseItem.y;
409+ displayMarginEnd = -Math.max(-displayMarginEnd, 0);
410+ displayMarginEnd = -Math.min(-displayMarginEnd, baseItem.height);
411+ displayMarginEnd = Math.round(displayMarginEnd);
412+ if (scopeView.isCurrent || scopeView.visibleToParent) {
413+ item.displayMarginBeginning = displayMarginBeginning;
414+ item.displayMarginEnd = displayMarginEnd;
415+ item.cacheBuffer = scopeView.isCurrent ? categoryView.height * 1.5 : 0;
416+ } else {
417+ var visibleRange = baseItem.height + displayMarginEnd + displayMarginBeginning;
418+ if (visibleRange < 0) {
419+ item.displayMarginBeginning = displayMarginBeginning;
420+ item.displayMarginEnd = displayMarginEnd;
421+ item.cacheBuffer = 0;
422+ } else {
423+ // This should be visibleRange/2 in each of the properties
424+ // but some item views still (like GridView) like creating sync delegates even if
425+ // the visible range is 0 so let's make sure the visible range is negative
426+ item.displayMarginBeginning = displayMarginBeginning - visibleRange;
427+ item.displayMarginEnd = displayMarginEnd - visibleRange;
428+ item.cacheBuffer = visibleRange;
429+ }
430+ }
405431 }
406432 }
407433 }
qml/Dash/ScopeListView.qml+4−2
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2014 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -20,5 +20,7 @@ import Dash 0.1
2020ListViewWithPageHeader {
2121 maximumFlickVelocity: height * 10
2222 flickDeceleration: height * 2
23− cacheBuffer: Number.MAX_VALUE
23+ // 1073741823 is s^30 -1. A quite big number so that you have "infinite" cache, but not so
24+ // big so that if you add if with itself you're outside the 2^31 int range
25+ cacheBuffer: 1073741823
2426}
tests/plugins/Dash/horizontaljournaltest.qml+1
@@ -25,6 +25,7 @@ Item {
2525 rowHeight: 150
2626 columnSpacing: 10
2727 rowSpacing: 10
28+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
2829
2930 delegate: Rectangle {
3031 property real randomValue: Math.random()
tests/plugins/Dash/listviewwithpageheadertest.cpp+1−1
@@ -1920,7 +1920,7 @@ private Q_SLOTS:
19201920
19211921 void testAllCacheBuffer()
19221922 {
1923− lvwph->setCacheBuffer(std::numeric_limits<qreal>::max());
1923+ lvwph->setCacheBuffer(std::numeric_limits<int>::max());
19241924 QTRY_COMPARE(lvwph->m_visibleItems.count(), 6);
19251925 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
19261926 verifyItem(0, 50., 150., false);
tests/plugins/Dash/organicgridtest.qml+1
@@ -27,6 +27,7 @@ Item {
2727 rowSpacing: 10
2828 smallDelegateSize: Qt.size(90, 90)
2929 bigDelegateSize: Qt.size(180, 180)
30+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
3031
3132 delegate: Rectangle {
3233 property real randomValue: Math.random()
tests/plugins/Dash/verticaljournaltest.qml+1
@@ -26,6 +26,7 @@ Item {
2626 columnWidth: 150
2727 columnSpacing: 10
2828 rowSpacing: 10
29+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
2930
3031 delegate: Rectangle {
3132 property real randomValue: Math.random()
tests/qmltests/Dash/tst_GenericScopeView.qml+1
@@ -59,6 +59,7 @@ Item {
5959 GenericScopeView {
6060 id: genericScopeView
6161 anchors.fill: parent
62+ visibleToParent: true
6263
6364 UT.UnityTestCase {
6465 id: testCase