Merge lp:~unity-team/unity/8.carousel-listview into lp:unity/8.0
- 8.carousel-listview
- Merge into 8.0
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 |
Related bugs: |
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.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
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)
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 :)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:682
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Exactly the same code i have in the branch i had for testing the listview-carousel crashes
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'Components/Carousel.qml' |
2 | --- Components/Carousel.qml 2013-06-05 22:03:08 +0000 |
3 | +++ Components/Carousel.qml 2013-06-06 08:03:28 +0000 |
4 | @@ -18,26 +18,50 @@ |
5 | import Ubuntu.Components 0.1 |
6 | import "carousel.js" as CarouselJS |
7 | |
8 | +/*! The Carousel component presents the items of a model in a carousel view. It's similar to a |
9 | + cover flow. But it stops at it's boundaries (therefore no PathView is used). |
10 | + */ |
11 | Item { |
12 | id: carousel |
13 | |
14 | + /// The component to be used as delegate. This component has to be derived from BaseCarouselDelegate |
15 | property Component itemComponent |
16 | - property var model |
17 | - property alias minimumTileWidth: flickable.minimumTileWidth |
18 | - property alias pathItemCount: flickable.pathItemCount |
19 | - property alias tileAspectRatio: flickable.tileAspectRatio |
20 | - property int cacheBuffer: 0 |
21 | + /// Model for the Carousel, which has to be a model usable by a ListView |
22 | + property alias model: listView.model |
23 | + /// A minimal width of a tile can be set here. Per default a best fit will be calculated |
24 | + property alias minimumTileWidth: listView.minimumTileWidth |
25 | + /// Sets the number of tiles that are visible |
26 | + property alias pathItemCount: listView.pathItemCount |
27 | + /// Aspect ratio of the tiles width/height |
28 | + property alias tileAspectRatio: listView.tileAspectRatio |
29 | + /// Used to cache some delegates for performance reasons. See the ListView documentation for details |
30 | + property alias cacheBuffer: listView.cacheBuffer |
31 | + /// Width of the "draw buffer" in pixel. The drawBuffer is an additional area at start/end where |
32 | + /// items drawn, even if it is not in the visible area. |
33 | + /// cacheBuffer controls only the to retain delegates outside the visible area (and is used on top of the drawBuffer) |
34 | + /// see https://bugreports.qt-project.org/browse/QTBUG-29173 |
35 | + property int drawBuffer: width / pathItemCount // an "ok" value - but values used from the listView cause loops |
36 | + /// The selected item can be shown in a different size controlled by selectedItemScaleFactor |
37 | property real selectedItemScaleFactor: 1.1 |
38 | |
39 | + /// Emitted when the user clicked on an item |
40 | + /// @param index is the index of the clicked item |
41 | + /// @param delegateItem is the clicked component/delegate itself |
42 | + /// @param itemY is y of the clicked delegate |
43 | signal clicked(int index, var delegateItem, real itemY) |
44 | |
45 | - implicitHeight: flickable.tileHeight * selectedItemScaleFactor |
46 | - |
47 | - /* TODO: evaluate if the component could be more efficient with a ListView, |
48 | - using this technique https://bugreports.qt-project.org/browse/QTBUG-29173 */ |
49 | - |
50 | - Flickable { |
51 | - id: flickable |
52 | + implicitHeight: listView.tileHeight * selectedItemScaleFactor |
53 | + |
54 | + /* Basic idea behind the carousel effect is to move the items of the delegates (compacting /stuffing them). |
55 | + One drawback is, that more delegates have to be drawn than usually. As some items are moved from the |
56 | + invisible to the visible area. Setting the cacheBuffer does not fix this. |
57 | + See https://bugreports.qt-project.org/browse/QTBUG-29173 |
58 | + Therefore the ListView has negative left and right anchors margins, and in addition a header |
59 | + and footer item to compensate that. |
60 | + |
61 | + The scaling of the items is controlled by the variable continuousIndex, described below. */ |
62 | + ListView { |
63 | + id: listView |
64 | |
65 | property real minimumTileWidth: 0 |
66 | property real newContentX: -1 |
67 | @@ -57,20 +81,27 @@ |
68 | - 'gapToEndPhase' gap in pixels between middle and end phase |
69 | - 'kGapEnd' constant used to calculate 'continuousIndex' in end phase |
70 | - 'kMiddleIndex' constant used to calculate 'continuousIndex' in middle phase |
71 | - - 'kXBeginningEnd' constant used to calculate 'continuousIndex' in beginning and end phase. */ |
72 | + - 'kXBeginningEnd' constant used to calculate 'continuousIndex' in beginning and end phase |
73 | + - 'realContentWidth' the width of all the delegates only (without header/footer) |
74 | + - 'realContentX' the 'contentX' of the listview ignoring the 'drawBuffer' |
75 | + - 'realWidth' the 'width' of the listview, as it is used as component. */ |
76 | |
77 | - readonly property real gapToMiddlePhase: Math.min(width / 2 - tileWidth / 2, (contentWidth - width) / 2) |
78 | - readonly property real gapToEndPhase: contentWidth - width - gapToMiddlePhase |
79 | + readonly property real gapToMiddlePhase: Math.min(realWidth / 2 - tileWidth / 2, (realContentWidth - realWidth) / 2) |
80 | + readonly property real gapToEndPhase: realContentWidth - realWidth - gapToMiddlePhase |
81 | readonly property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase) |
82 | - readonly property real kMiddleIndex: (width / 2) / tileWidth - 0.5 |
83 | + readonly property real kMiddleIndex: (realWidth / 2) / tileWidth - 0.5 |
84 | readonly property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase |
85 | - readonly property real realPathItemCount: Math.min(width / tileWidth, pathItemCount) |
86 | - readonly property real referenceGapToMiddlePhase: width / 2 - tileWidth / 2 |
87 | + readonly property real maximumItemTranslation: (listView.tileWidth * 3) / listView.scaleFactor |
88 | + readonly property real realContentWidth: contentWidth - 2 * carousel.drawBuffer |
89 | + readonly property real realContentX: contentX + carousel.drawBuffer |
90 | + readonly property real realPathItemCount: Math.min(realWidth / tileWidth, pathItemCount) |
91 | + readonly property real realWidth: carousel.width |
92 | + readonly property real referenceGapToMiddlePhase: realWidth / 2 - tileWidth / 2 |
93 | readonly property real referencePathItemCount: referenceWidth / referenceTileWidth |
94 | readonly property real referenceWidth: 848 |
95 | readonly property real referenceTileWidth: 175 |
96 | readonly property real scaleFactor: tileWidth / referenceTileWidth |
97 | - readonly property real tileWidth: Math.max(width / pathItemCount, minimumTileWidth) |
98 | + readonly property real tileWidth: Math.max(realWidth / pathItemCount, minimumTileWidth) |
99 | readonly property real tileHeight: tileWidth / tileAspectRatio |
100 | readonly property real translationXViewFactor: 0.2 * (referenceGapToMiddlePhase / gapToMiddlePhase) |
101 | readonly property real verticalMargin: (parent.height - tileHeight) / 2 |
102 | @@ -80,20 +111,36 @@ |
103 | fill: parent |
104 | topMargin: verticalMargin |
105 | bottomMargin: verticalMargin |
106 | - } |
107 | - contentWidth: view.width |
108 | - contentHeight: height |
109 | + // extending the "drawing area" |
110 | + leftMargin: -carousel.drawBuffer |
111 | + rightMargin: -carousel.drawBuffer |
112 | + } |
113 | + |
114 | + /* The header and footer help to "extend" the area, the listview draws items. |
115 | + This together with anchors.leftMargin and anchors.rightMargin. */ |
116 | + header: Item { |
117 | + width: carousel.drawBuffer |
118 | + height: listView.tileHeight |
119 | + } |
120 | + footer: Item { |
121 | + width: carousel.drawBuffer |
122 | + height: listView.tileHeight |
123 | + } |
124 | + |
125 | boundsBehavior: Flickable.StopAtBounds |
126 | - flickDeceleration: Math.max(1500 * Math.pow(width / referenceWidth, 1.5), 1500) // 1500 is platform default |
127 | - maximumFlickVelocity: Math.max(2500 * Math.pow(width / referenceWidth, 1.5), 2500) // 2500 is platform default |
128 | + cacheBuffer: carousel.cacheBuffer |
129 | + flickDeceleration: Math.max(1500 * Math.pow(realWidth / referenceWidth, 1.5), 1500) // 1500 is platform default |
130 | + maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default |
131 | + orientation: ListView.Horizontal |
132 | |
133 | function itemClicked(index, delegateItem) { |
134 | var x = CarouselJS.getXFromContinuousIndex(index, |
135 | - width, |
136 | - contentWidth, |
137 | + realWidth, |
138 | + realContentWidth, |
139 | tileWidth, |
140 | gapToMiddlePhase, |
141 | - gapToEndPhase) |
142 | + gapToEndPhase, |
143 | + carousel.drawBuffer) |
144 | |
145 | if (Math.abs(x - contentX) < 1) { |
146 | /* We're clicking the selected item and |
147 | @@ -116,22 +163,22 @@ |
148 | newContentX = -1 |
149 | } |
150 | onMovementEnded: { |
151 | - if (contentX > 0 && contentX < contentWidth - width) |
152 | + if (realContentX > 0 && realContentX < realContentWidth - realWidth) |
153 | stepAnimation.start() |
154 | } |
155 | |
156 | SmoothedAnimation { |
157 | id: stepAnimation |
158 | |
159 | - target: flickable |
160 | + target: listView |
161 | property: "contentX" |
162 | - from: flickable.contentX |
163 | - to: CarouselJS.getXFromContinuousIndex(view.selectedIndex, |
164 | - flickable.width, |
165 | - flickable.contentWidth, |
166 | - flickable.tileWidth, |
167 | - flickable.gapToMiddlePhase, |
168 | - flickable.gapToEndPhase) |
169 | + to: CarouselJS.getXFromContinuousIndex(listView.selectedIndex, |
170 | + listView.realWidth, |
171 | + listView.realContentWidth, |
172 | + listView.tileWidth, |
173 | + listView.gapToMiddlePhase, |
174 | + listView.gapToEndPhase, |
175 | + carousel.drawBuffer) |
176 | duration: 450 |
177 | velocity: 200 |
178 | easing.type: Easing.InOutQuad |
179 | @@ -141,113 +188,97 @@ |
180 | id: newContentXAnimation |
181 | |
182 | NumberAnimation { |
183 | - target: flickable |
184 | + target: listView |
185 | property: "contentX" |
186 | - from: flickable.contentX |
187 | - to: flickable.newContentX |
188 | + from: listView.contentX |
189 | + to: listView.newContentX |
190 | duration: 300 |
191 | easing.type: Easing.InOutQuad |
192 | } |
193 | ScriptAction { |
194 | - script: flickable.newContentX = -1 |
195 | + script: listView.newContentX = -1 |
196 | } |
197 | } |
198 | |
199 | - Row { |
200 | - id: view |
201 | - |
202 | - readonly property int selectedIndex: Math.round(continuousIndex) |
203 | - readonly property real continuousIndex: CarouselJS.getContinuousIndex(flickable.contentX, |
204 | - flickable.tileWidth, |
205 | - flickable.gapToMiddlePhase, |
206 | - flickable.gapToEndPhase, |
207 | - flickable.kGapEnd, |
208 | - flickable.kMiddleIndex, |
209 | - flickable.kXBeginningEnd) |
210 | - |
211 | - height: parent.height |
212 | - anchors.verticalCenter: parent.verticalCenter |
213 | + readonly property int selectedIndex: Math.round(continuousIndex) |
214 | + readonly property real continuousIndex: CarouselJS.getContinuousIndex(listView.realContentX, |
215 | + listView.tileWidth, |
216 | + listView.gapToMiddlePhase, |
217 | + listView.gapToEndPhase, |
218 | + listView.kGapEnd, |
219 | + listView.kMiddleIndex, |
220 | + listView.kXBeginningEnd) |
221 | + |
222 | + property real viewTranslation: CarouselJS.getViewTranslation(listView.realContentX, |
223 | + listView.tileWidth, |
224 | + listView.gapToMiddlePhase, |
225 | + listView.gapToEndPhase, |
226 | + listView.translationXViewFactor) |
227 | + |
228 | + delegate: Loader { |
229 | + property bool explicitlyScaled: explicitScaleFactor == carousel.selectedItemScaleFactor |
230 | + property real explicitScaleFactor: explicitScale ? carousel.selectedItemScaleFactor : 1.0 |
231 | + readonly property bool explicitScale: (!listView.moving || |
232 | + listView.realContentX <= 0 || |
233 | + listView.realContentX >= listView.realContentWidth - listView.realWidth) && |
234 | + listView.newContentX < 0 && |
235 | + index === listView.selectedIndex |
236 | + readonly property real cachedTiles: listView.realPathItemCount + carousel.drawBuffer / listView.tileWidth |
237 | + readonly property real distance: listView.continuousIndex - index |
238 | + readonly property real itemTranslationScale: CarouselJS.getItemScale(0.5, |
239 | + (index + 0.5), // good approximation of scale while changing selected item |
240 | + listView.count, |
241 | + listView.visibleTilesScaleFactor) |
242 | + readonly property real itemScale: CarouselJS.getItemScale(distance, |
243 | + listView.continuousIndex, |
244 | + listView.count, |
245 | + listView.visibleTilesScaleFactor) |
246 | + readonly property real translationX: CarouselJS.getItemTranslation(index, |
247 | + listView.selectedIndex, |
248 | + distance, |
249 | + itemScale, |
250 | + itemTranslationScale, |
251 | + listView.maximumItemTranslation) |
252 | + |
253 | + width: listView.tileWidth |
254 | + height: listView.tileHeight |
255 | + scale: itemScale * explicitScaleFactor |
256 | + sourceComponent: itemComponent |
257 | + z: cachedTiles - Math.abs(index - listView.selectedIndex) |
258 | |
259 | transform: Translate { |
260 | - x: CarouselJS.getViewTranslation(flickable.contentX, |
261 | - flickable.tileWidth, |
262 | - flickable.gapToMiddlePhase, |
263 | - flickable.gapToEndPhase, |
264 | - flickable.translationXViewFactor) |
265 | + x: listView.viewTranslation + translationX * listView.scaleFactor |
266 | } |
267 | |
268 | - Repeater { |
269 | - id: repeater |
270 | - |
271 | - model: carousel.model |
272 | - |
273 | - Loader { |
274 | - property bool explicitlyScaled: explicitScaleFactor == carousel.selectedItemScaleFactor |
275 | - property real explicitScaleFactor: explicitScale ? carousel.selectedItemScaleFactor : 1.0 |
276 | - readonly property bool explicitScale: (!flickable.moving || |
277 | - flickable.contentX <= 0 || |
278 | - flickable.contentX >= flickable.contentWidth - flickable.width) && |
279 | - flickable.newContentX < 0 && |
280 | - index === view.selectedIndex |
281 | - readonly property real cachedTiles: flickable.realPathItemCount + carousel.cacheBuffer / flickable.tileWidth |
282 | - readonly property real distance: view.continuousIndex - index |
283 | - readonly property real itemTranslationScale: CarouselJS.getItemScale(0.5, |
284 | - (index + 0.5), // good approximation of scale while changing selected item |
285 | - repeater.count, |
286 | - flickable.visibleTilesScaleFactor) |
287 | - readonly property real itemScale: CarouselJS.getItemScale(distance, |
288 | - view.continuousIndex, |
289 | - repeater.count, |
290 | - flickable.visibleTilesScaleFactor) |
291 | - readonly property real translationFactor: (flickable.tileWidth * 3) / flickable.scaleFactor |
292 | - readonly property real translationX: index === view.selectedIndex ? 0 : |
293 | - CarouselJS.getItemTranslation(distance, |
294 | - itemScale, |
295 | - itemTranslationScale, |
296 | - translationFactor) |
297 | - |
298 | - width: flickable.tileWidth |
299 | - height: flickable.tileHeight |
300 | - scale: itemScale * explicitScaleFactor |
301 | - opacity: scale > 0.02 ? 1 : 0 |
302 | - sourceComponent: z > 0 ? itemComponent : undefined |
303 | - z: cachedTiles - Math.abs(index - view.selectedIndex) |
304 | - |
305 | - transform: Translate { |
306 | - x: translationX * flickable.scaleFactor |
307 | - } |
308 | - |
309 | - Behavior on explicitScaleFactor { |
310 | - SequentialAnimation { |
311 | - ScriptAction { |
312 | - script: if (!explicitScale) |
313 | - explicitlyScaled = false |
314 | - } |
315 | - NumberAnimation { |
316 | - duration: explicitScaleFactor === 1.0 ? 250 : 150 |
317 | - easing.type: Easing.InOutQuad |
318 | - } |
319 | - ScriptAction { |
320 | - script: if (explicitScale) |
321 | - explicitlyScaled = true |
322 | - } |
323 | - } |
324 | - } |
325 | - |
326 | - onLoaded: { |
327 | - item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; }) |
328 | - item.model = Qt.binding(function() { return model; }) |
329 | - } |
330 | - |
331 | - MouseArea { |
332 | - id: mouseArea |
333 | - |
334 | - anchors.fill: parent |
335 | - |
336 | - onClicked: flickable.itemClicked(index, item) |
337 | + Behavior on explicitScaleFactor { |
338 | + SequentialAnimation { |
339 | + ScriptAction { |
340 | + script: if (!explicitScale) |
341 | + explicitlyScaled = false |
342 | + } |
343 | + NumberAnimation { |
344 | + duration: explicitScaleFactor === 1.0 ? 250 : 150 |
345 | + easing.type: Easing.InOutQuad |
346 | + } |
347 | + ScriptAction { |
348 | + script: if (explicitScale) |
349 | + explicitlyScaled = true |
350 | } |
351 | } |
352 | } |
353 | + |
354 | + onLoaded: { |
355 | + item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; }) |
356 | + item.model = Qt.binding(function() { return model; }) |
357 | + } |
358 | + |
359 | + MouseArea { |
360 | + id: mouseArea |
361 | + |
362 | + anchors.fill: parent |
363 | + |
364 | + onClicked: listView.itemClicked(index, item) |
365 | + } |
366 | } |
367 | } |
368 | } |
369 | |
370 | === modified file 'Components/carousel.js' |
371 | --- Components/carousel.js 2013-06-05 22:03:08 +0000 |
372 | +++ Components/carousel.js 2013-06-06 08:03:28 +0000 |
373 | @@ -16,7 +16,15 @@ |
374 | |
375 | .pragma library |
376 | |
377 | -// get the element which is selected accordingly to x, the hero of the view |
378 | +/*! get the element which is selected accordingly to x, the hero of the view |
379 | + @param x contentX of the ListView |
380 | + @param tileWidth width of a single tile |
381 | + @param gapToMiddlePhase gap in pixels between beginning and middle phase |
382 | + @param gapToEndPhase gap in pixels between middle and end phase |
383 | + @param kGapEnd |
384 | + @param kMiddleIndex |
385 | + @param kXBeginningEnd |
386 | +*/ |
387 | function getContinuousIndex(x, tileWidth, gapToMiddlePhase, gapToEndPhase, kGapEnd, kMiddleIndex, kXBeginningEnd) { |
388 | if (x < gapToMiddlePhase) { |
389 | // beginning |
390 | @@ -30,8 +38,16 @@ |
391 | return x / tileWidth + kMiddleIndex |
392 | } |
393 | |
394 | -// obtain x position relative to an index, essentially an inverse of getContinuousIndex() |
395 | -function getXFromContinuousIndex(index, viewWidth, contentWidth, tileWidth, gapToMiddlePhase, gapToEndPhase) { |
396 | +/*! obtain x position relative to an index, essentially an inverse of getContinuousIndex() |
397 | + @param index index of the item to calcualte the proper X value for |
398 | + @param viewWidth visible width of the view |
399 | + @param contentWidth width off all items in the view |
400 | + @param tileWidth width of one item |
401 | + @param gapToMiddlePhase |
402 | + @param gapToEndPhase |
403 | + @param drawBuffer width of the drawBuffer |
404 | +*/ |
405 | +function getXFromContinuousIndex(index, viewWidth, contentWidth, tileWidth, gapToMiddlePhase, gapToEndPhase, drawBuffer) { |
406 | var middleX = (index + 0.5) * tileWidth - viewWidth / 2 |
407 | |
408 | if (middleX < gapToMiddlePhase) { |
409 | @@ -40,6 +56,7 @@ |
410 | ((1 / tileWidth) + |
411 | (viewWidth / (2 * tileWidth * gapToMiddlePhase)) - |
412 | 1 / (2 * gapToMiddlePhase)) |
413 | + - drawBuffer |
414 | } else if (middleX > gapToEndPhase) { |
415 | // inverse of 'middleIndex + kGap' of getContinuousIndex() |
416 | return (index + |
417 | @@ -50,13 +67,19 @@ |
418 | (1 / tileWidth + |
419 | viewWidth / (2 * tileWidth * gapToMiddlePhase) - |
420 | 1 / (2 * gapToMiddlePhase)) |
421 | + - drawBuffer |
422 | } |
423 | |
424 | // inverse of 'middleIndex' of getContinuousIndex() |
425 | - return middleX |
426 | + return middleX - drawBuffer |
427 | } |
428 | |
429 | -// get translation of the whole view, adds gaps on sides |
430 | +/*! get translation of the whole view, adds gaps on sides |
431 | + @param x contentX of the ListView |
432 | + @param gapToMiddlePhase |
433 | + @param gapToEndPhase |
434 | + @param translationXViewFactor |
435 | +*/ |
436 | function getViewTranslation(x, tileWidth, gapToMiddlePhase, gapToEndPhase, translationXViewFactor) { |
437 | if (x < gapToMiddlePhase) { |
438 | // beginning |
439 | @@ -70,16 +93,29 @@ |
440 | return 0 |
441 | } |
442 | |
443 | -// item scale |
444 | -function getItemScale(distance, continuousIndex, end, scaleFactor) { |
445 | +/*! item scale |
446 | + @param distance is the difference of the item's index to the continuousIndex |
447 | + @param continuousIndex the current index in real number |
448 | + @param numberOfItems the total number of items in the model |
449 | + @param scaleFactor if bigger than 1, the scaling is done slower (more distance needed) |
450 | +*/ |
451 | +function getItemScale(distance, continuousIndex, numberOfItems, scaleFactor) { |
452 | var distanceAbs = Math.abs(distance) |
453 | - var distanceToBounds = Math.min(continuousIndex, end - continuousIndex) |
454 | + var distanceToBounds = Math.min(continuousIndex, numberOfItems - continuousIndex) |
455 | var k = Math.max(200 + 100 * (-distanceToBounds / (3 * scaleFactor)), 50) |
456 | return Math.max(0.01, 1 - Math.pow(distanceAbs, 2.5) / (k * scaleFactor)) |
457 | } |
458 | |
459 | -// item translation |
460 | -function getItemTranslation(distance, scale, maxScale, translationFactor) { |
461 | +/*! item translation |
462 | + @param index index of the current item |
463 | + @param selectedIndex index of the selected item |
464 | + @param distance controls the direction wich is left/negative and right/positive |
465 | + @param scale is the current scale factor of the item |
466 | + @param maxScale the maximum scale factor (the one used when the index is on that item |
467 | + @param maxTranslation the maximum translation length in pixel |
468 | +*/ |
469 | +function getItemTranslation(index, selectedIndex, distance, scale, maxScale, maxTranslation) { |
470 | + if (index === selectedIndex) return 0 |
471 | var sign = distance > 0 ? 1 : -1 |
472 | - return sign * (maxScale - scale) * translationFactor |
473 | + return sign * (maxScale - scale) * maxTranslation |
474 | } |
475 | |
476 | === modified file 'tests/qmltests/Components/tst_Carousel.qml' |
477 | --- tests/qmltests/Components/tst_Carousel.qml 2013-06-05 22:03:08 +0000 |
478 | +++ tests/qmltests/Components/tst_Carousel.qml 2013-06-06 08:03:28 +0000 |
479 | @@ -19,6 +19,7 @@ |
480 | import "../../../Components/carousel.js" as Carousel |
481 | |
482 | TestCase { |
483 | + id: root |
484 | name: "Carousel" |
485 | |
486 | property real carouselWidth |
487 | @@ -49,9 +50,9 @@ |
488 | } |
489 | |
490 | function test_getContinuousIndex(data) { |
491 | - carouselWidth = data.carouselWidth |
492 | - tileWidth = data.tileWidth |
493 | - itemCount = data.itemCount |
494 | + root.carouselWidth = data.carouselWidth |
495 | + root.tileWidth = data.tileWidth |
496 | + root.itemCount = data.itemCount |
497 | |
498 | var index = Carousel.getContinuousIndex(data.x, |
499 | data.tileWidth, |
500 | @@ -69,23 +70,23 @@ |
501 | index: 0, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 0}, |
502 | {tag:"in startup", |
503 | index: 2, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 100}, |
504 | -// {tag:"in startup with drawBuffer", |
505 | -// index: 2, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 0}, |
506 | + {tag:"in startup with drawBuffer", |
507 | + index: 2, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 0}, |
508 | {tag:"in the middle", |
509 | index: 5, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 350}, |
510 | -// {tag:"in the middle with drawBuffer", |
511 | -// index: 5, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 250}, |
512 | + {tag:"in the middle with drawBuffer", |
513 | + index: 5, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 250}, |
514 | {tag:"at end", |
515 | index: 9, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:0, result: 600}, |
516 | -// {tag:"at end with drawBuffer", |
517 | -// index: 9, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 500}, |
518 | + {tag:"at end with drawBuffer", |
519 | + index: 9, carouselWidth:400, tileWidth:100, itemCount:10, drawBuffer:100, result: 500}, |
520 | ] |
521 | } |
522 | |
523 | function test_getXFromContinuousIndex(data) { |
524 | - carouselWidth = data.carouselWidth |
525 | - tileWidth = data.tileWidth |
526 | - itemCount = data.itemCount |
527 | + root.carouselWidth = data.carouselWidth |
528 | + root.tileWidth = data.tileWidth |
529 | + root.itemCount = data.itemCount |
530 | |
531 | var x = Carousel.getXFromContinuousIndex(data.index, |
532 | data.carouselWidth, |
533 | @@ -113,14 +114,14 @@ |
534 | } |
535 | |
536 | function test_getViewTranslation(data) { |
537 | - carouselWidth = data.carouselWidth |
538 | - tileWidth = data.tileWidth |
539 | - itemCount = data.itemCount |
540 | + root.carouselWidth = data.carouselWidth |
541 | + root.tileWidth = data.tileWidth |
542 | + root.itemCount = data.itemCount |
543 | |
544 | var x = Carousel.getViewTranslation(data.x, |
545 | data.tileWidth, |
546 | - gapToMiddlePhase, |
547 | - gapToEndPhase, |
548 | + root.gapToMiddlePhase, |
549 | + root.gapToEndPhase, |
550 | data.translationXViewFactor) |
551 | compare(x, data.result) |
552 | } |
553 | @@ -158,30 +159,33 @@ |
554 | |
555 | // test for the getItemTranslation() function |
556 | function test_getItemTranslation_data() { |
557 | - return [ // tests if distance only affects the sign |
558 | - {distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
559 | -// {distance: 99, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
560 | - {distance: 0, scale: 0, maxScale: 1, maxTranslation: 10, result: -10}, |
561 | - {distance: -1, scale: 0, maxScale: 1, maxTranslation: 10, result: -10}, |
562 | + return [ // tests for index and selectedIndex |
563 | + {index: 1, selectedIndex: 1, distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0}, |
564 | + // tests if distance only affects the sign |
565 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
566 | + {index: 1, selectedIndex: 2, distance: 99, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
567 | + {index: 1, selectedIndex: 2, distance: -1, scale: 0, maxScale: 1, maxTranslation: 10, result: -10}, |
568 | + {index: 1, selectedIndex: 2, distance: -99, scale: 0, maxScale: 1, maxTranslation: 10, result: -10}, |
569 | // tests for the scale |
570 | - {distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0}, |
571 | - {distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
572 | - {distance: 1, scale: 0.5, maxScale: 1, maxTranslation: 10, result: 5}, |
573 | + {index: 1, selectedIndex: 2, distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0}, |
574 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
575 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0.5, maxScale: 1, maxTranslation: 10, result: 5}, |
576 | // tests for maxScale |
577 | - {distance: 1, scale: 1, maxScale: 1, maxTranslation: 10, result: 0}, |
578 | - {distance: 1, scale: 1, maxScale: 2, maxTranslation: 10, result: 10}, |
579 | -// {distance: 1, scale: 1, maxScale: 0, maxTranslation: 10, result: 0}, |
580 | -// {distance: 1, scale: 1, maxScale: 99, maxTranslation: 10, result: 10}, |
581 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 0.98, maxTranslation: 10, result: 9.8}, |
582 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0.5, maxScale: 0.95, maxTranslation: 10, result: 4.5}, |
583 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0.8, maxScale: 0.93, maxTranslation: 10, result: 1.3}, |
584 | // test for maxTranslation |
585 | - {distance: 1, scale: 1, maxScale: 1, maxTranslation: 1, result: 0}, |
586 | - {distance: 1, scale: 0, maxScale: 1, maxTranslation: 1, result: 1}, |
587 | - {distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
588 | - {distance: 1, scale: 0, maxScale: 1, maxTranslation: 0, result: 0}, |
589 | + {index: 1, selectedIndex: 2, distance: 1, scale: 1, maxScale: 1, maxTranslation: 1, result: 0}, |
590 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 1, result: 1}, |
591 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 10, result: 10}, |
592 | + {index: 1, selectedIndex: 2, distance: 1, scale: 0, maxScale: 1, maxTranslation: 0, result: 0}, |
593 | ] |
594 | } |
595 | |
596 | function test_getItemTranslation(data) { |
597 | - var scale = Carousel.getItemTranslation(data.distance, |
598 | + var scale = Carousel.getItemTranslation(data.index, |
599 | + data.selectedIndex, |
600 | + data.distance, |
601 | data.scale, |
602 | data.maxScale, |
603 | data.maxTranslation) |
FAILED: Continuous integration, rev:682 jenkins. qa.ubuntu. com/job/ unity-phablet- ci/991/ s-jenkins: 8080/job/ unity-phablet- qmluitests/ 963 jenkins. qa.ubuntu. com/job/ unity-phablet- raring- armhf-ci/ 867 jenkins. qa.ubuntu. com/job/ unity-phablet- raring- armhf-ci/ 867/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ unity-phablet- raring- i386-ci/ 871 jenkins. qa.ubuntu. com/job/ generic- mediumtests- runner/ 1581
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-phablet- ci/991/ rebuild
http://