@@ -32,6 +32,18 @@ Rectangle {
32 property bool spreadEnabled: true // If false, animations and right edge will be disabled
32 property bool spreadEnabled: true // If false, animations and right edge will be disabled
33 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
33 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
34 property int orientation: Qt.PortraitOrientation
34 property int orientation: Qt.PortraitOrientation
35+ property QtObject applicationManager: ApplicationManager
36+ property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
37+ property bool altTabEnabled: true
38+ property real startScale: 1.1
39+ property real endScale: 0.7
41+ // How far left the stage has been dragged
42+ readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
44+ readonly property alias dragging: spreadDragArea.dragging
36 color: "#111111"
48 color: "#111111"
@@ -52,30 +64,30 @@ Rectangle {
52 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
64 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
53 // left edge drag released. Minimum distance is given by design.
65 // left edge drag released. Minimum distance is given by design.
54 if (priv.oldInverseProgress > units.gu(22)) {
66 if (priv.oldInverseProgress > units.gu(22)) {
55− ApplicationManager.focusApplication("unity8-dash");
67+ applicationManager.focusApplication("unity8-dash");
58 priv.oldInverseProgress = inverseProgress;
70 priv.oldInverseProgress = inverseProgress;
61 Connections {
73 Connections {
62− target: ApplicationManager
74+ target: applicationManager
64 onFocusRequested: {
76 onFocusRequested: {
65 if (spreadView.phase > 0) {
77 if (spreadView.phase > 0) {
66 spreadView.snapTo(priv.indexOf(appId));
78 spreadView.snapTo(priv.indexOf(appId));
68− ApplicationManager.focusApplication(appId);
80+ applicationManager.focusApplication(appId);
72 onApplicationAdded: {
84 onApplicationAdded: {
73 if (spreadView.phase == 2) {
85 if (spreadView.phase == 2) {
74− spreadView.snapTo(ApplicationManager.count - 1);
86+ spreadView.snapTo(applicationManager.count - 1);
76 spreadView.phase = 0;
88 spreadView.phase = 0;
77 spreadView.contentX = -spreadView.shift;
89 spreadView.contentX = -spreadView.shift;
78− ApplicationManager.focusApplication(appId);
90+ applicationManager.focusApplication(appId);
@@ -90,9 +102,9 @@ Rectangle {
92 function focusTopMostApp() {
104 function focusTopMostApp() {
93− if (ApplicationManager.count > 0) {
105+ if (applicationManager.count > 0) {
94− var topmostApp = ApplicationManager.get(0);
106+ var topmostApp = applicationManager.get(0);
95− ApplicationManager.focusApplication(topmostApp.appId);
107+ applicationManager.focusApplication(topmostApp.appId);
@@ -100,8 +112,9 @@ Rectangle {
100 QtObject {
112 QtObject {
115+ readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
103− property string focusedAppId: ApplicationManager.focusedApplicationId
116+ property string focusedAppId: applicationManager.focusedApplicationId
104− property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
117+ property var focusedApplication: applicationManager.findApplication(focusedAppId)
105 property var focusedAppDelegate: null
118 property var focusedAppDelegate: null
107 property real oldInverseProgress: 0
120 property real oldInverseProgress: 0
@@ -110,8 +123,8 @@ Rectangle {
110 onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
123 onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
112 function indexOf(appId) {
125 function indexOf(appId) {
113− for (var i = 0; i < ApplicationManager.count; i++) {
126+ for (var i = 0; i < applicationManager.count; i++) {
114− if (ApplicationManager.get(i).appId == appId) {
127+ if (applicationManager.get(i).appId == appId) {
115 return i;
128 return i;
@@ -197,10 +210,17 @@ Rectangle {
197 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
210 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
198 snapAnimation.targetContentX = width * positionMarker4 + 1 - shift;
211 snapAnimation.targetContentX = width * positionMarker4 + 1 - shift;
199 snapAnimation.start();
212 snapAnimation.start();
202 function snapTo(index) {
216 function snapTo(index) {
203− if (ApplicationManager.count <= index) {
217+ if (!root.altTabEnabled) {
218+ // Reset to start instead
219+ snapAnimation.targetContentX = -shift;
220+ snapAnimation.start();
223+ if (applicationManager.count <= index) {
204 // In case we're trying to snap to some non existing app, lets snap back to the first one
224 // In case we're trying to snap to some non existing app, lets snap back to the first one
205 index = 0;
225 index = 0;
@@ -215,7 +235,7 @@ Rectangle {
215 snapAnimation.start();
235 snapAnimation.start();
218− // In case the ApplicationManager already holds an app when starting up we're missing animations
238+ // In case the applicationManager already holds an app when starting up we're missing animations
219 // Make sure we end up in the same state
239 // Make sure we end up in the same state
220 Component.onCompleted: {
240 Component.onCompleted: {
221 spreadView.contentX = -spreadView.shift
241 spreadView.contentX = -spreadView.shift
@@ -235,7 +255,7 @@ Rectangle {
235 ScriptAction {
255 ScriptAction {
236 script: {
256 script: {
237 if (spreadView.selectedIndex >= 0) {
257 if (spreadView.selectedIndex >= 0) {
238− ApplicationManager.focusApplication(ApplicationManager.get(spreadView.selectedIndex).appId);
258+ applicationManager.focusApplication(applicationManager.get(spreadView.selectedIndex).appId);
240 spreadView.selectedIndex = -1;
260 spreadView.selectedIndex = -1;
241 spreadView.phase = 0;
261 spreadView.phase = 0;
@@ -250,7 +270,7 @@ Rectangle {
250 // This width controls how much the spread can be flicked left/right. It's composed of:
270 // This width controls how much the spread can be flicked left/right. It's composed of:
251 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
271 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
252 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
272 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
253− width: Math.max(3, ApplicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
273+ width: Math.max(3, applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
254 height: parent.height
274 height: parent.height
255 Behavior on width {
275 Behavior on width {
256 enabled: spreadView.closingIndex >= 0
276 enabled: spreadView.closingIndex >= 0
@@ -265,20 +285,22 @@ Rectangle {
265 x: spreadView.contentX
285 x: spreadView.contentX
267 onClicked: {
287 onClicked: {
288+ if (root.altTabEnabled) {
268− spreadView.snapTo(0);
289+ spreadView.snapTo(0);
271 Repeater {
293 Repeater {
272 id: spreadRepeater
294 id: spreadRepeater
273 objectName: "spreadRepeater"
295 objectName: "spreadRepeater"
274− model: ApplicationManager
296+ model: applicationManager
275 delegate: TransformedSpreadDelegate {
297 delegate: TransformedSpreadDelegate {
276 id: appDelegate
298 id: appDelegate
277 objectName: "appDelegate" + index
299 objectName: "appDelegate" + index
278 startAngle: 45
300 startAngle: 45
279 endAngle: 5
301 endAngle: 5
280− startScale: 1.1
302+ startScale: root.startScale
281− endScale: 0.7
303+ endScale: root.endScale
282 startDistance: spreadView.tileDistance
304 startDistance: spreadView.tileDistance
283 endDistance: units.gu(.5)
305 endDistance: units.gu(.5)
284 width: spreadView.width
306 width: spreadView.width
@@ -286,11 +308,12 @@ Rectangle {
286 selected: spreadView.selectedIndex == index
308 selected: spreadView.selectedIndex == index
287 otherSelected: spreadView.selectedIndex >= 0 && !selected
309 otherSelected: spreadView.selectedIndex >= 0 && !selected
288 interactive: !spreadView.interactive && spreadView.phase === 0
310 interactive: !spreadView.interactive && spreadView.phase === 0
289− && spreadView.shiftedContentX === 0 && root.interactive && index === 0
311+ && spreadView.shiftedContentX === 0 && root.interactive && isFocused
290− swipeToCloseEnabled: spreadView.interactive && !snapAnimation.running
312+ swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running
291 maximizedAppTopMargin: root.maximizedAppTopMargin
313 maximizedAppTopMargin: root.maximizedAppTopMargin
292 dropShadow: spreadView.active ||
314 dropShadow: spreadView.active ||
293 (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
315 (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
316+ focusFirstApp: root.focusFirstApp
295 readonly property bool isDash: model.appId == "unity8-dash"
318 readonly property bool isDash: model.appId == "unity8-dash"
@@ -298,7 +321,7 @@ Rectangle {
300 // focused app is always positioned at 0 except when following left edge drag
323 // focused app is always positioned at 0 except when following left edge drag
301− if (index == 0) {
324+ if (isFocused) {
302 if (!isDash && root.inverseProgress > 0) {
325 if (!isDash && root.inverseProgress > 0) {
303 return root.inverseProgress;
326 return root.inverseProgress;
@@ -309,10 +332,10 @@ Rectangle {
311 // Otherwise line up for the spread
334 // Otherwise line up for the spread
312− return spreadView.width + (index - 1) * spreadView.tileDistance;
335+ return spreadView.width + spreadIndex * spreadView.tileDistance;
315− application: ApplicationManager.get(index)
338+ application: applicationManager.get(index)
316 closeable: !isDash
339 closeable: !isDash
318 property real behavioredIndex: index
341 property real behavioredIndex: index
@@ -350,7 +373,7 @@ Rectangle {
350 progress: {
373 progress: {
351 var tileProgress = (spreadView.shiftedContentX - behavioredIndex * spreadView.tileDistance) / spreadView.width;
374 var tileProgress = (spreadView.shiftedContentX - behavioredIndex * spreadView.tileDistance) / spreadView.width;
352 // Tile 1 needs to move directly from the beginning...
375 // Tile 1 needs to move directly from the beginning...
353− if (behavioredIndex == 1 && spreadView.phase < 2) {
376+ if (root.focusFirstApp && behavioredIndex == 1 && spreadView.phase < 2) {
354 tileProgress += spreadView.tileDistance / spreadView.width;
377 tileProgress += spreadView.tileDistance / spreadView.width;
356 // Limiting progress to ~0 and 1.7 to avoid binding calculations when tiles are not
379 // Limiting progress to ~0 and 1.7 to avoid binding calculations when tiles are not
@@ -365,7 +388,7 @@ Rectangle {
366 // This mostly is the same as progress, just adds the snapping to phase 1 for tiles 0 and 1
389 // This mostly is the same as progress, just adds the snapping to phase 1 for tiles 0 and 1
367 animatedProgress: {
390 animatedProgress: {
368− if (spreadView.phase == 0 && index < 2) {
391+ if (spreadView.phase == 0 && index <= priv.firstSpreadIndex) {
369 if (progress < spreadView.positionMarker1) {
392 if (progress < spreadView.positionMarker1) {
370 return progress;
393 return progress;
371 } else if (progress < spreadView.positionMarker1 + 0.05){
394 } else if (progress < spreadView.positionMarker1 + 0.05){
@@ -390,11 +413,11 @@ Rectangle {
392 onClicked: {
415 onClicked: {
393− if (spreadView.phase == 2) {
416+ if (root.altTabEnabled && spreadView.phase == 2) {
394− if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) {
417+ if (applicationManager.focusedApplicationId == applicationManager.get(index).appId) {
395 spreadView.snapTo(index);
418 spreadView.snapTo(index);
397− ApplicationManager.requestFocusApplication(ApplicationManager.get(index).appId);
420+ applicationManager.requestFocusApplication(applicationManager.get(index).appId);
@@ -409,7 +432,7 @@ Rectangle {
410 onClosed: {
433 onClosed: {
411 spreadView.closingIndex = index;
434 spreadView.closingIndex = index;
412− ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
435+ applicationManager.stopApplication(applicationManager.get(index).appId);