on xenial help sign in
make workspaces a listview
commite73e035ddda439a87ad76af0371ce38ffd43c37c authorMichael Zanetti <michael.zanetti@canonical.com> dateFri 3 Feb 2017, 13:55 (10 years ago) parent0144005
6 files changed+507−105
qml/Stage/Spread/ScreensAndWorkspaces.qml+48−3 qml/Stage/Spread/WorkspacePreview.qml+183 qml/Stage/Spread/Workspaces.qml+124 qml/Stage/Stage.qml+1−1 qml/Stage/WorkspacePreview.qml+149−101 tests/qmltests/tst_Shell.qml+2
qml/Stage/Spread/ScreensAndWorkspaces.qml+48−3
@@ -11,15 +11,60 @@ Item {
1111 Row {
1212 anchors.bottom: parent.bottom
1313 anchors.bottomMargin: units.gu(1)
14− anchors.horizontalCenter: parent.horizontalCenter
14+// anchors.horizontalCenter: parent.horizontalCenter
15+ anchors.left: parent.left
1516 spacing: units.gu(1)
1617
1718 Repeater {
1819 model: Screens
1920
20− delegate: WorkspacePreview {
21+ delegate: Item {
2122 height: root.height - units.gu(6)
22− background: root.background
23+ width: workspaces.implicitWidth
24+
25+
26+ Rectangle { anchors.fill: parent; color: "blue" }
27+
28+ Rectangle {
29+ id: header
30+ anchors { left: parent.left; top: parent.top; right: parent.right }
31+ height: units.gu(7)
32+ color: "white"
33+
34+ Column {
35+ anchors.fill: parent
36+ anchors.margins: units.gu(1)
37+
38+ Label {
39+ text: model.name
40+ color: "black"
41+ }
42+
43+ Label {
44+ text: model.outputType === Screens.LVDS ? "Built-in" : "Clone"
45+ color: "black"
46+ fontSize: "x-small"
47+ }
48+
49+ Label {
50+ text: model.geometry.width + "x" + model.geometry.height
51+ color: "black"
52+ fontSize: "x-small"
53+ }
54+ }
55+ }
56+
57+
58+ Workspaces {
59+ id: workspaces
60+ height: parent.height - header.height
61+ anchors.bottom: parent.bottom
62+ }
63+
64+// WorkspacePreview {
65+// height: root.height - units.gu(6)
66+// background: root.background
67+// }
2368 }
2469 }
2570 }
qml/Stage/Spread/WorkspacePreview.qmlnew file+183
@@ -0,0 +1,183 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+import Unity.Screens 0.1
4+import Unity.Application 0.1
5+import "../../Components"
6+
7+UbuntuShape {
8+ id: previewSpace
9+
10+ // Set the height. this preview will then automatically adjust the width, keeping aspect ratio of the screen
11+ width: model.geometry.width * previewScale * 4
12+ color: "white"
13+ property string background
14+
15+ property int screenWidth: model.geometry.width
16+ property int screenHeight: model.geometry.height
17+ property real previewScale: previewSpace.height / previewSpace.screenHeight
18+
19+
20+ Rectangle {
21+ anchors.fill: parent
22+ color: "blue"
23+
24+ Repeater {
25+ id: workspaceRepeater
26+ model: 15
27+
28+ delegate: Item {
29+ x: index * previewSpace.screenWidth * previewScale
30+ height: previewSpace.screenHeight * previewScale
31+ width: previewSpace.screenWidth * previewScale
32+ clip: true
33+
34+ Wallpaper {
35+ source: previewSpace.background
36+ anchors.fill: parent
37+
38+ // Repeater {
39+ // id: topLevelSurfaceRepeater
40+ // model: visible ? topLevelSurfaceList : null
41+ // delegate: Rectangle {
42+ // width: surfaceItem.width
43+ // height: surfaceItem.height + decorationHeight * previewScale
44+ // x: model.window.position.x * previewScale
45+ // y: (model.window.position.y - decorationHeight) * previewScale
46+ // color: "blue"
47+ // z: topLevelSurfaceRepeater.count - index
48+
49+ // property int decorationHeight: units.gu(3)
50+
51+ // WindowDecoration {
52+ // width: surfaceItem.implicitWidth
53+ // height: parent.decorationHeight
54+ // transform: Scale {
55+ // origin.x: 0
56+ // origin.y: 0
57+ // xScale: previewScale
58+ // yScale: previewScale
59+ // }
60+ // title: model.window && model.window.surface ? model.window.surface.name : ""
61+ // z: 3
62+ // }
63+
64+ // MirSurfaceItem {
65+ // id: surfaceItem
66+ // y: parent.decorationHeight * previewScale
67+ // width: implicitWidth * previewScale
68+ // height: implicitHeight * previewScale
69+ // surfaceWidth: -1
70+ // surfaceHeight: -1
71+ // onImplicitHeightChanged: print("item", surfaceItem, "height changed", implicitHeight)
72+ // surface: model.window.surface
73+ // }
74+ // }
75+ // }
76+ }
77+ }
78+
79+
80+// MouseArea {
81+// id: mouseArea
82+// anchors.centerIn: parent
83+// anchors.verticalCenterOffset: header.height / 2
84+// width: units.gu(8)
85+// height: width
86+// hoverEnabled: true
87+// opacity: containsMouse ? 1 : 0
88+
89+// Rectangle {
90+// anchors.fill: parent
91+// color: "#80000000"
92+// radius: height / 2
93+// }
94+
95+// NumberAnimation {
96+// target: canvas
97+// property: "progress"
98+// duration: 2000
99+// running: mouseArea.containsMouse
100+// from: 0
101+// to: 1
102+// }
103+
104+// Canvas {
105+// id: canvas
106+// height: parent.height
107+// width: height
108+// anchors.centerIn: parent
109+
110+// property real progress: 0.5
111+// property int lineWidth: units.dp(4)
112+// onProgressChanged: {
113+// requestPaint();
114+// if (progress == 1) {
115+// Screens.activateScreen(index);
116+// }
117+// }
118+
119+// rotation: -90
120+
121+// onPaint: {
122+// var ctx = canvas.getContext("2d");
123+// ctx.save();
124+// ctx.reset();
125+
126+// ctx.lineWidth = lineWidth;
127+
128+// ctx.strokeStyle = "#3bffffff"
129+// ctx.beginPath();
130+// ctx.arc(canvas.width/2,canvas.height/2, (canvas.height - ctx.lineWidth) / 2, 0, (Math.PI*2),false);
131+// ctx.stroke();
132+// ctx.closePath();
133+
134+// ctx.strokeStyle = "white"
135+// ctx.beginPath();
136+// ctx.arc(canvas.width/2,canvas.height/2, (canvas.height - ctx.lineWidth) / 2, 0, (Math.PI*2*(progress)),false);
137+// ctx.stroke();
138+// ctx.closePath();
139+
140+// ctx.restore();
141+// }
142+// }
143+
144+// Icon {
145+// source: "graphics/multi-monitor_leave.png"
146+// height: units.gu(4)
147+// width: height
148+// anchors.centerIn: parent
149+// }
150+// }
151+ }
152+
153+ FloatingFlickable {
154+ id: flickable
155+ anchors.fill: parent
156+ contentWidth: workspaceRepeater.count * previewSpace.screenWidth * previewScale
157+ property real progress: contentX / contentWidth
158+ onContentXChanged: print("contentX:", contentX, "progress:", progress)
159+ }
160+
161+ MouseArea {
162+ anchors.fill: parent
163+ hoverEnabled: true
164+ property int scrollAreaWidth: width / 3
165+
166+ onMouseXChanged: {
167+ var margins = flickable.width * 0.05;
168+
169+ // do we need to scroll?
170+ if (mouseX < scrollAreaWidth + margins) {
171+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
172+ var contentX = (1 - progress) * (flickable.contentWidth - flickable.width)
173+ flickable.contentX = Math.max(0, Math.min(flickable.contentX, contentX))
174+ }
175+ if (mouseX > flickable.width - scrollAreaWidth) {
176+ var progress = Math.min(1, (mouseX - (flickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
177+ var contentX = progress * (flickable.contentWidth - flickable.width)
178+ flickable.contentX = Math.min(flickable.contentWidth - flickable.width, Math.max(flickable.contentX, contentX))
179+ }
180+ }
181+ }
182+ }
183+}
qml/Stage/Spread/Workspaces.qmlnew file+124
@@ -0,0 +1,124 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+
4+Item {
5+ id: root
6+ implicitWidth: listView.count * (height * 16/9)
7+
8+ property var screen: null
9+
10+ ListView {
11+ id: listView
12+ anchors.fill: parent
13+ anchors.leftMargin: -itemWidth
14+ anchors.rightMargin: -itemWidth
15+
16+ model: 5
17+
18+ orientation: ListView.Horizontal
19+ spacing: units.gu(1)
20+ leftMargin: itemWidth
21+ rightMargin: itemWidth
22+
23+ property int itemWidth: height * 16 / 9
24+ property int foldingAreaWidth: units.gu(10)
25+ property real realContentX: contentX - originX + leftMargin
26+
27+ displaced: Transition { UbuntuNumberAnimation { properties: "x" } }
28+
29+ delegate: Item {
30+ objectName: "delegate" + index
31+ height: parent.height
32+ width: dndArea.draggedIndex == index ? units.gu(5) : listView.itemWidth
33+ Behavior on width { UbuntuNumberAnimation {} }
34+
35+ property int itemX: -listView.contentX - listView.leftMargin + index * (listView.itemWidth + listView.spacing)
36+ property int distanceFromLeft: itemX
37+ property int distanceFromRight: listView.width - listView.leftMargin - listView.rightMargin - itemX - listView.itemWidth
38+
39+ property int maxAngle: 40
40+
41+ property int itemAngle: {
42+ if (index == 0) {
43+ if (distanceFromLeft < 0) {
44+ var progress = (distanceFromLeft + listView.foldingAreaWidth) / listView.foldingAreaWidth
45+ return linearAnimation(1, -1, 0, maxAngle, Math.max(-1, Math.min(1, progress)));
46+ }
47+ return 0
48+ }
49+ if (index == listView.count - 1) {
50+ if (distanceFromRight < 0) {
51+ var progress = (distanceFromRight + listView.foldingAreaWidth) / listView.foldingAreaWidth
52+ return linearAnimation(1, -1, 0, -maxAngle, Math.max(-1, Math.min(1, progress)));
53+ }
54+ return 0
55+ }
56+
57+ if (distanceFromLeft < listView.foldingAreaWidth) {
58+ // itemX : 10gu = p : 100
59+ var progress = distanceFromLeft / listView.foldingAreaWidth
60+ return linearAnimation(1, -1, 0, maxAngle, Math.max(-1, Math.min(1, progress)));
61+ }
62+ if (distanceFromRight < listView.foldingAreaWidth) {
63+ var progress = distanceFromRight / listView.foldingAreaWidth
64+ return linearAnimation(1, -1, 0, -maxAngle, Math.max(-1, Math.min(1, progress)));
65+ }
66+ return 0
67+ }
68+
69+ property int itemOffset: {
70+ if (index == 0) {
71+ if (distanceFromLeft < 0) {
72+ return -distanceFromLeft
73+ }
74+ return 0
75+ }
76+ if (index == listView.count - 1) {
77+ if (distanceFromRight < 0) {
78+ return distanceFromRight
79+ }
80+ return 0
81+ }
82+
83+ if (itemX < -listView.foldingAreaWidth) {
84+ return -itemX
85+ }
86+ if (distanceFromLeft < listView.foldingAreaWidth) {
87+ var progress = distanceFromLeft / listView.foldingAreaWidth
88+ return (listView.foldingAreaWidth - distanceFromLeft) / 2
89+ }
90+
91+ if (distanceFromRight < -listView.foldingAreaWidth) {
92+ return distanceFromRight
93+ }
94+
95+ if (distanceFromRight < listView.foldingAreaWidth) {
96+ var progress = distanceFromRight / listView.foldingAreaWidth;
97+ return -(listView.foldingAreaWidth - distanceFromRight) / 2
98+ }
99+
100+ return 0
101+ }
102+
103+// onItemXChanged: if (index == 1) print("x", itemX, listView.contentX)
104+
105+ z: itemOffset < 0 ? itemOffset : -itemOffset
106+ transform: [
107+ Rotation {
108+ angle: itemAngle
109+ axis { x: 0; y: 1; z: 0 }
110+ origin { x: /*itemAngle > 0 ? 0 : listView.itemWidth*/ listView.itemWidth / 2; y: height / 2 }
111+ },
112+ Translate {
113+ x: itemOffset
114+ }
115+
116+ ]
117+
118+ WorkspacePreview {
119+
120+ }
121+
122+ }
123+ }
124+}
qml/Stage/Stage.qml+1−1
@@ -565,7 +565,7 @@ FocusScope {
565565
566566 ScreensAndWorkspaces {
567567 id: screensAndWorkspaces
568− anchors { left: parent.left; top: parent.top; right: parent.right }
568+ anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: root.leftMargin }
569569 height: parent.height / 3
570570 background: root.background
571571 opacity: 0
qml/Stage/WorkspacePreview.qml+149−101
@@ -8,7 +8,7 @@ UbuntuShape {
88 id: previewSpace
99
1010 // Set the height. this preview will then automatically adjust the width, keeping aspect ratio of the screen
11− width: model.geometry.width * previewScale
11+ width: model.geometry.width * previewScale * 4
1212 color: "white"
1313 property string background
1414
@@ -20,6 +20,7 @@ UbuntuShape {
2020 id: header
2121 anchors { left: parent.left; top: parent.top; right: parent.right }
2222 height: units.gu(7)
23+
2324 Column {
2425 anchors.fill: parent
2526 anchors.margins: units.gu(1)
@@ -44,121 +45,168 @@ UbuntuShape {
4445 }
4546
4647
47− Wallpaper {
48+ Rectangle {
4849 anchors.fill: parent
4950 anchors.topMargin: header.height
50− source: previewSpace.background
51− clip: true
51+ color: "blue"
5252
5353 Repeater {
54− id: topLevelSurfaceRepeater
55− model: visible ? topLevelSurfaceList : null
56− delegate: Rectangle {
57− width: surfaceItem.width
58− height: surfaceItem.height + decorationHeight * previewScale
59− x: model.window.position.x * previewScale
60− y: (model.window.position.y - decorationHeight) * previewScale
61− color: "blue"
62− z: topLevelSurfaceRepeater.count - index
63−
64− property int decorationHeight: units.gu(3)
65−
66− WindowDecoration {
67− width: surfaceItem.implicitWidth
68− height: parent.decorationHeight
69− transform: Scale {
70− origin.x: 0
71− origin.y: 0
72− xScale: previewScale
73− yScale: previewScale
74− }
75− title: model.window && model.window.surface ? model.window.surface.name : ""
76− z: 3
77− }
78−
79− MirSurfaceItem {
80− id: surfaceItem
81− y: parent.decorationHeight * previewScale
82− width: implicitWidth * previewScale
83− height: implicitHeight * previewScale
84− surfaceWidth: -1
85− surfaceHeight: -1
86− onImplicitHeightChanged: print("item", surfaceItem, "height changed", implicitHeight)
87− surface: model.window.surface
54+ id: workspaceRepeater
55+ model: 15
56+
57+ delegate: Item {
58+ x: index * previewSpace.screenWidth * previewScale
59+ height: previewSpace.screenHeight * previewScale
60+ width: previewSpace.screenWidth * previewScale
61+ clip: true
62+
63+ Wallpaper {
64+ source: previewSpace.background
65+ anchors.fill: parent
66+
67+ // Repeater {
68+ // id: topLevelSurfaceRepeater
69+ // model: visible ? topLevelSurfaceList : null
70+ // delegate: Rectangle {
71+ // width: surfaceItem.width
72+ // height: surfaceItem.height + decorationHeight * previewScale
73+ // x: model.window.position.x * previewScale
74+ // y: (model.window.position.y - decorationHeight) * previewScale
75+ // color: "blue"
76+ // z: topLevelSurfaceRepeater.count - index
77+
78+ // property int decorationHeight: units.gu(3)
79+
80+ // WindowDecoration {
81+ // width: surfaceItem.implicitWidth
82+ // height: parent.decorationHeight
83+ // transform: Scale {
84+ // origin.x: 0
85+ // origin.y: 0
86+ // xScale: previewScale
87+ // yScale: previewScale
88+ // }
89+ // title: model.window && model.window.surface ? model.window.surface.name : ""
90+ // z: 3
91+ // }
92+
93+ // MirSurfaceItem {
94+ // id: surfaceItem
95+ // y: parent.decorationHeight * previewScale
96+ // width: implicitWidth * previewScale
97+ // height: implicitHeight * previewScale
98+ // surfaceWidth: -1
99+ // surfaceHeight: -1
100+ // onImplicitHeightChanged: print("item", surfaceItem, "height changed", implicitHeight)
101+ // surface: model.window.surface
102+ // }
103+ // }
104+ // }
88105 }
89106 }
90− }
91− }
92107
93− MouseArea {
94− id: mouseArea
95− anchors.centerIn: parent
96− anchors.verticalCenterOffset: header.height / 2
97− width: units.gu(8)
98− height: width
99− hoverEnabled: true
100− opacity: containsMouse ? 1 : 0
101108
102− Rectangle {
103− anchors.fill: parent
104− color: "#80000000"
105− radius: height / 2
109+// MouseArea {
110+// id: mouseArea
111+// anchors.centerIn: parent
112+// anchors.verticalCenterOffset: header.height / 2
113+// width: units.gu(8)
114+// height: width
115+// hoverEnabled: true
116+// opacity: containsMouse ? 1 : 0
117+
118+// Rectangle {
119+// anchors.fill: parent
120+// color: "#80000000"
121+// radius: height / 2
122+// }
123+
124+// NumberAnimation {
125+// target: canvas
126+// property: "progress"
127+// duration: 2000
128+// running: mouseArea.containsMouse
129+// from: 0
130+// to: 1
131+// }
132+
133+// Canvas {
134+// id: canvas
135+// height: parent.height
136+// width: height
137+// anchors.centerIn: parent
138+
139+// property real progress: 0.5
140+// property int lineWidth: units.dp(4)
141+// onProgressChanged: {
142+// requestPaint();
143+// if (progress == 1) {
144+// Screens.activateScreen(index);
145+// }
146+// }
147+
148+// rotation: -90
149+
150+// onPaint: {
151+// var ctx = canvas.getContext("2d");
152+// ctx.save();
153+// ctx.reset();
154+
155+// ctx.lineWidth = lineWidth;
156+
157+// ctx.strokeStyle = "#3bffffff"
158+// ctx.beginPath();
159+// ctx.arc(canvas.width/2,canvas.height/2, (canvas.height - ctx.lineWidth) / 2, 0, (Math.PI*2),false);
160+// ctx.stroke();
161+// ctx.closePath();
162+
163+// ctx.strokeStyle = "white"
164+// ctx.beginPath();
165+// ctx.arc(canvas.width/2,canvas.height/2, (canvas.height - ctx.lineWidth) / 2, 0, (Math.PI*2*(progress)),false);
166+// ctx.stroke();
167+// ctx.closePath();
168+
169+// ctx.restore();
170+// }
171+// }
172+
173+// Icon {
174+// source: "graphics/multi-monitor_leave.png"
175+// height: units.gu(4)
176+// width: height
177+// anchors.centerIn: parent
178+// }
179+// }
106180 }
107181
108− NumberAnimation {
109− target: canvas
110− property: "progress"
111− duration: 2000
112− running: mouseArea.containsMouse
113− from: 0
114− to: 1
182+ FloatingFlickable {
183+ id: flickable
184+ anchors.fill: parent
185+ contentWidth: workspaceRepeater.count * previewSpace.screenWidth * previewScale
186+ property real progress: contentX / contentWidth
187+ onContentXChanged: print("contentX:", contentX, "progress:", progress)
115188 }
116189
117− Canvas {
118− id: canvas
119− height: parent.height
120− width: height
121− anchors.centerIn: parent
122−
123− property real progress: 0.5
124− property int lineWidth: units.dp(4)
125− onProgressChanged: {
126− requestPaint();
127− if (progress == 1) {
128− Screens.activateScreen(index);
129− }
130− }
131−
132− rotation: -90
133−
134− onPaint: {
135− var ctx = canvas.getContext("2d");
136− ctx.save();
137− ctx.reset();
138−
139− ctx.lineWidth = lineWidth;
140−
141− ctx.strokeStyle = "#3bffffff"
142− ctx.beginPath();
143− ctx.arc(canvas.width/2,canvas.height/2, (canvas.height - ctx.lineWidth) / 2, 0, (Math.PI*2),false);
144− ctx.stroke();
145− ctx.closePath();
190+ MouseArea {
191+ anchors.fill: parent
192+ hoverEnabled: true
193+ property int scrollAreaWidth: width / 3
146194
147− ctx.strokeStyle = "white"
148− ctx.beginPath();
149− ctx.arc(canvas.width/2,canvas.height/2, (canvas.height - ctx.lineWidth) / 2, 0, (Math.PI*2*(progress)),false);
150− ctx.stroke();
151− ctx.closePath();
195+ onMouseXChanged: {
196+ var margins = flickable.width * 0.05;
152197
153− ctx.restore();
198+ // do we need to scroll?
199+ if (mouseX < scrollAreaWidth + margins) {
200+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
201+ var contentX = (1 - progress) * (flickable.contentWidth - flickable.width)
202+ flickable.contentX = Math.max(0, Math.min(flickable.contentX, contentX))
203+ }
204+ if (mouseX > flickable.width - scrollAreaWidth) {
205+ var progress = Math.min(1, (mouseX - (flickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
206+ var contentX = progress * (flickable.contentWidth - flickable.width)
207+ flickable.contentX = Math.min(flickable.contentWidth - flickable.width, Math.max(flickable.contentX, contentX))
208+ }
154209 }
155210 }
156−
157− Icon {
158− source: "graphics/multi-monitor_leave.png"
159− height: units.gu(4)
160− width: height
161− anchors.centerIn: parent
162− }
163211 }
164212}
tests/qmltests/tst_Shell.qml+2
@@ -276,6 +276,7 @@ Rectangle {
276276 anchors { left: parent.left; right: parent.right }
277277 activeFocusOnPress: false
278278 model: ["phone", "tablet", "desktop"]
279+ selectedIndex: 2
279280 onSelectedIndexChanged: {
280281 shellLoader.state = model[selectedIndex];
281282 }
@@ -289,6 +290,7 @@ Rectangle {
289290 anchors { left: parent.left; right: parent.right }
290291 activeFocusOnPress: false
291292 model: ["phone", "tablet", "desktop"]
293+ selectedIndex: 2
292294 }
293295 MouseTouchEmulationCheckbox {
294296 id: mouseEmulation