on xenial help sign in
make workspaces a listview
e73e035Michael Zanetti
qml/Stage/Spread/ScreensAndWorkspaces.qml+48−3
@@ -11,15 +11,60 @@ Item {
11 Row {
11 Row {
12 anchors.bottom: parent.bottom
12 anchors.bottom: parent.bottom
13 anchors.bottomMargin: units.gu(1)
13 anchors.bottomMargin: units.gu(1)
14− anchors.horizontalCenter: parent.horizontalCenter
14+// anchors.horizontalCenter: parent.horizontalCenter
15+ anchors.left: parent.left
15 spacing: units.gu(1)
16 spacing: units.gu(1)
16
17
17 Repeater {
18 Repeater {
18 model: Screens
19 model: Screens
19
20
20− delegate: WorkspacePreview {
21+ delegate: Item {
21 height: root.height - units.gu(6)
22 height: root.height - units.gu(6)
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)
22− background: root.background
66+// background: root.background
67+// }
23 }
68 }
24 }
69 }
25 }
70 }
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 {
565
565
566 ScreensAndWorkspaces {
566 ScreensAndWorkspaces {
567 id: screensAndWorkspaces
567 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 }
569 height: parent.height / 3
569 height: parent.height / 3
570 background: root.background
570 background: root.background
571 opacity: 0
571 opacity: 0
qml/Stage/WorkspacePreview.qml+149−101
@@ -8,7 +8,7 @@ UbuntuShape {
8 id: previewSpace
8 id: previewSpace
9
9
10 // Set the height. this preview will then automatically adjust the width, keeping aspect ratio of the screen
10 // 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
12 color: "white"
12 color: "white"
13 property string background
13 property string background
14
14
@@ -20,6 +20,7 @@ UbuntuShape {
20 id: header
20 id: header
21 anchors { left: parent.left; top: parent.top; right: parent.right }
21 anchors { left: parent.left; top: parent.top; right: parent.right }
22 height: units.gu(7)
22 height: units.gu(7)
23+
23 Column {
24 Column {
24 anchors.fill: parent
25 anchors.fill: parent
25 anchors.margins: units.gu(1)
26 anchors.margins: units.gu(1)
@@ -44,121 +45,168 @@ UbuntuShape {
44 }
45 }
45
46
46
47
47− Wallpaper {
48+ Rectangle {
48 anchors.fill: parent
49 anchors.fill: parent
49 anchors.topMargin: header.height
50 anchors.topMargin: header.height
50− source: previewSpace.background
51+ color: "blue"
51− clip: true
52
52
53 Repeater {
53 Repeater {
54− id: topLevelSurfaceRepeater
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
55− model: visible ? topLevelSurfaceList : null
69+ // model: visible ? topLevelSurfaceList : null
56− delegate: Rectangle {
70+ // delegate: Rectangle {
57− width: surfaceItem.width
71+ // width: surfaceItem.width
58− height: surfaceItem.height + decorationHeight * previewScale
72+ // height: surfaceItem.height + decorationHeight * previewScale
59− x: model.window.position.x * previewScale
73+ // x: model.window.position.x * previewScale
60− y: (model.window.position.y - decorationHeight) * previewScale
74+ // y: (model.window.position.y - decorationHeight) * previewScale
61− color: "blue"
75+ // color: "blue"
62− z: topLevelSurfaceRepeater.count - index
76+ // z: topLevelSurfaceRepeater.count - index
63−
77+
64− property int decorationHeight: units.gu(3)
78+ // property int decorationHeight: units.gu(3)
65−
79+
66− WindowDecoration {
80+ // WindowDecoration {
67− width: surfaceItem.implicitWidth
81+ // width: surfaceItem.implicitWidth
68− height: parent.decorationHeight
82+ // height: parent.decorationHeight
69− transform: Scale {
83+ // transform: Scale {
70− origin.x: 0
84+ // origin.x: 0
71− origin.y: 0
85+ // origin.y: 0
72− xScale: previewScale
86+ // xScale: previewScale
73− yScale: previewScale
87+ // yScale: previewScale
74− }
88+ // }
75− title: model.window && model.window.surface ? model.window.surface.name : ""
89+ // title: model.window && model.window.surface ? model.window.surface.name : ""
76− z: 3
90+ // z: 3
77− }
91+ // }
78−
92+
79− MirSurfaceItem {
93+ // MirSurfaceItem {
80− id: surfaceItem
94+ // id: surfaceItem
81− y: parent.decorationHeight * previewScale
95+ // y: parent.decorationHeight * previewScale
82− width: implicitWidth * previewScale
96+ // width: implicitWidth * previewScale
83− height: implicitHeight * previewScale
97+ // height: implicitHeight * previewScale
84− surfaceWidth: -1
98+ // surfaceWidth: -1
85− surfaceHeight: -1
99+ // surfaceHeight: -1
86− onImplicitHeightChanged: print("item", surfaceItem, "height changed", implicitHeight)
100+ // onImplicitHeightChanged: print("item", surfaceItem, "height changed", implicitHeight)
87− surface: model.window.surface
101+ // surface: model.window.surface
102+ // }
103+ // }
104+ // }
88 }
105 }
89 }
106 }
90− }
91− }
92
107
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
101
108
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+
102− Rectangle {
118+// Rectangle {
103− anchors.fill: parent
119+// anchors.fill: parent
104− color: "#80000000"
120+// color: "#80000000"
105− radius: height / 2
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+// }
106 }
180 }
107
181
108− NumberAnimation {
182+ FloatingFlickable {
109− target: canvas
183+ id: flickable
184+ anchors.fill: parent
185+ contentWidth: workspaceRepeater.count * previewSpace.screenWidth * previewScale
110− property: "progress"
186+ property real progress: contentX / contentWidth
111− duration: 2000
187+ onContentXChanged: print("contentX:", contentX, "progress:", progress)
112− running: mouseArea.containsMouse
113− from: 0
114− to: 1
115 }
188 }
116
189
117− Canvas {
190+ MouseArea {
118− id: canvas
119− height: parent.height
120− width: height
121− anchors.centerIn: parent
191+ anchors.fill: parent
122−
192+ hoverEnabled: true
123− property real progress: 0.5
193+ property int scrollAreaWidth: width / 3
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();
146
194
147− ctx.strokeStyle = "white"
195+ onMouseXChanged: {
148− ctx.beginPath();
196+ var margins = flickable.width * 0.05;
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();
152
197
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+ }
154 }
209 }
155 }
210 }
156−
157− Icon {
158− source: "graphics/multi-monitor_leave.png"
159− height: units.gu(4)
160− width: height
161− anchors.centerIn: parent
162− }
163 }
211 }
164}
212}
tests/qmltests/tst_Shell.qml+2
@@ -276,6 +276,7 @@ Rectangle {
276 anchors { left: parent.left; right: parent.right }
276 anchors { left: parent.left; right: parent.right }
277 activeFocusOnPress: false
277 activeFocusOnPress: false
278 model: ["phone", "tablet", "desktop"]
278 model: ["phone", "tablet", "desktop"]
279+ selectedIndex: 2
279 onSelectedIndexChanged: {
280 onSelectedIndexChanged: {
280 shellLoader.state = model[selectedIndex];
281 shellLoader.state = model[selectedIndex];
281 }
282 }
@@ -289,6 +290,7 @@ Rectangle {
289 anchors { left: parent.left; right: parent.right }
290 anchors { left: parent.left; right: parent.right }
290 activeFocusOnPress: false
291 activeFocusOnPress: false
291 model: ["phone", "tablet", "desktop"]
292 model: ["phone", "tablet", "desktop"]
293+ selectedIndex: 2
292 }
294 }
293 MouseTouchEmulationCheckbox {
295 MouseTouchEmulationCheckbox {
294 id: mouseEmulation
296 id: mouseEmulation