on xenial help sign in
split spread from regular stage
commitc97ac4acf3eaf2bace487714c0cd09ac5e6782fe authorMichael Zanetti <michael.zanetti@canonical.com> dateThu 10 Sep 2015, 12:03 (11 years ago) parentae38fda
2 files changed+507−481
qml/Stages/DesktopSpread.qml+497 qml/Stages/DesktopStage.qml+10−481
qml/Stages/DesktopSpread.qmlnew file+497
@@ -0,0 +1,497 @@
1+import QtQuick 2.4
2+import QtQuick.Layouts 1.1
3+import Ubuntu.Components 1.2
4+import Ubuntu.Gestures 0.1
5+import Unity.Application 0.1
6+
7+FocusScope {
8+ id: root
9+
10+ property bool altTabPressed: false
11+ property Item workspace: null
12+
13+ readonly property alias highlightedIndex: spreadRepeater.highlightedIndex
14+
15+
16+ Keys.onPressed: {
17+ switch (event.key) {
18+ case Qt.Key_Left:
19+ case Qt.Key_Backtab:
20+ selectPrevious(event.isAutoRepeat)
21+ event.accepted = true;
22+ break;
23+ case Qt.Key_Right:
24+ case Qt.Key_Tab:
25+ selectNext(event.isAutoRepeat)
26+ event.accepted = true;
27+ break;
28+ case Qt.Key_Escape:
29+ spreadRepeater.highlightedIndex = -1
30+ // Falling through intentionally
31+ case Qt.Key_Enter:
32+ case Qt.Key_Return:
33+ case Qt.Key_Space:
34+ root.state = ""
35+ event.accepted = true;
36+ }
37+ }
38+
39+ function selectNext(isAutoRepeat) {
40+ if (isAutoRepeat && spreadRepeater.highlightedIndex >= ApplicationManager.count -1) {
41+ return; // AutoRepeat is not allowed to wrap around
42+ }
43+
44+ spreadRepeater.highlightedIndex = (spreadRepeater.highlightedIndex + 1) % ApplicationManager.count;
45+ var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, spreadRepeater.highlightedIndex - 3));
46+ if (spreadFlickable.contentX < newContentX || spreadRepeater.highlightedIndex == 0) {
47+ spreadFlickable.snapTo(newContentX)
48+ }
49+ }
50+
51+ function selectPrevious(isAutoRepeat) {
52+ if (isAutoRepeat && spreadRepeater.highlightedIndex == 0) {
53+ return; // AutoRepeat is not allowed to wrap around
54+ }
55+
56+ var newIndex = spreadRepeater.highlightedIndex - 1 >= 0 ? spreadRepeater.highlightedIndex - 1 : ApplicationManager.count - 1;
57+ spreadRepeater.highlightedIndex = newIndex;
58+ var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, spreadRepeater.highlightedIndex - 1));
59+ if (spreadFlickable.contentX > newContentX || newIndex == ApplicationManager.count -1) {
60+ spreadFlickable.snapTo(newContentX)
61+ }
62+ }
63+
64+ function focusSelected() {
65+ if (spreadRepeater.highlightedIndex != -1) {
66+ var application = ApplicationManager.get(spreadRepeater.highlightedIndex);
67+ ApplicationManager.focusApplication(application.appId);
68+ }
69+ }
70+
71+ Item {
72+ id: spreadContainer
73+ anchors.fill: parent
74+ visible: false
75+
76+ Repeater {
77+ id: spreadRepeater
78+ model: ApplicationManager
79+
80+ property int highlightedIndex: -1
81+ property int closingIndex: -1
82+
83+ function indexOf(delegateItem) {
84+ for (var i = 0; i < spreadRepeater.count; i++) {
85+ if (spreadRepeater.itemAt(i) === delegateItem) {
86+ return i;
87+ }
88+ }
89+ return -1;
90+ }
91+
92+ delegate: Item {
93+ id: spreadDelegate
94+ objectName: "spreadDelegate"
95+ width: units.gu(20)
96+ height: units.gu(20)
97+
98+ property real angle: 0
99+ property real itemScale: 1
100+ property int itemScaleOriginX: 0
101+ property int itemScaleOriginY: 0
102+
103+ Behavior on x {
104+ id: closeBehavior
105+ enabled: spreadRepeater.closingIndex >= 0
106+ UbuntuNumberAnimation {
107+ onRunningChanged: if (!running) spreadRepeater.closingIndex = -1
108+ }
109+ }
110+
111+ DesktopSpreadDelegate {
112+ id: clippedSpreadDelegate
113+ objectName: "clippedSpreadDelegate"
114+ anchors.left: parent.left
115+ anchors.top: parent.top
116+ application: ApplicationManager.get(index)
117+ width: spreadMaths.spreadHeight
118+ height: spreadMaths.spreadHeight
119+
120+ transform: [
121+ Scale {
122+ origin.x: itemScaleOriginX
123+ origin.y: itemScaleOriginY
124+ xScale: itemScale
125+ yScale: itemScale
126+ },
127+ Rotation {
128+ origin { x: 0; y: (clippedSpreadDelegate.height - (clippedSpreadDelegate.height * itemScale / 2)) }
129+ axis { x: 0; y: 1; z: 0 }
130+ angle: spreadDelegate.angle
131+ }
132+ ]
133+
134+ MouseArea {
135+ id: spreadSelectArea
136+ anchors.fill: parent
137+ anchors.margins: -units.gu(2)
138+ enabled: false
139+ onClicked: {
140+ spreadRepeater.highlightedIndex = index;
141+ root.state = "";
142+ }
143+ }
144+ }
145+
146+ SpreadMaths {
147+ id: spreadMaths
148+ flickable: spreadFlickable
149+ itemIndex: index
150+ totalItems: Math.max(6, ApplicationManager.count)
151+ sceneHeight: root.height
152+ itemHeight: spreadDelegate.height
153+ }
154+
155+ states: [
156+ State {
157+ name: "altTab"; when: root.state == "altTab" && spreadContainer.visible
158+ PropertyChanges {
159+ target: spreadDelegate
160+ x: spreadMaths.animatedX
161+ y: spreadMaths.animatedY + (spreadDelegate.height - clippedSpreadDelegate.height) - units.gu(2)
162+ width: spreadMaths.spreadHeight
163+ height: spreadMaths.sceneHeight
164+ angle: spreadMaths.animatedAngle
165+ itemScale: spreadMaths.scale
166+ itemScaleOriginY: clippedSpreadDelegate.height / 2;
167+ z: index
168+ visible: spreadMaths.itemVisible
169+ }
170+ PropertyChanges {
171+ target: clippedSpreadDelegate
172+ highlightShown: index == spreadRepeater.highlightedIndex
173+ state: "transformed"
174+ shadowOpacity: spreadMaths.shadowOpacity
175+ anchors.topMargin: units.gu(2)
176+ }
177+ PropertyChanges {
178+ target: tileInfo
179+ visible: true
180+ opacity: spreadMaths.tileInfoOpacity
181+ }
182+ PropertyChanges {
183+ target: spreadSelectArea
184+ enabled: true
185+ }
186+ }
187+ ]
188+ transitions: [
189+ Transition {
190+ from: ""
191+ to: "altTab"
192+ PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
193+ PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
194+ PropertyAnimation {
195+ target: spreadDelegate; properties: "x"
196+ from: root.width
197+ duration: rightEdgePushArea.containsMouse ? UbuntuAnimation.FastDuration :0
198+ easing: UbuntuAnimation.StandardEasing
199+ }
200+ }
201+ ]
202+
203+ MouseArea {
204+ id: tileInfo
205+ objectName: "tileInfo"
206+ anchors { left: parent.left; top: clippedSpreadDelegate.bottom; topMargin: units.gu(5) }
207+ width: units.gu(30)
208+ height: titleInfoColumn.height
209+ visible: false
210+ hoverEnabled: true
211+
212+ onContainsMouseChanged: {
213+ if (containsMouse) {
214+ spreadRepeater.highlightedIndex = index
215+ }
216+ }
217+
218+ onClicked: {
219+ root.state = ""
220+ }
221+
222+ ColumnLayout {
223+ id: titleInfoColumn
224+ anchors { left: parent.left; top: parent.top; right: parent.right }
225+ spacing: units.gu(1)
226+
227+ UbuntuShape {
228+ Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
229+ Layout.preferredWidth: height * 8 / 7.6
230+ image: Image {
231+ anchors.fill: parent
232+ source: model.icon
233+ }
234+ }
235+ Label {
236+ Layout.fillWidth: true
237+ Layout.preferredHeight: units.gu(6)
238+ text: model.name
239+ wrapMode: Text.WordWrap
240+ maximumLineCount: 2
241+ }
242+ }
243+ }
244+
245+ Image {
246+ id: closeImage
247+ anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset + units.gu(2) }
248+ source: "graphics/window-close.svg"
249+ readonly property var mousePos: hoverMouseArea.mapToItem(spreadDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
250+ visible: index == spreadRepeater.highlightedIndex
251+ && mousePos.y < (clippedSpreadDelegate.height / 3)
252+ && mousePos.y > -units.gu(4)
253+ && mousePos.x > -units.gu(4)
254+ && mousePos.x < (clippedSpreadDelegate.width * 2 / 3)
255+ height: units.gu(1.5)
256+ width: height
257+ sourceSize.width: width
258+ sourceSize.height: height
259+
260+ MouseArea {
261+ id: closeMouseArea
262+ objectName: "closeMouseArea"
263+ anchors.fill: closeImage
264+ anchors.margins: -units.gu(2)
265+ onClicked: {
266+ spreadRepeater.closingIndex = index;
267+ ApplicationManager.stopApplication(model.appId)
268+ }
269+ }
270+ }
271+ }
272+ }
273+ }
274+
275+
276+ MouseArea {
277+ id: hoverMouseArea
278+ anchors.fill: spreadContainer
279+ propagateComposedEvents: true
280+ hoverEnabled: true
281+ enabled: false
282+
283+ property int scrollAreaWidth: root.width / 3
284+ property bool progressiveScrollingEnabled: false
285+
286+ onMouseXChanged: {
287+ mouse.accepted = false
288+
289+ if (hoverMouseArea.pressed) {
290+ return;
291+ }
292+
293+ // Find the hovered item and mark it active
294+ var mapped = mapToItem(spreadContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
295+ var itemUnder = spreadContainer.childAt(mapped.x, mapped.y)
296+ if (itemUnder) {
297+ mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
298+ var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
299+ if (delegateChild && (delegateChild.objectName === "clippedSpreadDelegate" || delegateChild.objectName === "tileInfo")) {
300+ spreadRepeater.highlightedIndex = spreadRepeater.indexOf(itemUnder)
301+ }
302+ }
303+
304+ if (spreadFlickable.contentWidth > spreadFlickable.minContentWidth) {
305+ var margins = spreadFlickable.width * 0.05;
306+
307+ if (!progressiveScrollingEnabled && mouseX < spreadFlickable.width - scrollAreaWidth) {
308+ progressiveScrollingEnabled = true
309+ }
310+
311+ // do we need to scroll?
312+ if (mouseX < scrollAreaWidth) {
313+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
314+ var contentX = (1 - progress) * (spreadFlickable.contentWidth - spreadFlickable.width)
315+ spreadFlickable.contentX = Math.max(0, Math.min(spreadFlickable.contentX, contentX))
316+ }
317+ if (mouseX > spreadFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
318+ var progress = Math.min(1, (mouseX - (spreadFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
319+ var contentX = progress * (spreadFlickable.contentWidth - spreadFlickable.width)
320+ spreadFlickable.contentX = Math.min(spreadFlickable.contentWidth - spreadFlickable.width, Math.max(spreadFlickable.contentX, contentX))
321+ }
322+ }
323+ }
324+ onPressed: mouse.accepted = false
325+ }
326+
327+ FloatingFlickable {
328+ id: spreadFlickable
329+ objectName: "spreadFlickable"
330+ anchors.fill: parent
331+ property int minContentWidth: 6 * Math.min(height / 4, width / 5)
332+ contentWidth: Math.max(6, ApplicationManager.count) * Math.min(height / 4, width / 5)
333+ enabled: false
334+
335+ function snapTo(contentX) {
336+ snapAnimation.stop();
337+ snapAnimation.to = contentX
338+ snapAnimation.start();
339+ }
340+
341+ UbuntuNumberAnimation {
342+ id: snapAnimation
343+ target: spreadFlickable
344+ property: "contentX"
345+ }
346+ }
347+
348+ Item {
349+ id: workspaceSelector
350+ anchors {
351+ left: parent.left
352+ top: parent.top
353+ right: parent.right
354+ topMargin: units.gu(3.5)
355+ }
356+ height: root.height * 0.25
357+ visible: false
358+
359+ RowLayout {
360+ anchors.fill: parent
361+ spacing: units.gu(1)
362+ Item { Layout.fillWidth: true }
363+ Repeater {
364+ model: 1 // TODO: will be a workspacemodel in the future
365+ Item {
366+ Layout.fillHeight: true
367+ Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
368+ Image {
369+ source: root.background
370+ anchors {
371+ left: parent.left
372+ right: parent.right
373+ verticalCenter: parent.verticalCenter
374+ }
375+ height: parent.height * 0.75
376+
377+ ShaderEffect {
378+ anchors.fill: parent
379+
380+ property var source: ShaderEffectSource {
381+ id: shaderEffectSource
382+ sourceItem: appContainer
383+ }
384+
385+ fragmentShader: "
386+ varying highp vec2 qt_TexCoord0;
387+ uniform sampler2D source;
388+ void main(void)
389+ {
390+ highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
391+ gl_FragColor = sourceColor;
392+ }"
393+ }
394+ }
395+
396+ // TODO: This is the bar for the currently selected workspace
397+ // Enable this once the workspace stuff is implemented
398+ // Rectangle {
399+ // anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
400+ // height: units.dp(2)
401+ // color: UbuntuColors.orange
402+ // visible: index == 0 // TODO: should be active workspace index
403+ // }
404+ }
405+
406+ }
407+ // TODO: This is the "new workspace" button. Enable this once workspaces are implemented
408+ // Item {
409+ // Layout.fillHeight: true
410+ // Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
411+ // Rectangle {
412+ // anchors {
413+ // left: parent.left
414+ // right: parent.right
415+ // verticalCenter: parent.verticalCenter
416+ // }
417+ // height: parent.height * 0.75
418+ // color: "#22ffffff"
419+
420+ // Label {
421+ // anchors.centerIn: parent
422+ // font.pixelSize: parent.height / 2
423+ // text: "+"
424+ // }
425+ // }
426+ // }
427+ Item { Layout.fillWidth: true }
428+ }
429+ }
430+
431+ Label {
432+ id: currentSelectedLabel
433+ anchors { bottom: parent.bottom; bottomMargin: root.height * 0.625; horizontalCenter: parent.horizontalCenter }
434+ text: spreadRepeater.highlightedIndex >= 0 ? ApplicationManager.get(spreadRepeater.highlightedIndex).name : ""
435+ visible: false
436+ fontSize: "large"
437+ }
438+
439+ states: [
440+ State {
441+ name: "altTab"; when: root.altTabPressed
442+ PropertyChanges { target: blurLayer; saturation: 0.8; blurRadius: 60; visible: true }
443+ PropertyChanges { target: workspaceSelector; visible: true }
444+ PropertyChanges { target: spreadContainer; visible: true }
445+ PropertyChanges { target: spreadFlickable; enabled: spreadFlickable.contentWidth > spreadFlickable.minContentWidth }
446+ PropertyChanges { target: currentSelectedLabel; visible: true }
447+ PropertyChanges { target: spreadBackground; visible: true }
448+ PropertyChanges { target: hoverMouseArea; enabled: true }
449+ }
450+ ]
451+ transitions: [
452+ Transition {
453+ from: "*"
454+ to: "altTab"
455+ SequentialAnimation {
456+ PropertyAction { target: hoverMouseArea; property: "progressiveScrollingEnabled"; value: false }
457+ PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: Math.min(ApplicationManager.count - 1, 1) }
458+ PauseAnimation { duration: 50 }
459+ PropertyAction { target: workspaceSelector; property: "visible" }
460+ PropertyAction { target: spreadContainer; property: "visible" }
461+ ParallelAnimation {
462+ UbuntuNumberAnimation { target: blurLayer; properties: "saturation,blurRadius" }
463+ PropertyAction { target: spreadFlickable; property: "visible" }
464+ PropertyAction { targets: [currentSelectedLabel,spreadBackground]; property: "visible" }
465+ PropertyAction { target: spreadFlickable; property: "contentX"; value: 0 }
466+ }
467+ }
468+ },
469+ Transition {
470+ from: "*"
471+ to: "*"
472+ PropertyAnimation { property: "opacity" }
473+ ScriptAction { script: { root.focusSelected() } }
474+ PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: -1 }
475+ }
476+
477+ ]
478+
479+ MouseArea {
480+ id: rightEdgePushArea
481+ anchors {
482+ top: parent.top
483+ right: parent.right
484+ bottom: parent.bottom
485+ }
486+ // TODO: Make this a push to edge thing like the launcher when we can,
487+ // for now, yes, we want 1 pixel, regardless of the scaling
488+ width: 1
489+ hoverEnabled: true
490+ onContainsMouseChanged: {
491+ if (containsMouse) {
492+ root.state = "altTab";
493+ }
494+ }
495+ }
496+}
497+
qml/Stages/DesktopStage.qml+10−481
@@ -42,6 +42,8 @@ Rectangle {
4242 property bool beingResized: false
4343 property bool keepDashRunning: true
4444 property bool suspended: false
45+ property alias background: wallpaper.source
46+ property alias altTabPressed: spread.altTabPressed
4547
4648 // functions to be called from outside
4749 function updateFocusedAppOrientation() { /* TODO */ }
@@ -54,14 +56,11 @@ Rectangle {
5456 property int mainAppWindowOrientationAngle: 0
5557 readonly property bool orientationChangesEnabled: false
5658
57− property alias background: wallpaper.source
58− property bool altTabPressed: false
59−
6059 Connections {
6160 target: ApplicationManager
6261 onApplicationAdded: {
63− if (root.state == "altTab") {
64− root.state = "";
62+ if (spread.state == "altTab") {
63+ spread.state = "";
6564 }
6665
6766 ApplicationManager.requestFocusApplication(appId)
@@ -115,62 +114,6 @@ Rectangle {
115114 anchors.fill: parent
116115 focus: true
117116
118− Keys.onPressed: {
119− switch (event.key) {
120− case Qt.Key_Left:
121− case Qt.Key_Backtab:
122− selectPrevious(event.isAutoRepeat)
123− event.accepted = true;
124− break;
125− case Qt.Key_Right:
126− case Qt.Key_Tab:
127− selectNext(event.isAutoRepeat)
128− event.accepted = true;
129− break;
130− case Qt.Key_Escape:
131− spreadRepeater.highlightedIndex = -1
132− // Falling through intentionally
133− case Qt.Key_Enter:
134− case Qt.Key_Return:
135− case Qt.Key_Space:
136− root.state = ""
137− event.accepted = true;
138− }
139− }
140−
141− function selectNext(isAutoRepeat) {
142− print("should select next", isAutoRepeat)
143− if (isAutoRepeat && spreadRepeater.highlightedIndex >= ApplicationManager.count -1) {
144− return; // AutoRepeat is not allowed to wrap around
145− }
146−
147− spreadRepeater.highlightedIndex = (spreadRepeater.highlightedIndex + 1) % ApplicationManager.count;
148− var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, spreadRepeater.highlightedIndex - 3));
149− if (spreadFlickable.contentX < newContentX || spreadRepeater.highlightedIndex == 0) {
150− spreadFlickable.snapTo(newContentX)
151− }
152− }
153−
154− function selectPrevious(isAutoRepeat) {
155− if (isAutoRepeat && spreadRepeater.highlightedIndex == 0) {
156− return; // AutoRepeat is not allowed to wrap around
157− }
158−
159− var newIndex = spreadRepeater.highlightedIndex - 1 >= 0 ? spreadRepeater.highlightedIndex - 1 : ApplicationManager.count - 1;
160− spreadRepeater.highlightedIndex = newIndex;
161− var newContentX = ((spreadFlickable.contentWidth) / (ApplicationManager.count + 1)) * Math.max(0, Math.min(ApplicationManager.count - 5, spreadRepeater.highlightedIndex - 1));
162− if (spreadFlickable.contentX > newContentX || newIndex == ApplicationManager.count -1) {
163− spreadFlickable.snapTo(newContentX)
164− }
165− }
166−
167− function focusSelected() {
168− if (spreadRepeater.highlightedIndex != -1) {
169− var application = ApplicationManager.get(spreadRepeater.highlightedIndex);
170− ApplicationManager.focusApplication(application.appId);
171− }
172− }
173−
174117 CrossFadeImage {
175118 id: wallpaper
176119 anchors.fill: parent
@@ -196,7 +139,7 @@ Rectangle {
196139 property bool maximized: false
197140 property bool minimized: false
198141
199− focus: priv.focusedAppId === model.appId && root.state !== "altTab"
142+ focus: priv.focusedAppId === model.appId && spread.state !== "altTab"
200143
201144 Binding {
202145 target: ApplicationManager.get(index)
@@ -248,7 +191,7 @@ Rectangle {
248191 target: appDelegate
249192 property: "z"
250193 value: ApplicationManager.count + 1
251− when: index == spreadRepeater.highlightedIndex && blurLayer.ready
194+ when: index == spread.highlightedIndex && blurLayer.ready
252195 }
253196
254197 WindowMoveResizeArea {
@@ -295,424 +238,10 @@ Rectangle {
295238 visible: false
296239 }
297240
298− Item {
299− id: spreadContainer
300− visible: false
301− onVisibleChanged: print("container visible changed", visible)
302−
303− Repeater {
304− id: spreadRepeater
305− model: ApplicationManager
306−
307− property int highlightedIndex: -1
308− property int closingIndex: -1
309−
310− function indexOf(delegateItem) {
311− for (var i = 0; i < spreadRepeater.count; i++) {
312− if (spreadRepeater.itemAt(i) === delegateItem) {
313− return i;
314− }
315− }
316− return -1;
317− }
318−
319− delegate: Item {
320− id: spreadDelegate
321− objectName: "spreadDelegate"
322− width: units.gu(20)
323− height: units.gu(20)
324−
325− property real angle: 0
326− property real itemScale: 1
327− property int itemScaleOriginX: 0
328− property int itemScaleOriginY: 0
329−
330− Behavior on x {
331− id: closeBehavior
332− enabled: spreadRepeater.closingIndex >= 0
333− UbuntuNumberAnimation {
334− onRunningChanged: if (!running) spreadRepeater.closingIndex = -1
335− }
336− }
337−
338− DesktopSpreadDelegate {
339− id: clippedSpreadDelegate
340− objectName: "clippedSpreadDelegate"
341− anchors.left: parent.left
342− anchors.top: parent.top
343− application: ApplicationManager.get(index)
344− width: spreadMaths.spreadHeight
345− height: spreadMaths.spreadHeight
346−
347− transform: [
348− Scale {
349− origin.x: itemScaleOriginX
350− origin.y: itemScaleOriginY
351− xScale: itemScale
352− yScale: itemScale
353− },
354− Rotation {
355− origin { x: 0; y: (clippedSpreadDelegate.height - (clippedSpreadDelegate.height * itemScale / 2)) }
356− axis { x: 0; y: 1; z: 0 }
357− angle: spreadDelegate.angle
358− }
359− ]
360−
361− MouseArea {
362− id: spreadSelectArea
363− anchors.fill: parent
364− anchors.margins: -units.gu(2)
365− enabled: false
366− onClicked: {
367− root.state = ""
368− }
369− }
370− }
371−
372− SpreadMaths {
373− id: spreadMaths
374− flickable: spreadFlickable
375− itemIndex: index
376− totalItems: Math.max(6, ApplicationManager.count)
377− sceneHeight: root.height
378− itemHeight: spreadDelegate.height
379− }
380−
381− states: [
382− State {
383− name: "altTab"; when: root.state == "altTab" && spreadContainer.visible
384− PropertyChanges {
385− target: spreadDelegate
386− x: spreadMaths.animatedX
387− y: spreadMaths.animatedY + (spreadDelegate.height - clippedSpreadDelegate.height) - units.gu(2)
388− width: spreadMaths.spreadHeight
389− height: spreadMaths.sceneHeight
390− angle: spreadMaths.animatedAngle
391− itemScale: spreadMaths.scale
392− itemScaleOriginY: clippedSpreadDelegate.height / 2;
393− z: index
394− visible: spreadMaths.itemVisible
395− }
396− PropertyChanges {
397− target: clippedSpreadDelegate
398− highlightShown: index == spreadRepeater.highlightedIndex
399− state: "transformed"
400− shadowOpacity: spreadMaths.shadowOpacity
401− anchors.topMargin: units.gu(2)
402− }
403− PropertyChanges {
404− target: tileInfo
405− visible: true
406− opacity: spreadMaths.tileInfoOpacity
407− }
408− PropertyChanges {
409− target: spreadSelectArea
410− enabled: true
411− }
412− }
413− ]
414− transitions: [
415− Transition {
416− from: ""
417− to: "altTab"
418− PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
419− PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
420− PropertyAnimation {
421− target: spreadDelegate; properties: "x"
422− from: root.width
423− duration: rightEdgePushArea.containsMouse ? UbuntuAnimation.FastDuration :0
424− easing: UbuntuAnimation.StandardEasing
425− }
426− }
427− ]
428−
429− MouseArea {
430− id: tileInfo
431− objectName: "tileInfo"
432− anchors { left: parent.left; top: clippedSpreadDelegate.bottom; topMargin: units.gu(5) }
433− width: units.gu(30)
434− height: titleInfoColumn.height
435− visible: false
436− hoverEnabled: true
437−
438− onContainsMouseChanged: {
439− if (containsMouse) {
440− spreadRepeater.highlightedIndex = index
441− }
442− }
443−
444− onClicked: {
445− root.state = ""
446− }
447−
448− ColumnLayout {
449− id: titleInfoColumn
450− anchors { left: parent.left; top: parent.top; right: parent.right }
451− spacing: units.gu(1)
452−
453− UbuntuShape {
454− Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
455− Layout.preferredWidth: height * 8 / 7.6
456− image: Image {
457− anchors.fill: parent
458− source: model.icon
459− }
460− }
461− Label {
462− Layout.fillWidth: true
463− Layout.preferredHeight: units.gu(6)
464− text: model.name
465− wrapMode: Text.WordWrap
466− maximumLineCount: 2
467− }
468− }
469− }
470−
471− Image {
472− id: closeImage
473− anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset + units.gu(2) }
474− source: "graphics/window-close.svg"
475− readonly property var mousePos: hoverMouseArea.mapToItem(spreadDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
476− visible: index == spreadRepeater.highlightedIndex
477− && mousePos.y < (clippedSpreadDelegate.height / 3)
478− && mousePos.y > -units.gu(4)
479− && mousePos.x > -units.gu(4)
480− && mousePos.x < (clippedSpreadDelegate.width * 2 / 3)
481− height: units.gu(1.5)
482− width: height
483− sourceSize.width: width
484− sourceSize.height: height
485−
486− MouseArea {
487− id: closeMouseArea
488− objectName: "closeMouseArea"
489− anchors.fill: closeImage
490− anchors.margins: -units.gu(2)
491− onClicked: {
492− spreadRepeater.closingIndex = index;
493− ApplicationManager.stopApplication(model.appId)
494− }
495− }
496− }
497− }
498− }
499− }
500−
501−
502− MouseArea {
503− id: hoverMouseArea
504− anchors.fill: appContainer
505− propagateComposedEvents: true
506− hoverEnabled: true
507− enabled: false
508−
509− property int scrollAreaWidth: root.width / 3
510− property bool progressiveScrollingEnabled: false
511−
512− onMouseXChanged: {
513− mouse.accepted = false
514−
515− // Find the hovered item and mark it active
516− var mapped = mapToItem(spreadContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
517− var itemUnder = spreadContainer.childAt(mapped.x, mapped.y)
518− if (itemUnder) {
519− mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
520− var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
521− if (delegateChild && (delegateChild.objectName === "clippedSpreadDelegate" || delegateChild.objectName === "tileInfo")) {
522− spreadRepeater.highlightedIndex = spreadRepeater.indexOf(itemUnder)
523− }
524− }
525−
526− if (spreadFlickable.contentWidth > spreadFlickable.minContentWidth) {
527− var margins = spreadFlickable.width * 0.05;
528−
529− if (!progressiveScrollingEnabled && mouseX < spreadFlickable.width - scrollAreaWidth) {
530− progressiveScrollingEnabled = true
531− }
532−
533− // do we need to scroll?
534− if (mouseX < scrollAreaWidth) {
535− var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
536− var contentX = (1 - progress) * (spreadFlickable.contentWidth - spreadFlickable.width)
537− spreadFlickable.contentX = Math.max(0, Math.min(spreadFlickable.contentX, contentX))
538− }
539− if (mouseX > spreadFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
540− var progress = Math.min(1, (mouseX - (spreadFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
541− var contentX = progress * (spreadFlickable.contentWidth - spreadFlickable.width)
542− spreadFlickable.contentX = Math.min(spreadFlickable.contentWidth - spreadFlickable.width, Math.max(spreadFlickable.contentX, contentX))
543− }
544− }
545− }
546− onPressed: mouse.accepted = false
547− }
548−
549− FloatingFlickable {
550− id: spreadFlickable
551− objectName: "spreadFlickable"
241+ DesktopSpread {
242+ id: spread
552243 anchors.fill: parent
553− property int minContentWidth: 6 * Math.min(height / 4, width / 5)
554− contentWidth: Math.max(6, ApplicationManager.count) * Math.min(height / 4, width / 5)
555− enabled: false
556−
557− function snapTo(contentX) {
558− snapAnimation.stop();
559− snapAnimation.to = contentX
560− snapAnimation.start();
561− }
562−
563− UbuntuNumberAnimation {
564− id: snapAnimation
565− target: spreadFlickable
566− property: "contentX"
567− }
568− }
569−
570− Item {
571− id: workspaceSelector
572− anchors {
573− left: parent.left
574− top: parent.top
575− right: parent.right
576− topMargin: units.gu(3.5)
577− }
578− height: root.height * 0.25
579− visible: false
580−
581− RowLayout {
582− anchors.fill: parent
583− spacing: units.gu(1)
584− Item { Layout.fillWidth: true }
585− Repeater {
586− model: 1 // TODO: will be a workspacemodel in the future
587− Item {
588− Layout.fillHeight: true
589− Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
590− Image {
591− source: root.background
592− anchors {
593− left: parent.left
594− right: parent.right
595− verticalCenter: parent.verticalCenter
596− }
597− height: parent.height * 0.75
598−
599− ShaderEffect {
600− anchors.fill: parent
601−
602− property var source: ShaderEffectSource {
603− id: shaderEffectSource
604− sourceItem: appContainer
605− }
606−
607− fragmentShader: "
608− varying highp vec2 qt_TexCoord0;
609− uniform sampler2D source;
610− void main(void)
611− {
612− highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
613− gl_FragColor = sourceColor;
614− }"
615− }
616− }
617−
618− // TODO: This is the bar for the currently selected workspace
619− // Enable this once the workspace stuff is implemented
620−// Rectangle {
621−// anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
622−// height: units.dp(2)
623−// color: UbuntuColors.orange
624−// visible: index == 0 // TODO: should be active workspace index
625−// }
626− }
627−
628− }
629− // TODO: This is the "new workspace" button. Enable this once workspaces are implemented
630−// Item {
631−// Layout.fillHeight: true
632−// Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
633−// Rectangle {
634−// anchors {
635−// left: parent.left
636−// right: parent.right
637−// verticalCenter: parent.verticalCenter
638−// }
639−// height: parent.height * 0.75
640−// color: "#22ffffff"
641−
642−// Label {
643−// anchors.centerIn: parent
644−// font.pixelSize: parent.height / 2
645−// text: "+"
646−// }
647−// }
648−// }
649− Item { Layout.fillWidth: true }
650− }
651− }
652−
653− Label {
654− id: currentSelectedLabel
655− anchors { bottom: parent.bottom; bottomMargin: root.height * 0.625; horizontalCenter: parent.horizontalCenter }
656− text: spreadRepeater.highlightedIndex >= 0 ? ApplicationManager.get(spreadRepeater.highlightedIndex).name : ""
657− visible: false
658− fontSize: "large"
659− }
660−
661− states: [
662− State {
663− name: "altTab"; when: root.altTabPressed
664− PropertyChanges { target: blurLayer; saturation: 0.8; blurRadius: 60; visible: true }
665− PropertyChanges { target: workspaceSelector; visible: true }
666− PropertyChanges { target: spreadContainer; visible: true }
667− PropertyChanges { target: spreadFlickable; enabled: spreadFlickable.contentWidth > spreadFlickable.minContentWidth }
668− PropertyChanges { target: currentSelectedLabel; visible: true }
669− PropertyChanges { target: spreadBackground; visible: true }
670− PropertyChanges { target: hoverMouseArea; enabled: true }
671− }
672− ]
673− transitions: [
674− Transition {
675− from: "*"
676− to: "altTab"
677− SequentialAnimation {
678− PropertyAction { target: hoverMouseArea; property: "progressiveScrollingEnabled"; value: false }
679− PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: Math.min(ApplicationManager.count - 1, 1) }
680− PauseAnimation { duration: 50 }
681− PropertyAction { target: workspaceSelector; property: "visible" }
682− PropertyAction { target: spreadContainer; property: "visible" }
683− ParallelAnimation {
684− UbuntuNumberAnimation { target: blurLayer; properties: "saturation,blurRadius" }
685− PropertyAction { target: spreadFlickable; property: "visible" }
686− PropertyAction { targets: [currentSelectedLabel,spreadBackground]; property: "visible" }
687− PropertyAction { target: spreadFlickable; property: "contentX"; value: 0 }
688− }
689− }
690− },
691− Transition {
692− from: "*"
693− to: "*"
694− PropertyAnimation { property: "opacity" }
695− ScriptAction { script: { appContainer.focusSelected() } }
696− PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: -1 }
697− }
698−
699− ]
700−
701− MouseArea {
702− id: rightEdgePushArea
703− anchors {
704− top: parent.top
705− right: parent.right
706− bottom: parent.bottom
707− }
708− // TODO: Make this a push to edge thing like the launcher when we can,
709− // for now, yes, we want 1 pixel, regardless of the scaling
710− width: 1
711− hoverEnabled: true
712− onContainsMouseChanged: {
713− if (containsMouse) {
714− root.state = "altTab";
715− }
716− }
244+ workspace: appContainer
245+ focus: root.altTabPressed
717246 }
718247}