2
* Copyright (C) 2015-2016 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
22
import "../Components"
28
property bool altTabPressed: false
29
property Item workspace: null
31
readonly property alias ready: blurLayer.ready
32
readonly property alias highlightedIndex: spreadRepeater.highlightedIndex
34
signal playFocusAnimation(int index)
37
spreadContainer.animateIn = true;
38
root.state = "altTab";
42
// When the spread comes active, we want to keep focus to the input handler below
43
// Make sure nothing inside the ApplicationWindow grabs our focus!
53
selectPrevious(event.isAutoRepeat)
54
event.accepted = true;
58
selectNext(event.isAutoRepeat)
59
event.accepted = true;
62
spreadRepeater.highlightedIndex = -1
63
// Falling through intentionally
68
event.accepted = true;
72
function selectNext(isAutoRepeat) {
73
if (isAutoRepeat && spreadRepeater.highlightedIndex >= topLevelSurfaceList.count -1) {
74
return; // AutoRepeat is not allowed to wrap around
77
spreadRepeater.highlightedIndex = (spreadRepeater.highlightedIndex + 1) % topLevelSurfaceList.count;
78
var newContentX = ((spreadFlickable.contentWidth) / (topLevelSurfaceList.count + 1)) * Math.max(0, Math.min(topLevelSurfaceList.count - 5, spreadRepeater.highlightedIndex - 3));
79
if (spreadFlickable.contentX < newContentX || spreadRepeater.highlightedIndex == 0) {
80
spreadFlickable.snapTo(newContentX)
84
function selectPrevious(isAutoRepeat) {
85
if (isAutoRepeat && spreadRepeater.highlightedIndex == 0) {
86
return; // AutoRepeat is not allowed to wrap around
89
var newIndex = spreadRepeater.highlightedIndex - 1 >= 0 ? spreadRepeater.highlightedIndex - 1 : topLevelSurfaceList.count - 1;
90
spreadRepeater.highlightedIndex = newIndex;
91
var newContentX = ((spreadFlickable.contentWidth) / (topLevelSurfaceList.count + 1)) * Math.max(0, Math.min(topLevelSurfaceList.count - 5, spreadRepeater.highlightedIndex - 1));
92
if (spreadFlickable.contentX > newContentX || newIndex == topLevelSurfaceList.count -1) {
93
spreadFlickable.snapTo(newContentX)
97
function focusSelected() {
98
if (spreadRepeater.highlightedIndex != -1) {
99
if (spreadContainer.visible) {
100
root.playFocusAnimation(spreadRepeater.highlightedIndex)
102
var surface = topLevelSurfaceList.surfaceAt(spreadRepeater.highlightedIndex);
103
surface.requestFocus();
108
spreadRepeater.highlightedIndex = -1;
115
source: root.workspace
124
opacity: visible ? 1 : 0
125
Behavior on opacity {
126
UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
133
visible: spreadBackground.visible
139
objectName: "spreadContainer"
143
property bool animateIn: false
147
objectName: "spreadRepeater"
148
model: topLevelSurfaceList
150
property int highlightedIndex: -1
151
property int closingIndex: -1
153
function indexOf(delegateItem) {
154
for (var i = 0; i < spreadRepeater.count; i++) {
155
if (spreadRepeater.itemAt(i) === delegateItem) {
164
objectName: "spreadDelegate"
168
property real angle: 0
169
property real itemScale: 1
170
property int itemScaleOriginX: 0
171
property int itemScaleOriginY: 0
173
readonly property string windowTitle: clippedSpreadDelegate.window.title
177
enabled: spreadRepeater.closingIndex >= 0
178
UbuntuNumberAnimation {
179
onRunningChanged: if (!running) spreadRepeater.closingIndex = -1
183
DesktopSpreadDelegate {
184
id: clippedSpreadDelegate
185
objectName: "clippedSpreadDelegate"
186
anchors.left: parent.left
187
anchors.top: parent.top
188
application: model.application
189
surface: model.surface
190
width: spreadMaths.spreadHeight
191
height: spreadMaths.spreadHeight
195
origin.x: itemScaleOriginX
196
origin.y: itemScaleOriginY
201
origin { x: 0; y: (clippedSpreadDelegate.height - (clippedSpreadDelegate.height * itemScale / 2)) }
202
axis { x: 0; y: 1; z: 0 }
203
angle: spreadDelegate.angle
210
anchors.margins: -units.gu(2)
213
spreadRepeater.highlightedIndex = index;
221
flickable: spreadFlickable
223
totalItems: Math.max(6, topLevelSurfaceList.count)
224
sceneHeight: root.height
225
itemHeight: spreadDelegate.height
230
name: "altTab"; when: root.state == "altTab" && spreadContainer.visible
232
target: spreadDelegate
233
x: spreadMaths.animatedX
234
y: spreadMaths.animatedY + (spreadDelegate.height - clippedSpreadDelegate.height) - units.gu(2)
235
width: spreadMaths.spreadHeight
236
height: spreadMaths.sceneHeight
237
angle: spreadMaths.animatedAngle
238
itemScale: spreadMaths.scale
239
itemScaleOriginY: clippedSpreadDelegate.height / 2;
241
visible: spreadMaths.itemVisible
244
target: clippedSpreadDelegate
245
highlightShown: index == spreadRepeater.highlightedIndex
247
shadowOpacity: spreadMaths.shadowOpacity
248
anchors.topMargin: units.gu(2)
253
opacity: spreadMaths.tileInfoOpacity
256
target: spreadSelectArea
265
SequentialAnimation {
267
PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
268
PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
270
target: spreadDelegate; properties: "x"
272
duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration :0
273
easing: UbuntuAnimation.StandardEasing
275
UbuntuNumberAnimation { target: clippedSpreadDelegate; property: "shadowOpacity"; from: 0; to: spreadMaths.shadowOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
276
UbuntuNumberAnimation { target: tileInfo; property: "opacity"; from: 0; to: spreadMaths.tileInfoOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
278
PropertyAction { target: spreadSelectArea; property: "enabled" }
285
objectName: "tileInfo"
288
top: clippedSpreadDelegate.bottom
289
topMargin: ((spreadMaths.sceneHeight - spreadDelegate.y) - clippedSpreadDelegate.height) * 0.2
291
property int nextItemX: spreadRepeater.count > index + 1 ? spreadRepeater.itemAt(index + 1).x : spreadDelegate.x + units.gu(30)
292
width: Math.min(units.gu(30), nextItemX - spreadDelegate.x)
293
height: titleInfoColumn.height
297
onContainsMouseChanged: {
299
spreadRepeater.highlightedIndex = index
309
anchors { left: parent.left; top: parent.top; right: parent.right }
313
Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
314
Layout.preferredWidth: height * 8 / 7.6
317
source: model.application.icon
321
opacity: clippedSpreadDelegate.highlightShown ? 0 : .1
322
Behavior on opacity {
323
UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
329
Layout.fillWidth: true
330
Layout.preferredHeight: units.gu(6)
331
text: model.application ? model.application.name : spreadDelegate.windowTitle
332
wrapMode: Text.WordWrap
333
elide: Text.ElideRight
341
anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset + units.gu(2) }
342
source: "graphics/window-close.svg"
343
readonly property var mousePos: hoverMouseArea.mapToItem(spreadDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
344
visible: index == spreadRepeater.highlightedIndex
345
&& mousePos.y < (clippedSpreadDelegate.height / 3)
346
&& mousePos.y > -units.gu(4)
347
&& mousePos.x > -units.gu(4)
348
&& mousePos.x < (clippedSpreadDelegate.width * 2 / 3)
349
height: units.gu(1.5)
351
sourceSize.width: width
352
sourceSize.height: height
356
objectName: "closeMouseArea"
357
anchors.fill: closeImage
358
anchors.margins: -units.gu(2)
360
spreadRepeater.closingIndex = index;
361
model.surface.close();
372
objectName: "hoverMouseArea"
373
anchors.fill: spreadContainer
374
propagateComposedEvents: true
379
property int scrollAreaWidth: root.width / 3
380
property bool progressiveScrollingEnabled: false
383
mouse.accepted = false
385
if (hoverMouseArea.pressed) {
389
// Find the hovered item and mark it active
390
var mapped = mapToItem(spreadContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
391
var itemUnder = spreadContainer.childAt(mapped.x, mapped.y)
393
mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
394
var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
395
if (delegateChild && (delegateChild.objectName === "clippedSpreadDelegate" || delegateChild.objectName === "tileInfo")) {
396
spreadRepeater.highlightedIndex = spreadRepeater.indexOf(itemUnder)
400
if (spreadFlickable.contentWidth > spreadFlickable.minContentWidth) {
401
var margins = spreadFlickable.width * 0.05;
403
if (!progressiveScrollingEnabled && mouseX < spreadFlickable.width - scrollAreaWidth) {
404
progressiveScrollingEnabled = true
407
// do we need to scroll?
408
if (mouseX < scrollAreaWidth + margins) {
409
var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
410
var contentX = (1 - progress) * (spreadFlickable.contentWidth - spreadFlickable.width)
411
spreadFlickable.contentX = Math.max(0, Math.min(spreadFlickable.contentX, contentX))
413
if (mouseX > spreadFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
414
var progress = Math.min(1, (mouseX - (spreadFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
415
var contentX = progress * (spreadFlickable.contentWidth - spreadFlickable.width)
416
spreadFlickable.contentX = Math.min(spreadFlickable.contentWidth - spreadFlickable.width, Math.max(spreadFlickable.contentX, contentX))
420
onPressed: mouse.accepted = false
425
objectName: "spreadFlickable"
427
property int minContentWidth: 6 * Math.min(height / 4, width / 5)
428
contentWidth: Math.max(6, topLevelSurfaceList.count) * Math.min(height / 4, width / 5)
431
function snapTo(contentX) {
432
snapAnimation.stop();
433
snapAnimation.to = contentX
434
snapAnimation.start();
437
UbuntuNumberAnimation {
439
target: spreadFlickable
445
id: workspaceSelector
450
topMargin: units.gu(3.5)
452
height: root.height * 0.25
458
Item { Layout.fillWidth: true }
460
model: 1 // TODO: will be a workspacemodel in the future
462
Layout.fillHeight: true
463
Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
465
source: root.background
469
verticalCenter: parent.verticalCenter
471
height: parent.height * 0.75
476
property var source: ShaderEffectSource {
477
id: shaderEffectSource
478
sourceItem: root.workspace
482
varying highp vec2 qt_TexCoord0;
483
uniform sampler2D source;
486
highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
487
gl_FragColor = sourceColor;
492
// TODO: This is the bar for the currently selected workspace
493
// Enable this once the workspace stuff is implemented
495
// anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
496
// height: units.dp(2)
497
// color: theme.palette.normal.focus
498
// visible: index == 0 // TODO: should be active workspace index
503
// TODO: This is the "new workspace" button. Enable this once workspaces are implemented
505
// Layout.fillHeight: true
506
// Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
510
// right: parent.right
511
// verticalCenter: parent.verticalCenter
513
// height: parent.height * 0.75
514
// color: "#22ffffff"
517
// anchors.centerIn: parent
518
// font.pixelSize: parent.height / 2
523
Item { Layout.fillWidth: true }
528
id: currentSelectedLabel
529
anchors { bottom: parent.bottom; bottomMargin: root.height * 0.625; horizontalCenter: parent.horizontalCenter }
530
text: spreadRepeater.highlightedIndex >= 0 ? spreadRepeater.itemAt(spreadRepeater.highlightedIndex).windowTitle: ""
537
name: "altTab"; when: root.altTabPressed
538
PropertyChanges { target: blurLayer; saturation: 0.8; blurRadius: 60; visible: true }
539
PropertyChanges { target: workspaceSelector; visible: true }
540
PropertyChanges { target: spreadContainer; visible: true }
541
PropertyChanges { target: spreadFlickable; enabled: spreadFlickable.contentWidth > spreadFlickable.minContentWidth }
542
PropertyChanges { target: currentSelectedLabel; visible: true }
543
PropertyChanges { target: spreadBackground; visible: true }
544
PropertyChanges { target: hoverMouseArea; enabled: true }
551
SequentialAnimation {
552
PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: Math.min(topLevelSurfaceList.count - 1, 1) }
553
PauseAnimation { duration: spreadContainer.animateIn ? 0 : 140 }
554
PropertyAction { target: workspaceSelector; property: "visible" }
555
PropertyAction { target: spreadContainer; property: "visible" }
557
UbuntuNumberAnimation { target: blurLayer; properties: "saturation,blurRadius"; duration: UbuntuAnimation.SnapDuration }
558
PropertyAction { target: spreadFlickable; property: "visible" }
559
PropertyAction { targets: [currentSelectedLabel,spreadBackground]; property: "visible" }
560
PropertyAction { target: spreadFlickable; property: "contentX"; value: 0 }
562
PropertyAction { target: hoverMouseArea; properties: "enabled,progressiveScrollingEnabled"; value: false }
568
PropertyAnimation { property: "opacity" }
569
ScriptAction { script: { root.focusSelected() } }
570
PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: -1 }
571
PropertyAction { target: spreadContainer; property: "animateIn"; value: false }