on xenial help sign in
inital try on unifying the stages
commitffcc69a8cadeab0ba1d3ec6a8e0e26e2c94cd6e6 authorMichael Zanetti <michael.zanetti@canonical.com> dateTue 31 May 2016, 12:12 (10 years ago) parent0365d75
6 files changed+328−77
plugins/Ubuntu/Gestures/TouchGate.cpp+1−1 qml/Shell.qml+7−8 qml/Stages/DecoratedWindow.qml+6−3 qml/Stages/DesktopSpreadDelegate.qml+55−19 qml/Stages/DesktopStage.qml+221−46 qml/Stages/StagedRightEdgeMaths.qml+38
plugins/Ubuntu/Gestures/TouchGate.cpp+1−1
@@ -59,7 +59,7 @@ void TouchGate::touchEvent(QTouchEvent *event)
5959 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
6060
6161 if (touchPoint.state() == Qt::TouchPointPressed) {
62− Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
62+// Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
6363 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
6464 m_touchInfoMap[touchPoint.id()].ended = false;
6565 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
qml/Shell.qml+7−8
@@ -258,6 +258,8 @@ Item {
258258 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
259259 ? "phone"
260260 : shell.usageScenario
261+
262+ source: "Stages/DesktopStage.qml"
261263 readonly property string qmlComponent: {
262264 if(shell.mode === "greeter") {
263265 return "Stages/ShimStage.qml"
@@ -269,14 +271,6 @@ Item {
269271 return "Stages/DesktopStage.qml";
270272 }
271273 }
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− }
280274
281275 property bool interactive: (!greeter || !greeter.shown)
282276 && panel.indicators.fullyClosed
@@ -285,6 +279,11 @@ Item {
285279
286280 onInteractiveChanged: { if (interactive) { focus = true; } }
287281
282+ Binding {
283+ target: applicationsDisplayLoader.item
284+ property: "mode"
285+ value: applicationsDisplayLoader.usageScenario == "phone" ? "staged" : "windowed"
286+ }
288287 Binding {
289288 target: applicationsDisplayLoader.item
290289 property: "focus"
qml/Stages/DecoratedWindow.qml+6−3
@@ -32,7 +32,10 @@ FocusScope {
3232 readonly property alias title: applicationWindow.title
3333 property alias fullscreen: applicationWindow.fullscreen
3434
35− readonly property bool decorationShown: !fullscreen
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)
38+ readonly property bool decorationShown: showDecoration && !fullscreen
3639 property bool highlightShown: false
3740 property real shadowOpacity: 1
3841
@@ -96,9 +99,9 @@ FocusScope {
9699 id: applicationWindow
97100 objectName: "appWindow"
98101 anchors.top: parent.top
99− anchors.topMargin: decoration.height
102+ anchors.topMargin: root.decorationShown ? decoration.height : 0
100103 anchors.left: parent.left
101− requestedHeight: root.requestedHeight - (root.decorationShown ? decoration.height : 0)
104+ requestedHeight: root.requestedHeight
102105 interactive: true
103106 focus: true
104107 }
qml/Stages/DesktopSpreadDelegate.qml+55−19
@@ -33,6 +33,26 @@ Item {
3333 property int windowWidth: surface ? surface.size.width : 0
3434 property int windowHeight: surface ? surface.size.height : 0
3535
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+
3656 state: "normal"
3757 states: [
3858 State {
@@ -49,6 +69,7 @@ Item {
4969 target: applicationWindow
5070 itemScale: Math.max(root.width / root.windowWidth, root.height / root.windowHeight)
5171 interactive: false
72+ showDecoration: false
5273 }
5374 PropertyChanges {
5475 target: clipper
@@ -92,27 +113,42 @@ Item {
92113 id: clipper
93114 anchors.fill: parent
94115
95− ApplicationWindow {
116+ DecoratedWindow {
96117 id: applicationWindow
97− objectName: application ? "appWindow_" + application.appId : "appWindow_null"
98− anchors.top: parent.top
99− anchors.topMargin: 0
100− anchors.left: parent.left
101− width: root.windowWidth
102− height: root.windowHeight
103− interactive: false
104− resizeSurface: false
105− focus: false
106−
107− property real itemScale: 1
108− transform: [
109− Scale {
110− origin.x: 0; origin.y: 0
111− xScale: applicationWindow.itemScale
112− yScale: applicationWindow.itemScale
113− }
114− ]
118+ objectName: "decoratedWindow"
119+ anchors.left: root.left
120+ anchors.top: root.top
121+ active: root.focus
122+ focus: true
123+ showDecoration: true
124+
125+ onClose: root.close()
126+ onMaximize: root.maximize()
127+ onMinimize: root.minimize()
128+ onDecorationPressed: root.decorationPressed()
115129 }
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+// }
116152 }
117153
118154 Rectangle {
qml/Stages/DesktopStage.qml+221−46
@@ -37,8 +37,10 @@ AbstractStage {
3737 }
3838 }
3939
40+ property string mode: "staged"
41+
4042 // Used by TutorialRight
41− property bool spreadShown: spread.state == "altTab"
43+ property bool spreadShown: state == "altTab"
4244
4345 mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
4446
@@ -57,7 +59,7 @@ AbstractStage {
5759 GlobalShortcut {
5860 id: showSpreadShortcut
5961 shortcut: Qt.MetaModifier|Qt.Key_W
60− onTriggered: spread.state = "altTab"
62+ onTriggered: state = "altTab"
6163 }
6264
6365 GlobalShortcut {
@@ -104,8 +106,8 @@ AbstractStage {
104106 Connections {
105107 target: root.topLevelSurfaceList
106108 onCountChanged: {
107− if (spread.state == "altTab") {
108− spread.cancel();
109+ if (root.state == "spread") {
110+ priv.goneToSpread = false;
109111 }
110112 }
111113 }
@@ -116,13 +118,15 @@ AbstractStage {
116118
117119 property var focusedAppDelegate: null
118120 onFocusedAppDelegateChanged: {
119− if (spread.state == "altTab") {
120− spread.state = "";
121+ if (root.state == "spread") {
122+ goneToSpread = false;
121123 }
122124 }
123125
124126 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
125127
128+ property bool goneToSpread: false
129+
126130 function updateForegroundMaximizedApp() {
127131 var found = false;
128132 for (var i = 0; i < appRepeater.count && !found; i++) {
@@ -180,12 +184,12 @@ AbstractStage {
180184 target: PanelState
181185 property: "title"
182186 value: {
183− if (priv.focusedAppDelegate !== null && spread.state == "") {
184− if (priv.focusedAppDelegate.maximized)
185− return priv.focusedAppDelegate.title
186− else
187− return priv.focusedAppDelegate.appName
188− }
187+// if (priv.focusedAppDelegate !== null && spread.state == "") {
188+// if (priv.focusedAppDelegate.maximized)
189+// return priv.focusedAppDelegate.title
190+// else
191+// return priv.focusedAppDelegate.appName
192+// }
189193 return ""
190194 }
191195 when: priv.focusedAppDelegate
@@ -231,6 +235,25 @@ AbstractStage {
231235 when: !appRepeater.startingUp && root.parent
232236 }
233237
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+
234257 FocusScope {
235258 id: appContainer
236259 objectName: "appContainer"
@@ -298,6 +321,8 @@ AbstractStage {
298321
299322 readonly property var surface: model.surface
300323
324+ property real angle: 0
325+
301326 function claimFocus() {
302327 if (spread.state == "altTab") {
303328 spread.cancel();
@@ -378,7 +403,7 @@ AbstractStage {
378403 && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
379404 )
380405 || decoratedWindow.fullscreen
381− || (spread.state == "altTab" && index === spread.highlightedIndex)
406+ // || (root.state == "altTab" && index === spread.highlightedIndex)
382407
383408 function close() {
384409 model.surface.close();
@@ -440,29 +465,80 @@ AbstractStage {
440465 duration: UbuntuAnimation.SnapDuration
441466 }
442467
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)
443499 states: [
444500 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"
446512 PropertyChanges {
447− target: appDelegate;
448− x: 0;
449− y: -PanelState.panelHeight
450− requestedWidth: appContainer.width;
451− requestedHeight: appContainer.height;
513+ target: stagedRightEdgeMaths
514+ progress: rightEdgeDragArea.progress
515+ }
516+ PropertyChanges {
517+ target: appDelegate
518+ y: PanelState.panelHeight
519+ x: stagedRightEdgeMaths.animatedX
520+ requestedWidth: stagedRightEdgeMaths.animatedWidth
521+ requestedHeight: stagedRightEdgeMaths.animatedHeight
522+ angle: stagedRightEdgeMaths.animatedAngle
523+ z: index
452524 }
525+ PropertyChanges { target: decoratedWindow; showDecoration: false }
453526 },
454527 State {
455− name: "normal";
456− when: !appDelegate.maximized && !appDelegate.minimized
457− && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
528+ name: "staged"; when: root.state == "staged"
458529 PropertyChanges {
459− target: appDelegate;
460− visuallyMinimized: false;
461− visuallyMaximized: false
530+ target: appDelegate
531+ x: 0; y: 0
532+ visuallyMaximized: true
533+ }
534+ PropertyChanges {
535+ target: decoratedWindow
536+ requestedWidth: appContainer.width - root.leftMargin;
537+ requestedHeight: appContainer.height;
462538 }
463539 },
464540 State {
465− name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
541+ name: "maximized"; when: root.state === "windowed" && appDelegate.maximized && !appDelegate.minimized
466542 PropertyChanges {
467543 target: appDelegate;
468544 x: root.leftMargin;
@@ -476,6 +552,26 @@ AbstractStage {
476552 requestedHeight: appContainer.height;
477553 }
478554 },
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+ },
479575 State {
480576 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
481577 PropertyChanges {
@@ -513,6 +609,7 @@ AbstractStage {
513609 visuallyMaximized: false
514610 }
515611 }
612+
516613 ]
517614 transitions: [
518615 Transition {
@@ -543,7 +640,7 @@ AbstractStage {
543640 }
544641 },
545642 Transition {
546− to: "*" //maximized and fullscreen
643+ to: "maximized,fullscreen" //maximized and fullscreen
547644 enabled: appDelegate.animationsEnabled
548645 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
549646 SequentialAnimation {
@@ -553,16 +650,25 @@ AbstractStage {
553650 }
554651 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
555652 }
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 }
556661 }
662+
557663 ]
558664
559− Binding {
560− id: previewBinding
561− target: appDelegate
562− property: "z"
563− value: topLevelSurfaceList.count + 1
564− when: index == spread.highlightedIndex && spread.ready
565− }
665+// Binding {
666+// id: previewBinding
667+// target: appDelegate
668+// property: "z"
669+// value: topLevelSurfaceList.count + 1
670+// when: index == spread.highlightedIndex
671+// }
566672
567673 WindowResizeArea {
568674 id: resizeArea
@@ -607,6 +713,7 @@ AbstractStage {
607713 surface: model.surface
608714 active: appDelegate.focus
609715 focus: true
716+ showDecoration: true
610717
611718 requestedWidth: appDelegate.requestedWidth
612719 requestedHeight: appDelegate.requestedHeight
@@ -650,23 +757,91 @@ AbstractStage {
650757 }
651758 }
652759
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+
653769 DirectionalDragArea {
770+ id: rightEdgeDragArea
654771 direction: Direction.Leftwards
655772 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
656− width: units.gu(1)
657− onDraggingChanged: { if (dragging) { spread.show(); } }
658− }
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: {
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;
794+ }
659795
660− DesktopSpread {
661− id: spread
662− objectName: "spread"
663− anchors.fill: appContainer
664− workspace: appContainer
665− focus: state == "altTab"
666− altTabPressed: root.altTabPressed
796+ gesturePoints.push(touchX);
797+ }
667798
668− onPlayFocusAnimation: {
669− appRepeater.itemAt(index).playFocusAnimation();
799+ onDraggingChanged: {
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+ }
670832 }
671833 }
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+// }
672847}
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+}