on xenial help sign in
Support shell rotation
784c062Daniel d'Andrada
debian/unity8.install+1
@@ -6,4 +6,5 @@ usr/share/unity8/Hud
6usr/share/unity8/Launcher
6usr/share/unity8/Launcher
7usr/share/unity8/Panel
7usr/share/unity8/Panel
8usr/share/unity8/Shell.qml
8usr/share/unity8/Shell.qml
9+usr/share/unity8/OrientedShell.qml
9usr/share/unity8/Stages
10usr/share/unity8/Stages
qml/Greeter/Greeter.qml+14
@@ -30,6 +30,20 @@ Showable {
30 // 1 when fully shown and 0 when fully hidden
30 // 1 when fully shown and 0 when fully hidden
31 property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
31 property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
32
32
33+ // Adjust the "hidden" position of the greeter when its size changes,
34+ // otherwise parts of it might show up on the screen.
35+ // Also, showProgress property will show up a greater than 0 value in such case, and
36+ // that must not happen
37+ onWidthChanged: {
38+ if (!shown) {
39+ if (x > 0) {
40+ x = width;
41+ } else {
42+ x = -width;
43+ }
44+ }
45+ }
46+
33 showAnimation: StandardAnimation { property: "x"; to: 0 }
47 showAnimation: StandardAnimation { property: "x"; to: 0 }
34 hideAnimation: __leftHideAnimation
48 hideAnimation: __leftHideAnimation
35
49
qml/OrientedShell.qmlnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 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 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 General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtQuick.Window 2.0
19+import Ubuntu.Components 0.1
20+
21+Item {
22+ id: orientedShell
23+
24+ // this is only here to select the width / height of the window if not running fullscreen
25+ property bool tablet: false
26+ width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
27+ height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
28+
29+ property int orientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
30+
31+ state: orientationAngle.toString()
32+ states: [
33+ State {
34+ name: "0"
35+ PropertyChanges {
36+ target: shell
37+ rotation: 0
38+ x: 0
39+ y: 0
40+ width: orientedShell.width
41+ height: orientedShell.height
42+ }
43+ },
44+ State {
45+ name: "180"
46+ PropertyChanges {
47+ target: shell
48+ rotation: 180
49+ x: orientedShell.width
50+ y: orientedShell.height
51+ width: orientedShell.width
52+ height: orientedShell.height
53+ }
54+ },
55+ State {
56+ name: "270"
57+ PropertyChanges {
58+ target: shell
59+ rotation: 270
60+ x: 0
61+ y: orientedShell.height
62+ width: orientedShell.height
63+ height: orientedShell.width
64+ }
65+ },
66+ State {
67+ name: "90"
68+ PropertyChanges {
69+ target: shell
70+ rotation: 90
71+ x: orientedShell.width
72+ y: 0
73+ width: orientedShell.height
74+ height: orientedShell.width
75+ }
76+ }
77+ ]
78+
79+ Shell {
80+ id: shell
81+ transformOrigin: Item.TopLeft
82+ orientationAngle: orientedShell.orientationAngle
83+ }
84+}
qml/Shell.qml+11−7
@@ -36,11 +36,7 @@ import Unity.Notifications 1.0 as NotificationBackend
36FocusScope {
36FocusScope {
37 id: shell
37 id: shell
38
38
39− // this is only here to select the width / height of the window if not running fullscreen
39+ property int orientationAngle
40− property bool tablet: false
41− width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
42− height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
43−
44 property real edgeSize: units.gu(2)
40 property real edgeSize: units.gu(2)
45 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
41 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
46 property url background
42 property url background
@@ -181,11 +177,14 @@ FocusScope {
181 color: "khaki"
177 color: "khaki"
182
178
183 x: shown ? launcher.progress : stagesDragArea.progress
179 x: shown ? launcher.progress : stagesDragArea.progress
184− Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
180+ //Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
185
181
186 property bool shown: false
182 property bool shown: false
187
183
184+ // Avoid a silent "divide by zero -> NaN" situation during init as shell.width will be
185+ // zero. That breaks the property binding and the function won't be reevaluated once
186+ // shell.width is set, with the NaN result staying there for good.
188− property real showProgress: MathUtils.clamp(1 - x / shell.width, 0, 1)
187+ property real showProgress: shell.width ? MathUtils.clamp(1 - x / shell.width, 0, 1) : 0
189
188
190 property bool fullyShown: x == 0
189 property bool fullyShown: x == 0
191 property bool fullyHidden: x == width
190 property bool fullyHidden: x == width
@@ -217,6 +216,11 @@ FocusScope {
217 property: "dragAreaWidth"
216 property: "dragAreaWidth"
218 value: shell.edgeSize
217 value: shell.edgeSize
219 }
218 }
219+ Binding {
220+ target: applicationsDisplayLoader.item
221+ property: "orientationAngleOfSurfaces"
222+ value: shell.orientationAngle
223+ }
220 }
224 }
221 }
225 }
222
226
qml/Stages/PhoneStage.qml+9
@@ -25,6 +25,8 @@ Rectangle {
25 id: root
25 id: root
26 color: "green"
26 color: "green"
27
27
28+ property int orientationAngleOfSurfaces
29+
28 // Controls to be set from outside
30 // Controls to be set from outside
29 property int dragAreaWidth
31 property int dragAreaWidth
30
32
@@ -39,6 +41,12 @@ Rectangle {
39 spreadView.snapTo(priv.indexOf(appId))
41 spreadView.snapTo(priv.indexOf(appId))
40 }
42 }
41
43
44+ onWidthChanged: {
45+ spreadView.selectedIndex = -1;
46+ spreadView.phase = 0;
47+ spreadView.contentX = -spreadView.shift;
48+ }
49+
42 Connections {
50 Connections {
43 target: ApplicationManager
51 target: ApplicationManager
44
52
@@ -232,6 +240,7 @@ Rectangle {
232 delegate: TransformedSpreadDelegate {
240 delegate: TransformedSpreadDelegate {
233 id: appDelegate
241 id: appDelegate
234 objectName: "appDelegate" + index
242 objectName: "appDelegate" + index
243+ orientationAngle: root.orientationAngleOfSurfaces
235 startAngle: 45
244 startAngle: 45
236 endAngle: 5
245 endAngle: 5
237 startScale: 1.1
246 startScale: 1.1
qml/Stages/SpreadDelegate.qml+55−3
@@ -24,21 +24,73 @@ Item {
24 signal clicked()
24 signal clicked()
25 property real topMarginProgress
25 property real topMarginProgress
26 property bool interactive: true
26 property bool interactive: true
27+ property int orientationAngle
27
28
28 // FIXME: This really should be invisible to QML code.
29 // FIXME: This really should be invisible to QML code.
29 // e.g. Create a SurfaceItem {} in C++ which we just use without any imperative hacks.
30 // e.g. Create a SurfaceItem {} in C++ which we just use without any imperative hacks.
30 property var surface
31 property var surface
31 onSurfaceChanged: {
32 onSurfaceChanged: {
32 if (surface) {
33 if (surface) {
33− root.width = surface.implicitWidth;
34− root.height = surface.implicitHeight;
35 surface.parent = root;
34 surface.parent = root;
36− surface.anchors.fill = root;
37 surface.enabled = root.interactive;
35 surface.enabled = root.interactive;
38 surface.z = 1;
36 surface.z = 1;
37+
38+ // for the counter-rotation
39+ surface.transformOrigin = Item.TopLeft;
39 }
40 }
40 }
41 }
41
42
43+ // Applications already rotate automatically. And so does the shell
44+ // Therefore we have to counter-rotate the app item to undo the rotation applied to
45+ // it by the shell
46+ state: orientationAngle.toString()
47+ states: [
48+ State {
49+ name: "0"
50+ PropertyChanges {
51+ target: surface
52+ rotation: 0
53+ x: 0
54+ y: 0
55+ width: root.width
56+ height: root.height
57+ }
58+ },
59+ State {
60+ name: "90"
61+ PropertyChanges {
62+ target: surface
63+ rotation: -90
64+ x: 0
65+ y: root.height
66+ width: root.height
67+ height: root.width
68+ }
69+ },
70+ State {
71+ name: "180"
72+ PropertyChanges {
73+ target: surface
74+ rotation: -180
75+ x: root.width
76+ y: root.height
77+ width: root.width
78+ height: root.height
79+ }
80+ },
81+ State {
82+ name: "270"
83+ PropertyChanges {
84+ target: surface
85+ rotation: -270
86+ x: root.width
87+ y: 0
88+ width: root.height
89+ height: root.width
90+ }
91+ }
92+ ]
93+
42 Component.onDestruction: {
94 Component.onDestruction: {
43 if (surface) {
95 if (surface) {
44 surface.release();
96 surface.release();
src/main.cpp+1−1
@@ -135,7 +135,7 @@ Load the testability driver");
135 nativeInterface->setProperty("ubuntuSessionType", 1);
135 nativeInterface->setProperty("ubuntuSessionType", 1);
136 view->setProperty("role", 2); // INDICATOR_ACTOR_ROLE
136 view->setProperty("role", 2); // INDICATOR_ACTOR_ROLE
137
137
138− QUrl source(::qmlDirectory()+"Shell.qml");
138+ QUrl source(::qmlDirectory()+"OrientedShell.qml");
139 prependImportPaths(view->engine(), ::overrideImportPaths());
139 prependImportPaths(view->engine(), ::overrideImportPaths());
140 if (!isMirServer) {
140 if (!isMirServer) {
141 prependImportPaths(view->engine(), ::nonMirImportPaths());
141 prependImportPaths(view->engine(), ::nonMirImportPaths());