@@ -32,6 +32,21 @@ 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
46+ // Only used by the tutorial right now, when it is teasing the right edge
47+ property real dragAreaOverlap
36 color: "#111111"
51 color: "#111111"
@@ -52,30 +67,30 @@ Rectangle {
52 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
67 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
53 // left edge drag released. Minimum distance is given by design.
68 // left edge drag released. Minimum distance is given by design.
54 if (priv.oldInverseProgress > units.gu(22)) {
69 if (priv.oldInverseProgress > units.gu(22)) {
55− ApplicationManager.requestFocusApplication("unity8-dash");
70+ applicationManager.requestFocusApplication("unity8-dash");
58 priv.oldInverseProgress = inverseProgress;
73 priv.oldInverseProgress = inverseProgress;
61 Connections {
76 Connections {
62− target: ApplicationManager
77+ target: applicationManager
64 onFocusRequested: {
79 onFocusRequested: {
65 if (spreadView.phase > 0) {
80 if (spreadView.phase > 0) {
66 spreadView.snapTo(priv.indexOf(appId));
81 spreadView.snapTo(priv.indexOf(appId));
68− ApplicationManager.focusApplication(appId);
83+ applicationManager.focusApplication(appId);
72 onApplicationAdded: {
87 onApplicationAdded: {
73 if (spreadView.phase == 2) {
88 if (spreadView.phase == 2) {
74− spreadView.snapTo(ApplicationManager.count - 1);
89+ spreadView.snapTo(applicationManager.count - 1);
76 spreadView.phase = 0;
91 spreadView.phase = 0;
77 spreadView.contentX = -spreadView.shift;
92 spreadView.contentX = -spreadView.shift;
78− ApplicationManager.focusApplication(appId);
93+ applicationManager.focusApplication(appId);
@@ -90,9 +105,9 @@ Rectangle {
92 function focusTopMostApp() {
107 function focusTopMostApp() {
93− if (ApplicationManager.count > 0) {
108+ if (applicationManager.count > 0) {
94− var topmostApp = ApplicationManager.get(0);
109+ var topmostApp = applicationManager.get(0);
95− ApplicationManager.focusApplication(topmostApp.appId);
110+ applicationManager.focusApplication(topmostApp.appId);
@@ -100,20 +115,21 @@ Rectangle {
100 QtObject {
115 QtObject {
118+ readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
103− property string focusedAppId: ApplicationManager.focusedApplicationId
119+ property string focusedAppId: applicationManager.focusedApplicationId
104− property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
120+ property var focusedApplication: applicationManager.findApplication(focusedAppId)
105 property var focusedAppDelegate: null
121 property var focusedAppDelegate: null
107 property real oldInverseProgress: 0
123 property real oldInverseProgress: 0
108− property bool animateX: true
124+ property bool animateX: false
110 onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
126 onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
112 onFocusedAppDelegateChanged: focusedAppDelegate.focus = true;
128 onFocusedAppDelegateChanged: focusedAppDelegate.focus = true;
114 function indexOf(appId) {
130 function indexOf(appId) {
115− for (var i = 0; i < ApplicationManager.count; i++) {
131+ for (var i = 0; i < applicationManager.count; i++) {
116− if (ApplicationManager.get(i).appId == appId) {
132+ if (applicationManager.get(i).appId == appId) {
117 return i;
133 return i;
@@ -133,7 +149,7 @@ Rectangle {
134 // This indicates when the spreadView is active. That means, all the animations
150 // This indicates when the spreadView is active. That means, all the animations
135 // are activated and tiles need to line up for the spread.
151 // are activated and tiles need to line up for the spread.
136− readonly property bool active: shiftedContentX > 0 || spreadDragArea.status === DirectionalDragArea.Recognized
152+ readonly property bool active: shiftedContentX > 0 || spreadDragArea.status === DirectionalDragArea.Recognized || !root.focusFirstApp
138 // The flickable needs to fill the screen in order to get touch events all over.
154 // The flickable needs to fill the screen in order to get touch events all over.
139 // However, we don't want to the user to be able to scroll back all the way. For
155 // However, we don't want to the user to be able to scroll back all the way. For
@@ -199,10 +215,17 @@ Rectangle {
199 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
215 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
200 snapAnimation.targetContentX = width * positionMarker4 + 1 - shift;
216 snapAnimation.targetContentX = width * positionMarker4 + 1 - shift;
201 snapAnimation.start();
217 snapAnimation.start();
204 function snapTo(index) {
221 function snapTo(index) {
205− if (ApplicationManager.count <= index) {
222+ if (!root.altTabEnabled) {
223+ // Reset to start instead
224+ snapAnimation.targetContentX = -shift;
225+ snapAnimation.start();
228+ if (applicationManager.count <= index) {
206 // In case we're trying to snap to some non existing app, lets snap back to the first one
229 // In case we're trying to snap to some non existing app, lets snap back to the first one
207 index = 0;
230 index = 0;
@@ -217,10 +240,12 @@ Rectangle {
217 snapAnimation.start();
240 snapAnimation.start();
220− // In case the ApplicationManager already holds an app when starting up we're missing animations
243+ // In case the applicationManager already holds an app when starting up we're missing animations
221 // Make sure we end up in the same state
244 // Make sure we end up in the same state
222 Component.onCompleted: {
245 Component.onCompleted: {
223 spreadView.contentX = -spreadView.shift
246 spreadView.contentX = -spreadView.shift
247+ priv.animateX = true;
248+ snapAnimation.complete();
226 SequentialAnimation {
251 SequentialAnimation {
@@ -237,7 +262,7 @@ Rectangle {
237 ScriptAction {
262 ScriptAction {
238 script: {
263 script: {
239 if (spreadView.selectedIndex >= 0) {
264 if (spreadView.selectedIndex >= 0) {
240− ApplicationManager.focusApplication(ApplicationManager.get(spreadView.selectedIndex).appId);
265+ applicationManager.focusApplication(applicationManager.get(spreadView.selectedIndex).appId);
242 spreadView.selectedIndex = -1;
267 spreadView.selectedIndex = -1;
243 spreadView.phase = 0;
268 spreadView.phase = 0;
@@ -252,7 +277,7 @@ Rectangle {
252 // This width controls how much the spread can be flicked left/right. It's composed of:
277 // This width controls how much the spread can be flicked left/right. It's composed of:
253 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
278 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
254 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
279 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
255− width: Math.max(3, ApplicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
280+ width: Math.max(3, applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
256 height: parent.height
281 height: parent.height
257 Behavior on width {
282 Behavior on width {
258 enabled: spreadView.closingIndex >= 0
283 enabled: spreadView.closingIndex >= 0
@@ -267,20 +292,22 @@ Rectangle {
267 x: spreadView.contentX
292 x: spreadView.contentX
269 onClicked: {
294 onClicked: {
295+ if (root.altTabEnabled) {
270− spreadView.snapTo(0);
296+ spreadView.snapTo(0);
273 Repeater {
300 Repeater {
274 id: spreadRepeater
301 id: spreadRepeater
275 objectName: "spreadRepeater"
302 objectName: "spreadRepeater"
276− model: ApplicationManager
303+ model: applicationManager
277 delegate: TransformedSpreadDelegate {
304 delegate: TransformedSpreadDelegate {
278 id: appDelegate
305 id: appDelegate
279 objectName: "appDelegate" + index
306 objectName: "appDelegate" + index
280 startAngle: 45
307 startAngle: 45
281 endAngle: 5
308 endAngle: 5
282− startScale: 1.1
309+ startScale: root.startScale
283− endScale: 0.7
310+ endScale: root.endScale
284 startDistance: spreadView.tileDistance
311 startDistance: spreadView.tileDistance
285 endDistance: units.gu(.5)
312 endDistance: units.gu(.5)
286 width: spreadView.width
313 width: spreadView.width
@@ -288,11 +315,12 @@ Rectangle {
288 selected: spreadView.selectedIndex == index
315 selected: spreadView.selectedIndex == index
289 otherSelected: spreadView.selectedIndex >= 0 && !selected
316 otherSelected: spreadView.selectedIndex >= 0 && !selected
290 interactive: !spreadView.interactive && spreadView.phase === 0
317 interactive: !spreadView.interactive && spreadView.phase === 0
291− && spreadView.shiftedContentX === 0 && root.interactive && index === 0
318+ && spreadView.shiftedContentX === 0 && root.interactive && isFocused
292− swipeToCloseEnabled: spreadView.interactive && !snapAnimation.running
319+ swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running
293 maximizedAppTopMargin: root.maximizedAppTopMargin
320 maximizedAppTopMargin: root.maximizedAppTopMargin
294 dropShadow: spreadView.active ||
321 dropShadow: spreadView.active ||
295 (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
322 (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
323+ focusFirstApp: root.focusFirstApp
297 readonly property bool isDash: model.appId == "unity8-dash"
325 readonly property bool isDash: model.appId == "unity8-dash"
@@ -300,7 +328,7 @@ Rectangle {
302 // focused app is always positioned at 0 except when following left edge drag
330 // focused app is always positioned at 0 except when following left edge drag
303− if (index == 0) {
331+ if (isFocused) {
304 if (!isDash && root.inverseProgress > 0 && spreadView.phase === 0) {
332 if (!isDash && root.inverseProgress > 0 && spreadView.phase === 0) {
305 return root.inverseProgress;
333 return root.inverseProgress;
@@ -311,10 +339,10 @@ Rectangle {
313 // Otherwise line up for the spread
341 // Otherwise line up for the spread
314− return spreadView.width + (index - 1) * spreadView.tileDistance;
342+ return spreadView.width + spreadIndex * spreadView.tileDistance;
317− application: ApplicationManager.get(index)
345+ application: applicationManager.get(index)
318 closeable: !isDash
346 closeable: !isDash
320 property real behavioredIndex: index
348 property real behavioredIndex: index
@@ -352,7 +380,7 @@ Rectangle {
352 progress: {
380 progress: {
353 var tileProgress = (spreadView.shiftedContentX - behavioredIndex * spreadView.tileDistance) / spreadView.width;
381 var tileProgress = (spreadView.shiftedContentX - behavioredIndex * spreadView.tileDistance) / spreadView.width;
354 // Tile 1 needs to move directly from the beginning...
382 // Tile 1 needs to move directly from the beginning...
355− if (behavioredIndex == 1 && spreadView.phase < 2) {
383+ if (root.focusFirstApp && behavioredIndex == 1 && spreadView.phase < 2) {
356 tileProgress += spreadView.tileDistance / spreadView.width;
384 tileProgress += spreadView.tileDistance / spreadView.width;
358 // Limiting progress to ~0 and 1.7 to avoid binding calculations when tiles are not
386 // Limiting progress to ~0 and 1.7 to avoid binding calculations when tiles are not
@@ -367,7 +395,7 @@ Rectangle {
368 // This mostly is the same as progress, just adds the snapping to phase 1 for tiles 0 and 1
396 // This mostly is the same as progress, just adds the snapping to phase 1 for tiles 0 and 1
369 animatedProgress: {
397 animatedProgress: {
370− if (spreadView.phase == 0 && index < 2) {
398+ if (spreadView.phase == 0 && index <= priv.firstSpreadIndex) {
371 if (progress < spreadView.positionMarker1) {
399 if (progress < spreadView.positionMarker1) {
372 return progress;
400 return progress;
373 } else if (progress < spreadView.positionMarker1 + 0.05){
401 } else if (progress < spreadView.positionMarker1 + 0.05){
@@ -392,11 +420,11 @@ Rectangle {
394 onClicked: {
422 onClicked: {
395− if (spreadView.phase == 2) {
423+ if (root.altTabEnabled && spreadView.phase == 2) {
396− if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) {
424+ if (applicationManager.focusedApplicationId == applicationManager.get(index).appId) {
397 spreadView.snapTo(index);
425 spreadView.snapTo(index);
399− ApplicationManager.requestFocusApplication(ApplicationManager.get(index).appId);
427+ applicationManager.requestFocusApplication(applicationManager.get(index).appId);
@@ -411,7 +439,7 @@ Rectangle {
412 onClosed: {
440 onClosed: {
413 spreadView.closingIndex = index;
441 spreadView.closingIndex = index;
414− ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
442+ applicationManager.stopApplication(applicationManager.get(index).appId);
@@ -424,7 +452,7 @@ Rectangle {
424 direction: Direction.Leftwards
452 direction: Direction.Leftwards
425 enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging
453 enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging
427− anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
455+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom; rightMargin: -root.dragAreaOverlap }
428 width: root.dragAreaWidth
456 width: root.dragAreaWidth
430 property var gesturePoints: new Array()
458 property var gesturePoints: new Array()