2 import Ubuntu.Components 1.3
3 import WindowManager 1.0
4 import "MathUtils.js" as MathUtils
5 import "../../Components"
9 implicitWidth: listView.contentWidth
10 readonly property int minimumWidth: {
11 var count = Math.min(3, listView.count);
12 return listView.itemWidth * count + listView.spacing * (count - 1)
15 property QtObject screen: null
16 property alias workspaceModel: listView.model
17 property var background // TODO: should be stored in the workspace data
18 property int selectedIndex: -1
19 property bool readOnly: true
20 property var activeWorkspace: null
22 signal commitScreenSetup();
24 signal clicked(var workspace);
32 var index = listView.getDropIndex(drag);
33 drag.source.workspace.assign(workspaceModel, index)
34 drag.source.inDropArea = true;
38 var index = listView.getDropIndex(drag);
39 if (listView.dropItemIndex == index) return;
40 listView.model.move(listView.dropItemIndex, index, 1);
41 listView.dropItemIndex = index;
45 drag.source.workspace.unassign()
46 listView.dropItemIndex = -1;
47 listView.hoveredWorkspaceIndex = -1;
48 drag.source.inDropArea = false;
52 drop.accept(Qt.MoveAction);
53 listView.dropItemIndex = -1;
54 drag.source.inDropArea = false;
62 listView.progressiveScroll(drag.x)
63 listView.updateDropProperties(drag)
66 listView.hoveredWorkspaceIndex = -1
69 var surface = drag.source.surface;
70 drag.source.surface = null;
71 var workspace = listView.model.get(listView.hoveredWorkspaceIndex);
72 WorkspaceManager.moveSurfaceToWorkspace(surface, workspace);
73 drop.accept(Qt.MoveAction)
74 if (listView.hoveredHalf == "right") {
79 listView.hoveredWorkspaceIndex = -1
83 onSelectedIndexChanged: {
84 listView.positionViewAtIndex(selectedIndex, ListView.Center);
88 // We need to clip the listview as it has left/right margins and it would
89 // overlap with items next to it and eat mouse input. However, we can't
90 // just clip at the actual bounds as the delegates have the close button
91 // on hover which reaches a bit outside, so lets some margins for the clipping
93 anchors.margins: -units.gu(2)
101 topMargin: -parent.anchors.margins
102 bottomMargin: -parent.anchors.margins
103 leftMargin: -itemWidth - parent.anchors.margins
104 rightMargin: -itemWidth - parent.anchors.margins
106 boundsBehavior: Flickable.StopAtBounds
108 Behavior on contentX {
109 SmoothedAnimation { duration: 200 }
112 property var clickedWorkspace: null
114 orientation: ListView.Horizontal
116 leftMargin: itemWidth
117 rightMargin: itemWidth
119 property int screenWidth: screen.availableModes[screen.currentModeIndex].size.width
120 property int screenHeight: screen.availableModes[screen.currentModeIndex].size.height
121 property int itemWidth: height * screenWidth / screenHeight
122 property int foldingAreaWidth: itemWidth / 2
123 property int maxAngle: 40
125 property real realContentX: contentX - originX + leftMargin
126 property int dropItemIndex: -1
127 property int hoveredWorkspaceIndex: -1
128 property string hoveredHalf: "" // left or right
130 function getDropIndex(drag) {
131 var coords = mapToItem(listView.contentItem, drag.x, drag.y)
132 var index = Math.floor((drag.x + listView.realContentX) / (listView.itemWidth + listView.spacing));
133 if (index < 0) index = 0;
134 var upperLimit = dropItemIndex == -1 ? listView.count : listView.count - 1
135 if (index > upperLimit) index = upperLimit;
139 function updateDropProperties(drag) {
140 var coords = mapToItem(listView.contentItem, drag.x, drag.y)
141 var index = Math.floor(drag.x + listView.realContentX) / (listView.itemWidth + listView.spacing);
143 listView.hoveredWorkspaceIndex = -1;
144 listView.hoveredHalf = "";
148 var upperLimit = dropItemIndex == -1 ? listView.count : listView.count - 1
149 if (index > upperLimit) index = upperLimit;
150 listView.hoveredWorkspaceIndex = index;
151 var pixelsInTile = (drag.x + listView.realContentX) % (listView.itemWidth + listView.spacing);
152 listView.hoveredHalf = (pixelsInTile / listView.itemWidth) < .5 ? "left" : "right";
155 function progressiveScroll(mouseX) {
156 var progress = Math.max(0, Math.min(1, (mouseX - listView.itemWidth) / (width - listView.leftMargin * 2 - listView.itemWidth * 2)))
157 listView.contentX = listView.originX + (listView.contentWidth - listView.width + listView.leftMargin + listView.rightMargin) * progress - listView.leftMargin
160 displaced: Transition { UbuntuNumberAnimation { properties: "x" } }
163 id: workspaceDelegate
164 objectName: "delegate" + index
165 height: parent.height
166 width: listView.itemWidth
167 Behavior on width { UbuntuNumberAnimation {} }
168 visible: listView.dropItemIndex !== index
170 property int itemX: -listView.realContentX + index * (listView.itemWidth + listView.spacing)
171 property int distanceFromLeft: itemX //- listView.leftMargin
172 property int distanceFromRight: listView.width - listView.leftMargin - listView.rightMargin - itemX - listView.itemWidth
174 property int itemAngle: {
176 if (distanceFromLeft < 0) {
177 var progress = (distanceFromLeft + listView.foldingAreaWidth) / listView.foldingAreaWidth
178 return MathUtils.linearAnimation(1, -1, 0, listView.maxAngle, Math.max(-1, Math.min(1, progress)));
182 if (index == listView.count - 1) {
183 if (distanceFromRight < 0) {
184 var progress = (distanceFromRight + listView.foldingAreaWidth) / listView.foldingAreaWidth
185 return MathUtils.linearAnimation(1, -1, 0, -listView.maxAngle, Math.max(-1, Math.min(1, progress)));
190 if (distanceFromLeft < listView.foldingAreaWidth) {
191 // itemX : 10gu = p : 100
192 var progress = distanceFromLeft / listView.foldingAreaWidth
193 return MathUtils.linearAnimation(1, -1, 0, listView.maxAngle, Math.max(-1, Math.min(1, progress)));
195 if (distanceFromRight < listView.foldingAreaWidth) {
196 var progress = distanceFromRight / listView.foldingAreaWidth
197 return MathUtils.linearAnimation(1, -1, 0, -listView.maxAngle, Math.max(-1, Math.min(1, progress)));
202 property int itemOffset: {
204 if (distanceFromLeft < 0) {
205 return -distanceFromLeft
209 if (index == listView.count - 1) {
210 if (distanceFromRight < 0) {
211 return distanceFromRight
216 if (itemX < -listView.foldingAreaWidth) {
219 if (distanceFromLeft < listView.foldingAreaWidth) {
220 return (listView.foldingAreaWidth - distanceFromLeft) / 2
223 if (distanceFromRight < -listView.foldingAreaWidth) {
224 return distanceFromRight
227 if (distanceFromRight < listView.foldingAreaWidth) {
228 return -(listView.foldingAreaWidth - distanceFromRight) / 2
234 z: itemOffset < 0 ? itemOffset : -itemOffset
238 axis { x: 0; y: 1; z: 0 }
239 origin { x: itemAngle < 0 ? listView.itemWidth : 0; y: height / 2 }
248 height: listView.height
249 width: listView.itemWidth
250 background: root.background
251 screenHeight: listView.screenHeight
252 containsDragLeft: listView.hoveredWorkspaceIndex == index && listView.hoveredHalf == "left"
253 containsDragRight: listView.hoveredWorkspaceIndex == index && listView.hoveredHalf == "right"
254 isActive: workspace.isSameAs(root.activeWorkspace)
255 isSelected: index === root.selectedIndex
256 workspace: model.workspace
261 root.clicked(model.workspace)
264 model.workspace.activate();
271 objectName: "closeMouseArea"
272 anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 }
276 visible: !root.readOnly && listView.count > 1
279 model.workspace.unassign();
280 root.commitScreenSetup();
284 source: "../graphics/window-close.svg"
285 anchors.fill: closeMouseArea
286 anchors.margins: units.gu(1)
287 sourceSize.width: width
288 sourceSize.height: height
289 readonly property var mousePos: hoverMouseArea.mapToItem(workspaceDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
290 readonly property bool shown: (hoverMouseArea.containsMouse || parent.containsMouse)
291 && mousePos.y < workspaceDelegate.width / 4
292 && mousePos.y > -units.gu(2)
293 && mousePos.x > -units.gu(2)
294 && mousePos.x < workspaceDelegate.height / 4
295 opacity: shown ? 1 : 0
297 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
307 propagateComposedEvents: true
308 anchors.leftMargin: listView.leftMargin
309 anchors.rightMargin: listView.rightMargin
310 enabled: !root.readOnly
312 property int draggedIndex: -1
314 property int startX: 0
315 property int startY: 0
318 if (!pressed || dragging) {
319 listView.progressiveScroll(mouseX)
323 if (Math.abs(mouseY - startY) > units.gu(3)) {
324 drag.axis = Drag.XAndYAxis;
329 var result = fakeDragItem.Drag.drop();
330 // if (result == Qt.IgnoreAction) {
331 // WorkspaceManager.destroyWorkspace(fakeDragItem.workspace);
333 root.commitScreenSetup();
337 property bool dragging: drag.active
340 var ws = listView.model.get(draggedIndex);
341 if (ws) ws.unassign();
348 if (listView.model.count < 2) return;
350 var coords = mapToItem(listView.contentItem, mouseX, mouseY)
351 draggedIndex = listView.indexAt(coords.x, coords.y)
352 var clickedItem = listView.itemAt(coords.x, coords.y)
354 var itemCoords = clickedItem.mapToItem(listView, -listView.leftMargin, 0);
355 fakeDragItem.x = itemCoords.x
356 fakeDragItem.y = itemCoords.y
357 fakeDragItem.workspace = listView.model.get(draggedIndex)
359 var mouseCoordsInItem = mapToItem(clickedItem, mouseX, mouseY);
360 fakeDragItem.Drag.hotSpot.x = mouseCoordsInItem.x
361 fakeDragItem.Drag.hotSpot.y = mouseCoordsInItem.y
363 drag.axis = Drag.YAxis;
364 drag.target = fakeDragItem;
369 height: listView.height
370 width: listView.itemWidth
371 background: root.background
372 screenHeight: screen.availableModes[screen.currentModeIndex].size.height
375 Drag.active: hoverMouseArea.drag.active
376 Drag.keys: ['workspace']
378 property bool inDropArea: false
383 opacity: parent.inDropArea ? 0 : 1
384 Behavior on opacity { UbuntuNumberAnimation { } }
386 anchors.centerIn: parent
396 anchors.centerIn: parent
404 when: fakeDragItem.Drag.active
405 ParentChange { target: fakeDragItem; parent: shell }