2 * Copyright (C) 2015 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 import QtQuick.Layouts 1.1
19 import Ubuntu.Components 1.3
20 import Ubuntu.Gestures 0.1
21 import Unity.Application 0.1
26 property bool altTabPressed: false
27 property Item workspace: null
29 readonly property alias highlightedIndex: spreadRepeater.highlightedIndex
32 spreadContainer.animateIn = true;
33 root.state = "altTab";
37 // When the spread comes active, we want to keep focus to the input handler below
38 // Make sure nothing inside the ApplicationWindow grabs our focus!
48 selectPrevious(event.isAutoRepeat)
49 event.accepted = true;
53 selectNext(event.isAutoRepeat)
54 event.accepted = true;
57 spreadRepeater.highlightedIndex = -1
58 // Falling through intentionally
63 event.accepted = true;
67 function selectNext(isAutoRepeat) {
68 if (isAutoRepeat && spreadRepeater.highlightedIndex >= ApplicationManager.count -1) {
69 return; // AutoRepeat is not allowed to wrap around
72 spreadRepeater.highlightedIndex = (spreadRepeater.highlightedIndex + 1) % ApplicationManager.count;
73 var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, spreadRepeater.highlightedIndex - 3));
74 if (spreadFlickable.contentX < newContentX || spreadRepeater.highlightedIndex == 0) {
75 spreadFlickable.snapTo(newContentX)
79 function selectPrevious(isAutoRepeat) {
80 if (isAutoRepeat && spreadRepeater.highlightedIndex == 0) {
81 return; // AutoRepeat is not allowed to wrap around
84 var newIndex = spreadRepeater.highlightedIndex - 1 >= 0 ? spreadRepeater.highlightedIndex - 1 : ApplicationManager.count - 1;
85 spreadRepeater.highlightedIndex = newIndex;
86 var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, spreadRepeater.highlightedIndex - 1));
87 if (spreadFlickable.contentX > newContentX || newIndex == ApplicationManager.count -1) {
88 spreadFlickable.snapTo(newContentX)
92 function focusSelected() {
93 if (spreadRepeater.highlightedIndex != -1) {
94 var application = ApplicationManager.get(spreadRepeater.highlightedIndex);
95 ApplicationManager.requestFocusApplication(application.appId);
100 spreadRepeater.highlightedIndex = -1;
106 objectName: "spreadContainer"
110 property bool animateIn: false
114 objectName: "spreadRepeater"
115 model: ApplicationManager
117 property int highlightedIndex: -1
118 property int closingIndex: -1
120 function indexOf(delegateItem) {
121 for (var i = 0; i < spreadRepeater.count; i++) {
122 if (spreadRepeater.itemAt(i) === delegateItem) {
131 objectName: "spreadDelegate"
135 property real angle: 0
136 property real itemScale: 1
137 property int itemScaleOriginX: 0
138 property int itemScaleOriginY: 0
142 enabled: spreadRepeater.closingIndex >= 0
143 UbuntuNumberAnimation {
144 onRunningChanged: if (!running) spreadRepeater.closingIndex = -1
148 DesktopSpreadDelegate {
149 id: clippedSpreadDelegate
150 objectName: "clippedSpreadDelegate"
151 anchors.left: parent.left
152 anchors.top: parent.top
153 application: ApplicationManager.get(index)
154 width: spreadMaths.spreadHeight
155 height: spreadMaths.spreadHeight
159 origin.x: itemScaleOriginX
160 origin.y: itemScaleOriginY
165 origin { x: 0; y: (clippedSpreadDelegate.height - (clippedSpreadDelegate.height * itemScale / 2)) }
166 axis { x: 0; y: 1; z: 0 }
167 angle: spreadDelegate.angle
174 anchors.margins: -units.gu(2)
177 spreadRepeater.highlightedIndex = index;
185 flickable: spreadFlickable
187 totalItems: Math.max(6, ApplicationManager.count)
188 sceneHeight: root.height
189 itemHeight: spreadDelegate.height
194 name: "altTab"; when: root.state == "altTab" && spreadContainer.visible
196 target: spreadDelegate
197 x: spreadMaths.animatedX
198 y: spreadMaths.animatedY + (spreadDelegate.height - clippedSpreadDelegate.height) - units.gu(2)
199 width: spreadMaths.spreadHeight
200 height: spreadMaths.sceneHeight
201 angle: spreadMaths.animatedAngle
202 itemScale: spreadMaths.scale
203 itemScaleOriginY: clippedSpreadDelegate.height / 2;
205 visible: spreadMaths.itemVisible
208 target: clippedSpreadDelegate
209 highlightShown: index == spreadRepeater.highlightedIndex
211 shadowOpacity: spreadMaths.shadowOpacity
212 anchors.topMargin: units.gu(2)
217 opacity: spreadMaths.tileInfoOpacity
220 target: spreadSelectArea
229 PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
230 PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
232 target: spreadDelegate; properties: "x"
234 duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration :0
235 easing: UbuntuAnimation.StandardEasing
242 objectName: "tileInfo"
243 anchors { left: parent.left; top: clippedSpreadDelegate.bottom; topMargin: units.gu(5) }
244 property int nextItemX: spreadRepeater.count > index + 1 ? spreadRepeater.itemAt(index + 1).x : spreadDelegate.x + units.gu(30)
245 width: Math.min(units.gu(30), nextItemX - spreadDelegate.x)
246 height: titleInfoColumn.height
250 onContainsMouseChanged: {
252 spreadRepeater.highlightedIndex = index
262 anchors { left: parent.left; top: parent.top; right: parent.right }
266 Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
267 Layout.preferredWidth: height * 8 / 7.6
274 Layout.fillWidth: true
275 Layout.preferredHeight: units.gu(6)
277 wrapMode: Text.WordWrap
278 elide: Text.ElideRight
286 anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset + units.gu(2) }
287 source: "graphics/window-close.svg"
288 readonly property var mousePos: hoverMouseArea.mapToItem(spreadDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
289 visible: index == spreadRepeater.highlightedIndex
290 && mousePos.y < (clippedSpreadDelegate.height / 3)
291 && mousePos.y > -units.gu(4)
292 && mousePos.x > -units.gu(4)
293 && mousePos.x < (clippedSpreadDelegate.width * 2 / 3)
294 height: units.gu(1.5)
296 sourceSize.width: width
297 sourceSize.height: height
301 objectName: "closeMouseArea"
302 anchors.fill: closeImage
303 anchors.margins: -units.gu(2)
305 spreadRepeater.closingIndex = index;
306 ApplicationManager.stopApplication(model.appId)
317 objectName: "hoverMouseArea"
318 anchors.fill: spreadContainer
319 propagateComposedEvents: true
324 property int scrollAreaWidth: root.width / 3
325 property bool progressiveScrollingEnabled: false
328 mouse.accepted = false
330 if (hoverMouseArea.pressed) {
334 // Find the hovered item and mark it active
335 var mapped = mapToItem(spreadContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
336 var itemUnder = spreadContainer.childAt(mapped.x, mapped.y)
338 mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
339 var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
340 if (delegateChild && (delegateChild.objectName === "clippedSpreadDelegate" || delegateChild.objectName === "tileInfo")) {
341 spreadRepeater.highlightedIndex = spreadRepeater.indexOf(itemUnder)
345 if (spreadFlickable.contentWidth > spreadFlickable.minContentWidth) {
346 var margins = spreadFlickable.width * 0.05;
348 if (!progressiveScrollingEnabled && mouseX < spreadFlickable.width - scrollAreaWidth) {
349 progressiveScrollingEnabled = true
352 // do we need to scroll?
353 if (mouseX < scrollAreaWidth + margins) {
354 var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
355 var contentX = (1 - progress) * (spreadFlickable.contentWidth - spreadFlickable.width)
356 spreadFlickable.contentX = Math.max(0, Math.min(spreadFlickable.contentX, contentX))
358 if (mouseX > spreadFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
359 var progress = Math.min(1, (mouseX - (spreadFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
360 var contentX = progress * (spreadFlickable.contentWidth - spreadFlickable.width)
361 spreadFlickable.contentX = Math.min(spreadFlickable.contentWidth - spreadFlickable.width, Math.max(spreadFlickable.contentX, contentX))
365 onPressed: mouse.accepted = false
370 objectName: "spreadFlickable"
372 property int minContentWidth: 6 * Math.min(height / 4, width / 5)
373 contentWidth: Math.max(6, ApplicationManager.count) * Math.min(height / 4, width / 5)
376 function snapTo(contentX) {
377 snapAnimation.stop();
378 snapAnimation.to = contentX
379 snapAnimation.start();
382 UbuntuNumberAnimation {
384 target: spreadFlickable
390 id: workspaceSelector
395 topMargin: units.gu(3.5)
397 height: root.height * 0.25
403 Item { Layout.fillWidth: true }
405 model: 1 // TODO: will be a workspacemodel in the future
407 Layout.fillHeight: true
408 Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
410 source: root.background
414 verticalCenter: parent.verticalCenter
416 height: parent.height * 0.75
421 property var source: ShaderEffectSource {
422 id: shaderEffectSource
423 sourceItem: appContainer
427 varying highp vec2 qt_TexCoord0;
428 uniform sampler2D source;
431 highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
432 gl_FragColor = sourceColor;
437 // TODO: This is the bar for the currently selected workspace
438 // Enable this once the workspace stuff is implemented
440 // anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
441 // height: units.dp(2)
442 // color: UbuntuColors.orange
443 // visible: index == 0 // TODO: should be active workspace index
448 // TODO: This is the "new workspace" button. Enable this once workspaces are implemented
450 // Layout.fillHeight: true
451 // Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
455 // right: parent.right
456 // verticalCenter: parent.verticalCenter
458 // height: parent.height * 0.75
459 // color: "#22ffffff"
462 // anchors.centerIn: parent
463 // font.pixelSize: parent.height / 2
468 Item { Layout.fillWidth: true }
473 id: currentSelectedLabel
474 anchors { bottom: parent.bottom; bottomMargin: root.height * 0.625; horizontalCenter: parent.horizontalCenter }
475 text: spreadRepeater.highlightedIndex >= 0 ? ApplicationManager.get(spreadRepeater.highlightedIndex).name : ""
482 name: "altTab"; when: root.altTabPressed
483 PropertyChanges { target: blurLayer; saturation: 0.8; blurRadius: 60; visible: true }
484 PropertyChanges { target: workspaceSelector; visible: true }
485 PropertyChanges { target: spreadContainer; visible: true }
486 PropertyChanges { target: spreadFlickable; enabled: spreadFlickable.contentWidth > spreadFlickable.minContentWidth }
487 PropertyChanges { target: currentSelectedLabel; visible: true }
488 PropertyChanges { target: spreadBackground; visible: true }
489 PropertyChanges { target: hoverMouseArea; enabled: true }
496 SequentialAnimation {
497 PropertyAction { target: hoverMouseArea; property: "progressiveScrollingEnabled"; value: false }
498 PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: Math.min(ApplicationManager.count - 1, 1) }
499 PauseAnimation { duration: 140 }
500 PropertyAction { target: workspaceSelector; property: "visible" }
501 PropertyAction { target: spreadContainer; property: "visible" }
503 UbuntuNumberAnimation {
504 target: blurLayer; properties: "saturation,blurRadius";
505 duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0
507 PropertyAction { target: spreadFlickable; property: "visible" }
508 PropertyAction { targets: [currentSelectedLabel,spreadBackground]; property: "visible" }
509 PropertyAction { target: spreadFlickable; property: "contentX"; value: 0 }
516 PropertyAnimation { property: "opacity" }
517 ScriptAction { script: { root.focusSelected() } }
518 PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: -1 }
519 PropertyAction { target: spreadContainer; property: "animateIn"; value: false }