Merge lp:~unity-team/unity8/carousel-shader into lp:unity8

Proposed by Andrea Cimitan
Status: Rejected
Rejected by: Albert Astals Cid
Proposed branch: lp:~unity-team/unity8/carousel-shader
Merge into: lp:unity8
Prerequisite: lp:~unity-team/unity8/dash-renderers
Diff against target: 610 lines (+322/-267)
1 file modified
qml/Components/Carousel.qml (+322/-267)
To merge this branch: bzr merge lp:~unity-team/unity8/carousel-shader
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Disapprove
PS Jenkins bot (community) continuous-integration Approve
Michał Sawicz Needs Fixing
Review via email: mp+196942@code.launchpad.net

Commit message

Use a shader to improve the look of the carousel when the preview is opened

Description of the change

Use a shader to improve the look of the carousel when the preview is opened

To post a comment you must log in.
530. By Andrea Cimitan

Moved to new API for Carousel signals

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:530
http://jenkins.qa.ubuntu.com/job/unity8-ci/1759/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/1208/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/1187/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/449
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/282
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/283
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/283/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/282
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/1073/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1208
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1208/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1187
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1187/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/3743/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/1860

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/1759/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Failed due to bug #1255578.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:530
http://jenkins.qa.ubuntu.com/job/unity8-ci/1776/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/1259
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/1233/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/467
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/299
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/300
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/300/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/299
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/1116
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1259
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1259/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1233
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1233/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/3785/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/1905

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/1776/rebuild

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

FAILED: Continuous integration, rev:530
http://jenkins.qa.ubuntu.com/job/unity8-ci/1783/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/1280
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/1254/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/480
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/306
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/307
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/307/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/306
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/1135
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1280
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1280/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1254
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1254/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/3802/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/1922

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/1783/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Have you talked to design about this?

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:530
http://jenkins.qa.ubuntu.com/job/unity8-ci/1799/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/1339
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/1313/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/523
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/322
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/323
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/323/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/322
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/1190
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1339
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/1339/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1313
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1313/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/3857/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/1980

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/1799/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Cimitan (cimi) wrote :

> Have you talked to design about this?

Nope but of course they will agree on that

Revision history for this message
Albert Astals Cid (aacid) wrote :

