on xenial help sign in
inital try on unifying the stages
ffcc69aMichael Zanetti
plugins/Ubuntu/Gestures/TouchGate.cpp+1−1
@@ -59,7 +59,7 @@ void TouchGate::touchEvent(QTouchEvent *event)
59 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
59 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
60
60
61 if (touchPoint.state() == Qt::TouchPointPressed) {
61 if (touchPoint.state() == Qt::TouchPointPressed) {
62− Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
62+// Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
63 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
63 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
64 m_touchInfoMap[touchPoint.id()].ended = false;
64 m_touchInfoMap[touchPoint.id()].ended = false;
65 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
65 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
qml/Shell.qml+7−8
@@ -258,6 +258,8 @@ Item {
258 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
258 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
259 ? "phone"
259 ? "phone"
260 : shell.usageScenario
260 : shell.usageScenario
261+
262+ source: "Stages/DesktopStage.qml"
261 readonly property string qmlComponent: {
263 readonly property string qmlComponent: {
262 if(shell.mode === "greeter") {
264 if(shell.mode === "greeter") {
263 return "Stages/ShimStage.qml"
265 return "Stages/ShimStage.qml"
@@ -269,14 +271,6 @@ Item {
269 return "Stages/DesktopStage.qml";
271 return "Stages/DesktopStage.qml";
270 }
272 }
271 }
273 }
272− // TODO: Ensure the current stage is destroyed before the new one gets loaded.
273− // Currently the new one will get loaded while the old is still hanging
274− // around for a bit, which might lead to conflicts where both stages
275− // change the model simultaneously.
276− onQmlComponentChanged: {
277− if (item) item.stageAboutToBeUnloaded();
278− source = qmlComponent;
279− }
280
274
281 property bool interactive: (!greeter || !greeter.shown)
275 property bool interactive: (!greeter || !greeter.shown)
282 && panel.indicators.fullyClosed
276 && panel.indicators.fullyClosed
@@ -285,6 +279,11 @@ Item {
285
279
286 onInteractiveChanged: { if (interactive) { focus = true; } }
280 onInteractiveChanged: { if (interactive) { focus = true; } }
287
281
282+ Binding {
283+ target: applicationsDisplayLoader.item
284+ property: "mode"
285+ value: applicationsDisplayLoader.usageScenario == "phone" ? "staged" : "windowed"
286+ }
288 Binding {
287 Binding {
289 target: applicationsDisplayLoader.item
288 target: applicationsDisplayLoader.item
290 property: "focus"
289 property: "focus"
qml/Stages/DecoratedWindow.qml+6−3
@@ -32,7 +32,10 @@ FocusScope {
32 readonly property alias title: applicationWindow.title
32 readonly property alias title: applicationWindow.title
33 property alias fullscreen: applicationWindow.fullscreen
33 property alias fullscreen: applicationWindow.fullscreen
34
34
35+ // Whether we want it to sho in general
36+ property bool showDecoration: true
37+ // Whether it is actually shown. Even if showDecoration is true, this might be false for other reasons (e.g. app is fullscreened)
35− readonly property bool decorationShown: !fullscreen
38+ readonly property bool decorationShown: showDecoration && !fullscreen
36 property bool highlightShown: false
39 property bool highlightShown: false
37 property real shadowOpacity: 1
40 property real shadowOpacity: 1
38
41
@@ -96,9 +99,9 @@ FocusScope {
96 id: applicationWindow
99 id: applicationWindow
97 objectName: "appWindow"
100 objectName: "appWindow"
98 anchors.top: parent.top
101 anchors.top: parent.top
99− anchors.topMargin: decoration.height
102+ anchors.topMargin: root.decorationShown ? decoration.height : 0
100 anchors.left: parent.left
103 anchors.left: parent.left
101− requestedHeight: root.requestedHeight - (root.decorationShown ? decoration.height : 0)
104+ requestedHeight: root.requestedHeight
102 interactive: true
105 interactive: true
103 focus: true
106 focus: true
104 }
107 }
qml/Stages/DesktopSpreadDelegate.qml+55−19
@@ -33,6 +33,26 @@ Item {
33 property int windowWidth: surface ? surface.size.width : 0
33 property int windowWidth: surface ? surface.size.width : 0
34 property int windowHeight: surface ? surface.size.height : 0
34 property int windowHeight: surface ? surface.size.height : 0
35
35
36+ property alias requestedHeight: applicationWindow.requestedHeight
37+ property alias requestedWidth: applicationWindow.requestedWidth
38+
39+ property alias minimumWidth: applicationWindow.minimumWidth
40+ property alias minimumHeight: applicationWindow.minimumHeight
41+ property alias maximumWidth: applicationWindow.maximumWidth
42+ property alias maximumHeight: applicationWindow.maximumHeight
43+ property alias widthIncrement: applicationWindow.widthIncrement
44+ property alias heightIncrement: applicationWindow.heightIncrement
45+
46+ property alias fullscreen: applicationWindow.fullscreen
47+ property alias title: applicationWindow.title
48+ property alias showDecoration: applicationWindow.showDecoration
49+ property alias active: applicationWindow.active
50+
51+ signal close()
52+ signal maximize()
53+ signal minimize()
54+ signal decorationPressed()
55+
36 state: "normal"
56 state: "normal"
37 states: [
57 states: [
38 State {
58 State {
@@ -49,6 +69,7 @@ Item {
49 target: applicationWindow
69 target: applicationWindow
50 itemScale: Math.max(root.width / root.windowWidth, root.height / root.windowHeight)
70 itemScale: Math.max(root.width / root.windowWidth, root.height / root.windowHeight)
51 interactive: false
71 interactive: false
72+ showDecoration: false
52 }
73 }
53 PropertyChanges {
74 PropertyChanges {
54 target: clipper
75 target: clipper
@@ -92,27 +113,42 @@ Item {
92 id: clipper
113 id: clipper
93 anchors.fill: parent
114 anchors.fill: parent
94
115
95− ApplicationWindow {
116+ DecoratedWindow {
96 id: applicationWindow
117 id: applicationWindow
97− objectName: application ? "appWindow_" + application.appId : "appWindow_null"
118+ objectName: "decoratedWindow"
98− anchors.top: parent.top
119+ anchors.left: root.left
99− anchors.topMargin: 0
120+ anchors.top: root.top
100− anchors.left: parent.left
121+ active: root.focus
101− width: root.windowWidth
122+ focus: true
102− height: root.windowHeight
123+ showDecoration: true
103− interactive: false
124+
104− resizeSurface: false
125+ onClose: root.close()
105− focus: false
126+ onMaximize: root.maximize()
106−
127+ onMinimize: root.minimize()
107− property real itemScale: 1
128+ onDecorationPressed: root.decorationPressed()
108− transform: [
109− Scale {
110− origin.x: 0; origin.y: 0
111− xScale: applicationWindow.itemScale
112− yScale: applicationWindow.itemScale
113− }
114− ]
115 }
129 }
130+
131+// ApplicationWindow {
132+// id: applicationWindow
133+// objectName: application ? "appWindow_" + application.appId : "appWindow_null"
134+// anchors.top: parent.top
135+// anchors.topMargin: 0
136+// anchors.left: parent.left
137+// width: root.windowWidth
138+// height: root.windowHeight
139+// interactive: false
140+// resizeSurface: false
141+// focus: false
142+
143+// property real itemScale: 1
144+// transform: [
145+// Scale {
146+// origin.x: 0; origin.y: 0
147+// xScale: applicationWindow.itemScale
148+// yScale: applicationWindow.itemScale
149+// }
150+// ]
151+// }
116 }
152 }
117
153
118 Rectangle {
154 Rectangle {
qml/Stages/DesktopStage.qml+221−46
@@ -37,8 +37,10 @@ AbstractStage {
37 }
37 }
38 }
38 }
39
39
40+ property string mode: "staged"
41+
40 // Used by TutorialRight
42 // Used by TutorialRight
41− property bool spreadShown: spread.state == "altTab"
43+ property bool spreadShown: state == "altTab"
42
44
43 mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
45 mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
44
46
@@ -57,7 +59,7 @@ AbstractStage {
57 GlobalShortcut {
59 GlobalShortcut {
58 id: showSpreadShortcut
60 id: showSpreadShortcut
59 shortcut: Qt.MetaModifier|Qt.Key_W
61 shortcut: Qt.MetaModifier|Qt.Key_W
60− onTriggered: spread.state = "altTab"
62+ onTriggered: state = "altTab"
61 }
63 }
62
64
63 GlobalShortcut {
65 GlobalShortcut {
@@ -104,8 +106,8 @@ AbstractStage {
104 Connections {
106 Connections {
105 target: root.topLevelSurfaceList
107 target: root.topLevelSurfaceList
106 onCountChanged: {
108 onCountChanged: {
107− if (spread.state == "altTab") {
109+ if (root.state == "spread") {
108− spread.cancel();
110+ priv.goneToSpread = false;
109 }
111 }
110 }
112 }
111 }
113 }
@@ -116,13 +118,15 @@ AbstractStage {
116
118
117 property var focusedAppDelegate: null
119 property var focusedAppDelegate: null
118 onFocusedAppDelegateChanged: {
120 onFocusedAppDelegateChanged: {
119− if (spread.state == "altTab") {
121+ if (root.state == "spread") {
120− spread.state = "";
122+ goneToSpread = false;
121 }
123 }
122 }
124 }
123
125
124 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
126 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
125
127
128+ property bool goneToSpread: false
129+
126 function updateForegroundMaximizedApp() {
130 function updateForegroundMaximizedApp() {
127 var found = false;
131 var found = false;
128 for (var i = 0; i < appRepeater.count && !found; i++) {
132 for (var i = 0; i < appRepeater.count && !found; i++) {
@@ -180,12 +184,12 @@ AbstractStage {
180 target: PanelState
184 target: PanelState
181 property: "title"
185 property: "title"
182 value: {
186 value: {
183− if (priv.focusedAppDelegate !== null && spread.state == "") {
187+// if (priv.focusedAppDelegate !== null && spread.state == "") {
184− if (priv.focusedAppDelegate.maximized)
188+// if (priv.focusedAppDelegate.maximized)
185− return priv.focusedAppDelegate.title
189+// return priv.focusedAppDelegate.title
186− else
190+// else
187− return priv.focusedAppDelegate.appName
191+// return priv.focusedAppDelegate.appName
188− }
192+// }
189 return ""
193 return ""
190 }
194 }
191 when: priv.focusedAppDelegate
195 when: priv.focusedAppDelegate
@@ -231,6 +235,25 @@ AbstractStage {
231 when: !appRepeater.startingUp && root.parent
235 when: !appRepeater.startingUp && root.parent
232 }
236 }
233
237
238+ states: [
239+ State {
240+ name: "spread"; when: root.altTabPressed || priv.goneToSpread
241+ },
242+ State {
243+ name: "stagedrightedge"; when: rightEdgeDragArea.dragging && root.mode == "staged"
244+ },
245+ State {
246+ name: "windowedrightedge"; when: rightEdgeDragArea.dragging && root.mode == "windowed"
247+ },
248+ State {
249+ name: "staged"; when: root.mode === "staged"
250+ },
251+ State {
252+ name: "windowed"; when: root.mode === "windowed"
253+ }
254+ ]
255+ onStateChanged: print("spread going to state:", state)
256+
234 FocusScope {
257 FocusScope {
235 id: appContainer
258 id: appContainer
236 objectName: "appContainer"
259 objectName: "appContainer"
@@ -298,6 +321,8 @@ AbstractStage {
298
321
299 readonly property var surface: model.surface
322 readonly property var surface: model.surface
300
323
324+ property real angle: 0
325+
301 function claimFocus() {
326 function claimFocus() {
302 if (spread.state == "altTab") {
327 if (spread.state == "altTab") {
303 spread.cancel();
328 spread.cancel();
@@ -378,7 +403,7 @@ AbstractStage {
378 && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
403 && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
379 )
404 )
380 || decoratedWindow.fullscreen
405 || decoratedWindow.fullscreen
381− || (spread.state == "altTab" && index === spread.highlightedIndex)
406+ // || (root.state == "altTab" && index === spread.highlightedIndex)
382
407
383 function close() {
408 function close() {
384 model.surface.close();
409 model.surface.close();
@@ -440,29 +465,80 @@ AbstractStage {
440 duration: UbuntuAnimation.SnapDuration
465 duration: UbuntuAnimation.SnapDuration
441 }
466 }
442
467
468+ SpreadMaths {
469+ id: spreadMaths
470+ itemIndex: index
471+ totalItems: appRepeater.count
472+ flickable: floatingFlickable
473+ }
474+ StagedRightEdgeMaths {
475+ id: stagedRightEdgeMaths
476+ itemIndex: index
477+ sceneWidth: root.width
478+ sceneHeight: root.height
479+ progress: 0
480+ targetX: spreadMaths.animatedX
481+ targetAngle: spreadMaths.animatedAngle
482+ }
483+
484+ transform: [
485+ Scale {
486+ origin.x: itemScaleOriginX
487+ origin.y: itemScaleOriginY
488+ xScale: itemScale
489+ yScale: itemScale
490+ },
491+ Rotation {
492+// origin { x: 0; y: (clippedSpreadDelegate.height - (clippedSpreadDelegate.height * itemScale / 2)) }
493+ axis { x: 0; y: 1; z: 0 }
494+ angle: appDelegate.angle
495+ }
496+ ]
497+
498+ onRequestedWidthChanged: if (index == 0) print("requestedWidth", requestedWidth)
443 states: [
499 states: [
444 State {
500 State {
445− name: "fullscreen"; when: decoratedWindow.fullscreen && !appDelegate.minimized
501+ name: "spread"; when: root.state == "spread"
502+ PropertyChanges { target: appDelegate;
503+ x: spreadMaths.animatedX
504+ y: spreadMaths.animatedY
505+ z: index
506+ angle: spreadMaths.animatedAngle
507+ }
508+ PropertyChanges { target: decoratedWindow; showDecoration: false }
509+ },
510+ State {
511+ name: "stagedrightedge"; when: root.state == "stagedrightedge"
446 PropertyChanges {
512 PropertyChanges {
513+ target: stagedRightEdgeMaths
514+ progress: rightEdgeDragArea.progress
515+ }
516+ PropertyChanges {
447− target: appDelegate;
517+ target: appDelegate
448− x: 0;
449− y: -PanelState.panelHeight
518+ y: PanelState.panelHeight
450− requestedWidth: appContainer.width;
519+ x: stagedRightEdgeMaths.animatedX
451− requestedHeight: appContainer.height;
520+ requestedWidth: stagedRightEdgeMaths.animatedWidth
521+ requestedHeight: stagedRightEdgeMaths.animatedHeight
522+ angle: stagedRightEdgeMaths.animatedAngle
523+ z: index
452 }
524 }
525+ PropertyChanges { target: decoratedWindow; showDecoration: false }
453 },
526 },
454 State {
527 State {
455− name: "normal";
528+ name: "staged"; when: root.state == "staged"
456− when: !appDelegate.maximized && !appDelegate.minimized
457− && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
458 PropertyChanges {
529 PropertyChanges {
459− target: appDelegate;
530+ target: appDelegate
460− visuallyMinimized: false;
531+ x: 0; y: 0
461− visuallyMaximized: false
532+ visuallyMaximized: true
533+ }
534+ PropertyChanges {
535+ target: decoratedWindow
536+ requestedWidth: appContainer.width - root.leftMargin;
537+ requestedHeight: appContainer.height;
462 }
538 }
463 },
539 },
464 State {
540 State {
465− name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
541+ name: "maximized"; when: root.state === "windowed" && appDelegate.maximized && !appDelegate.minimized
466 PropertyChanges {
542 PropertyChanges {
467 target: appDelegate;
543 target: appDelegate;
468 x: root.leftMargin;
544 x: root.leftMargin;
@@ -476,6 +552,26 @@ AbstractStage {
476 requestedHeight: appContainer.height;
552 requestedHeight: appContainer.height;
477 }
553 }
478 },
554 },
555+ State {
556+ name: "fullscreen"; when: decoratedWindow.fullscreen && !appDelegate.minimized
557+ PropertyChanges {
558+ target: appDelegate;
559+ x: 0;
560+ y: -PanelState.panelHeight
561+ requestedWidth: appContainer.width;
562+ requestedHeight: appContainer.height;
563+ }
564+ },
565+ State {
566+ name: "normal";
567+ when: !appDelegate.maximized && !appDelegate.minimized
568+ && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
569+ PropertyChanges {
570+ target: appDelegate;
571+ visuallyMinimized: false;
572+ visuallyMaximized: false
573+ }
574+ },
479 State {
575 State {
480 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
576 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
481 PropertyChanges {
577 PropertyChanges {
@@ -513,6 +609,7 @@ AbstractStage {
513 visuallyMaximized: false
609 visuallyMaximized: false
514 }
610 }
515 }
611 }
612+
516 ]
613 ]
517 transitions: [
614 transitions: [
518 Transition {
615 Transition {
@@ -543,7 +640,7 @@ AbstractStage {
543 }
640 }
544 },
641 },
545 Transition {
642 Transition {
546− to: "*" //maximized and fullscreen
643+ to: "maximized,fullscreen" //maximized and fullscreen
547 enabled: appDelegate.animationsEnabled
644 enabled: appDelegate.animationsEnabled
548 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
645 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
549 SequentialAnimation {
646 SequentialAnimation {
@@ -553,16 +650,25 @@ AbstractStage {
553 }
650 }
554 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
651 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
555 }
652 }
653+ },
654+ Transition {
655+ to: "spread"
656+ PropertyAnimation { target: appDelegate; properties: "x,y,width,height"; duration: UbuntuAnimation.FastDuration }
657+ },
658+ Transition {
659+ to: "staged";
660+ PropertyAnimation { target: appDelegate; properties: "x,y,width,height"; duration: UbuntuAnimation.FastDuration }
556 }
661 }
662+
557 ]
663 ]
558
664
559− Binding {
665+// Binding {
560− id: previewBinding
666+// id: previewBinding
561− target: appDelegate
667+// target: appDelegate
562− property: "z"
668+// property: "z"
563− value: topLevelSurfaceList.count + 1
669+// value: topLevelSurfaceList.count + 1
564− when: index == spread.highlightedIndex && spread.ready
670+// when: index == spread.highlightedIndex
565− }
671+// }
566
672
567 WindowResizeArea {
673 WindowResizeArea {
568 id: resizeArea
674 id: resizeArea
@@ -607,6 +713,7 @@ AbstractStage {
607 surface: model.surface
713 surface: model.surface
608 active: appDelegate.focus
714 active: appDelegate.focus
609 focus: true
715 focus: true
716+ showDecoration: true
610
717
611 requestedWidth: appDelegate.requestedWidth
718 requestedWidth: appDelegate.requestedWidth
612 requestedHeight: appDelegate.requestedHeight
719 requestedHeight: appDelegate.requestedHeight
@@ -650,23 +757,91 @@ AbstractStage {
650 }
757 }
651 }
758 }
652
759
760+ FloatingFlickable {
761+ id: floatingFlickable
762+ anchors.fill: parent
763+
764+ property int minContentWidth: 6 * Math.min(height / 4, width / 5)
765+ contentWidth: Math.max(6, appRepeater.count) * Math.min(height / 4, width / 5)
766+
767+ }
768+
653 DirectionalDragArea {
769 DirectionalDragArea {
770+ id: rightEdgeDragArea
654 direction: Direction.Leftwards
771 direction: Direction.Leftwards
655 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
772 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
656− width: units.gu(1)
773+ width: root.dragAreaWidth
774+
775+ property var gesturePoints: new Array()
776+
777+ property real progress: -touchX / root.width
778+ onProgressChanged: print("dda progress", progress, root.width, touchX, root.width + touchX)
779+
780+ Rectangle { color: "blue"; anchors.fill: parent }
781+ onTouchXChanged: {
657− onDraggingChanged: { if (dragging) { spread.show(); } }
782+ if (dragging) {
783+ // Gesture recognized. Let's move the spreadView with the finger
784+// var dragX = Math.min(touchX + width, width); // Prevent dragging rightwards
785+// dragX = -dragX + spreadDragArea.width - spreadView.shift;
786+// // Don't allow dragging further than the animation crossing with phase2's animation
787+// var maxMovement = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
788+
789+// spreadView.contentX = Math.min(dragX, maxMovement);
790+ } else {
791+// // Initial touch. Let's reset the spreadView to the starting position.
792+// spreadView.phase = 0;
793+// spreadView.contentX = -spreadView.shift;
658− }
794+ }
659
795
660− DesktopSpread {
796+ gesturePoints.push(touchX);
661− id: spread
797+ }
662− objectName: "spread"
663− anchors.fill: appContainer
664− workspace: appContainer
665− focus: state == "altTab"
666− altTabPressed: root.altTabPressed
667
798
668− onPlayFocusAnimation: {
799+ onDraggingChanged: {
669− appRepeater.itemAt(index).playFocusAnimation();
800+ print("dda dragging changed", dragging)
801+ if (dragging) {
802+ // A potential edge-drag gesture has started. Start recording it
803+ gesturePoints = [];
804+ } else {
805+ if (gesturePoints[gesturePoints.length - 1] < -root.width / 2) {
806+ priv.goneToSpread = true;
807+ }
808+
809+// // Ok. The user released. Find out if it was a one-way movement.
810+// var oneWayFlick = true;
811+// var smallestX = spreadDragArea.width;
812+// for (var i = 0; i < gesturePoints.length; i++) {
813+// if (gesturePoints[i] >= smallestX) {
814+// oneWayFlick = false;
815+// break;
816+// }
817+// smallestX = gesturePoints[i];
818+// }
819+// gesturePoints = [];
820+
821+// if (oneWayFlick && spreadView.shiftedContentX > units.gu(2) &&
822+// spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) {
823+// // If it was a short one-way movement, do the Alt+Tab switch
824+// // no matter if we didn't cross positionMarker1 yet.
825+// spreadView.snapTo(1);
826+// } else if (!dragging) {
827+// // otherwise snap to the closest snap position we can find
828+// // (might be back to start, to app 1 or to spread)
829+// spreadView.snap();
830+// }
831+ }
670 }
832 }
671 }
833 }
834+
835+// DesktopSpread {
836+// id: spread
837+// objectName: "spread"
838+// anchors.fill: appContainer
839+// workspace: appContainer
840+// focus: state == "altTab"
841+// altTabPressed: root.altTabPressed
842+
843+// onPlayFocusAnimation: {
844+// appRepeater.itemAt(index).playFocusAnimation();
845+// }
846+// }
672}
847}
qml/Stages/StagedRightEdgeMaths.qmlnew file+38
@@ -0,0 +1,38 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+
4+QtObject {
5+ id: root
6+
7+ // Input
8+ property int itemIndex: 0
9+ property real progress: 0
10+ property int sceneWidth: 0
11+ property int sceneHeight: 0
12+ property int targetX: 0
13+ property int targetAngle: 0
14+
15+ // Output
16+ readonly property int animtedWidth: {
17+ return root.sceneWidth
18+ }
19+
20+ readonly property int animatedHeight: {
21+ return root.sceneHeight
22+ }
23+
24+ readonly property int animatedX: {
25+ if (index == 0) {
26+ // aX : tX = p : 1
27+ return root.targetX * root.progress
28+ }
29+ var startX = sceneWidth + (root.itemIndex - 1) * units.gu(10)
30+ var distance = startX - root.targetX
31+ return startX - distance * root.progress;
32+ }
33+
34+ readonly property real animatedAngle: {
35+ // a : tA = p : 1
36+ return root.targetAngle * root.progress
37+ }
38+}