on xenial help sign in
add drag and drop wor workspaces between screens
1c77322Michael Zanetti
qml/Stage/Spread/ScreensAndWorkspaces.qml+44−3
@@ -1,18 +1,19 @@
1import QtQuick 2.4
1import QtQuick 2.4
2import Ubuntu.Components 1.3
2import Ubuntu.Components 1.3
3+import Ubuntu.Components.Popups 1.3
3import Unity.Screens 0.1
4import Unity.Screens 0.1
4import Unity.Application 0.1
5import Unity.Application 0.1
5import ".."
6import ".."
6
7
7Item {
8Item {
8 id: root
9 id: root
10+
9 property string background
11 property string background
10
12
11 Row {
13 Row {
12 anchors.bottom: parent.bottom
14 anchors.bottom: parent.bottom
13− anchors.bottomMargin: units.gu(1)
15+ anchors.horizontalCenter: parent.horizontalCenter
14−// anchors.horizontalCenter: parent.horizontalCenter
15− anchors.left: parent.left
16+// anchors.left: parent.left
16 spacing: units.gu(1)
17 spacing: units.gu(1)
17
18
18 Repeater {
19 Repeater {
@@ -21,12 +22,14 @@ Item {
21 delegate: Item {
22 delegate: Item {
22 height: root.height - units.gu(6)
23 height: root.height - units.gu(6)
23 width: workspaces.width
24 width: workspaces.width
25+ clip: true
24
26
25 UbuntuShape {
27 UbuntuShape {
26 id: header
28 id: header
27 anchors { left: parent.left; top: parent.top; right: parent.right }
29 anchors { left: parent.left; top: parent.top; right: parent.right }
28 height: units.gu(7)
30 height: units.gu(7)
29 backgroundColor: "white"
31 backgroundColor: "white"
32+ z: 1
30
33
31 Column {
34 Column {
32 anchors.fill: parent
35 anchors.fill: parent
@@ -49,6 +52,29 @@ Item {
49 fontSize: "x-small"
52 fontSize: "x-small"
50 }
53 }
51 }
54 }
55+
56+ MouseArea {
57+ anchors.fill: parent
58+// acceptedButtons: Qt.RightButton
59+
60+
61+ onClicked: {
62+ print("should open popup")
63+ PopupUtils.open(contextMenu)
64+ }
65+ }
66+
67+ Component {
68+ id: contextMenu
69+ ActionSelectionPopover {
70+ actions: ActionList {
71+ Action {
72+ text: "Add workspace"
73+ onTriggered: workspaces.workspaceModel.append({text: "" + workspaces.workspaceModel.count})
74+ }
75+ }
76+ }
77+ }
52 }
78 }
53
79
54
80
@@ -56,10 +82,25 @@ Item {
56 id: workspaces
82 id: workspaces
57 height: parent.height - header.height - units.gu(2)
83 height: parent.height - header.height - units.gu(2)
58 width: Math.min(implicitWidth, units.gu(80), root.width)
84 width: Math.min(implicitWidth, units.gu(80), root.width)
85+ Behavior on width { UbuntuNumberAnimation {} }
59 anchors.bottom: parent.bottom
86 anchors.bottom: parent.bottom
87+ anchors.bottomMargin: units.gu(1)
60 anchors.horizontalCenter: parent.horizontalCenter
88 anchors.horizontalCenter: parent.horizontalCenter
61 screen: model.screen
89 screen: model.screen
62 background: root.background
90 background: root.background
91+
92+ workspaceModel: ListModel {
93+ onCountChanged: print("model count changed to", count)
94+ ListElement {text: "1"}
95+// ListElement {text: "2"}
96+// ListElement {text: "3"}
97+// ListElement {text: "4"}
98+// ListElement {text: "5"}
99+// ListElement {text: "6"}
100+// ListElement {text: "7"}
101+// ListElement {text: "8"}
102+// ListElement {text: "9"}
103+ }
63 }
104 }
64 }
105 }
65 }
106 }
qml/Stage/Spread/Workspaces.qml+134−73
@@ -2,15 +2,46 @@ import QtQuick 2.4
2import Ubuntu.Components 1.3
2import Ubuntu.Components 1.3
3import "MathUtils.js" as MathUtils
3import "MathUtils.js" as MathUtils
4
4
5−Rectangle {
5+Item {
6 id: root
6 id: root
7− implicitWidth: listView.count * (height * 16/9)
7+ implicitWidth: listView.count * (height * 16/9 + listView.spacing) - listView.spacing
8− color: "blue"
8+// color: "blue"
9
9
10− property var screen: null
10+ property QtObject screen: null
11+ property alias workspaceModel: listView.model
11 property var background // TODO: should be stored in the workspace data
12 property var background // TODO: should be stored in the workspace data
12
13
14+ DropArea {
13−// Rectangle { anchors.fill: parent; color: "green" }
15+ anchors.fill: root
16+
17+ keys: ['workspace']
18+
19+ onEntered: {
20+ var index = listView.getDropIndex(drag);
21+ listView.model.insert(index, {text: drag.source.text})
22+ listView.dropItemIndex = index;
23+ drag.source.inDropArea = true;
24+ }
25+
26+ onPositionChanged: {
27+ var index = listView.getDropIndex(drag);
28+ if (listView.dropItemIndex == index) return;
29+ listView.model.move(listView.dropItemIndex, index, 1);
30+ listView.dropItemIndex = index;
31+ }
32+
33+ onExited: {
34+ listView.model.remove(listView.dropItemIndex, 1);
35+ listView.dropItemIndex = -1;
36+ drag.source.inDropArea = false;
37+ }
38+
39+ onDropped: {
40+ listView.dropItemIndex = -1;
41+ drag.source.inDropArea = false;
42+ }
43+ }
44+
14 ListView {
45 ListView {
15 id: listView
46 id: listView
16 anchors.fill: parent
47 anchors.fill: parent
@@ -18,19 +49,6 @@ Rectangle {
18 anchors.rightMargin: -itemWidth
49 anchors.rightMargin: -itemWidth
19 interactive: false
50 interactive: false
20
51
21− model: ListModel {
22− ListElement {text: "1"}
23− ListElement {text: "2"}
24− ListElement {text: "3"}
25− ListElement {text: "4"}
26− ListElement {text: "5"}
27− ListElement {text: "6"}
28− ListElement {text: "7"}
29− ListElement {text: "8"}
30− ListElement {text: "9"}
31− }
32−
33−
34 orientation: ListView.Horizontal
52 orientation: ListView.Horizontal
35 spacing: units.gu(1)
53 spacing: units.gu(1)
36 leftMargin: itemWidth
54 leftMargin: itemWidth
@@ -39,14 +57,25 @@ Rectangle {
39 property int itemWidth: height * 16 / 9
57 property int itemWidth: height * 16 / 9
40 property int foldingAreaWidth: units.gu(10)
58 property int foldingAreaWidth: units.gu(10)
41 property real realContentX: contentX - originX + leftMargin
59 property real realContentX: contentX - originX + leftMargin
60+ property int dropItemIndex: -1
61+
62+ function getDropIndex(drag) {
63+ var coords = mapToItem(listView.contentItem, drag.x, drag.y)
64+ var index = Math.floor((drag.x + listView.realContentX) / (listView.itemWidth + listView.spacing));
65+ if (index < 0) index = 0;
66+ var upperLimit = dropItemIndex == -1 ? listView.count : listView.count - 1
67+ if (index > upperLimit) index = upperLimit;
68+ return index;
69+ }
42
70
43 displaced: Transition { UbuntuNumberAnimation { properties: "x" } }
71 displaced: Transition { UbuntuNumberAnimation { properties: "x" } }
44
72
45 delegate: Item {
73 delegate: Item {
46 objectName: "delegate" + index
74 objectName: "delegate" + index
47 height: parent.height
75 height: parent.height
48− width: /*dndArea.draggedIndex == index ? units.gu(5) :*/ listView.itemWidth
76+ width: listView.itemWidth
49 Behavior on width { UbuntuNumberAnimation {} }
77 Behavior on width { UbuntuNumberAnimation {} }
78+ visible: listView.dropItemIndex !== index
50
79
51 property int itemX: -listView.realContentX + index * (listView.itemWidth + listView.spacing)
80 property int itemX: -listView.realContentX + index * (listView.itemWidth + listView.spacing)
52 property int distanceFromLeft: itemX //- listView.leftMargin
81 property int distanceFromLeft: itemX //- listView.leftMargin
@@ -83,34 +112,33 @@ Rectangle {
83 }
112 }
84
113
85 property int itemOffset: {
114 property int itemOffset: {
115+ var rotationOffset = (1 - Math.cos(itemAngle * Math.PI / 360)) * listView.itemWidth
86 if (index == 0) {
116 if (index == 0) {
87 if (distanceFromLeft < 0) {
117 if (distanceFromLeft < 0) {
88− return -distanceFromLeft
118+ return -distanceFromLeft - rotationOffset
89 }
119 }
90 return 0
120 return 0
91 }
121 }
92 if (index == listView.count - 1) {
122 if (index == listView.count - 1) {
93 if (distanceFromRight < 0) {
123 if (distanceFromRight < 0) {
94− return distanceFromRight
124+ return distanceFromRight + rotationOffset
95 }
125 }
96 return 0
126 return 0
97 }
127 }
98
128
99 if (itemX < -listView.foldingAreaWidth) {
129 if (itemX < -listView.foldingAreaWidth) {
100− return -itemX
130+ return -itemX - rotationOffset
101 }
131 }
102 if (distanceFromLeft < listView.foldingAreaWidth) {
132 if (distanceFromLeft < listView.foldingAreaWidth) {
103− var progress = distanceFromLeft / listView.foldingAreaWidth
104− return (listView.foldingAreaWidth - distanceFromLeft) / 2
133+ return (listView.foldingAreaWidth - distanceFromLeft) / 2 - rotationOffset
105 }
134 }
106
135
107 if (distanceFromRight < -listView.foldingAreaWidth) {
136 if (distanceFromRight < -listView.foldingAreaWidth) {
108− return distanceFromRight
137+ return distanceFromRight + rotationOffset
109 }
138 }
110
139
111 if (distanceFromRight < listView.foldingAreaWidth) {
140 if (distanceFromRight < listView.foldingAreaWidth) {
112− var progress = distanceFromRight / listView.foldingAreaWidth;
113− return -(listView.foldingAreaWidth - distanceFromRight) / 2
141+ return -(listView.foldingAreaWidth - distanceFromRight) / 2 + rotationOffset
114 }
142 }
115
143
116 return 0
144 return 0
@@ -123,38 +151,36 @@ Rectangle {
123 Rotation {
151 Rotation {
124 angle: itemAngle
152 angle: itemAngle
125 axis { x: 0; y: 1; z: 0 }
153 axis { x: 0; y: 1; z: 0 }
126− origin { x: /*itemAngle > 0 ? 0 : listView.itemWidth*/ listView.itemWidth / 2; y: height / 2 }
154+ origin { x: listView.itemWidth / 2; y: height / 2 }
127 },
155 },
128 Translate {
156 Translate {
129 x: itemOffset
157 x: itemOffset
130 }
158 }
131−
132 ]
159 ]
133
160
134 WorkspacePreview {
161 WorkspacePreview {
135 height: listView.height
162 height: listView.height
136 width: listView.itemWidth
163 width: listView.itemWidth
137 background: root.background
164 background: root.background
138− screenHeight: screen.physicalSize.height
165+ screenHeight: root.screen.physicalSize.height
139− }
140
166
141− Label {
167+ Label {
142− anchors.centerIn: parent
168+ anchors.centerIn: parent
143− text: model.text
169+ text: model.text
170+ color: "red"
144− fontSize: "large"
171+ fontSize: "large"
145− color: "red"
172+ }
146 }
173 }
147 }
174 }
148
175
149 MouseArea {
176 MouseArea {
150− id: dndArea
177+ id: mouseArea
151 anchors.fill: parent
178 anchors.fill: parent
152 hoverEnabled: true
179 hoverEnabled: true
153 preventStealing: true
180 preventStealing: true
154 anchors.leftMargin: listView.leftMargin
181 anchors.leftMargin: listView.leftMargin
155 anchors.rightMargin: listView.rightMargin
182 anchors.rightMargin: listView.rightMargin
156
183
157−
158 property int draggedIndex: -1
184 property int draggedIndex: -1
159
185
160 onMouseXChanged: {
186 onMouseXChanged: {
@@ -162,54 +188,89 @@ Rectangle {
162// var progress = mouseX / width
188// var progress = mouseX / width
163// print("p:", progress)
189// print("p:", progress)
164 listView.contentX = listView.originX + (listView.contentWidth - listView.width + listView.leftMargin + listView.rightMargin) * progress - listView.leftMargin
190 listView.contentX = listView.originX + (listView.contentWidth - listView.width + listView.leftMargin + listView.rightMargin) * progress - listView.leftMargin
191+ }
165
192
193+ onReleased: {
194+ fakeDragItem.Drag.drop();
195+ drag.target = null;
196+ }
166
197
167− if (draggedIndex == -1) {
198+ property bool dragging: drag.active
168− return;
199+ onDraggingChanged: {
200+ if (drag.active) {
201+ print("drai", draggedIndex)
202+ listView.model.remove(draggedIndex, 1)
169 }
203 }
204+ }
170
205
171−// var newIndex = (listView.realContentX) / listView.itemWidth
206+ onPressed: {
172− var coords = mapToItem(listView.contentItem, mouseX + listView.itemWidth, mouseY)
207+ if (listView.model.count < 2) return;
173− var newIndex = (coords.x + listView.leftMargin) / (listView.itemWidth + listView.spacing)
174− print("newIndex", newIndex)
175−// var newIndex = listView.indexAt(coords.x, coords.y)
176−// if (newIndex == -1) return;
177−
178− if (newIndex > draggedIndex + 1) {
179− newIndex = draggedIndex + 1
180− } else if (newIndex < draggedIndex) {
181− newIndex = draggedIndex - 1
182− } else {
183− return
184− }
185
208
186− if (newIndex >= 0 && newIndex < listView.count) {
209+ var coords = mapToItem(listView.contentItem, mouseX, mouseY)
187− listView.model.move(draggedIndex, newIndex, 1)
210+ draggedIndex = listView.indexAt(coords.x, coords.y)
188− draggedIndex = newIndex
211+ var clickedItem = listView.itemAt(coords.x, coords.y)
189− }
190− }
191
212
192− onReleased: {
213+ var itemCoords = clickedItem.mapToItem(listView, -listView.leftMargin, 0);
193− draggedIndex = -1
214+ fakeDragItem.x = itemCoords.x
194− }
215+ fakeDragItem.y = itemCoords.y
216+ fakeDragItem.text = listView.model.get(draggedIndex).text
195
217
196− onPressAndHold: {
197−// var clickedItem = listView.itemAt(mouseX /*+ listView.realContentX*/, mouseY)
218+ var mouseCoordsInItem = mapToItem(clickedItem, mouseX, mouseY);
198−// var clickedIndex = listView.indexAt(mouseX /*- listView.realContentX*/, mouseY)
219+ fakeDragItem.Drag.hotSpot.x = mouseCoordsInItem.x
220+ fakeDragItem.Drag.hotSpot.y = mouseCoordsInItem.y
221+
222+ drag.target = fakeDragItem;
223+ }
199
224
200− for (var i = 0; i < listView.count; i++) {
225+ WorkspacePreview {
226+ id: fakeDragItem
227+ height: listView.height
201− var x = -listView.leftMargin + i * listView.itemWidth - units.gu(1);
228+ width: listView.itemWidth
202− print("x:", x, "index:", listView.indexAt(x, listView.height / 2))
229+ background: root.background
230+ screenHeight: root.screen.physicalSize.height
231+ visible: Drag.active
232+
233+ Drag.active: mouseArea.drag.active
234+ Drag.keys: ['workspace']
235+
236+ property string text
237+ property bool inDropArea: false
238+ Label {
239+ anchors.centerIn: parent
240+ text: parent.text
241+ color: "red"
242+ fontSize: "large"
203 }
243 }
204
244
205− var coords = mapToItem(listView.contentItem, mouseX, mouseY)
245+ Rectangle {
206− var clickedIndex = listView.indexAt(coords.x, coords.y)
246+ anchors.fill: parent
247+ color: "#33000000"
248+ opacity: parent.inDropArea ? 0 : 1
249+ Behavior on opacity { UbuntuNumberAnimation { } }
250+ Rectangle {
251+ anchors.centerIn: parent
252+ width: units.gu(6)
253+ height: units.gu(6)
254+ radius: width / 2
255+ color: "#aa000000"
256+ }
207
257
208− draggedIndex = clickedIndex
258+ Icon {
259+ height: units.gu(3)
260+ width: height
261+ anchors.centerIn: parent
262+ name: "edit-delete"
263+ color: "white"
264+ }
265+ }
209
266
210− print("index:", mouseX, clickedIndex)
267+ states: [
268+ State {
269+ when: fakeDragItem.Drag.active
270+ ParentChange { target: fakeDragItem; parent: shell }
271+ }
272+ ]
211 }
273 }
212−
213 }
274 }
214 }
275 }
215}
276}