Can you make the 200 that is part of this diff to be a property we set from the same place we set the other 200 you are referencing so they stay in sync? (i'm guessing they need to stay in sync otherwise you would have not added the comment)

review: Needs Fixing
Revision history for this message
Andrea Cimitan (cimi) wrote :

> Can you make the 200 that is part of this diff to be a property we set from
> the same place we set the other 200 you are referencing so they stay in sync?
> (i'm guessing they need to stay in sync otherwise you would have not added the
> comment)

I think we should tackle all those animation timings into a new different branch that will use Ubuntu Animation and remove custom durations

Revision history for this message
Albert Astals Cid (aacid) wrote :

My comment was not about the custom durations vs "standarized" Ubuntu Animation duration, which i agree we should fix and use, let's say UbuntuAnimation.FastDuration (165) instead of 200, and i do agree we can do that later.

But then there is the question i wanted to make (and maybe it did not get through)

"Should the ShaderEffect animation always have exactly the same duration than the OpenEffect one in GenericScopeView.qml?"
Because if they should, switching to UbuntuAnimation.XYZ won't help here (since later someone could change one to UbuntuAnimation.BriskAnimation and forget about the other), if they have to be the same we actually need to make sure there's a property we can bind to each other so they are always in sync.

Revision history for this message
Andrea Cimitan (cimi) wrote :

> My comment was not about the custom durations vs "standarized" Ubuntu
> Animation duration, which i agree we should fix and use, let's say
> UbuntuAnimation.FastDuration (165) instead of 200, and i do agree we can do
> that later.
>
> But then there is the question i wanted to make (and maybe it did not get
> through)
>
> "Should the ShaderEffect animation always have exactly the same duration than
> the OpenEffect one in GenericScopeView.qml?"
> Because if they should, switching to UbuntuAnimation.XYZ won't help here
> (since later someone could change one to UbuntuAnimation.BriskAnimation and
> forget about the other), if they have to be the same we actually need to make
> sure there's a property we can bind to each other so they are always in sync.

I don't think it's a requirement... we can have them async

Revision history for this message
Albert Astals Cid (aacid) wrote :

Ok, looks reasonable then.

Someone will have to comment on the aesthetics and top approve, and that's not me for sure :D

review: Abstain
Revision history for this message
Michał Sawicz (saviq) wrote :

We're missing an animation when switching the focused item - it goes from translucent to opaque in one frame.

And I still need to understand why we need a shader here, and why wouldn't layers work...

review: Needs Fixing
Revision history for this message
Andrea Cimitan (cimi) wrote :

> We're missing an animation when switching the focused item - it goes from
> translucent to opaque in one frame.
>
> And I still need to understand why we need a shader here, and why wouldn't
> layers work...
layers didn't work for me...

Revision history for this message
Gerry Boland (gerboland) wrote :

How does this perform on nexus10? The carousel is a very large item to copy into its own texture. I'm worried about GPU memory usage and general performance with this approach.

531. By Andrea Cimitan

merged trunk

532. By Andrea Cimitan

added behaviour on opacity

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:532
http://jenkins.qa.ubuntu.com/job/unity8-ci/1989/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/2005
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/1918
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-phablet-qmluitests-trusty/808
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-amd64-ci/511
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/513
        deb: http://jenkins.qa.ubuntu.com/job/unity8-trusty-armhf-ci/513/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity8-trusty-i386-ci/511
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/1762
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/2005
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/2005/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1918
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/1918/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/4394
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/2731

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity8-ci/1989/rebuild

review: Approve (continuous-integration)
Revision history for this message
Andrea Cimitan (cimi) wrote :

> How does this perform on nexus10? The carousel is a very large item to copy
> into its own texture. I'm worried about GPU memory usage and general
> performance with this approach.

testing it soon, nexus 10 battery was so dead this morning

Revision history for this message
Andrea Cimitan (cimi) wrote :

> How does this perform on nexus10? The carousel is a very large item to copy
> into its own texture. I'm worried about GPU memory usage and general
> performance with this approach.

It slows down a bit, as expected. I much prefer the visuals with this shader, though.

Revision history for this message
Albert Astals Cid (aacid) wrote :

Speaking with Saviq, the concept of highlight seems that will be disappearing soon due to a design change so no need to put more work into this if it's going to vanish

review: Disapprove

Unmerged revisions

532. By Andrea Cimitan

added behaviour on opacity

531. By Andrea Cimitan

merged trunk

530. By Andrea Cimitan

Moved to new API for Carousel signals

529. By Andrea Cimitan

Use shader to improve look of Carousel with preview opened

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qml/Components/Carousel.qml'
2--- qml/Components/Carousel.qml 2013-11-22 13:53:00 +0000
3+++ qml/Components/Carousel.qml 2014-01-06 15:15:42 +0000
4@@ -52,6 +52,8 @@
5 /// exposes the distance to the next row (only one row in carousel, so it's the topMargins)
6 readonly property alias verticalSpacing: listView.verticalMargin
7
8+ readonly property bool shaderEnabled: highlightIndex !== -1
9+
10 /// Emitted when the user clicked on an item
11 /// @param index is the index of the clicked item
12 /// @param itemY is y of the clicked delegate
13@@ -63,277 +65,330 @@
14 signal pressAndHold(int index, real itemY)
15
16 implicitHeight: listView.tileHeight * selectedItemScaleFactor
17- opacity: listView.highlightIndex === -1 ? 1 : 0.6
18-
19- /* Basic idea behind the carousel effect is to move the items of the delegates (compacting /stuffing them).
20- One drawback is, that more delegates have to be drawn than usually. As some items are moved from the
21- invisible to the visible area. Setting the cacheBuffer does not fix this.
22- See https://bugreports.qt-project.org/browse/QTBUG-29173
23- Therefore the ListView has negative left and right anchors margins, and in addition a header
24- and footer item to compensate that.
25-
26- The scaling of the items is controlled by the variable continuousIndex, described below. */
27- ListView {
28- id: listView
29-
30- property int highlightIndex: -1
31- property real minimumTileWidth: 0
32- property real newContentX: disabledNewContentX
33- property real pathItemCount: referenceWidth / referenceTileWidth
34- property real tileAspectRatio: 1
35-
36- /* The positioning and scaling of the items in the carousel is based on the variable
37- 'continuousIndex', a continuous real variable between [0, 'carousel.model.count'],
38- roughly representing the index of the item that is prioritised over the others.
39- 'continuousIndex' is not linear, but is weighted depending on if it is close
40- to the beginning of the content (beginning phase), in the middle (middle phase)
41- or at the end (end phase).
42- Each tile is scaled and transformed in proportion to the difference between
43- its own index and continuousIndex.
44- To efficiently calculate continuousIndex, we have these values:
45- - 'gapToMiddlePhase' gap in pixels between beginning and middle phase
46- - 'gapToEndPhase' gap in pixels between middle and end phase
47- - 'kGapEnd' constant used to calculate 'continuousIndex' in end phase
48- - 'kMiddleIndex' constant used to calculate 'continuousIndex' in middle phase
49- - 'kXBeginningEnd' constant used to calculate 'continuousIndex' in beginning and end phase
50- - 'realContentWidth' the width of all the delegates only (without header/footer)
51- - 'realContentX' the 'contentX' of the listview ignoring the 'drawBuffer'
52- - 'realWidth' the 'width' of the listview, as it is used as component. */
53-
54- readonly property real gapToMiddlePhase: Math.min(realWidth / 2 - tileWidth / 2, (realContentWidth - realWidth) / 2)
55- readonly property real gapToEndPhase: realContentWidth - realWidth - gapToMiddlePhase
56- readonly property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
57- readonly property real kMiddleIndex: (realWidth / 2) / tileWidth - 0.5
58- readonly property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
59- readonly property real maximumItemTranslation: (listView.tileWidth * 3) / listView.scaleFactor
60- readonly property real disabledNewContentX: -carousel.drawBuffer - 1
61- readonly property real realContentWidth: contentWidth - 2 * carousel.drawBuffer
62- readonly property real realContentX: contentX + carousel.drawBuffer
63- readonly property real realPathItemCount: Math.min(realWidth / tileWidth, pathItemCount)
64- readonly property real realWidth: carousel.width
65- readonly property real referenceGapToMiddlePhase: realWidth / 2 - tileWidth / 2
66- readonly property real referencePathItemCount: referenceWidth / referenceTileWidth
67- readonly property real referenceWidth: 848
68- readonly property real referenceTileWidth: 175
69- readonly property real scaleFactor: tileWidth / referenceTileWidth
70- readonly property real tileWidth: Math.max(realWidth / pathItemCount, minimumTileWidth)
71- readonly property real tileHeight: tileWidth / tileAspectRatio
72- readonly property real translationXViewFactor: 0.2 * (referenceGapToMiddlePhase / gapToMiddlePhase)
73- readonly property real verticalMargin: (parent.height - tileHeight) / 2
74- readonly property real visibleTilesScaleFactor: realPathItemCount / referencePathItemCount
75-
76- anchors {
77- fill: parent
78- topMargin: verticalMargin
79- bottomMargin: verticalMargin
80- // extending the "drawing area"
81- leftMargin: -carousel.drawBuffer
82- rightMargin: -carousel.drawBuffer
83- }
84-
85- /* The header and footer help to "extend" the area, the listview draws items.
86- This together with anchors.leftMargin and anchors.rightMargin. */
87- header: Item {
88- width: carousel.drawBuffer
89- height: listView.tileHeight
90- }
91- footer: Item {
92- width: carousel.drawBuffer
93- height: listView.tileHeight
94- }
95-
96- boundsBehavior: Flickable.DragOverBounds
97- cacheBuffer: carousel.cacheBuffer
98- flickDeceleration: Math.max(1500 * Math.pow(realWidth / referenceWidth, 1.5), 1500) // 1500 is platform default
99- maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
100- orientation: ListView.Horizontal
101-
102- function itemClicked(index, delegateItem) {
103- listView.currentIndex = index
104- var x = CarouselJS.getXFromContinuousIndex(index,
105- realWidth,
106- realContentWidth,
107- tileWidth,
108- gapToMiddlePhase,
109- gapToEndPhase,
110- carousel.drawBuffer)
111-
112- if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
113- /* We're clicking the selected item and
114- we're in the neighbourhood of radius 1 pixel from it.
115- Let's emit the clicked signal. */
116- carousel.clicked(index, delegateItem.y)
117- return
118- }
119-
120- stepAnimation.stop()
121- newContentXAnimation.stop()
122-
123- newContentX = x
124- newContentXAnimation.start()
125- }
126-
127- function itemPressAndHold(index, delegateItem) {
128- var x = CarouselJS.getXFromContinuousIndex(index,
129- realWidth,
130- realContentWidth,
131- tileWidth,
132- gapToMiddlePhase,
133- gapToEndPhase,
134- carousel.drawBuffer);
135-
136- if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
137- /* We're pressAndHold the selected item and
138- we're in the neighbourhood of radius 1 pixel from it.
139- Let's emit the pressAndHold signal. */
140- carousel.pressAndHold(index, delegateItem.y);
141- return;
142- }
143-
144- stepAnimation.stop();
145- newContentXAnimation.stop();
146-
147- newContentX = x;
148- newContentXAnimation.start();
149- }
150-
151- onHighlightIndexChanged: {
152- if (highlightIndex != -1) {
153- itemClicked(highlightIndex)
154- }
155- }
156-
157- onMovementStarted: {
158- stepAnimation.stop()
159- newContentXAnimation.stop()
160- newContentX = disabledNewContentX
161- }
162- onMovementEnded: {
163- if (realContentX > 0 && realContentX < realContentWidth - realWidth)
164- stepAnimation.start()
165- }
166-
167- SmoothedAnimation {
168- id: stepAnimation
169-
170- target: listView
171- property: "contentX"
172- to: CarouselJS.getXFromContinuousIndex(listView.selectedIndex,
173- listView.realWidth,
174- listView.realContentWidth,
175- listView.tileWidth,
176- listView.gapToMiddlePhase,
177- listView.gapToEndPhase,
178- carousel.drawBuffer)
179- duration: 450
180- velocity: 200
181- easing.type: Easing.InOutQuad
182- }
183-
184- SequentialAnimation {
185- id: newContentXAnimation
186-
187- NumberAnimation {
188+
189+ Item {
190+ id: shaderItem
191+ anchors.fill: parent
192+
193+ /* Basic idea behind the carousel effect is to move the items of the delegates (compacting /stuffing them).
194+ One drawback is, that more delegates have to be drawn than usually. As some items are moved from the
195+ invisible to the visible area. Setting the cacheBuffer does not fix this.
196+ See https://bugreports.qt-project.org/browse/QTBUG-29173
197+ Therefore the ListView has negative left and right anchors margins, and in addition a header
198+ and footer item to compensate that.
199+
200+ The scaling of the items is controlled by the variable continuousIndex, described below. */
201+ ListView {
202+ id: listView
203+
204+ property int highlightIndex: -1
205+ property real minimumTileWidth: 0
206+ property real newContentX: disabledNewContentX
207+ property real pathItemCount: referenceWidth / referenceTileWidth
208+ property real tileAspectRatio: 1
209+
210+ /* The positioning and scaling of the items in the carousel is based on the variable
211+ 'continuousIndex', a continuous real variable between [0, 'carousel.model.count'],
212+ roughly representing the index of the item that is prioritised over the others.
213+ 'continuousIndex' is not linear, but is weighted depending on if it is close
214+ to the beginning of the content (beginning phase), in the middle (middle phase)
215+ or at the end (end phase).
216+ Each tile is scaled and transformed in proportion to the difference between
217+ its own index and continuousIndex.
218+ To efficiently calculate continuousIndex, we have these values:
219+ - 'gapToMiddlePhase' gap in pixels between beginning and middle phase
220+ - 'gapToEndPhase' gap in pixels between middle and end phase
221+ - 'kGapEnd' constant used to calculate 'continuousIndex' in end phase
222+ - 'kMiddleIndex' constant used to calculate 'continuousIndex' in middle phase
223+ - 'kXBeginningEnd' constant used to calculate 'continuousIndex' in beginning and end phase
224+ - 'realContentWidth' the width of all the delegates only (without header/footer)
225+ - 'realContentX' the 'contentX' of the listview ignoring the 'drawBuffer'
226+ - 'realWidth' the 'width' of the listview, as it is used as component. */
227+
228+ readonly property real gapToMiddlePhase: Math.min(realWidth / 2 - tileWidth / 2, (realContentWidth - realWidth) / 2)
229+ readonly property real gapToEndPhase: realContentWidth - realWidth - gapToMiddlePhase
230+ readonly property real kGapEnd: kMiddleIndex * (1 - gapToEndPhase / gapToMiddlePhase)
231+ readonly property real kMiddleIndex: (realWidth / 2) / tileWidth - 0.5
232+ readonly property real kXBeginningEnd: 1 / tileWidth + kMiddleIndex / gapToMiddlePhase
233+ readonly property real maximumItemTranslation: (listView.tileWidth * 3) / listView.scaleFactor
234+ readonly property real disabledNewContentX: -carousel.drawBuffer - 1
235+ readonly property real realContentWidth: contentWidth - 2 * carousel.drawBuffer
236+ readonly property real realContentX: contentX + carousel.drawBuffer
237+ readonly property real realPathItemCount: Math.min(realWidth / tileWidth, pathItemCount)
238+ readonly property real realWidth: carousel.width
239+ readonly property real referenceGapToMiddlePhase: realWidth / 2 - tileWidth / 2
240+ readonly property real referencePathItemCount: referenceWidth / referenceTileWidth
241+ readonly property real referenceWidth: 848
242+ readonly property real referenceTileWidth: 175
243+ readonly property real scaleFactor: tileWidth / referenceTileWidth
244+ readonly property real tileWidth: Math.max(realWidth / pathItemCount, minimumTileWidth)
245+ readonly property real tileHeight: tileWidth / tileAspectRatio
246+ readonly property real translationXViewFactor: 0.2 * (referenceGapToMiddlePhase / gapToMiddlePhase)
247+ readonly property real verticalMargin: (parent.height - tileHeight) / 2
248+ readonly property real visibleTilesScaleFactor: realPathItemCount / referencePathItemCount
249+
250+ anchors {
251+ fill: parent
252+ topMargin: verticalMargin
253+ bottomMargin: verticalMargin
254+ // extending the "drawing area"
255+ leftMargin: -carousel.drawBuffer
256+ rightMargin: -carousel.drawBuffer
257+ }
258+
259+ /* The header and footer help to "extend" the area, the listview draws items.
260+ This together with anchors.leftMargin and anchors.rightMargin. */
261+ header: Item {
262+ width: carousel.drawBuffer
263+ height: listView.tileHeight
264+ }
265+ footer: Item {
266+ width: carousel.drawBuffer
267+ height: listView.tileHeight
268+ }
269+
270+ boundsBehavior: Flickable.DragOverBounds
271+ cacheBuffer: carousel.cacheBuffer
272+ flickDeceleration: Math.max(1500 * Math.pow(realWidth / referenceWidth, 1.5), 1500) // 1500 is platform default
273+ maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
274+ orientation: ListView.Horizontal
275+
276+ function itemClicked(index, delegateItem) {
277+ listView.currentIndex = index
278+ var x = CarouselJS.getXFromContinuousIndex(index,
279+ realWidth,
280+ realContentWidth,
281+ tileWidth,
282+ gapToMiddlePhase,
283+ gapToEndPhase,
284+ carousel.drawBuffer)
285+
286+ if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
287+ /* We're clicking the selected item and
288+ we're in the neighbourhood of radius 1 pixel from it.
289+ Let's emit the clicked signal. */
290+ carousel.clicked(index, delegateItem.y)
291+ return
292+ }
293+
294+ stepAnimation.stop()
295+ newContentXAnimation.stop()
296+
297+ newContentX = x
298+ newContentXAnimation.start()
299+ }
300+
301+ function itemPressAndHold(index, delegateItem) {
302+ var x = CarouselJS.getXFromContinuousIndex(index,
303+ realWidth,
304+ realContentWidth,
305+ tileWidth,
306+ gapToMiddlePhase,
307+ gapToEndPhase,
308+ carousel.drawBuffer);
309+
310+ if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
311+ /* We're pressAndHold the selected item and
312+ we're in the neighbourhood of radius 1 pixel from it.
313+ Let's emit the pressAndHold signal. */
314+ carousel.pressAndHold(index, delegateItem.y);
315+ return;
316+ }
317+
318+ stepAnimation.stop();
319+ newContentXAnimation.stop();
320+
321+ newContentX = x;
322+ newContentXAnimation.start();
323+ }
324+
325+ onHighlightIndexChanged: {
326+ if (highlightIndex != -1) {
327+ itemClicked(highlightIndex)
328+ }
329+ }
330+
331+ onMovementStarted: {
332+ stepAnimation.stop()
333+ newContentXAnimation.stop()
334+ newContentX = disabledNewContentX
335+ }
336+ onMovementEnded: {
337+ if (realContentX > 0 && realContentX < realContentWidth - realWidth)
338+ stepAnimation.start()
339+ }
340+
341+ SmoothedAnimation {
342+ id: stepAnimation
343+
344 target: listView
345 property: "contentX"
346- from: listView.contentX
347- to: listView.newContentX
348- duration: 300
349+ to: CarouselJS.getXFromContinuousIndex(listView.selectedIndex,
350+ listView.realWidth,
351+ listView.realContentWidth,
352+ listView.tileWidth,
353+ listView.gapToMiddlePhase,
354+ listView.gapToEndPhase,
355+ carousel.drawBuffer)
356+ duration: 450
357+ velocity: 200
358 easing.type: Easing.InOutQuad
359 }
360- ScriptAction {
361- script: listView.newContentX = listView.disabledNewContentX
362- }
363- }
364-
365- readonly property int selectedIndex: Math.round(continuousIndex)
366- readonly property real continuousIndex: CarouselJS.getContinuousIndex(listView.realContentX,
367- listView.tileWidth,
368- listView.gapToMiddlePhase,
369- listView.gapToEndPhase,
370- listView.kGapEnd,
371- listView.kMiddleIndex,
372- listView.kXBeginningEnd)
373-
374- property real viewTranslation: CarouselJS.getViewTranslation(listView.realContentX,
375- listView.tileWidth,
376- listView.gapToMiddlePhase,
377- listView.gapToEndPhase,
378- listView.translationXViewFactor)
379-
380- delegate: Loader {
381- property bool explicitlyScaled: explicitScaleFactor == carousel.selectedItemScaleFactor
382- property real explicitScaleFactor: explicitScale ? carousel.selectedItemScaleFactor : 1.0
383- readonly property bool explicitScale: (!listView.moving ||
384- listView.realContentX <= 0 ||
385- listView.realContentX >= listView.realContentWidth - listView.realWidth) &&
386- listView.newContentX === listView.disabledNewContentX &&
387- index === listView.selectedIndex
388- readonly property real cachedTiles: listView.realPathItemCount + carousel.drawBuffer / listView.tileWidth
389- readonly property real distance: listView.continuousIndex - index
390- readonly property real itemTranslationScale: CarouselJS.getItemScale(0.5,
391- (index + 0.5), // good approximation of scale while changing selected item
392- listView.count,
393- listView.visibleTilesScaleFactor)
394- readonly property real itemScale: CarouselJS.getItemScale(distance,
395- listView.continuousIndex,
396- listView.count,
397- listView.visibleTilesScaleFactor)
398- readonly property real translationX: CarouselJS.getItemTranslation(index,
399- listView.selectedIndex,
400- distance,
401- itemScale,
402- itemTranslationScale,
403- listView.maximumItemTranslation)
404-
405- readonly property real xTransform: listView.viewTranslation + translationX * listView.scaleFactor
406- readonly property real center: x - listView.contentX + xTransform - drawBuffer + (width/2)
407-
408- width: listView.tileWidth
409- height: listView.tileHeight
410- scale: itemScale * explicitScaleFactor
411- sourceComponent: itemComponent
412- z: cachedTiles - Math.abs(index - listView.selectedIndex)
413-
414- transform: Translate {
415- x: xTransform
416- }
417-
418- Behavior on explicitScaleFactor {
419- SequentialAnimation {
420- ScriptAction {
421- script: if (!explicitScale)
422- explicitlyScaled = false
423- }
424+
425+ SequentialAnimation {
426+ id: newContentXAnimation
427+
428+ NumberAnimation {
429+ target: listView
430+ property: "contentX"
431+ from: listView.contentX
432+ to: listView.newContentX
433+ duration: 300
434+ easing.type: Easing.InOutQuad
435+ }
436+ ScriptAction {
437+ script: listView.newContentX = listView.disabledNewContentX
438+ }
439+ }
440+
441+ readonly property int selectedIndex: Math.round(continuousIndex)
442+ readonly property real continuousIndex: CarouselJS.getContinuousIndex(listView.realContentX,
443+ listView.tileWidth,
444+ listView.gapToMiddlePhase,
445+ listView.gapToEndPhase,
446+ listView.kGapEnd,
447+ listView.kMiddleIndex,
448+ listView.kXBeginningEnd)
449+
450+ property real viewTranslation: CarouselJS.getViewTranslation(listView.realContentX,
451+ listView.tileWidth,
452+ listView.gapToMiddlePhase,
453+ listView.gapToEndPhase,
454+ listView.translationXViewFactor)
455+
456+ delegate: Loader {
457+ property bool explicitlyScaled: explicitScaleFactor == carousel.selectedItemScaleFactor
458+ property real explicitScaleFactor: explicitScale ? carousel.selectedItemScaleFactor : 1.0
459+ readonly property bool explicitScale: (!listView.moving ||
460+ listView.realContentX <= 0 ||
461+ listView.realContentX >= listView.realContentWidth - listView.realWidth) &&
462+ listView.newContentX === listView.disabledNewContentX &&
463+ index === listView.selectedIndex
464+ readonly property real cachedTiles: listView.realPathItemCount + carousel.drawBuffer / listView.tileWidth
465+ readonly property real distance: listView.continuousIndex - index
466+ readonly property real itemTranslationScale: CarouselJS.getItemScale(0.5,
467+ (index + 0.5), // good approximation of scale while changing selected item
468+ listView.count,
469+ listView.visibleTilesScaleFactor)
470+ readonly property real itemScale: CarouselJS.getItemScale(distance,
471+ listView.continuousIndex,
472+ listView.count,
473+ listView.visibleTilesScaleFactor)
474+ readonly property real translationX: CarouselJS.getItemTranslation(index,
475+ listView.selectedIndex,
476+ distance,
477+ itemScale,
478+ itemTranslationScale,
479+ listView.maximumItemTranslation)
480+
481+ readonly property real xTransform: listView.viewTranslation + translationX * listView.scaleFactor
482+ readonly property real center: x - listView.contentX + xTransform - drawBuffer + (width/2)
483+
484+ width: listView.tileWidth
485+ height: listView.tileHeight
486+ scale: itemScale * explicitScaleFactor
487+ sourceComponent: itemComponent
488+ z: cachedTiles - Math.abs(index - listView.selectedIndex)
489+ opacity: carousel.shaderEnabled ? (highlightIndex === index ? 1.0 : 0.33) : 1.0
490+
491+ Behavior on opacity {
492 NumberAnimation {
493- duration: explicitScaleFactor === 1.0 ? 250 : 150
494- easing.type: Easing.InOutQuad
495- }
496- ScriptAction {
497- script: if (explicitScale)
498- explicitlyScaled = true
499- }
500- }
501- }
502-
503- onLoaded: {
504- item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; })
505- item.model = Qt.binding(function() { return model; })
506- }
507-
508- MouseArea {
509- id: mouseArea
510-
511- anchors.fill: parent
512-
513- onClicked: {
514- listView.itemClicked(index, item)
515- }
516-
517- onPressAndHold: {
518- listView.itemPressAndHold(index, item)
519- }
520- }
521- }
522+ duration: UbuntuAnimation.SnapDuration
523+ }
524+ }
525+
526+ transform: Translate {
527+ x: xTransform
528+ }
529+
530+ Behavior on explicitScaleFactor {
531+ SequentialAnimation {
532+ ScriptAction {
533+ script: if (!explicitScale)
534+ explicitlyScaled = false
535+ }
536+ NumberAnimation {
537+ duration: explicitScaleFactor === 1.0 ? 250 : 150
538+ easing.type: Easing.InOutQuad
539+ }
540+ ScriptAction {
541+ script: if (explicitScale)
542+ explicitlyScaled = true
543+ }
544+ }
545+ }
546+
547+ onLoaded: {
548+ item.explicitlyScaled = Qt.binding(function() { return explicitlyScaled; })
549+ item.model = Qt.binding(function() { return model; })
550+ }
551+
552+ MouseArea {
553+ id: mouseArea
554+
555+ anchors.fill: parent
556+
557+ onClicked: {
558+ listView.itemClicked(index, item)
559+ }
560+
561+ onPressAndHold: {
562+ listView.itemPressAndHold(index, item)
563+ }
564+ }
565+ }
566+ }
567+ }
568+
569+ ShaderEffectSource {
570+ id: shaderSource
571+ anchors.centerIn: parent
572+ sourceItem: shaderItem
573+ visible: carousel.shaderEnabled
574+ hideSource: visible
575+ width: 1
576+ height: 1
577+ }
578+
579+ ShaderEffect {
580+ anchors.fill: parent
581+ visible: carousel.shaderEnabled
582+ opacity: visible ? 0.6 : 1
583+
584+ Behavior on opacity {
585+ NumberAnimation {
586+ duration: 200 // Just like the OpenEffect in GenericScopeView.qml
587+ }
588+ }
589+
590+ property var src: shaderSource
591+
592+ vertexShader: "
593+ uniform highp mat4 qt_Matrix;
594+ attribute highp vec4 qt_Vertex;
595+ attribute highp vec2 qt_MultiTexCoord0;
596+ varying highp vec2 coord;
597+ void main() {
598+ coord = qt_MultiTexCoord0;
599+ gl_Position = qt_Matrix * qt_Vertex;
600+ }"
601+ fragmentShader: "
602+ varying highp vec2 coord;
603+ uniform sampler2D src;
604+ uniform lowp float qt_Opacity;
605+ void main() {
606+ gl_FragColor = texture2D(src, coord);
607+ gl_FragColor.a *= qt_Opacity;
608+ }"
609 }
610 }

Subscribers

People subscribed via source and target branches