Merge lp:~unity-team/unity/8.carousel-listview into lp:unity/8.0

Proposed by Michał Sawicz
Status: Merged
Approved by: Albert Astals Cid
Approved revision: no longer in the source branch.
Merged at revision: 9
Proposed branch: lp:~unity-team/unity/8.carousel-listview
Merge into: lp:unity/8.0
Diff against target: 603 lines (+244/-173)
3 files modified
Components/Carousel.qml (+159/-128)
Components/carousel.js (+47/-11)
tests/qmltests/Components/tst_Carousel.qml (+38/-34)
To merge this branch: bzr merge lp:~unity-team/unity/8.carousel-listview
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Albert Astals Cid (community) Approve
Andrea Cimitan Pending
Review via email: mp+167713@code.launchpad.net

This proposal supersedes a proposal from 2013-05-22.

Commit message

Bring back ListView'ed Carousel now that Qt is fixed.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Cimitan (cimi) wrote : Posted in a previous version of this proposal

Since we are here, shall we add some extra tests? (in case, push as unity-team so I can contribute)

Revision history for this message
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal

> Since we are here, shall we add some extra tests? (in case, push as unity-team so I can contribute)

Done. Test away :)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Exactly the same code i have in the branch i had for testing the listview-carousel crashes

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Components/Carousel.qml'
--- Components/Carousel.qml 2013-06-05 22:03:08 +0000
+++ Components/Carousel.qml 2013-06-06 08:03:28 +0000
@@ -18,26 +18,50 @@
18import Ubuntu.Components 0.118import Ubuntu.Components 0.1
19import "carousel.js" as CarouselJS19import "carousel.js" as CarouselJS
2020
21/*! The Carousel component presents the items of a model in a carousel view. It's similar to a
22 cover flow. But it stops at it's boundaries (therefore no PathView is used).
23 */
21Item {24Item {
22 id: carousel25 id: carousel
2326
27 /// The component to be used as delegate. This component has to be derived from BaseCarouselDelegate
24 property Component itemComponent28 property Component itemComponent
25 property var model29 /// Model for the Carousel, which has to be a model usable by a ListView
26 property alias minimumTileWidth: flickable.minimumTileWidth30 property alias model: listView.model
27 property alias pathItemCount: flickable.pathItemCount31 /// A minimal width of a tile can be set here. Per default a best fit will be calculated
28 property alias tileAspectRatio: flickable.tileAspectRatio32 property alias minimumTileWidth: listView.minimumTileWidth
29 property int cacheBuffer: 033 /// Sets the number of tiles that are visible
34 property alias pathItemCount: listView.pathItemCount
35 /// Aspect ratio of the tiles width/height
36 property alias tileAspectRatio: listView.tileAspectRatio
37 /// Used to cache some delegates for performance reasons. See the ListView documentation for details
38 property alias cacheBuffer: listView.cacheBuffer
39 /// Width of the "draw buffer" in pixel. The drawBuffer is an additional area at start/end where
40 /// items drawn, even if it is not in the visible area.
41 /// cacheBuffer controls only the to retain delegates outside the visible area (and is used on top of the drawBuffer)
42 /// see https://bugreports.qt-project.org/browse/QTBUG-29173
43 property int drawBuffer: width / pathItemCount // an "ok" value - but values used from the listView cause loops
44 /// The selected item can be shown in a different size controlled by selectedItemScaleFactor
30 property real selectedItemScaleFactor: 1.145 property real selectedItemScaleFactor: 1.1
3146
47 /// Emitted when the user clicked on an item
48 /// @param index is the index of the clicked item
49 /// @param delegateItem is the clicked component/delegate itself
50 /// @param itemY is y of the clicked delegate
32 signal clicked(int index, var delegateItem, real itemY)51 signal clicked(int index, var delegateItem, real itemY)
3352
34 implicitHeight: flickable.tileHeight * selectedItemScaleFactor53 implicitHeight: listView.tileHeight * selectedItemScaleFactor
3554
36 /* TODO: evaluate if the component could be more efficient with a ListView,55 /* Basic idea behind the carousel effect is to move the items of the delegates (compacting /stuffing them).
37 using this technique https://bugreports.qt-project.org/browse/QTBUG-29173 */56 One drawback is, that more delegates have to be drawn than usually. As some items are moved from the
3857 invisible to the visible area. Setting the cacheBuffer does not fix this.
39 Flickable {58 See https://bugreports.qt-project.org/browse/QTBUG-29173
40 id: flickable59 Therefore the ListView has negative left and right anchors margins, and in addition a header
60 and footer item to compensate that.
61
62 The scaling of the items is controlled by the variable continuousIndex, described below. */
63 ListView {
64 id: listView
4165
42 property real minimumTileWidth: 066 property real minimumTileWidth: 0
43 property real newContentX: -167 property real newContentX: -1
@@ -57,20 +81,27 @@
57 - 'gapToEndPhase' gap in pixels between middle and end phase81 - 'gapToEndPhase' gap in pixels between middle and end phase
58 - 'kGapEnd' constant used to calculate 'continuousIndex' in end phase82 - 'kGapEnd' constant used to calculate 'continuousIndex' in end phase
59 - 'kMiddleIndex' constant used to calculate 'continuousIndex' in middle phase83 - 'kMiddleIndex' constant used to calculate 'continuousIndex' in middle phase
60 - 'kXBeginningEnd' constant used to calculate 'continuousIndex' in beginning and end phase. */84 - 'kXBeginningEnd' constant used to calculate 'continuousIndex' in beginning and end phase
85 - 'realContentWidth' the width of all the delegates only (without header/footer)
86 - 'realContentX' the 'contentX' of the listview ignoring the 'drawBuffer'
87 - 'realWidth' the 'width' of the listview, as it is used as component. */
6188
62 readonly property real gapToMiddlePhase: Math.min(width / 2 - tileWidth / 2, (contentWidth - width) / 2)89 readonly property real gapToMiddlePhase: Math.min(realWidth / 2 - tileWidth / 2, (realContentWidth - realWidth) / 2)
63 readonly property real gapToEndPhase: contentWidth - width - gapToMiddlePhase90 readonly property real gapToEndPhase: realContentWidth - realWidth - gapToMiddlePhase
64 readonly property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)91 readonly property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
65 readonly property real kMiddleIndex: (width / 2) / tileWidth - 0.592 readonly property real kMiddleIndex: (realWidth / 2) / tileWidth - 0.5
66 readonly property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase93 readonly property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
67 readonly property real realPathItemCount: Math.min(width / tileWidth, pathItemCount)94 readonly property real maximumItemTranslation: (listView.tileWidth * 3) / listView.scaleFactor
68 readonly property real referenceGapToMiddlePhase: width / 2 - tileWidth / 295 readonly property real realContentWidth: contentWidth - 2 * carousel.drawBuffer
96 readonly property real realContentX: contentX + carousel.drawBuffer
97 readonly property real realPathItemCount: Math.min(realWidth / tileWidth, pathItemCount)
98 readonly property real realWidth: carousel.width
99 readonly property real referenceGapToMiddlePhase: realWidth / 2 - tileWidth / 2
69 readonly property real referencePathItemCount: referenceWidth / referenceTileWidth100 readonly property real referencePathItemCount: referenceWidth / referenceTileWidth
70 readonly property real referenceWidth: 848101 readonly property real referenceWidth: 848
71 readonly property real referenceTileWidth: 175102 readonly property real referenceTileWidth: 175
72 readonly property real scaleFactor: tileWidth / referenceTileWidth103 readonly property real scaleFactor: tileWidth / referenceTileWidth
73 readonly property real tileWidth: Math.max(width / pathItemCount, minimumTileWidth)104 readonly property real tileWidth: Math.max(realWidth / pathItemCount, minimumTileWidth)
74 readonly property real tileHeight: tileWidth / tileAspectRatio105 readonly property real tileHeight: tileWidth / tileAspectRatio
75 readonly property real translationXViewFactor: 0.2 * (referenceGapToMiddlePhase / gapToMiddlePhase)106 readonly property real translationXViewFactor: 0.2 * (referenceGapToMiddlePhase / gapToMiddlePhase)
76 readonly property real verticalMargin: (parent.height - tileHeight) / 2107 readonly property real verticalMargin: (parent.height - tileHeight) / 2
@@ -80,20 +111,36 @@
80 fill: parent111 fill: parent
81 topMargin: verticalMargin112 topMargin: verticalMargin
82 bottomMargin: verticalMargin113 bottomMargin: verticalMargin
83 }114 // extending the "drawing area"
84 contentWidth: view.width115 leftMargin: -carousel.drawBuffer
85 contentHeight: height116 rightMargin: -carousel.drawBuffer
117 }
118
119 /* The header and footer help to "extend" the area, the listview draws items.
120 This together with anchors.leftMargin and anchors.rightMargin. */
121 header: Item {
122 width: carousel.drawBuffer
123 height: listView.tileHeight
124 }
125 footer: Item {
126 width: carousel.drawBuffer
127 height: listView.tileHeight
128 }
129
86 boundsBehavior: Flickable.StopAtBounds130 boundsBehavior: Flickable.StopAtBounds
87 flickDeceleration: Math.max(1500 * Math.pow(width / referenceWidth, 1.5), 1500) // 1500 is platform default131 cacheBuffer: carousel.cacheBuffer
88 maximumFlickVelocity: Math.max(2500 * Math.pow(width / referenceWidth, 1.5), 2500) // 2500 is platform default132 flickDeceleration: Math.max(1500 * Math.pow(realWidth / referenceWidth, 1.5), 1500) // 1500 is platform default
133 maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
134 orientation: ListView.Horizontal
89135
90 function itemClicked(index, delegateItem) {136 function itemClicked(index, delegateItem) {
91 var x = CarouselJS.getXFromContinuousIndex(index,137 var x = CarouselJS.getXFromContinuousIndex(index,
92 width,138 realWidth,
93 contentWidth,139 realContentWidth,
94 tileWidth,140 tileWidth,
95 gapToMiddlePhase,141 gapToMiddlePhase,
96 gapToEndPhase)142 gapToEndPhase,
143 carousel.drawBuffer)
97144
98 if (Math.abs(x - contentX) < 1) {145 if (Math.abs(x - contentX) < 1) {
99 /* We're clicking the selected item and146 /* We're clicking the selected item and
@@ -116,22 +163,22 @@
116 newContentX = -1163 newContentX = -1
117 }164 }
118 onMovementEnded: {165 onMovementEnded: {
119 if (contentX > 0 && contentX < contentWidth - width)166 if (realContentX > 0 && realContentX < realContentWidth - realWidth)
120 stepAnimation.start()167 stepAnimation.start()
121 }168 }
122169
123 SmoothedAnimation {170 SmoothedAnimation {
124 id: stepAnimation171 id: stepAnimation
125172
126 target: flickable173 target: listView
127 property: "contentX"174 property: "contentX"
128 from: flickable.contentX175 to: CarouselJS.getXFromContinuousIndex(listView.selectedIndex,
129 to: CarouselJS.getXFromContinuousIndex(view.selectedIndex,176 listView.realWidth,
130 flickable.width,177 listView.realContentWidth,
131 flickable.contentWidth,178 listView.tileWidth,
132 flickable.tileWidth,179 listView.gapToMiddlePhase,
133 flickable.gapToMiddlePhase,180 listView.gapToEndPhase,
134 flickable.gapToEndPhase)181 carousel.drawBuffer)
135 duration: 450182 duration: 450
136 velocity: 200183 velocity: 200
137 easing.type: Easing.InOutQuad184 easing.type: Easing.InOutQuad
@@ -141,113 +188,97 @@
141 id: newContentXAnimation188 id: newContentXAnimation
142189
143 NumberAnimation {190 NumberAnimation {
144 target: flickable191 target: listView
145 property: "contentX"192 property: "contentX"
146 from: flickable.contentX193 from: listView.contentX
147 to: flickable.newContentX194 to: listView.newContentX
148 duration: 300195 duration: 300
149 easing.type: Easing.InOutQuad196 easing.type: Easing.InOutQuad
150 }197 }
151 ScriptAction {198 ScriptAction {
152 script: flickable.newContentX = -1199 script: listView.newContentX = -1
153 }200 }
154 }201 }
155202
156 Row {203 readonly property int selectedIndex: Math.round(continuousIndex)
157 id: view204 readonly property real continuousIndex: CarouselJS.getContinuousIndex(listView.realContentX,
158205 listView.tileWidth,
159 readonly property int selectedIndex: Math.round(continuousIndex)206 listView.gapToMiddlePhase,
160 readonly property real continuousIndex: CarouselJS.getContinuousIndex(flickable.contentX,207 listView.gapToEndPhase,
161 flickable.tileWidth,208 listView.kGapEnd,
162 flickable.gapToMiddlePhase,209 listView.kMiddleIndex,
163 flickable.gapToEndPhase,210 listView.kXBeginningEnd)
164 flickable.kGapEnd,211
165 flickable.kMiddleIndex,212 property real viewTranslation: CarouselJS.getViewTranslation(listView.realContentX,
166 flickable.kXBeginningEnd)213 listView.tileWidth,
167214 listView.gapToMiddlePhase,
168 height: parent.height215 listView.gapToEndPhase,
169 anchors.verticalCenter: parent.verticalCenter216 listView.translationXViewFactor)
217
218 delegate: Loader {
219 property bool explicitlyScaled: explicitScaleFactor == carousel.selectedItemScaleFactor
220 property real explicitScaleFactor: explicitScale ? carousel.selectedItemScaleFactor : 1.0
221 readonly property bool explicitScale: (!listView.moving ||
222 listView.realContentX <= 0 ||
223 listView.realContentX >= listView.realContentWidth - listView.realWidth) &&
224 listView.newContentX < 0 &&
225 index === listView.selectedIndex
226 readonly property real cachedTiles: listView.realPathItemCount + carousel.drawBuffer / listView.tileWidth
227 readonly property real distance: listView.continuousIndex - index
228 readonly property real itemTranslationScale: CarouselJS.getItemScale(0.5,
229 (index + 0.5), // good approximation of scale while changing selected item
230 listView.count,
231 listView.visibleTilesScaleFactor)
232 readonly property real itemScale: CarouselJS.getItemScale(distance,
233 listView.continuousIndex,
234 listView.count,
235 listView.visibleTilesScaleFactor)
236 readonly property real translationX: CarouselJS.getItemTranslation(index,
237 listView.selectedIndex,
238 distance,
239 itemScale,
240 itemTranslationScale,
241 listView.maximumItemTranslation)
242
243 width: listView.tileWidth
244 height: listView.tileHeight
245 scale: itemScale * explicitScaleFactor
246 sourceComponent: itemComponent
247 z: cachedTiles - Math.abs(index - listView.selectedIndex)
170248
171 transform: Translate {249 transform: Translate {
172 x: CarouselJS.getViewTranslation(flickable.contentX,250 x: listView.viewTranslation + translationX * listView.scaleFactor
173 flickable.tileWidth,
174 flickable.gapToMiddlePhase,
175 flickable.gapToEndPhase,
176 flickable.translationXViewFactor)
177 }251 }
178252
179 Repeater {253 Behavior on explicitScaleFactor {
180 id: repeater254 SequentialAnimation {
181255 ScriptAction {
182 model: carousel.model256 script: if (!explicitScale)
183257 explicitlyScaled = false
184 Loader {258 }
185 property bool explicitlyScaled: explicitScaleFactor == carousel.selectedItemScaleFactor259 NumberAnimation {
186 property real explicitScaleFactor: explicitScale ? carousel.selectedItemScaleFactor : 1.0260 duration: explicitScaleFactor === 1.0 ? 250 : 150
187 readonly property bool explicitScale: (!flickable.moving ||261 easing.type: Easing.InOutQuad
188 flickable.contentX <= 0 ||262 }
189 flickable.contentX >= flickable.contentWidth - flickable.width) &&263 ScriptAction {
190 flickable.newContentX < 0 &&264 script: if (explicitScale)
191 index === view.selectedIndex265 explicitlyScaled = true
192 readonly property real cachedTiles: flickable.realPathItemCount + carousel.cacheBuffer / flickable.tileWidth
193 readonly property real distance: view.continuousIndex - index
194 readonly property real itemTranslationScale: CarouselJS.getItemScale(0.5,
195 (index + 0.5), // good approximation of scale while changing selected item
196 repeater.count,
197 flickable.visibleTilesScaleFactor)
198 readonly property real itemScale: CarouselJS.getItemScale(distance,
199 view.continuousIndex,
200 repeater.count,
201 flickable.visibleTilesScaleFactor)
202 readonly property real translationFactor: (flickable.tileWidth * 3) / flickable.scaleFactor
203 readonly property real translationX: index === view.selectedIndex ? 0 :
204 CarouselJS.getItemTranslation(distance,
205 itemScale,
206 itemTranslationScale,
207 translationFactor)
208
209 width: flickable.tileWidth
210 height: flickable.tileHeight
211 scale: itemScale * explicitScaleFactor
212 opacity: scale > 0.02 ? 1 : 0
213 sourceComponent: z > 0 ? itemComponent : undefined
214 z: cachedTiles - Math.abs(index - view.selectedIndex)
215
216 transform: Translate {
217 x: translationX * flickable.scaleFactor
218 }
219
220 Behavior on explicitScaleFactor {
221 SequentialAnimation {
222 ScriptAction {
223 script: if (!explicitScale)
224 explicitlyScaled = false
225 }
226 NumberAnimation {
227 duration: explicitScaleFactor === 1.0 ? 250 : 150
228 easing.type: Easing.InOutQuad
229 }
230 ScriptAction {
231 script: if (explicitScale)
232 explicitlyScaled = true
233 }
234 }
235 }
236
237 onLoaded: {
238 item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; })
239 item.model = Qt.binding(function() { return model; })
240 }
241
242 MouseArea {
243 id: mouseArea
244
245 anchors.fill: parent
246
247 onClicked: flickable.itemClicked(index, item)
248 }266 }
249 }267 }
250 }268 }
269
270 onLoaded: {
271 item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; })
272 item.model = Qt.binding(function() { return model; })
273 }
274
275 MouseArea {
276 id: mouseArea
277
278 anchors.fill: parent
279
280 onClicked: listView.itemClicked(index, item)
281 }
251 }282 }
252 }283 }
253}284}
254285
=== modified file 'Components/carousel.js'
--- Components/carousel.js 2013-06-05 22:03:08 +0000
+++ Components/carousel.js 2013-06-06 08:03:28 +0000
@@ -16,7 +16,15 @@
1616
17.pragma library17.pragma library
1818
19// get the element which is selected accordingly to x, the hero of the view19/*! get the element which is selected accordingly to x, the hero of the view
20 @param x contentX of the ListView
21 @param tileWidth width of a single tile
22 @param gapToMiddlePhase gap in pixels between beginning and middle phase
23 @param gapToEndPhase gap in pixels between middle and end phase
24 @param kGapEnd
25 @param kMiddleIndex
26 @param kXBeginningEnd
27*/
20function getContinuousIndex(x, tileWidth, gapToMiddlePhase, gapToEndPhase, kGapEnd, kMiddleIndex, kXBeginningEnd) {28function getContinuousIndex(x, tileWidth, gapToMiddlePhase, gapToEndPhase, kGapEnd, kMiddleIndex, kXBeginningEnd) {
21 if (x < gapToMiddlePhase) {29 if (x < gapToMiddlePhase) {
22 // beginning30 // beginning
@@ -30,8 +38,16 @@
30 return x / tileWidth + kMiddleIndex38 return x / tileWidth + kMiddleIndex
31}39}
3240
33// obtain x position relative to an index, essentially an inverse of getContinuousIndex()41/*! obtain x position relative to an index, essentially an inverse of getContinuousIndex()
34function getXFromContinuousIndex(index, viewWidth, contentWidth, tileWidth, gapToMiddlePhase, gapToEndPhase) {42 @param index index of the item to calcualte the proper X value for
43 @param viewWidth visible width of the view
44 @param contentWidth width off all items in the view
45 @param tileWidth width of one item
46 @param gapToMiddlePhase
47 @param gapToEndPhase
48 @param drawBuffer width of the drawBuffer
49*/
50function getXFromContinuousIndex(index, viewWidth, contentWidth, tileWidth, gapToMiddlePhase, gapToEndPhase, drawBuffer) {
35 var middleX = (index + 0.5) * tileWidth - viewWidth / 251 var middleX = (index + 0.5) * tileWidth - viewWidth / 2
3652
37 if (middleX < gapToMiddlePhase) {53 if (middleX < gapToMiddlePhase) {
@@ -40,6 +56,7 @@
40 ((1 / tileWidth) +56 ((1 / tileWidth) +
41 (viewWidth / (2 * tileWidth * gapToMiddlePhase)) -57 (viewWidth / (2 * tileWidth * gapToMiddlePhase)) -
42 1 / (2 * gapToMiddlePhase))58 1 / (2 * gapToMiddlePhase))
59 - drawBuffer
43 } else if (middleX > gapToEndPhase) {60 } else if (middleX > gapToEndPhase) {
44 // inverse of 'middleIndex + kGap' of getContinuousIndex()61 // inverse of 'middleIndex + kGap' of getContinuousIndex()
45 return (index +62 return (index +
@@ -50,13 +67,19 @@
50 (1 / tileWidth +67 (1 / tileWidth +
51 viewWidth / (2 * tileWidth * gapToMiddlePhase) -68 viewWidth / (2 * tileWidth * gapToMiddlePhase) -
52 1 / (2 * gapToMiddlePhase))69 1 / (2 * gapToMiddlePhase))
70 - drawBuffer
53 }71 }
5472
55 // inverse of 'middleIndex' of getContinuousIndex()73 // inverse of 'middleIndex' of getContinuousIndex()
56 return middleX74 return middleX - drawBuffer
57}75}
5876
59// get translation of the whole view, adds gaps on sides77/*! get translation of the whole view, adds gaps on sides
78 @param x contentX of the ListView
79 @param gapToMiddlePhase
80 @param gapToEndPhase
81 @param translationXViewFactor
82*/
60function getViewTranslation(x, tileWidth, gapToMiddlePhase, gapToEndPhase, translationXViewFactor) {83function getViewTranslation(x, tileWidth, gapToMiddlePhase, gapToEndPhase, translationXViewFactor) {
61 if (x < gapToMiddlePhase) {84 if (x < gapToMiddlePhase) {
62 // beginning85 // beginning
@@ -70,16 +93,29 @@
70 return 093 return 0
71}94}
7295
73// item scale96/*! item scale
74function getItemScale(distance, continuousIndex, end, scaleFactor) {97 @param distance is the difference of the item's index to the continuousIndex
98 @param continuousIndex the current index in real number
99 @param numberOfItems the total number of items in the model
100 @param scaleFactor if bigger than 1, the scaling is done slower (more distance needed)
101*/
102function getItemScale(distance, continuousIndex, numberOfItems, scaleFactor) {
75 var distanceAbs = Math.abs(distance)103 var distanceAbs = Math.abs(distance)
76 var distanceToBounds = Math.min(continuousIndex, end - continuousIndex)104 var distanceToBounds = Math.min(continuousIndex, numberOfItems - continuousIndex)
77 var k = Math.max(200 + 100 * (-distanceToBounds / (3 * scaleFactor)), 50)105 var k = Math.max(200 + 100 * (-distanceToBounds / (3 * scaleFactor)), 50)
78 return Math.max(0.01, 1 - Math.pow(distanceAbs, 2.5) / (k * scaleFactor))106 return Math.max(0.01, 1 - Math.pow(distanceAbs, 2.5) / (k * scaleFactor))
79}107}
80108
81// item translation109/*! item translation
82function getItemTranslation(distance, scale, maxScale, translationFactor) {110 @param index index of the current item
111 @param selectedIndex index of the selected item
112 @param distance controls the direction wich is left/negative and right/positive
113 @param scale is the current scale factor of the item
114 @param maxScale the maximum scale factor (the one used when the index is on that item
115 @param maxTranslation the maximum translation length in pixel
116*/
117function getItemTranslation(index, selectedIndex, distance, scale, maxScale, maxTranslation) {
118 if (index === selectedIndex) return 0
83 var sign = distance > 0 ? 1 : -1119 var sign = distance > 0 ? 1 : -1
84 return sign * (maxScale - scale) * translationFactor120 return sign * (maxScale - scale) * maxTranslation
85}121}
86122
=== modified file 'tests/qmltests/Components/tst_Carousel.qml'
--- tests/qmltests/Components/tst_Carousel.qml 2013-06-05 22:03:08 +0000
+++ tests/qmltests/Components/tst_Carousel.qml 2013-06-06 08:03:28 +0000
@@ -19,6 +19,7 @@
19import "../../../Components/carousel.js" as Carousel19import "../../../Components/carousel.js" as Carousel
2020
21TestCase {21TestCase {
22 id: root
22 name: "Carousel"23 name: "Carousel"
2324
24 property real carouselWidth25 property real carouselWidth
@@ -49,9 +50,9 @@
49 }50 }
5051
51 function test_getContinuousIndex(data) {52 function test_getContinuousIndex(data) {
52 carouselWidth = data.carouselWidth53 root.carouselWidth = data.carouselWidth
53 tileWidth = data.tileWidth54 root.tileWidth = data.tileWidth
54 itemCount = data.itemCount55 root.itemCount = data.itemCount
5556
56 var index = Carousel.getContinuousIndex(data.x,57 var index = Carousel.getContinuousIndex(data.x,
57 data.tileWidth,58 data.tileWidth,
@@ -69,23 +70,23 @@
69 index: 0, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 0},70 index: 0, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 0},
70 {tag:"in startup",71 {tag:"in startup",
71 index: 2, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 100},72 index: 2, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 100},
72// {tag:"in startup with drawBuffer",73 {tag:"in startup with drawBuffer",
73// index: 2, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 0},74 index: 2, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 0},
74 {tag:"in the middle",75 {tag:"in the middle",
75 index: 5, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 350},76 index: 5, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 350},
76// {tag:"in the middle with drawBuffer",77 {tag:"in the middle with drawBuffer",
77// index: 5, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 250},78 index: 5, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 250},
78 {tag:"at end",79 {tag:"at end",
79 index: 9, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 600},80 index: 9, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 600},
80// {tag:"at end with drawBuffer",81 {tag:"at end with drawBuffer",
81// index: 9, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 500},82 index: 9, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 500},
82 ]83 ]
83 }84 }
8485
85 function test_getXFromContinuousIndex(data) {86 function test_getXFromContinuousIndex(data) {
86 carouselWidth = data.carouselWidth87 root.carouselWidth = data.carouselWidth
87 tileWidth = data.tileWidth88 root.tileWidth = data.tileWidth
88 itemCount = data.itemCount89 root.itemCount = data.itemCount
8990
90 var x = Carousel.getXFromContinuousIndex(data.index,91 var x = Carousel.getXFromContinuousIndex(data.index,
91 data.carouselWidth,92 data.carouselWidth,
@@ -113,14 +114,14 @@
113 }114 }
114115
115 function test_getViewTranslation(data) {116 function test_getViewTranslation(data) {
116 carouselWidth = data.carouselWidth117 root.carouselWidth = data.carouselWidth
117 tileWidth = data.tileWidth118 root.tileWidth = data.tileWidth
118 itemCount = data.itemCount119 root.itemCount = data.itemCount
119120
120 var x = Carousel.getViewTranslation(data.x,121 var x = Carousel.getViewTranslation(data.x,
121 data.tileWidth,122 data.tileWidth,
122 gapToMiddlePhase,123 root.gapToMiddlePhase,
123 gapToEndPhase,124 root.gapToEndPhase,
124 data.translationXViewFactor)125 data.translationXViewFactor)
125 compare(x, data.result)126 compare(x, data.result)
126 }127 }
@@ -158,30 +159,33 @@
158159
159 // test for the getItemTranslation() function160 // test for the getItemTranslation() function
160 function test_getItemTranslation_data() {161 function test_getItemTranslation_data() {
161 return [ // tests if distance only affects the sign162 return [ // tests for index and selectedIndex
162 {distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},163 {index: 1, selectedIndex: 1, distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0},
163// {distance: 99, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},164 // tests if distance only affects the sign
164 {distance: 0, scale: 0, maxScale: 1, maxTranslation: 10, result: -10},165 {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},
165 {distance: -1, scale: 0, maxScale: 1, maxTranslation: 10, result: -10},166 {index: 1, selectedIndex: 2, distance: 99, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},
167 {index: 1, selectedIndex: 2, distance: -1, scale: 0, maxScale: 1, maxTranslation: 10, result: -10},
168 {index: 1, selectedIndex: 2, distance: -99, scale: 0, maxScale: 1, maxTranslation: 10, result: -10},
166 // tests for the scale169 // tests for the scale
167 {distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0},170 {index: 1, selectedIndex: 2, distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0},
168 {distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},171 {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},
169 {distance: 1, scale: 0.5, maxScale: 1, maxTranslation: 10, result: 5},172 {index: 1, selectedIndex: 2, distance: 1, scale: 0.5, maxScale: 1, maxTranslation: 10, result: 5},
170 // tests for maxScale173 // tests for maxScale
171 {distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0},174 {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 0.98, maxTranslation: 10, result: 9.8},
172 {distance: 1, scale: 1, maxScale: 2, maxTranslation: 10, result: 10},175 {index: 1, selectedIndex: 2, distance: 1, scale: 0.5, maxScale: 0.95, maxTranslation: 10, result: 4.5},
173// {distance: 1, scale: 1, maxScale: 0, maxTranslation: 10, result: 0},176 {index: 1, selectedIndex: 2, distance: 1, scale: 0.8, maxScale: 0.93, maxTranslation: 10, result: 1.3},
174// {distance: 1, scale: 1, maxScale: 99, maxTranslation: 10, result: 10},
175 // test for maxTranslation177 // test for maxTranslation
176 {distance: 1, scale: 1, maxScale: 1, maxTranslation: 1, result: 0},178 {index: 1, selectedIndex: 2, distance: 1, scale: 1, maxScale: 1, maxTranslation: 1, result: 0},
177 {distance: 1, scale: 0, maxScale: 1, maxTranslation: 1, result: 1},179 {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 1, result: 1},
178 {distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},180 {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10},
179 {distance: 1, scale: 0, maxScale: 1, maxTranslation: 0, result: 0},181 {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 0, result: 0},
180 ]182 ]
181 }183 }
182184
183 function test_getItemTranslation(data) {185 function test_getItemTranslation(data) {
184 var scale = Carousel.getItemTranslation(data.distance,186 var scale = Carousel.getItemTranslation(data.index,
187 data.selectedIndex,
188 data.distance,
185 data.scale,189 data.scale,
186 data.maxScale,190 data.maxScale,
187 data.maxTranslation)191 data.maxTranslation)

Subscribers

People subscribed via source and target branches

to all changes: