@@ -46,6 +46,7 @@ FocusScope {
4646 property int leftMargin: 0
4747 property bool oskEnabled: false
4848 property rect inputMethodRect
49+ property PanelState panelState
4950
5051 // Configuration
5152 property string mode: "staged"
@@ -348,20 +349,20 @@ FocusScope {
348349 Component.onCompleted: priv.updateMainAndSideStageIndexes();
349350
350351 Connections {
351− target: PanelState
352+ target: panelState
352353 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
353354 onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestMinimize(); } }
354355 onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestRestore(); } }
355356 }
356357
357358 Binding {
358− target: PanelState
359+ target: panelState
359360 property: "decorationsVisible"
360361 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
361362 }
362363
363364 Binding {
364− target: PanelState
365+ target: panelState
365366 property: "title"
366367 value: {
367368 if (priv.focusedAppDelegate !== null) {
@@ -376,7 +377,7 @@ FocusScope {
376377 }
377378
378379 Binding {
379− target: PanelState
380+ target: panelState
380381 property: "focusedPersistentSurfaceId"
381382 value: {
382383 if (priv.focusedAppDelegate !== null) {
@@ -390,21 +391,21 @@ FocusScope {
390391 }
391392
392393 Binding {
393− target: PanelState
394+ target: panelState
394395 property: "dropShadow"
395396 value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
396397 }
397398
398399 Binding {
399− target: PanelState
400+ target: panelState
400401 property: "closeButtonShown"
401402 value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
402403 }
403404
404405 Component.onDestruction: {
405− PanelState.title = "";
406− PanelState.decorationsVisible = false;
407− PanelState.dropShadow = false;
406+ panelState.title = "";
407+ panelState.decorationsVisible = false;
408+ panelState.dropShadow = false;
408409 }
409410
410411 Instantiator {
@@ -450,6 +451,7 @@ FocusScope {
450451 PropertyChanges { target: cancelSpreadMouseArea; enabled: true }
451452 PropertyChanges { target: blurLayer; visible: true; blurRadius: 32; brightness: .65; opacity: 1 }
452453 PropertyChanges { target: wallpaper; visible: false }
454+ PropertyChanges { target: screensAndWorkspaces; opacity: 1 }
453455 },
454456 State {
455457 name: "stagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "staged"
@@ -482,7 +484,7 @@ FocusScope {
482484 },
483485 State {
484486 name: "staged"; when: root.mode === "staged"
485− PropertyChanges { target: wallpaper; visible: false }
487+ PropertyChanges { target: wallpaper; visible: priv.focusedAppDelegate && priv.focusedAppDelegate.x === 0 }
486488 },
487489 State {
488490 name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
@@ -498,11 +500,13 @@ FocusScope {
498500 from: "stagedRightEdge,sideStagedRightEdge,windowedRightEdge"; to: "spread"
499501 PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
500502 PropertyAnimation { target: blurLayer; properties: "brightness,blurRadius"; duration: priv.animationDuration }
503+ UbuntuNumberAnimation { target: screensAndWorkspaces; property: "opacity"; duration: priv.animationDuration }
501504 },
502505 Transition {
503506 to: "spread"
504507 PropertyAction { target: spreadItem; property: "highlightedIndex"; value: appRepeater.count > 1 ? 1 : 0 }
505508 PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
509+ UbuntuNumberAnimation { target: screensAndWorkspaces; property: "opacity"; duration: priv.animationDuration }
506510 },
507511 Transition {
508512 from: "spread"
@@ -559,10 +563,19 @@ FocusScope {
559563 visible: false
560564 }
561565
566+ ScreensAndWorkspaces {
567+ id: screensAndWorkspaces
568+ anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: root.leftMargin }
569+ height: parent.height / 3
570+ background: root.background
571+ opacity: 0
572+ visible: opacity > 0
573+ }
574+
562575 Spread {
563576 id: spreadItem
564577 objectName: "spreadItem"
565− anchors.fill: appContainer
578+ anchors { left: parent.left; bottom: parent.bottom; right: parent.right; top: screensAndWorkspaces.bottom }
566579 leftMargin: root.leftMargin
567580 model: root.topLevelSurfaceList
568581 spreadFlickable: floatingFlickable
@@ -571,6 +584,83 @@ FocusScope {
571584 onLeaveSpread: {
572585 priv.goneToSpread = false;
573586 }
587+
588+ FloatingFlickable {
589+ id: floatingFlickable
590+ objectName: "spreadFlickable"
591+ anchors.fill: parent
592+ enabled: false
593+ contentWidth: spreadItem.spreadTotalWidth
594+
595+ function snap(toIndex) {
596+ var delegate = appRepeater.itemAt(toIndex)
597+ var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
598+ if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
599+ var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
600+ snapAnimation.to = floatingFlickable.contentX - offset;
601+ snapAnimation.start();
602+ } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
603+ var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
604+ snapAnimation.to = floatingFlickable.contentX - offset;
605+ snapAnimation.start();
606+ }
607+ }
608+ UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
609+ }
610+
611+ MouseArea {
612+ id: hoverMouseArea
613+ objectName: "hoverMouseArea"
614+ anchors.fill: parent
615+ propagateComposedEvents: true
616+ hoverEnabled: true
617+ enabled: false
618+ visible: enabled
619+
620+ property int scrollAreaWidth: width / 3
621+ property bool progressiveScrollingEnabled: false
622+
623+ onMouseXChanged: {
624+ mouse.accepted = false
625+
626+ if (hoverMouseArea.pressed) {
627+ return;
628+ }
629+
630+ // Find the hovered item and mark it active
631+ for (var i = appRepeater.count - 1; i >= 0; i--) {
632+ var appDelegate = appRepeater.itemAt(i);
633+ var mapped = mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
634+ var itemUnder = appDelegate.childAt(mapped.x, mapped.y);
635+ if (itemUnder && (itemUnder.objectName === "dragArea" || itemUnder.objectName === "windowInfoItem" || itemUnder.objectName == "closeMouseArea")) {
636+ spreadItem.highlightedIndex = i;
637+ break;
638+ }
639+ }
640+
641+ if (floatingFlickable.contentWidth > floatingFlickable.width) {
642+ var margins = floatingFlickable.width * 0.05;
643+
644+ if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
645+ progressiveScrollingEnabled = true
646+ }
647+
648+ // do we need to scroll?
649+ if (mouseX < scrollAreaWidth + margins) {
650+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
651+ var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
652+ floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
653+ }
654+ if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
655+ var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
656+ var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
657+ floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
658+ }
659+ }
660+ }
661+
662+ onPressed: mouse.accepted = false
663+ }
574664 }
575665
576666 Connections {
@@ -753,7 +843,7 @@ FocusScope {
753843 target: appDelegate
754844 property: "y"
755845 value: appDelegate.requestedY -
756− Math.min(appDelegate.requestedY - PanelState.panelHeight,
846+ Math.min(appDelegate.requestedY - panelState.panelHeight,
757847 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
758848 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
759849 && root.inputMethodRect.height > 0
@@ -890,7 +980,7 @@ FocusScope {
890980 screenWidth: appContainer.width
891981 screenHeight: appContainer.height
892982 leftMargin: root.leftMargin
893− minimumY: PanelState.panelHeight
983+ minimumY: panelState.panelHeight
894984 }
895985
896986 Connections {
@@ -1130,7 +1220,7 @@ FocusScope {
11301220 progress: 0
11311221 targetHeight: spreadItem.stackHeight
11321222 targetX: spreadMaths.targetX
1133− startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1223+ startY: appDelegate.fullscreen ? 0 : panelState.panelHeight
11341224 targetY: spreadMaths.targetY
11351225 targetAngle: spreadMaths.targetAngle
11361226 targetScale: spreadMaths.targetScale
@@ -1249,9 +1339,9 @@ FocusScope {
12491339 PropertyChanges {
12501340 target: appDelegate
12511341 x: stageMaths.itemX
1252− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1342+ y: appDelegate.fullscreen ? 0 : panelState.panelHeight
12531343 requestedWidth: appContainer.width
1254− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1344+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - panelState.panelHeight
12551345 visuallyMaximized: true
12561346 visible: appDelegate.x < root.width
12571347 }
@@ -1277,10 +1367,10 @@ FocusScope {
12771367 PropertyChanges {
12781368 target: appDelegate
12791369 x: stageMaths.itemX
1280− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1370+ y: appDelegate.fullscreen ? 0 : panelState.panelHeight
12811371 z: stageMaths.itemZ
12821372 requestedWidth: stageMaths.itemWidth
1283− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1373+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - panelState.panelHeight
12841374 visuallyMaximized: true
12851375 visible: appDelegate.x < root.width
12861376 }
@@ -1345,9 +1435,9 @@ FocusScope {
13451435 PropertyChanges {
13461436 target: appDelegate
13471437 windowedX: root.leftMargin
1348− windowedY: PanelState.panelHeight
1438+ windowedY: panelState.panelHeight
13491439 windowedWidth: (appContainer.width - root.leftMargin)/2
1350− windowedHeight: appContainer.height - PanelState.panelHeight
1440+ windowedHeight: appContainer.height - panelState.panelHeight
13511441 }
13521442 },
13531443 State {
@@ -1364,9 +1454,9 @@ FocusScope {
13641454 PropertyChanges {
13651455 target: appDelegate
13661456 windowedX: root.leftMargin
1367− windowedY: PanelState.panelHeight
1457+ windowedY: panelState.panelHeight
13681458 windowedWidth: (appContainer.width - root.leftMargin)/2
1369− windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1459+ windowedHeight: (appContainer.height - panelState.panelHeight)/2
13701460 }
13711461 },
13721462 State {
@@ -1383,7 +1473,7 @@ FocusScope {
13831473 PropertyChanges {
13841474 target: appDelegate
13851475 windowedX: root.leftMargin
1386− windowedY: (appContainer.height + PanelState.panelHeight)/2
1476+ windowedY: (appContainer.height + panelState.panelHeight)/2
13871477 windowedWidth: (appContainer.width - root.leftMargin)/2
13881478 windowedHeight: appContainer.height/2
13891479 }
@@ -1405,8 +1495,8 @@ FocusScope {
14051495 State {
14061496 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
14071497 extend: "normal"
1408− PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: PanelState.panelHeight;
1409− windowedWidth: windowedWidth; windowedHeight: appContainer.height - PanelState.panelHeight }
1498+ PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: panelState.panelHeight;
1499+ windowedWidth: windowedWidth; windowedHeight: appContainer.height - panelState.panelHeight }
14101500 },
14111501 State {
14121502 name: "minimized"; when: appDelegate.minimized
@@ -1505,7 +1595,7 @@ FocusScope {
15051595 ]
15061596
15071597 Binding {
1508− target: PanelState
1598+ target: panelState
15091599 property: "decorationsAlwaysVisible"
15101600 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
15111601 }
@@ -1520,7 +1610,7 @@ FocusScope {
15201610 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
15211611
15221612 target: appDelegate
1523− minimumY: PanelState.panelHeight // disallow resizing up past Panel
1613+ minimumY: panelState.panelHeight // disallow resizing up past Panel
15241614 minWidth: units.gu(10)
15251615 minHeight: units.gu(10)
15261616 borderThickness: units.gu(2)
@@ -1550,6 +1640,7 @@ FocusScope {
15501640 highlightSize: windowInfoItem.iconMargin / 2
15511641 stageWidth: appContainer.width
15521642 stageHeight: appContainer.height
1643+ panelState: root.panelState
15531644
15541645 requestedWidth: appDelegate.requestedWidth
15551646 requestedHeight: appDelegate.requestedHeight
@@ -1609,6 +1700,7 @@ FocusScope {
16091700 visible: enabled
16101701 stageWidth: appContainer.width
16111702 stageHeight: appContainer.height
1703+ panelState: root.panelState
16121704
16131705 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
16141706 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
@@ -1713,6 +1805,7 @@ FocusScope {
17131805 leftMargin: root.leftMargin
17141806 appContainerWidth: appContainer.width
17151807 appContainerHeight: appContainer.height
1808+ panelState: root.panelState
17161809 }
17171810
17181811 EdgeBarrier {
@@ -1739,83 +1832,6 @@ FocusScope {
17391832 }
17401833 }
17411834
1742− MouseArea {
1743− id: hoverMouseArea
1744− objectName: "hoverMouseArea"
1745− anchors.fill: appContainer
1746− propagateComposedEvents: true
1747− hoverEnabled: true
1748− enabled: false
1749− visible: enabled
1750−
1751− property int scrollAreaWidth: width / 3
1752− property bool progressiveScrollingEnabled: false
1753−
1754− onMouseXChanged: {
1755− mouse.accepted = false
1756−
1757− if (hoverMouseArea.pressed) {
1758− return;
1759− }
1760−
1761− // Find the hovered item and mark it active
1762− for (var i = appRepeater.count - 1; i >= 0; i--) {
1763− var appDelegate = appRepeater.itemAt(i);
1764− var mapped = mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1765− var itemUnder = appDelegate.childAt(mapped.x, mapped.y);
1766− if (itemUnder && (itemUnder.objectName === "dragArea" || itemUnder.objectName === "windowInfoItem" || itemUnder.objectName == "closeMouseArea")) {
1767− spreadItem.highlightedIndex = i;
1768− break;
1769− }
1770− }
1771−
1772− if (floatingFlickable.contentWidth > floatingFlickable.width) {
1773− var margins = floatingFlickable.width * 0.05;
1774−
1775− if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
1776− progressiveScrollingEnabled = true
1777− }
1778−
1779− // do we need to scroll?
1780− if (mouseX < scrollAreaWidth + margins) {
1781− var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
1782− var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
1783− floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
1784− }
1785− if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
1786− var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
1787− var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
1788− floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
1789− }
1790− }
1791− }
1792−
1793− onPressed: mouse.accepted = false
1794− }
1795−
1796− FloatingFlickable {
1797− id: floatingFlickable
1798− objectName: "spreadFlickable"
1799− anchors.fill: appContainer
1800− enabled: false
1801− contentWidth: spreadItem.spreadTotalWidth
1802−
1803− function snap(toIndex) {
1804− var delegate = appRepeater.itemAt(toIndex)
1805− var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
1806− if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
1807− var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
1808− snapAnimation.to = floatingFlickable.contentX - offset;
1809− snapAnimation.start();
1810− } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
1811− var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
1812− snapAnimation.to = floatingFlickable.contentX - offset;
1813− snapAnimation.start();
1814− }
1815− }
1816− UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
1817− }
1818−
18191835 PropertyAnimation {
18201836 id: shortRightEdgeSwipeAnimation
18211837 property: "x"