~paulliu/unity8/zoomImage

« back to all changes in this revision

Viewing changes to qml/Stages/TransformedSpreadDelegate.qml

  • Committer: Ying-Chun Liu
  • Date: 2014-04-22 15:33:24 UTC
  • mfrom: (734.1.119 unity8)
  • Revision ID: paul.liu@canonical.com-20140422153324-9o7r3gh3dzczx4sr
Merge upstream
[ Albert Astals ]
* Fix last item X position Fixes clicking on the last item sometimes
  not working (LP: #1301871)
* Use upstart in ./run Makes it so that you can use the lock button on
  the device without getting that nasty hwc crash
* Remove AnimationControllerWithSignals.
* Use the correct delegate base item for the Carousel test
* Some simplification in DashContent Kill the ScopeDelegateMapper in
  favour of a simple if (that will eventually go away). Removal of all
  the fake scopes in the tests that added nothing of value to the
  tests. Removal of movementEnded signal that was unused. Removal of
  movementStarted and positionedAtBeginning signals that were being
  used as function calls. Rework DashContent tests so they what the
  function does what it is supposed to do instead of just making sure
  QML signals work .
* Improve Card creation time by adding loaders that make sure only
  what's needed is loaded In my computer it goes from RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotSummaryMode
  l": 3.217 msecs per iteration (total: 3,218, iterations: 1000)
  RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotModel":
  1.647 msecs per iteration (total: 1,648, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtSubtitleModel": 1.514
  msecs per iteration (total: 1,515, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtModel": 1.471 msecs per
  iteration (total: 1,471, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardArtModel": 1.447 msecs per
  iteration (total: 1,448, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardTitleModel": 1.276 msecs per
  iteration (total: 1,276, iterations: 1000) to RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotSummaryMode
  l": 2.916 msecs per iteration (total: 2,917, iterations: 1000)
  RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtSubtitleMascotModel":
  1.504 msecs per iteration (total: 1,504, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtSubtitleModel": 1.060
  msecs per iteration (total: 1,061, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardTitleArtModel": 1.052 msecs per
  iteration (total: 1,053, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardArtModel": 0.727 msecs per
  iteration (total: 728, iterations: 1000) RESULT :
  qmltestrunner::benchmark_time:"cardTitleModel": 0.817 msecs per
  iteration (total: 818, iterations: 1000) (LP: #1297197)
[ Allan LeSage ]
* DashApps emulator get_applications should return a list ordered by
  visible y, x.
[ Andrea Cimitan ]
* Workaround for lp1301309 until fixes for palette in ui toolkit (LP:
  #1301309)
[ Leo Arias ]
* Reverted the change that returns application cards instead of
  titles.
[ Nick Dedekind ]
* Indicator services started by unity8 upstart configuration rather
  than manual emmision from indicator manager.
[ Mirco Müller ]
* Fix notification ap-test assertions.
[ Michael Terry ]
* Use new tablet and phone backgrounds from Design.
[ Michael Zanetti ]
* workaround the QTestLogger assertion issue with make tryXyz and our
  custom uqmlscene
[ Michael Terry ]
* When an application requests focus, handle it in Shell.qml by hiding
  the greeter and stopping any edge demo. (LP: #1227753)
[ Leo Arias ]
* Use subprocess.check_call when caling url-dispatcher, so an error
  will be raised if it fails.
* Test application life cycle with fake apps, instead of messaging and
  address book.
[ Didier Roche ]
* Resync trunk with previous revert upload
[ Michał Sawicz ]
* Set the Qt.ImhNoPredictiveText flag on wifi password field, fixes
  lp:1291575 (LP: #1291575)
[ Albert Astals ]
* Take into account the originY when specifying the delegate ranges
  Fixes bug #1300302 (LP: #1300302)
[ CI bot ]
* Resync trunk
[ Allan LeSage ]
* Swiping open an indicator must show its correct title--protect
  against lp:1253804 . (LP: #1253804)
[ Alexander Sack ]
* Fix TypeError: issue seen in system_integration autopilot test on
  image 279. (LP: #1303685)
[ Bill Filler ]
* Set the Qt.ImhNoPredictiveText flag on wifi password field, fixes
  lp:1291575 (LP: #1291575)
[ Leo Arias ]
* Added a search autopilot helper.
[ Michael Terry ]
* Provide a all-in-one script for getting a device to an unlocked
  state.
* Revert to previous version as it's linked to latest sdk change which
  is making gallery-app AP tests failing on the CI dashboard
[ Albert Astals ]
* Adapt to new TabBar
[ Michael Terry ]
* Re-enable test_networkmanager_integration autopilot test on phone
  platforms
[ CI bot ]
* Resync trunk
[ Leo Arias ]
* Reverted the open_preview autopilot helper to return a Preview
  object.
[ Albert Astals ]
* If not running in Mir load the "fake" application manager (LP:
  #1301547)
* Remove unused properties from DashRenderer
[ Michael Zanetti ]
* Fix tests after right edge merge. Drop old stages tests. Fix right
  edge tests if someone doesn't have the GRID_UNIT_PX exported. make
  GenericScopeView test more robust that broke because the ordering
  changed
* add "make xvfbtestSomething" target to run qml tests in xvfb
* make the "make test" commit hook work again
[ Michał Sawicz ]
* Bump version to ensure incompatibility with previous Unity.Application
  implementations.
* We'll only have the unity-mir and mock Ubuntu.Application plugins
  now, no need for mangling the import paths.
[ Michal Hruby ]
* Remove the albumart image provider. (LP: #1262711)
* Don't reset search string after 2 seconds. (LP: #1297246)
[ James Henstridge ]
* Remove the albumart image provider. (LP: #1262711)
[ Albert Astals ]
* Carousel: Add test to make sure we only create the needed delegates
  and not more
* LVWPH: Remove processEvents() call from updatePolish() It causes
  some reentrancy issues and in some times you end up in polishItems()
  with items that have been deleted because you called processEvents()
  This means i need a small tweak in itemGeometryChanged to not
  reposition items if we are inside a setContentHeight call and two
  small tweaks to tests since now things happen in a different order
  and numbers are different (though equivalent) (LP: #1297240)
* Card.qml binding loops are gone. hooray \o/ Also made the aspect
  properties readonly
[ Mirco Müller ]
* A potential fix for "Cannot read property 'state' of null"-failure
  on Jenkins with the VisualSnapDecisionsQueue QML-test of
  notifications.
[ Michael Terry ]
* Pass user's preference for auto-brightness on to powerd. (LP:
  #1273174)
[ Michael Zanetti ]
* Registers a dummy QObject as QTestRootObject in uqmlscene in order
  to fix make trySomething with Qt 5.2.
* For now, have libunity-private depending on libunity-core-6.0-9 as the
  gsettings schema is here. The dependency wasn't direct and dropped from
  Touch image #271. Consequently, unity8 didn't start (gsettings
  segfaulting).
  Proper strategy will be to include the schema in another package to only
  pull it.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2014 Canonical Ltd.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser General Public License as published by
 
6
 * the Free Software Foundation; version 3.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
11
 * GNU Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authors: Michael Zanetti <michael.zanetti@canonical.com>
 
17
*/
 
18
 
 
19
import QtQuick 2.0
 
20
import Utils 0.1
 
21
import Ubuntu.Components 0.1
 
22
 
 
23
SpreadDelegate {
 
24
    id: root
 
25
 
 
26
    property bool selected: false
 
27
    property bool otherSelected: false
 
28
 
 
29
    // The progress animates the tiles. A value > 0 makes it appear from the right edge. At 1 it reaches the end position.
 
30
    property real progress: 0
 
31
    // This is required to snap tile 1 during phase 1 and 2.
 
32
    property real animatedProgress: 0
 
33
 
 
34
    property real startAngle: 0
 
35
    property real endAngle: 0
 
36
 
 
37
    property real startScale: 1
 
38
    property real endScale: 1
 
39
 
 
40
    // Specific to just one tile
 
41
    property real tile1StartScale: startScale + .4
 
42
    property real tile0SnapAngle: 10
 
43
 
 
44
    property real startDistance: units.gu(5)
 
45
    property real endDistance: units.gu(.5)
 
46
 
 
47
    onSelectedChanged: {
 
48
        if (selected) {
 
49
            priv.snapshot();
 
50
        }
 
51
        priv.isSelected = selected;
 
52
    }
 
53
 
 
54
    onOtherSelectedChanged: {
 
55
        if (otherSelected) {
 
56
            priv.snapshot();
 
57
        }
 
58
        priv.otherSelected = otherSelected;
 
59
    }
 
60
 
 
61
    Connections {
 
62
        target: spreadView
 
63
        onPhaseChanged: {
 
64
            if (spreadView.phase == 1) {
 
65
                if (index == 0) {
 
66
                    priv.phase2startTranslate = priv.easingAnimation(0, spreadView.positionMarker4, 0, -spreadView.width, spreadView.positionMarker4) + spreadView.width;
 
67
                    priv.phase2startAngle = priv.easingAnimation(0, spreadView.positionMarker4, root.startAngle, root.endAngle, spreadView.positionMarker4);
 
68
                    priv.phase2startScale = priv.easingAnimation(0, spreadView.positionMarker4, root.startScale, root.endScale, spreadView.positionMarker4);
 
69
                    priv.phase2startTopMarginProgress = priv.easingAnimation(0, 1, 0, 1, spreadView.positionMarker4);
 
70
                } else if (index == 1) {
 
71
                    // find where the main easing for Tile 1 would be when reaching phase 2
 
72
                    var phase2Progress = spreadView.positionMarker4 - spreadView.tileDistance / spreadView.width;
 
73
                    priv.phase2startTranslate = priv.easingAnimation(0, phase2Progress, 0, -spreadView.width + root.endDistance, phase2Progress);
 
74
                    priv.phase2startAngle = priv.easingAnimation(0, phase2Progress, root.startAngle, root.endAngle, phase2Progress);
 
75
                    priv.phase2startScale = priv.easingAnimation(0, phase2Progress, root.startScale, root.endScale, phase2Progress);
 
76
                    priv.phase2startTopMarginProgress = priv.easingAnimation(0, 1, 0, spreadView.positionMarker4, phase2Progress);
 
77
                }
 
78
            }
 
79
        }
 
80
    }
 
81
 
 
82
    QtObject {
 
83
        id: priv
 
84
        property bool isSelected: false
 
85
        property bool otherSelected: false
 
86
        property real selectedProgress
 
87
        property real selectedXTranslate
 
88
        property real selectedAngle
 
89
        property real selectedScale
 
90
        property real selectedOpacity
 
91
        property real selectedTopMarginProgress
 
92
 
 
93
        // Those values are needed as target values for the end of phase 1.
 
94
        // As they are static values, lets calculate them once when entering phase 1 instead of calculating them in each animation pass.
 
95
        property real phase2startTranslate
 
96
        property real phase2startAngle
 
97
        property real phase2startScale
 
98
        property real phase2startTopMarginProgress
 
99
 
 
100
        function snapshot() {
 
101
            selectedProgress = root.progress;
 
102
            selectedXTranslate = xTranslate;
 
103
            selectedAngle = angle;
 
104
            selectedScale = scale;
 
105
            selectedOpacity = opacity;
 
106
            selectedTopMarginProgress = topMarginProgress;
 
107
        }
 
108
 
 
109
        // This calculates how much negative progress there can be if unwinding the spread completely
 
110
        // the progress for each tile starts at 0 when it crosses the right edge, so the later a tile comes in,
 
111
        // the bigger its negativeProgress can be.
 
112
        property real negativeProgress: {
 
113
            if (index == 1 && spreadView.phase < 2) {
 
114
                return 0;
 
115
            }
 
116
            return -index * spreadView.tileDistance / spreadView.width;
 
117
        }
 
118
 
 
119
        function linearAnimation(startProgress, endProgress, startValue, endValue, progress) {
 
120
            // progress : progressDiff = value : valueDiff => value = progress * valueDiff / progressDiff
 
121
            return (progress - startProgress) * (endValue - startValue) / (endProgress - startProgress) + startValue;
 
122
        }
 
123
 
 
124
        function easingAnimation(startProgress, endProgress, startValue, endValue, progress) {
 
125
            helperEasingCurve.progress = progress - startProgress;
 
126
            helperEasingCurve.period = endProgress - startProgress;
 
127
            return helperEasingCurve.value * (endValue - startValue) + startValue;
 
128
        }
 
129
 
 
130
        property real animatedEndDistance: linearAnimation(0, 2, root.endDistance, 0, root.progress)
 
131
 
 
132
        // The following blocks handle the animation of the tile in the spread.
 
133
        // At the beginning, each tile is attached at the right edge, outside the screen.
 
134
        // The progress for each tile starts at 0 and it reaches its end position at a progress of 1.
 
135
        // The first phases are handled special for the first 2 tiles. as we do the alt-tab and snapping in there
 
136
        // Once we reached phase 3, the animation is the same for all tiles.
 
137
        // When a tile is selected, the animation state is snapshotted, and the spreadView is unwound (progress animates
 
138
        // back to negativeProgress). All tiles are kept in place and faded out to 0 opacity except
 
139
        // the selected tile, which is animated from the snapshotted position to be fullscreen.
 
140
 
 
141
        property real xTranslate: {
 
142
            if (otherSelected) {
 
143
                if (spreadView.phase < 2 && index == 0) {
 
144
                    return linearAnimation(selectedProgress, negativeProgress,
 
145
                                           selectedXTranslate, selectedXTranslate - spreadView.tileDistance, root.progress);
 
146
                }
 
147
 
 
148
                return selectedXTranslate;
 
149
            }
 
150
 
 
151
            switch (index) {
 
152
            case 0:
 
153
                if (spreadView.phase == 0) {
 
154
                    return Math.min(0, linearAnimation(0, spreadView.positionMarker2,
 
155
                                                       0, -spreadView.width * .25, root.animatedProgress));
 
156
                } else if (spreadView.phase == 1){
 
157
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
158
                                           -spreadView.width * .25, priv.phase2startTranslate, root.progress);
 
159
                } else if (!priv.isSelected){ // phase 2
 
160
                    // Apply the same animation as with the rest but add spreadView.width to align it with the others.
 
161
                    return -easingCurve.value * spreadView.width + spreadView.width;
 
162
                } else if (priv.isSelected) {
 
163
                    return linearAnimation(selectedProgress, negativeProgress, selectedXTranslate, 0, root.progress);
 
164
                }
 
165
 
 
166
            case 1:
 
167
                if (spreadView.phase == 0 && !priv.isSelected) {
 
168
                    return linearAnimation(0, spreadView.positionMarker2,
 
169
                                           0, -spreadView.width * spreadView.snapPosition, root.animatedProgress);
 
170
                } else if (spreadView.phase == 1 && !priv.isSelected) {
 
171
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
172
                                           -spreadView.width * spreadView.snapPosition, priv.phase2startTranslate,
 
173
                                           root.progress);
 
174
                }
 
175
            }
 
176
 
 
177
            if (priv.isSelected) {
 
178
                // Distance to left edge
 
179
                var targetTranslate = -spreadView.width - ((index - 1) * root.startDistance);
 
180
                return linearAnimation(selectedProgress, negativeProgress,
 
181
                                       selectedXTranslate, targetTranslate, root.progress);
 
182
            }
 
183
 
 
184
            // Fix it at the right edge...
 
185
            var rightEdgeOffset =  -((index - 1) * root.startDistance);
 
186
            // ...and use our easing to move them to the left. Stop a bit earlier for each tile
 
187
            return -easingCurve.value * spreadView.width + (index * animatedEndDistance) + rightEdgeOffset;
 
188
 
 
189
        }
 
190
 
 
191
        property real angle: {
 
192
            if (priv.otherSelected) {
 
193
                return priv.selectedAngle;
 
194
            }
 
195
            if (priv.isSelected) {
 
196
                return linearAnimation(selectedProgress, negativeProgress, selectedAngle, 0, root.progress);
 
197
            }
 
198
            switch (index) {
 
199
            case 0:
 
200
                if (spreadView.phase == 0) {
 
201
                    return Math.max(0, linearAnimation(0, spreadView.positionMarker2,
 
202
                                                       0, root.tile0SnapAngle, root.animatedProgress));
 
203
                } else if (spreadView.phase == 1) {
 
204
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
205
                                           root.tile0SnapAngle, phase2startAngle, root.progress);
 
206
                }
 
207
            case 1:
 
208
                if (spreadView.phase == 0) {
 
209
                    return linearAnimation(0, spreadView.positionMarker2, root.startAngle,
 
210
                                           root.startAngle * (1-spreadView.snapPosition), root.animatedProgress);
 
211
                } else if (spreadView.phase == 1) {
 
212
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
213
                                           root.startAngle * (1-spreadView.snapPosition), priv.phase2startAngle,
 
214
                                           root.progress);
 
215
                }
 
216
            }
 
217
            return root.startAngle - easingCurve.value * (root.startAngle - root.endAngle);
 
218
        }
 
219
 
 
220
        property real scale: {
 
221
            if (priv.otherSelected) {
 
222
                return priv.selectedScale;
 
223
            }
 
224
            if (priv.isSelected) {
 
225
                return linearAnimation(selectedProgress, negativeProgress, selectedScale, 1, root.progress);
 
226
            }
 
227
 
 
228
            switch (index) {
 
229
            case 0:
 
230
                if (spreadView.phase == 0) {
 
231
                    return 1;
 
232
                } else if (spreadView.phase == 1) {
 
233
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
234
                                           1, phase2startScale, root.progress);
 
235
                }
 
236
            case 1:
 
237
                if (spreadView.phase == 0) {
 
238
                    var targetScale = tile1StartScale - ((tile1StartScale - 1) * spreadView.snapPosition);
 
239
                    return linearAnimation(0, spreadView.positionMarker2,
 
240
                                           root.tile1StartScale, targetScale, root.animatedProgress);
 
241
                } else if (spreadView.phase == 1) {
 
242
                    var startScale = tile1StartScale - ((tile1StartScale - 1) * spreadView.snapPosition);
 
243
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
244
                                           startScale, priv.phase2startScale, root.progress);
 
245
                }
 
246
            }
 
247
            return root.startScale - easingCurve.value * (root.startScale - root.endScale);
 
248
        }
 
249
 
 
250
        property real opacity: {
 
251
            if (priv.otherSelected) {
 
252
                return linearAnimation (selectedProgress, Math.max(0, selectedProgress - .5),
 
253
                                        selectedOpacity, 0, root.progress);
 
254
            }
 
255
            if (index == 0) {
 
256
                switch (spreadView.phase) {
 
257
                case 0:
 
258
                    return linearAnimation(0, spreadView.positionMarker2, 1, .3, root.animatedProgress);
 
259
                case 1:
 
260
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
261
                                           .3, 1, root.animatedProgress);
 
262
                }
 
263
            }
 
264
 
 
265
            return 1;
 
266
        }
 
267
 
 
268
        property real topMarginProgress: {
 
269
            if (priv.isSelected) {
 
270
                return linearAnimation(selectedProgress, negativeProgress, selectedTopMarginProgress, 0, root.progress);
 
271
            }
 
272
 
 
273
            switch (index) {
 
274
            case 0:
 
275
                if (spreadView.phase == 0) {
 
276
                    return 0;
 
277
                } else if (spreadView.phase == 1) {
 
278
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
279
                                           0, priv.phase2startTopMarginProgress, root.progress);
 
280
                }
 
281
                break;
 
282
            case 1:
 
283
                if (spreadView.phase == 0) {
 
284
                    return 0;
 
285
                } else if (spreadView.phase == 1) {
 
286
                    return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
 
287
                                           0, priv.phase2startTopMarginProgress, root.progress);
 
288
                }
 
289
            }
 
290
 
 
291
            return easingCurve.value;
 
292
        }
 
293
    }
 
294
 
 
295
    transform: [
 
296
        Rotation {
 
297
            origin { x: 0; y: spreadView.height / 2 }
 
298
            axis { x: 0; y: 1; z: 0 }
 
299
            angle: priv.angle
 
300
        },
 
301
        Scale {
 
302
            origin { x: 0; y: spreadView.height / 2 }
 
303
            xScale: priv.scale
 
304
            yScale: xScale
 
305
        },
 
306
        Translate {
 
307
            x: priv.xTranslate
 
308
        }
 
309
    ]
 
310
    opacity: priv.opacity
 
311
    topMarginProgress: priv.topMarginProgress
 
312
 
 
313
    EasingCurve {
 
314
        id: easingCurve
 
315
        type: EasingCurve.OutSine
 
316
        period: 1 - spreadView.positionMarker2
 
317
        progress: root.animatedProgress
 
318
    }
 
319
 
 
320
    // This is used as a calculation helper to figure values for progress other than the current one
 
321
    // Do not bind anything to this...
 
322
    EasingCurve {
 
323
        id: helperEasingCurve
 
324
        type: easingCurve.type
 
325
        period: easingCurve.period
 
326
    }
 
327
}