@@ -16,7 +16,7 @@
1616 * Authors: Michael Zanetti <michael.zanetti@canonical.com>
1717 */
1818
19−import QtQuick 2.3
19+import QtQuick 2.4
2020import QtQuick.Layouts 1.1
2121import Ubuntu.Components 1.1
2222import Unity.Application 0.1
@@ -192,6 +192,15 @@ Rectangle {
192192 property int highlightedIndex: -1
193193 property int closingIndex: -1
194194
195+ function indexOf(delegateItem) {
196+ for (var i = 0; i < appRepeater.count; i++) {
197+ if (appRepeater.itemAt(i) === delegateItem) {
198+ return i;
199+ }
200+ }
201+ return -1;
202+ }
203+
195204 delegate: FocusScope {
196205 id: appDelegate
197206 z: ApplicationManager.count - index
@@ -199,6 +208,12 @@ Rectangle {
199208 width: units.gu(60)
200209 height: units.gu(50)
201210
211+ property int windowWidth: 0
212+ property int windowHeight: 0
213+ // We don't want to resize the actual application when we're transforming things for the spread only
214+ onWidthChanged: if (appDelegate.state !== "altTab") windowWidth = width
215+ onHeightChanged: if (appDelegate.state !== "altTab") windowHeight = height
216+
202217 readonly property int minWidth: units.gu(10)
203218 readonly property int minHeight: units.gu(10)
204219
@@ -266,7 +281,9 @@ Rectangle {
266281 PropertyChanges {
267282 target: appDelegate
268283 x: spreadMaths.animatedX
269− y: spreadMaths.animatedY + (appDelegate.height - decoratedWindow.height)
284+ y: spreadMaths.animatedY + (appDelegate.height - decoratedWindow.height) - units.gu(2)
285+ width: spreadMaths.spreadHeight
286+ height: spreadMaths.sceneHeight
270287 angle: spreadMaths.animatedAngle
271288 itemScale: spreadMaths.scale
272289 itemScaleOriginY: decoratedWindow.height / 2;
@@ -281,6 +298,7 @@ Rectangle {
281298 width: spreadMaths.spreadHeight
282299 height: spreadMaths.spreadHeight
283300 shadowOpacity: spreadMaths.shadowOpacity
301+ anchors.topMargin: units.gu(2)
284302 }
285303 PropertyChanges {
286304 target: tileInfo
@@ -307,6 +325,7 @@ Rectangle {
307325 from: ""
308326 to: "altTab"
309327 PropertyAction { target: appDelegate; properties: "y,angle,z,itemScale,itemScaleOriginY" }
328+ PropertyAction { target: decoratedWindow; properties: "anchors.topMargin" }
310329 PropertyAnimation {
311330 target: appDelegate; properties: "x"
312331 from: root.width
@@ -345,8 +364,8 @@ Rectangle {
345364 objectName: "decoratedWindow"
346365 anchors.left: appDelegate.left
347366 anchors.top: appDelegate.top
348− windowWidth: appDelegate.width
349− windowHeight: appDelegate.height
367+ windowWidth: appDelegate.windowWidth
368+ windowHeight: appDelegate.windowHeight
350369 application: ApplicationManager.get(index)
351370 active: ApplicationManager.focusedApplicationId === model.appId
352371 focus: false
@@ -374,32 +393,8 @@ Rectangle {
374393 anchors.fill: parent
375394 anchors.margins: -units.gu(2)
376395 enabled: false
377− hoverEnabled: enabled
378−
379− // There is a bug in MouseArea where containsMouse doesn't
380− // return to false if the MouseArea is disabled while
381− // containing the mouse. Let's manage the property our own.
382− property bool upperThirdContainsMouse: false
383− onContainsMouseChanged: evaluateContainsMouse()
384− onMouseYChanged: evaluateContainsMouse()
385− function evaluateContainsMouse() {
386− if (containsMouse) {
387− appRepeater.highlightedIndex = index
388− }
389−
390− if (containsMouse && mouseY < height / 3) {
391− spreadSelectArea.upperThirdContainsMouse = true
392− } else {
393− spreadSelectArea.upperThirdContainsMouse = false;
394− }
395− }
396− onEnabledChanged: {
397− if (!enabled) {
398− spreadSelectArea.upperThirdContainsMouse = false
399− }
400− }
401−
402396 onClicked: {
397+ appRepeater.highlightedIndex = index;
403398 root.state = ""
404399 }
405400 }
@@ -407,24 +402,28 @@ Rectangle {
407402
408403 Image {
409404 id: closeImage
410− anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
405+ anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset + units.gu(2) }
411406 source: "graphics/window-close.svg"
412− visible: spreadSelectArea.upperThirdContainsMouse
407+ readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
408+ visible: index == appRepeater.highlightedIndex
409+ && mousePos.y < (decoratedWindow.height / 3)
410+ && mousePos.y > -units.gu(4)
411+ && mousePos.x > -units.gu(4)
412+ && mousePos.x < (decoratedWindow.width * 2 / 3)
413413 height: units.gu(1.5)
414414 width: height
415415 sourceSize.width: width
416416 sourceSize.height: height
417− }
418417
419− MouseArea {
420− id: closeMouseArea
421− objectName: "closeMouseArea"
422− anchors.fill: closeImage
423− anchors.margins: -units.gu(2)
424− enabled: spreadSelectArea.upperThirdContainsMouse
425− onClicked: {
426− appRepeater.closingIndex = index;
427− ApplicationManager.stopApplication(model.appId)
418+ MouseArea {
419+ id: closeMouseArea
420+ objectName: "closeMouseArea"
421+ anchors.fill: closeImage
422+ anchors.margins: -units.gu(2)
423+ onClicked: {
424+ appRepeater.closingIndex = index;
425+ ApplicationManager.stopApplication(model.appId)
426+ }
428427 }
429428 }
430429
@@ -473,9 +472,59 @@ Rectangle {
473472 }
474473 }
475474
475+ MouseArea {
476+ id: hoverMouseArea
477+ anchors.fill: appContainer
478+ propagateComposedEvents: true
479+ hoverEnabled: true
480+ enabled: false
481+
482+ property int scrollAreaWidth: root.width / 3
483+ property bool progressiveScrollingEnabled: false
484+
485+ onMouseXChanged: {
486+ mouse.accepted = false
487+ if (hoverMouseArea.pressed) return;
488+
489+ // Find the hovered item and mark it active
490+ var mapped = mapToItem(appContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
491+ var itemUnder = appContainer.childAt(mapped.x, mapped.y)
492+ if (itemUnder) {
493+ mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
494+ var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
495+ if (delegateChild.objectName === "decoratedWindow" || delegateChild.objectName === "tileInfo") {
496+ appRepeater.highlightedIndex = appRepeater.indexOf(itemUnder)
497+ }
498+ }
499+
500+ if (spreadFlickable.contentWidth > spreadFlickable.minContentWidth) {
501+ var margins = spreadFlickable.width * 0.05;
502+
503+ if (!progressiveScrollingEnabled && mouseX < spreadFlickable.width - scrollAreaWidth) {
504+ progressiveScrollingEnabled = true
505+ }
506+
507+ // do we need to scroll?
508+ if (mouseX < scrollAreaWidth) {
509+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
510+ var contentX = (1 - progress) * (spreadFlickable.contentWidth - spreadFlickable.width)
511+ spreadFlickable.contentX = Math.max(0, Math.min(spreadFlickable.contentX, contentX))
512+ }
513+ if (mouseX > spreadFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
514+ var progress = Math.min(1, (mouseX - (spreadFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
515+ var contentX = progress * (spreadFlickable.contentWidth - spreadFlickable.width)
516+ spreadFlickable.contentX = Math.min(spreadFlickable.contentWidth - spreadFlickable.width, Math.max(spreadFlickable.contentX, contentX))
517+ }
518+ }
519+ }
520+ onPressed: mouse.accepted = false
521+ }
522+
476523 FloatingFlickable {
477524 id: spreadFlickable
525+ objectName: "spreadFlickable"
478526 anchors.fill: parent
527+ property int minContentWidth: 6 * Math.min(height / 4, width / 5)
479528 contentWidth: Math.max(6, ApplicationManager.count) * Math.min(height / 4, width / 5)
480529 enabled: false
481530
@@ -590,10 +639,11 @@ Rectangle {
590639 State {
591640 name: "altTab"; when: root.altTabPressed
592641 PropertyChanges { target: workspaceSelector; visible: true }
593− PropertyChanges { target: spreadFlickable; enabled: true }
642+ PropertyChanges { target: spreadFlickable; enabled: spreadFlickable.contentWidth > spreadFlickable.minContentWidth }
594643 PropertyChanges { target: currentSelectedLabel; visible: true }
595644 PropertyChanges { target: spreadBackground; visible: true }
596645 PropertyChanges { target: appContainer; focus: true }
646+ PropertyChanges { target: hoverMouseArea; enabled: true }
597647 }
598648 ]
599649 signal updateWorkspaces();
@@ -603,6 +653,7 @@ Rectangle {
603653 from: "*"
604654 to: "altTab"
605655 SequentialAnimation {
656+ PropertyAction { target: hoverMouseArea; property: "progressiveScrollingEnabled"; value: false }
606657 PropertyAction { target: appRepeater; property: "highlightedIndex"; value: Math.min(ApplicationManager.count - 1, 1) }
607658 PauseAnimation { duration: 50 }
608659 PropertyAction { target: workspaceSelector; property: "visible" }