Merge lp:~azzar1/unity8/remove-UbuntuShapeForItem into lp:unity8

Proposed by Andrea Azzarone
Status: Superseded
Proposed branch: lp:~azzar1/unity8/remove-UbuntuShapeForItem
Merge into: lp:unity8
Diff against target: 12386 lines (+3481/-6203)
64 files modified
debian/changelog (+5/-3)
debian/unity8.install (+1/-1)
plugins/Ubuntu/Gestures/TouchGate.cpp (+4/-1)
plugins/WindowManager/TopLevelSurfaceList.cpp (+0/-5)
qml/CMakeLists.txt (+1/-1)
qml/Components/EdgeBarrier.qml (+2/-0)
qml/Components/FloatingFlickable.qml (+3/-0)
qml/Components/UbuntuShapeForItem.qml (+0/-47)
qml/Greeter/LoginAreaContainer.qml (+1/-1)
qml/Launcher/LauncherPanel.qml (+5/-2)
qml/Notifications/Notification.qml (+1/-1)
qml/Rotation/RotationStates.qml (+0/-6)
qml/Shell.qml (+54/-167)
qml/Stage/ApplicationWindow.qml (+13/-37)
qml/Stage/DecoratedWindow.qml (+123/-31)
qml/Stage/MoveHandler.qml (+2/-2)
qml/Stage/PromptSurfaceAnimations.qml (+2/-3)
qml/Stage/Spread/BezierCurve.qml (+45/-0)
qml/Stage/Spread/KeySpline.js (+66/-0)
qml/Stage/Spread/MathUtils.js (+95/-0)
qml/Stage/Spread/OpacityMask.qml (+82/-0)
qml/Stage/Spread/Spread.qml (+162/-0)
qml/Stage/Spread/SpreadDelegateInputArea.qml (+183/-0)
qml/Stage/Spread/SpreadMaths.qml (+78/-0)
qml/Stage/Spread/StagedRightEdgeMaths.qml (+174/-0)
qml/Stage/Spread/WindowedRightEdgeMaths.qml (+81/-0)
qml/Stage/Spread/cubic-bezier.js (+39/-0)
qml/Stage/Stage.qml (+1234/-185)
qml/Stage/StageMaths.qml (+79/-0)
qml/Stage/SurfaceContainer.qml (+5/-52)
qml/Stage/TopLevelSurfaceRepeater.qml (+9/-0)
qml/Stage/WindowDecoration.qml (+1/-1)
qml/Stage/WindowInfoItem.qml (+53/-0)
qml/Stage/WindowResizeArea.qml (+33/-32)
qml/Stages/AbstractStage.qml (+0/-93)
qml/Stages/DesktopSpread.qml (+0/-576)
qml/Stages/DesktopSpreadDelegate.qml (+0/-126)
qml/Stages/PhoneStage.qml (+0/-806)
qml/Stages/SpreadDelegate.qml (+0/-424)
qml/Stages/SpreadMaths.qml (+0/-164)
qml/Stages/TabletStage.qml (+0/-1201)
qml/Stages/TransformedSpreadDelegate.qml (+0/-391)
qml/Stages/TransformedTabletSpreadDelegate.qml (+0/-437)
qml/Tutorial/TutorialRight.qml (+1/-1)
tests/mocks/Unity/Application/ApplicationInfo.cpp (+2/-2)
tests/mocks/Unity/Application/ApplicationManager.cpp (+2/-0)
tests/mocks/Unity/Application/MirSurface.cpp (+1/-0)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+13/-0)
tests/mocks/Unity/Application/MirSurfaceListModel.cpp (+0/-1)
tests/mocks/Unity/Application/VirtualKeyboard.cpp (+9/-7)
tests/mocks/Unity/Application/resources/MirSurfaceItem.qml (+2/-5)
tests/qmltests/CMakeLists.txt (+8/-8)
tests/qmltests/Stage/tst_ApplicationWindow.qml (+1/-1)
tests/qmltests/Stage/tst_DecoratedWindow.qml (+232/-0)
tests/qmltests/Stage/tst_DesktopStage.qml (+29/-71)
tests/qmltests/Stage/tst_PhoneStage.qml (+152/-219)
tests/qmltests/Stage/tst_Splash.qml (+1/-1)
tests/qmltests/Stage/tst_SurfaceContainer.qml (+2/-2)
tests/qmltests/Stage/tst_TabletStage.qml (+104/-241)
tests/qmltests/Stage/tst_WindowResizeArea.qml (+40/-36)
tests/qmltests/Stages/tst_SpreadDelegate.qml (+0/-423)
tests/qmltests/tst_OrientedShell.qml (+38/-198)
tests/qmltests/tst_Shell.qml (+199/-180)
tests/qmltests/tst_ShellWithPin.qml (+9/-11)
To merge this branch: bzr merge lp:~azzar1/unity8/remove-UbuntuShapeForItem
Reviewer Review Type Date Requested Status
Lukáš Tinkl (community) Needs Fixing
Unity8 CI Bot continuous-integration Needs Fixing
Albert Astals Cid (community) Approve
Review via email: mp+305228@code.launchpad.net

This proposal has been superseded by a proposal from 2016-10-05.

Commit message

Remove UbuntuShapeForItem and replace its use with the more standard Ubuntu.Components.UbuntuShape.

Description of the change

* Are there any related MPs required for this MP to build/function as expected?
No

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

 * If you changed the UI, has there been a design review?
N/A

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2602
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2131/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/2801
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1551
    FAILURE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1551/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=qmluitests.sh/1551
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/2829
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2689/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2689
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2689/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2131/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2602
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2259/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/2979/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3007
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2865
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2865/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2865
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2865/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2865
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2865/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2865
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2865/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2865/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2865/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2865
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2865/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2865
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2865/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2865
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2865/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2259/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

The destkop spread change breaks something.

How to reproduce:
 * go to the "source root" dir and run
      ln -s `pwd`/tests/graphics .
   (this i needed because it seems the test is a bit broken)
 * go to the builddir
 * run
    make tryDesktopStage
 * start the dialer and webbrowser
 * show the desktop spread
 * without your patch, moving the mouse cursor over each window changes the opacity/brightness/something of the icon of said window
 * with your patch the icon stays the same

review: Needs Fixing
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Azzarone (azzar1) wrote :

> The destkop spread change breaks something.
>
> How to reproduce:
> * go to the "source root" dir and run
> ln -s `pwd`/tests/graphics .
> (this i needed because it seems the test is a bit broken)
> * go to the builddir
> * run
> make tryDesktopStage
> * start the dialer and webbrowser
> * show the desktop spread
> * without your patch, moving the mouse cursor over each window changes the
> opacity/brightness/something of the icon of said window
> * with your patch the icon stays the same

Fixed

Revision history for this message
Albert Astals Cid (aacid) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass? If not, please explain why.
Waiting for it before top approving

review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2603
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2288/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3011
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1668
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1668
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=qmluitests.sh/1668
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3039
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2896/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2896
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2896/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2288/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

This needs rebasing on top of lp:~mzanetti/unity8/unified-stages

review: Needs Fixing
2604. By Andrea Azzarone

Merge with lp:~mzanetti/unity8/unified-stages.

2605. By Andrea Azzarone

Resync with lp:~mzanetti/unity8/unified-stages

Unmerged revisions

2601. By Launchpad Translations on behalf of unity-team

Launchpad automatic translations update.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2016-10-04 15:02:29 +0000
3+++ debian/changelog 2016-10-05 11:22:21 +0000
4@@ -7,7 +7,7 @@
5
6 -- Michael Terry <mterry@ubuntu.com> Mon, 03 Oct 2016 10:43:25 -0400
7
8-unity8 (8.14+16.10.20160922-0ubuntu1) yakkety; urgency=medium
9+unity8 (8.14+16.10.20160914-0ubuntu1) yakkety; urgency=medium
10
11 [ Albert Astals Cid ]
12 * LVWPH: update clipItem height when list height changes (LP:
13@@ -55,12 +55,14 @@
14 the greeter.
15
16 [ Lukáš Tinkl ]
17- * Implement edge maximizing (aka window snapping) (LP: #1602628)
18 * On the PC platform (as opposed to running on $devices), use the
19 "mute" action instead of silent mode
20 * Respect Fitt's law wrt the window control buttons in panel (LP:
21 #1611959)
22 * Fix 2 failing color-related tests
23+ * Implement edge maximizing (aka window snapping) (LP: #1602628,
24+ #1611859)
25+ * Implement moving windows by Alt + left mouse button
26
27 [ Marco Trevisan (Treviño) ]
28 * Indicators, mocks: add fake indicators menuitem to populate mocks
29@@ -82,7 +84,7 @@
30 * Update look of infographic a bit
31 * Make infographic bubbles white even on the default wallpaper.
32
33- -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 22 Sep 2016 07:46:57 +0000
34+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 14 Sep 2016 00:46:45 +0000
35
36 unity8 (8.14+16.10.20160831.3-0ubuntu1) yakkety; urgency=medium
37
38
39=== modified file 'debian/unity8.install'
40--- debian/unity8.install 2016-06-20 22:42:46 +0000
41+++ debian/unity8.install 2016-10-05 11:22:21 +0000
42@@ -16,7 +16,7 @@
43 usr/share/unity8/OrientedShell.qml
44 usr/share/unity8/DisabledScreenNotice.qml
45 usr/share/unity8/Shell.qml
46-usr/share/unity8/Stages
47+usr/share/unity8/Stage
48 usr/share/unity8/Tutorial
49 usr/share/unity8/Wizard
50 usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
51
52=== modified file 'plugins/Ubuntu/Gestures/TouchGate.cpp'
53--- plugins/Ubuntu/Gestures/TouchGate.cpp 2016-07-13 07:29:00 +0000
54+++ plugins/Ubuntu/Gestures/TouchGate.cpp 2016-10-05 11:22:21 +0000
55@@ -61,7 +61,10 @@
56 const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
57
58 if (touchPoint.state() == Qt::TouchPointPressed) {
59- Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
60+// FIXME: This assert triggers frequently in make trySomething. We have verified
61+// that it's a bug in the mouse to touch conversion of the test environment
62+// and not in the actual product. Still, it probably should be cleaned up eventually.
63+// Q_ASSERT(!m_touchInfoMap.contains(touchPoint.id()));
64 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
65 m_touchInfoMap[touchPoint.id()].ended = false;
66 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
67
68=== modified file 'plugins/WindowManager/TopLevelSurfaceList.cpp'
69--- plugins/WindowManager/TopLevelSurfaceList.cpp 2016-04-04 13:43:41 +0000
70+++ plugins/WindowManager/TopLevelSurfaceList.cpp 2016-10-05 11:22:21 +0000
71@@ -133,11 +133,6 @@
72
73 void TopLevelSurfaceList::connectSurface(MirSurfaceInterface *surface)
74 {
75- connect(surface, &MirSurfaceInterface::focusedChanged, this, [this, surface](bool focused){
76- if (focused) {
77- this->raise(surface);
78- }
79- });
80 connect(surface, &MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
81 if (!live) {
82 onSurfaceDied(surface);
83
84=== modified file 'qml/CMakeLists.txt'
85--- qml/CMakeLists.txt 2015-03-06 04:44:11 +0000
86+++ qml/CMakeLists.txt 2016-10-05 11:22:21 +0000
87@@ -12,7 +12,7 @@
88 Launcher
89 Notifications
90 Panel
91- Stages
92+ Stage
93 Rotation
94 Tutorial
95 Wizard
96
97=== modified file 'qml/Components/EdgeBarrier.qml'
98--- qml/Components/EdgeBarrier.qml 2016-02-15 16:43:56 +0000
99+++ qml/Components/EdgeBarrier.qml 2016-10-05 11:22:21 +0000
100@@ -29,6 +29,8 @@
101 // Supported values are: Qt.LeftEdge, Qt.RightEdge
102 property int edge: Qt.LeftEdge
103
104+ readonly property alias progress: controller.progress
105+
106 property Item target: parent
107 function push(amount) { controller.push(amount); }
108 signal passed()
109
110=== modified file 'qml/Components/FloatingFlickable.qml'
111--- qml/Components/FloatingFlickable.qml 2016-08-08 10:41:38 +0000
112+++ qml/Components/FloatingFlickable.qml 2016-10-05 11:22:21 +0000
113@@ -35,6 +35,9 @@
114 property alias contentX: flickable.contentX
115 property alias contentY: flickable.contentY
116 property alias direction: swipeArea.direction
117+ property alias leftMargin: flickable.leftMargin
118+ property alias rightMargin: flickable.rightMargin
119+ property alias dragging: flickable.dragging
120
121 MouseEventGenerator {
122 id: mouseEventGenerator
123
124=== removed file 'qml/Components/UbuntuShapeForItem.qml'
125--- qml/Components/UbuntuShapeForItem.qml 2016-03-23 20:05:10 +0000
126+++ qml/Components/UbuntuShapeForItem.qml 1970-01-01 00:00:00 +0000
127@@ -1,47 +0,0 @@
128-/*
129- * Copyright (C) 2012 Canonical, Ltd.
130- *
131- * This program is free software; you can redistribute it and/or modify
132- * it under the terms of the GNU General Public License as published by
133- * the Free Software Foundation; version 3.
134- *
135- * This program is distributed in the hope that it will be useful,
136- * but WITHOUT ANY WARRANTY; without even the implied warranty of
137- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
138- * GNU General Public License for more details.
139- *
140- * You should have received a copy of the GNU General Public License
141- * along with this program. If not, see <http://www.gnu.org/licenses/>.
142- */
143-
144-import QtQuick 2.4
145-import Ubuntu.Components 1.3
146-
147-/* FIXME: This component is duplicating the UbuntuShape from the SDK, but shapes more
148- * general (Item-based) components. This ability should be incorporated into the SDK's
149- * UbuntuShape so this file can be removed.
150- * Bug: https://bugs.launchpad.net/tavastia/+bug/1089595
151- */
152-
153-Item {
154- id: root
155-
156- property alias radius: shape.radius
157- property alias image: source.sourceItem
158- property alias aspect: shape.aspect
159-
160- ShaderEffectSource {
161- id: source
162- anchors.centerIn: parent // Placed under shape, so it's hidden
163- width: 1
164- height: 1
165- hideSource: true
166- }
167-
168- Shape {
169- id: shape
170- image: source
171-
172- anchors.fill: parent
173- }
174-}
175
176=== modified file 'qml/Greeter/LoginAreaContainer.qml'
177--- qml/Greeter/LoginAreaContainer.qml 2016-06-14 17:34:35 +0000
178+++ qml/Greeter/LoginAreaContainer.qml 2016-10-05 11:22:21 +0000
179@@ -26,7 +26,7 @@
180 rightMargin: -units.gu(1.5)
181 bottomMargin: -units.gu(1.5)
182 }
183- source: "../Stages/graphics/dropshadow2gu.sci"
184+ source: "../graphics/dropshadow2gu.sci"
185 opacity: 0.35
186 }
187
188
189=== modified file 'qml/Launcher/LauncherPanel.qml'
190--- qml/Launcher/LauncherPanel.qml 2016-08-08 10:42:40 +0000
191+++ qml/Launcher/LauncherPanel.qml 2016-10-05 11:22:21 +0000
192@@ -632,7 +632,7 @@
193 }
194 }
195
196- UbuntuShapeForItem {
197+ UbuntuShape {
198 id: quickListShape
199 objectName: "quickListShape"
200 anchors.fill: quickList
201@@ -645,7 +645,10 @@
202 UbuntuNumberAnimation {}
203 }
204
205- image: quickList
206+ source: ShaderEffectSource {
207+ sourceItem: quickList
208+ hideSource: true
209+ }
210
211 Image {
212 anchors {
213
214=== modified file 'qml/Notifications/Notification.qml'
215--- qml/Notifications/Notification.qml 2016-08-19 13:27:05 +0000
216+++ qml/Notifications/Notification.qml 2016-10-05 11:22:21 +0000
217@@ -143,7 +143,7 @@
218 fill: contents
219 margins: shapedBack.visible ? -units.gu(1) : -units.gu(1.5)
220 }
221- source: "../Stages/graphics/dropshadow2gu.sci"
222+ source: "../graphics/dropshadow2gu.sci"
223 opacity: notification.opacity * 0.5
224 enabled: !fullscreen
225 }
226
227=== modified file 'qml/Rotation/RotationStates.qml'
228--- qml/Rotation/RotationStates.qml 2016-04-29 12:52:53 +0000
229+++ qml/Rotation/RotationStates.qml 2016-10-05 11:22:21 +0000
230@@ -121,12 +121,6 @@
231 }
232 }
233
234- property var shellBeingResized: Binding {
235- target: root.shell
236- property: "beingResized"
237- value: d.transitioning
238- }
239-
240 readonly property int fullAnimation: 0
241 readonly property int indicatorsBarAnimation: 1
242 readonly property int noAnimation: 2
243
244=== modified file 'qml/Shell.qml'
245--- qml/Shell.qml 2016-09-22 07:42:01 +0000
246+++ qml/Shell.qml 2016-10-05 11:22:21 +0000
247@@ -35,7 +35,7 @@
248 import "Panel"
249 import "Components"
250 import "Notifications"
251-import "Stages"
252+import "Stage"
253 import "Tutorial"
254 import "Wizard"
255 import Unity.Notifications 1.0 as NotificationBackend
256@@ -58,24 +58,22 @@
257 property real nativeWidth
258 property real nativeHeight
259 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
260- property bool beingResized
261 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
262 property string mode: "full-greeter"
263 property alias oskEnabled: inputMethod.enabled
264 function updateFocusedAppOrientation() {
265- applicationsDisplayLoader.item.updateFocusedAppOrientation();
266+ stage.updateFocusedAppOrientation();
267 }
268 function updateFocusedAppOrientationAnimated() {
269- applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
270+ stage.updateFocusedAppOrientationAnimated();
271 }
272 property bool hasMouse: false
273
274 // to be read from outside
275- readonly property int mainAppWindowOrientationAngle:
276- applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
277+ readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
278
279 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
280- && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
281+ && stage.orientationChangesEnabled
282 && (!greeter || !greeter.animating)
283
284 readonly property bool showingGreeter: greeter && greeter.shown
285@@ -89,19 +87,13 @@
286 return Qt.PrimaryOrientation;
287 } else if (showingGreeter || notifications.topmostIsFullscreen) {
288 return Qt.PrimaryOrientation;
289- } else if (applicationsDisplayLoader.item) {
290- return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
291 } else {
292- // we just don't care
293- return Qt.PortraitOrientation
294- | Qt.LandscapeOrientation
295- | Qt.InvertedPortraitOrientation
296- | Qt.InvertedLandscapeOrientation;
297+ return shell.orientations.map(stage.supportedOrientations);
298 }
299 }
300
301- readonly property var mainApp:
302- applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
303+ readonly property var mainApp: stage.mainApp
304+
305 onMainAppChanged: {
306 if (mainApp) {
307 _onMainAppChanged(mainApp.appId);
308@@ -278,154 +270,50 @@
309 applicationsModel: ApplicationManager
310 }
311
312- Loader {
313- id: applicationsDisplayLoader
314- objectName: "applicationsDisplayLoader"
315+ Stage {
316+ id: stage
317+ objectName: "stage"
318 anchors.fill: parent
319-
320- // When we have a locked app, we only want to show that one app.
321- // FIXME: do this in a less traumatic way. We currently only allow
322- // locked apps in phone mode (see FIXME in Lockscreen component in
323- // this same file). When that changes, we need to do something
324- // nicer here. But this code is currently just to prevent a
325- // theoretical attack where user enters lockedApp mode, then makes
326- // the screen larger (maybe connects to monitor) and tries to enter
327- // tablet mode.
328+ focus: true
329+
330+ dragAreaWidth: shell.edgeSize
331+ background: wallpaperResolver.background
332+ leftEdgeDragProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 :
333+ Math.max(0, (launcher.dragDistance * (stage.width - launcher.panelWidth) / stage.width) - launcher.panelWidth)
334+
335+ applicationManager: ApplicationManager
336+ topLevelSurfaceList: topLevelSurfaceList
337+ inputMethodRect: inputMethod.visibleRect
338
339 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
340- ? "phone"
341- : shell.usageScenario
342- readonly property string qmlComponent: {
343- if (applicationsDisplayLoader.usageScenario === "phone") {
344- return "Stages/PhoneStage.qml";
345- } else if (applicationsDisplayLoader.usageScenario === "tablet") {
346- return "Stages/TabletStage.qml";
347- } else {
348- return "Stages/DesktopStage.qml";
349- }
350- }
351- // TODO: Ensure the current stage is destroyed before the new one gets loaded.
352- // Currently the new one will get loaded while the old is still hanging
353- // around for a bit, which might lead to conflicts where both stages
354- // change the model simultaneously.
355- onQmlComponentChanged: {
356- if (item) item.stageAboutToBeUnloaded();
357- source = qmlComponent;
358- }
359-
360- property bool interactive: (!greeter || !greeter.shown)
361+ ? "phone"
362+ : shell.usageScenario
363+
364+ mode: usageScenario == "phone" ? "staged"
365+ : usageScenario == "tablet" ? "stagedWithSideStage"
366+ : "windowed"
367+
368+ shellOrientation: shell.orientation
369+ shellOrientationAngle: shell.orientationAngle
370+ orientations: shell.orientations
371+ nativeWidth: shell.nativeWidth
372+ nativeHeight: shell.nativeHeight
373+
374+ interactive: (!greeter || !greeter.shown)
375 && panel.indicators.fullyClosed
376 && launcher.progress == 0
377 && !notifications.useModal
378
379 onInteractiveChanged: { if (interactive) { focus = true; } }
380
381- Binding {
382- target: applicationsDisplayLoader.item
383- property: "focus"
384- value: true
385- }
386- Binding {
387- target: applicationsDisplayLoader.item
388- property: "objectName"
389- value: "stage"
390- }
391- Binding {
392- target: applicationsDisplayLoader.item
393- property: "dragAreaWidth"
394- value: shell.edgeSize
395- }
396- Binding {
397- target: applicationsDisplayLoader.item
398- property: "maximizedAppTopMargin"
399- // Not just using panel.panelHeight as that changes depending on the focused app.
400- value: panel.indicators.minimizedPanelHeight
401- }
402- Binding {
403- target: applicationsDisplayLoader.item
404- property: "interactive"
405- value: applicationsDisplayLoader.interactive
406- }
407- Binding {
408- target: applicationsDisplayLoader.item
409- property: "spreadEnabled"
410- value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
411- }
412- Binding {
413- target: applicationsDisplayLoader.item
414- property: "inverseProgress"
415- value: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 : launcher.progress
416- }
417- Binding {
418- target: applicationsDisplayLoader.item
419- property: "shellOrientationAngle"
420- value: shell.orientationAngle
421- }
422- Binding {
423- target: applicationsDisplayLoader.item
424- property: "shellOrientation"
425- value: shell.orientation
426- }
427- Binding {
428- target: applicationsDisplayLoader.item
429- property: "orientations"
430- value: shell.orientations
431- }
432- Binding {
433- target: applicationsDisplayLoader.item
434- property: "background"
435- value: wallpaperResolver.cachedBackground
436- }
437- Binding {
438- target: applicationsDisplayLoader.item
439- property: "nativeWidth"
440- value: shell.nativeWidth
441- }
442- Binding {
443- target: applicationsDisplayLoader.item
444- property: "nativeHeight"
445- value: shell.nativeHeight
446- }
447- Binding {
448- target: applicationsDisplayLoader.item
449- property: "beingResized"
450- value: shell.beingResized
451- }
452- Binding {
453- target: applicationsDisplayLoader.item
454- property: "keepDashRunning"
455- value: launcher.shown || launcher.dashSwipe
456- }
457- Binding {
458- target: applicationsDisplayLoader.item
459- property: "suspended"
460- value: greeter.shown
461- }
462- Binding {
463- target: applicationsDisplayLoader.item
464- property: "altTabPressed"
465- value: physicalKeysMapper.altTabPressed
466- }
467- Binding {
468- target: applicationsDisplayLoader.item
469- property: "leftMargin"
470- value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
471- }
472- Binding {
473- target: applicationsDisplayLoader.item
474- property: "applicationManager"
475- value: ApplicationManager
476- }
477- Binding {
478- target: applicationsDisplayLoader.item
479- property: "topLevelSurfaceList"
480- value: topLevelSurfaceList
481- }
482- Binding {
483- target: applicationsDisplayLoader.item
484- property: "oskEnabled"
485- value: shell.oskEnabled
486- }
487+ leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
488+ suspended: greeter.shown
489+ keepDashRunning: launcher.shown || launcher.dashSwipe
490+ altTabPressed: physicalKeysMapper.altTabPressed
491+ oskEnabled: shell.oskEnabled
492+
493+ // TODO: This is not implemented yet in the new stage...
494+ spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
495 }
496 }
497
498@@ -442,6 +330,7 @@
499
500 Loader {
501 id: greeterLoader
502+ objectName: "greeterLoader"
503 anchors.fill: parent
504 anchors.topMargin: panel.panelHeight
505 sourceComponent: shell.mode != "shell" ? integratedGreeter :
506@@ -650,7 +539,7 @@
507 }
508 onFocusChanged: {
509 if (!focus) {
510- applicationsDisplayLoader.focus = true;
511+ stage.focus = true;
512 }
513 }
514
515@@ -706,12 +595,12 @@
516 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
517 inputMethod.visible ||
518 (launcher.shown && !launcher.lockedVisible) ||
519- panel.indicators.shown || stage.dragProgress > 0
520+ panel.indicators.shown || stage.rightEdgeDragProgress > 0
521 usageScenario: shell.usageScenario
522 lastInputTimestamp: inputFilter.lastInputTimestamp
523 launcher: launcher
524 panel: panel
525- stage: applicationsDisplayLoader.item
526+ stage: stage
527 }
528
529 Wizard {
530@@ -802,7 +691,7 @@
531 z: dialogs.z + 10
532 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
533 Connections {
534- target: applicationsDisplayLoader.item
535+ target: stage
536 ignoreUnknownSignals: true
537 onItemSnapshotRequested: itemGrabber.capture(item)
538 }
539@@ -814,7 +703,7 @@
540 z: itemGrabber.z + 1
541 topBoundaryOffset: panel.panelHeight
542
543- confiningItem: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.itemConfiningMouseCursor : null
544+ confiningItem: stage.itemConfiningMouseCursor
545
546 property bool mouseNeverMoved: true
547 Binding {
548@@ -828,10 +717,9 @@
549
550 height: units.gu(3)
551
552- readonly property var previewRectangle: applicationsDisplayLoader.item && applicationsDisplayLoader.item.previewRectangle &&
553- applicationsDisplayLoader.item.previewRectangle.target &&
554- applicationsDisplayLoader.item.previewRectangle.target.dragging ?
555- applicationsDisplayLoader.item.previewRectangle : null
556+ readonly property var previewRectangle: stage.previewRectangle.target &&
557+ stage.previewRectangle.target.dragging ?
558+ stage.previewRectangle : null
559
560 onPushedLeftBoundary: {
561 if (buttons === Qt.NoButton) {
562@@ -842,9 +730,8 @@
563 }
564
565 onPushedRightBoundary: {
566- if (buttons === Qt.NoButton && applicationsDisplayLoader.item
567- && applicationsDisplayLoader.item.pushRightEdge) {
568- applicationsDisplayLoader.item.pushRightEdge(amount);
569+ if (buttons === Qt.NoButton) {
570+ stage.pushRightEdge(amount);
571 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
572 previewRectangle.maximizeRight(amount);
573 }
574
575=== renamed directory 'qml/Stages' => 'qml/Stage'
576=== modified file 'qml/Stage/ApplicationWindow.qml'
577--- qml/Stages/ApplicationWindow.qml 2016-08-08 11:18:19 +0000
578+++ qml/Stage/ApplicationWindow.qml 2016-10-05 11:22:21 +0000
579@@ -20,8 +20,8 @@
580
581 FocusScope {
582 id: root
583- implicitWidth: surfaceContainer.implicitWidth
584- implicitHeight: surfaceContainer.implicitHeight
585+ implicitWidth: requestedWidth
586+ implicitHeight: requestedHeight
587
588 // to be read from outside
589 property alias interactive: surfaceContainer.interactive
590@@ -29,22 +29,10 @@
591 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
592 readonly property QtObject focusedSurface: d.focusedSurface.surface
593
594- // overridable from outside
595- property bool fullscreen: {
596- if (surface) {
597- return surface.state === Mir.FullscreenState;
598- } else if (application) {
599- return application.fullscreen;
600- } else {
601- return false;
602- }
603- }
604-
605 // to be set from outside
606 property QtObject surface
607 property QtObject application
608 property int surfaceOrientationAngle
609- property alias resizeSurface: surfaceContainer.resizeSurface
610 property int requestedWidth: -1
611 property int requestedHeight: -1
612 property real splashRotation: 0
613@@ -156,6 +144,9 @@
614 id: screenshotImage
615 objectName: "screenshotImage"
616 anchors.fill: parent
617+ fillMode: Image.PreserveAspectCrop
618+ horizontalAlignment: Image.AlignLeft
619+ verticalAlignment: Image.AlignTop
620 antialiasing: !root.interactive
621 z: 1
622
623@@ -197,6 +188,7 @@
624
625 SurfaceContainer {
626 id: surfaceContainer
627+ anchors.fill: parent
628 z: splashLoader.z + 1
629 requestedWidth: root.requestedWidth
630 requestedHeight: root.requestedHeight
631@@ -220,6 +212,8 @@
632 surface: model.surface
633 width: root.width
634 height: root.height
635+ requestedWidth: root.requestedWidth
636+ requestedHeight: root.requestedHeight
637 isPromptSurface: true
638 z: surfaceContainer.z + (promptSurfacesRepeater.count - index)
639 property int index: model.index
640@@ -239,28 +233,6 @@
641 property Item first: null
642 }
643
644- // SurfaceContainer size drives ApplicationWindow size
645- Binding {
646- target: root; property: "width"
647- value: stateGroup.state === "surface" ? surfaceContainer.width : root.requestedWidth
648- when: root.requestedWidth >= 0
649- }
650- Binding {
651- target: root; property: "height"
652- value: stateGroup.state === "surface" ? surfaceContainer.height : root.requestedHeight
653- when: root.requestedHeight >= 0
654- }
655-
656- // ApplicationWindow size drives SurfaceContainer size
657- Binding {
658- target: surfaceContainer; property: "width"; value: root.width
659- when: root.requestedWidth < 0
660- }
661- Binding {
662- target: surfaceContainer; property: "height"; value: root.height
663- when: root.requestedHeight < 0
664- }
665-
666 StateGroup {
667 id: stateGroup
668 objectName: "applicationWindowStateGroup"
669@@ -287,6 +259,11 @@
670 (d.liveSurface ||
671 (d.applicationState !== ApplicationInfoInterface.Running
672 && screenshotImage.status !== Image.Ready))
673+ PropertyChanges {
674+ target: root
675+ implicitWidth: surfaceContainer.implicitWidth
676+ implicitHeight: surfaceContainer.implicitHeight
677+ }
678 },
679 State {
680 name: "screenshot"
681@@ -424,5 +401,4 @@
682 }
683 ]
684 }
685-
686 }
687
688=== modified file 'qml/Stage/DecoratedWindow.qml'
689--- qml/Stages/DecoratedWindow.qml 2016-09-08 14:13:27 +0000
690+++ qml/Stage/DecoratedWindow.qml 2016-10-05 11:22:21 +0000
691@@ -17,34 +17,46 @@
692 import QtQuick 2.4
693 import Ubuntu.Components 1.3
694 import Unity.Application 0.1
695+import "Spread/MathUtils.js" as MathUtils
696
697 FocusScope {
698 id: root
699
700- width: !counterRotate ? applicationWindow.width : applicationWindow.height
701- height: visibleDecorationHeight + (!counterRotate ? applicationWindow.height : applicationWindow.width)
702+ // The DecoratedWindow takes requestedWidth/requestedHeight and asks its surface to be resized to that
703+ // (minus the window decoration size in case hasDecoration and showDecoration are true)
704+ // The surface might not be able to resize to the requested values. It will return its actual size
705+ // in implicitWidth/implicitHeight.
706
707 property alias application: applicationWindow.application
708 property alias surface: applicationWindow.surface
709 readonly property alias focusedSurface: applicationWindow.focusedSurface
710 property alias active: decoration.active
711 readonly property alias title: applicationWindow.title
712- property alias fullscreen: applicationWindow.fullscreen
713 property alias maximizeButtonShown: decoration.maximizeButtonShown
714+ property alias interactive: applicationWindow.interactive
715+ readonly property alias orientationChangesEnabled: applicationWindow.orientationChangesEnabled
716
717- readonly property bool decorationShown: !fullscreen
718- property bool highlightShown: false
719- property real shadowOpacity: 1
720+ // Changing this will actually add/remove a decoration, meaning, requestedHeight will take the decoration into account.
721+ property bool hasDecoration: true
722+ // This will temporarily show/hide the decoration without actually changing the surface's dimensions
723+ property real showDecoration: 1
724+ property bool animateDecoration: false
725+ property bool showHighlight: false
726+ property int highlightSize: units.gu(1)
727+ property real shadowOpacity: 0
728+ property bool darkening: false
729
730 property real requestedWidth
731 property real requestedHeight
732+ property real scaleToPreviewProgress: 0
733+ property int scaleToPreviewSize: units.gu(30)
734
735 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
736- readonly property real visibleDecorationHeight: root.decorationShown ? decoration.height : 0
737+ readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
738 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
739
740 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
741- readonly property int minimumHeight: visibleDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
742+ readonly property int minimumHeight: decorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
743 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
744 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
745 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
746@@ -66,40 +78,97 @@
747 signal decorationPressed()
748 signal decorationReleased()
749
750+ QtObject {
751+ id: d
752+ property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
753+ Behavior on requestedDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
754+
755+ property int visibleDecorationHeight: root.hasDecoration ? root.showDecoration * decoration.height : 0
756+ Behavior on visibleDecorationHeight { enabled: root.animateDecoration; UbuntuNumberAnimation { } }
757+ }
758+
759+ StateGroup {
760+ states: [
761+ State {
762+ name: "normal"; when: root.scaleToPreviewProgress <= 0 && root.application.state === ApplicationInfoInterface.Running
763+ PropertyChanges {
764+ target: root
765+ implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
766+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
767+ }
768+ },
769+ State {
770+ name: "normalSuspended"; when: root.scaleToPreviewProgress <= 0 && root.application.state !== ApplicationInfoInterface.Running
771+ PropertyChanges {
772+ target: root
773+ implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
774+ implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
775+ }
776+// PropertyChanges { target: applicationWindow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
777+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - applicationWindow.implicitHeight) / 2 }
778+ },
779+ State {
780+ name: "preview"; when: root.scaleToPreviewProgress > 0 && root.application.state === ApplicationInfoInterface.Running
781+ PropertyChanges {
782+ target: root
783+ implicitWidth: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, root.scaleToPreviewSize, root.scaleToPreviewProgress)
784+ implicitHeight: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, root.scaleToPreviewSize, root.scaleToPreviewProgress)
785+ }
786+ PropertyChanges {
787+ target: applicationWindow;
788+ requestedWidth: applicationWindow.oldRequestedWidth
789+ requestedHeight: applicationWindow.oldRequestedHeight
790+ width: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedWidth, applicationWindow.minSize, root.scaleToPreviewProgress)
791+ height: MathUtils.linearAnimation(0, 1, applicationWindow.oldRequestedHeight, applicationWindow.minSize, root.scaleToPreviewProgress)
792+ itemScale: root.implicitWidth / width
793+ }
794+ },
795+ State {
796+ name: "previewSuspended"; when: root.scaleToPreviewProgress > 0 && root.application.state !== ApplicationInfoInterface.Running
797+ extend: "preview"
798+ PropertyChanges { target: applicationWindow;
799+ anchors.verticalCenterOffset: applicationWindow.implicitHeight < applicationWindow.height ?
800+ (root.height / applicationWindow.itemScale - applicationWindow.implicitHeight) / 2
801+ : (root.height / applicationWindow.itemScale - applicationWindow.height) / 2
802+ }
803+// PropertyChanges { target: dropShadow; anchors.topMargin: (root.height - root.implicitHeight) / 2 * (1 - root.scaleToPreviewProgress) }
804+ }
805+ ]
806+ }
807+
808 Rectangle {
809 id: selectionHighlight
810+ objectName: "selectionHighlight"
811 anchors.fill: parent
812- anchors.margins: -units.gu(1)
813+ anchors.margins: -root.highlightSize
814 color: "white"
815- opacity: highlightShown ? 0.15 : 0
816- }
817-
818- Rectangle {
819- anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
820- height: units.dp(2)
821- color: theme.palette.normal.focus
822- visible: highlightShown
823+ opacity: showHighlight ? 0.55 : 0
824+ visible: opacity > 0
825 }
826
827 BorderImage {
828+ id: dropShadow
829 anchors {
830- fill: root
831+ left: parent.left; top: parent.top; right: parent.right
832 margins: active ? -units.gu(2) : -units.gu(1.5)
833 }
834- source: "graphics/dropshadow2gu.sci"
835- opacity: root.shadowOpacity * .3
836- visible: !fullscreen
837+ height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
838+ + root.decorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
839+ source: "../graphics/dropshadow2gu.sci"
840+ opacity: root.shadowOpacity
841 }
842
843 WindowDecoration {
844 id: decoration
845- target: root.parent
846+ target: root.parent || null
847 objectName: "appWindowDecoration"
848 anchors { left: parent.left; top: parent.top; right: parent.right }
849 height: units.gu(3)
850 width: root.width
851 title: applicationWindow.title
852- visible: root.decorationShown
853+ opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
854+
855+ Behavior on opacity { UbuntuNumberAnimation { } }
856
857 onCloseClicked: root.closeClicked();
858 onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
859@@ -126,16 +195,25 @@
860 ApplicationWindow {
861 id: applicationWindow
862 objectName: "appWindow"
863- anchors.top: parent.top
864- anchors.topMargin: decoration.height
865+ anchors.verticalCenter: parent.verticalCenter
866+ anchors.verticalCenterOffset: (root.decorationHeight * Math.min(1, root.showDecoration)) / 2
867 anchors.left: parent.left
868- readonly property real requestedHeightMinusDecoration: root.requestedHeight - root.visibleDecorationHeight
869- requestedHeight: !counterRotate ? requestedHeightMinusDecoration : root.requestedWidth
870- requestedWidth: !counterRotate ? root.requestedWidth : requestedHeightMinusDecoration
871- interactive: true
872+ width: implicitWidth
873+ height: implicitHeight
874+ requestedHeight: !counterRotate ? root.requestedHeight - d.requestedDecorationHeight : root.requestedWidth
875+ requestedWidth: !counterRotate ? root.requestedWidth : root.requestedHeight - d.requestedDecorationHeight
876+ property int oldRequestedWidth: requestedWidth
877+ property int oldRequestedHeight: requestedHeight
878+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
879+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
880 focus: true
881
882- transform: Rotation {
883+ property real itemScale: 1
884+ property real minSize: Math.min(root.scaleToPreviewSize, Math.min(requestedHeight, Math.min(requestedWidth, Math.min(implicitHeight, implicitWidth))))
885+
886+ transform: [
887+ Rotation {
888+ id: rotationTransform
889 readonly property int rotationAngle: applicationWindow.application &&
890 applicationWindow.application.rotatesWindowContents
891 ? ((360 - applicationWindow.surfaceOrientationAngle) % 360) : 0
892@@ -152,6 +230,20 @@
893 else return 0;
894 }
895 angle: rotationAngle
896- }
897+ },
898+ Scale {
899+ origin.y: (applicationWindow.implicitHeight < applicationWindow.height ? applicationWindow.implicitHeight : applicationWindow.height) / 2
900+ xScale: applicationWindow.itemScale
901+ yScale: applicationWindow.itemScale
902+ }
903+ ]
904+
905+ }
906+
907+ Rectangle {
908+ anchors.fill: parent
909+ color: "black"
910+ opacity: root.darkening && !root.showHighlight ? 0.05 : 0
911+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
912 }
913 }
914
915=== modified file 'qml/Stage/MoveHandler.qml'
916--- qml/Stages/MoveHandler.qml 2016-09-08 14:13:27 +0000
917+++ qml/Stage/MoveHandler.qml 2016-10-05 11:22:21 +0000
918@@ -112,8 +112,8 @@
919 // Use integer coordinate values to ensure that target is left in a pixel-aligned
920 // position. Mouse movement could have subpixel precision, yielding a fractional
921 // mouse position.
922- target.requestedX = Math.round(pos.x - priv.distanceX);
923- target.requestedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
924+ target.windowedX = Math.round(pos.x - priv.distanceX);
925+ target.windowedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
926
927 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
928 if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < PanelState.panelHeight + priv.triggerArea
929
930=== modified file 'qml/Stage/PromptSurfaceAnimations.qml'
931--- qml/Stages/PromptSurfaceAnimations.qml 2016-04-04 13:38:56 +0000
932+++ qml/Stage/PromptSurfaceAnimations.qml 2016-10-05 11:22:21 +0000
933@@ -43,7 +43,7 @@
934 SequentialAnimation {
935 // clip so we don't go out of parent's bounds during spread
936 PropertyAction { target: root.container.parent; property: "clip"; value: true }
937- UbuntuNumberAnimation { target: root.surfaceItem; property: "y"; to: root.container.height
938+ UbuntuNumberAnimation { target: root.surfaceItem; property: "anchors.topMargin"; to: root.container.height
939 duration: UbuntuAnimation.BriskDuration }
940 PropertyAction { target: root.surfaceItem; property: "visible"; value: false }
941 PropertyAction { target: container.parent; property: "clip"; value: false }
942@@ -61,11 +61,10 @@
943 // clip so we don't go out of parent's bounds during spread
944 PropertyAction { target: root.container.parent; property: "clip"; value: true }
945 ScriptAction { script: {
946- root.surfaceItem.y = root.container.height;
947 root.surfaceItem.visible = true;
948 } }
949 UbuntuNumberAnimation {
950- target: root.surfaceItem; property: "y"; to: 0
951+ target: root.surfaceItem; property: "anchors.topMargin"; from: root.container.height; to: 0
952 duration: UbuntuAnimation.BriskDuration
953 }
954 PropertyAction { target: container.parent; property: "clip"; value: false }
955
956=== added directory 'qml/Stage/Spread'
957=== added file 'qml/Stage/Spread/BezierCurve.qml'
958--- qml/Stage/Spread/BezierCurve.qml 1970-01-01 00:00:00 +0000
959+++ qml/Stage/Spread/BezierCurve.qml 2016-10-05 11:22:21 +0000
960@@ -0,0 +1,45 @@
961+/*
962+ * Copyright (C) 2016 Canonical, Ltd.
963+ *
964+ * This program is free software; you can redistribute it and/or modify
965+ * it under the terms of the GNU General Public License as published by
966+ * the Free Software Foundation; version 3.
967+ *
968+ * This program is distributed in the hope that it will be useful,
969+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
970+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
971+ * GNU General Public License for more details.
972+ *
973+ * You should have received a copy of the GNU General Public License
974+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
975+ */
976+
977+import QtQuick 2.4
978+import Ubuntu.Components 1.3
979+import QtQuick.Window 2.2
980+import 'cubic-bezier.js' as Bezier
981+import 'KeySpline.js' as KeySpline
982+
983+Item {
984+ id: root
985+
986+ property var controlPoint1: {'x':0, 'y':0}
987+ property var controlPoint2: {'x':0, 'y':0}
988+ property var controlPoint3: {'x':0.58, 'y':1}
989+ property var controlPoint4: {'x':1, 'y':1}
990+
991+ function getValues(t) {
992+ if (t<0) t=0
993+ else if (t>1)t=1
994+
995+ return Bezier.getBezier(t, controlPoint1, controlPoint2, controlPoint3, controlPoint4)
996+ }
997+
998+ function getYFromX(x) {
999+ var spline = new KeySpline.keySpline(controlPoint2.x, controlPoint2.y, controlPoint3.x, controlPoint3.y)
1000+ if (x<0) x=0
1001+ else if (x>1)x=1
1002+
1003+ return spline.get(x)
1004+ }
1005+}
1006
1007=== added file 'qml/Stage/Spread/KeySpline.js'
1008--- qml/Stage/Spread/KeySpline.js 1970-01-01 00:00:00 +0000
1009+++ qml/Stage/Spread/KeySpline.js 2016-10-05 11:22:21 +0000
1010@@ -0,0 +1,66 @@
1011+/** MIT License
1012+ *
1013+ * KeySpline - use bezier curve for transition easing function
1014+ * Copyright (c) 2012 Gaetan Renaudeau <renaudeau.gaetan@gmail.com>
1015+ *
1016+ * Permission is hereby granted, free of charge, to any person obtaining a
1017+ * copy of this software and associated documentation files (the "Software"),
1018+ * to deal in the Software without restriction, including without limitation
1019+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1020+ * and/or sell copies of the Software, and to permit persons to whom the
1021+ * Software is furnished to do so, subject to the following conditions:
1022+ *
1023+ * The above copyright notice and this permission notice shall be included in
1024+ * all copies or substantial portions of the Software.
1025+ *
1026+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1027+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1028+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1029+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1030+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1031+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1032+ * DEALINGS IN THE SOFTWARE.
1033+ */
1034+/**
1035+* KeySpline - use bezier curve for transition easing function
1036+* is inspired from Firefox's nsSMILKeySpline.cpp
1037+* Usage:
1038+* var spline = new KeySpline(0.25, 0.1, 0.25, 1.0)
1039+* spline.get(x) => returns the easing value | x must be in [0, 1] range
1040+*/
1041+
1042+.pragma library
1043+
1044+function keySpline (mX1, mY1, mX2, mY2) {
1045+
1046+ this.get = function(aX) {
1047+ if (mX1 == mY1 && mX2 == mY2) return aX; // linear
1048+ return CalcBezier(GetTForX(aX), mY1, mY2);
1049+ }
1050+
1051+ function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
1052+ function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
1053+ function C(aA1) { return 3.0 * aA1; }
1054+
1055+ // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
1056+ function CalcBezier(aT, aA1, aA2) {
1057+ return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT;
1058+ }
1059+
1060+ // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
1061+ function GetSlope(aT, aA1, aA2) {
1062+ return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
1063+ }
1064+
1065+ function GetTForX(aX) {
1066+ // Newton raphson iteration
1067+ var aGuessT = aX;
1068+ for (var i = 0; i < 4; ++i) {
1069+ var currentSlope = GetSlope(aGuessT, mX1, mX2);
1070+ if (currentSlope == 0.0) return aGuessT;
1071+ var currentX = CalcBezier(aGuessT, mX1, mX2) - aX;
1072+ aGuessT -= currentX / currentSlope;
1073+ }
1074+ return aGuessT;
1075+ }
1076+}
1077
1078=== added file 'qml/Stage/Spread/MathUtils.js'
1079--- qml/Stage/Spread/MathUtils.js 1970-01-01 00:00:00 +0000
1080+++ qml/Stage/Spread/MathUtils.js 2016-10-05 11:22:21 +0000
1081@@ -0,0 +1,95 @@
1082+/*
1083+ * Copyright (C) 2016 Canonical, Ltd.
1084+ *
1085+ * This program is free software; you can redistribute it and/or modify
1086+ * it under the terms of the GNU General Public License as published by
1087+ * the Free Software Foundation; version 3.
1088+ *
1089+ * This program is distributed in the hope that it will be useful,
1090+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1091+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1092+ * GNU General Public License for more details.
1093+ *
1094+ * You should have received a copy of the GNU General Public License
1095+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1096+ */
1097+
1098+.pragma library
1099+
1100+/**
1101+ * From processing.js: https://raw.githubusercontent.com/processing-js/processing-js/v1.4.8/processing.js
1102+ *
1103+ * Re-map a number from one range to another. In the example above, the number
1104+ * '25' is converted from a value in the range 0..100 into a value that
1105+ * ranges from the left edge (0) to the right edge (width) of the screen.
1106+ * Numbers outside the range are not clamped to 0 and 1, because out-of-range
1107+ * values are often intentional and useful.
1108+ *
1109+ * @param {Number} value The incoming value to be converted
1110+ * @param {Number} istart Lower bound of the value's current range
1111+ * @param {Number} istop Upper bound of the value's current range
1112+ * @param {Number} ostart Lower bound of the value's target range
1113+ * @param {Number} ostop Upper bound of the value's target range
1114+ *
1115+ * @returns {Number}
1116+ */
1117+function map(value, istart, istop, ostart, ostop) {
1118+ return ostart + (ostop - ostart) * ((value - istart) / (istop - istart))
1119+}
1120+
1121+/**
1122+ * Return a value which is always between `min` and `max`
1123+ *
1124+ * @param {Number} value The current value
1125+ * @param {Number} min The minimum value
1126+ * @param {Number} max The maximum value
1127+ *
1128+ * @returns {Number}
1129+ */
1130+function clamp(value, min, max) {
1131+ if (value < min) return min
1132+ if (value > max) return max
1133+ return value
1134+}
1135+
1136+// calculates the distance from the middle of one rect to middle of other rect
1137+function rectDistance(rect1, rect2) {
1138+ return pointDistance(Qt.point(rect1.x + rect1.width / 2, rect1.y + rect1.height / 2),
1139+ Qt.point(rect2.x + rect2.width / 2, rect2.y + rect2.height / 2))
1140+}
1141+
1142+// calculates the distance between two points
1143+function pointDistance(point1, point2) {
1144+ return Math.sqrt(Math.pow(point1.x - point2.x, 2) +
1145+ Math.pow(point1.y - point2.y, 2)
1146+ )
1147+}
1148+
1149+// from http://stackoverflow.com/questions/14616829/java-method-to-find-the-rectangle-that-is-the-intersection-of-two-rectangles-usi
1150+function intersectionRect(r1, r2) {
1151+ var xmin = Math.max(r1.x, r2.x);
1152+ var xmax1 = r1.x + r1.width;
1153+ var xmax2 = r2.x + r2.width;
1154+ var xmax = Math.min(xmax1, xmax2);
1155+ var out = {x:0, y:0, width:0, height:0}
1156+ if (xmax > xmin) {
1157+ var ymin = Math.max(r1.y, r2.y);
1158+ var ymax1 = r1.y + r1.height;
1159+ var ymax2 = r2.y + r2.height;
1160+ var ymax = Math.min(ymax1, ymax2);
1161+ if (ymax > ymin) {
1162+ out.x = xmin;
1163+ out.y = ymin;
1164+ out.width = xmax - xmin;
1165+ out.height = ymax - ymin;
1166+ }
1167+ }
1168+ return out;
1169+}
1170+
1171+function easeOutCubic(t) { return (--t)*t*t+1 }
1172+
1173+function linearAnimation(startProgress, endProgress, startValue, endValue, progress) {
1174+ // progress : progressDiff = value : valueDiff => value = progress * valueDiff / progressDiff
1175+ return (progress - startProgress) * (endValue - startValue) / (endProgress - startProgress) + startValue;
1176+}
1177
1178=== added file 'qml/Stage/Spread/OpacityMask.qml'
1179--- qml/Stage/Spread/OpacityMask.qml 1970-01-01 00:00:00 +0000
1180+++ qml/Stage/Spread/OpacityMask.qml 2016-10-05 11:22:21 +0000
1181@@ -0,0 +1,82 @@
1182+/*
1183+ * Copyright (C) 2016 Canonical, Ltd.
1184+ *
1185+ * This program is free software; you can redistribute it and/or modify
1186+ * it under the terms of the GNU General Public License as published by
1187+ * the Free Software Foundation; version 3.
1188+ *
1189+ * This program is distributed in the hope that it will be useful,
1190+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1191+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1192+ * GNU General Public License for more details.
1193+ *
1194+ * You should have received a copy of the GNU General Public License
1195+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1196+ */
1197+
1198+import QtQuick 2.4
1199+
1200+Item {
1201+ id: root
1202+ anchors.fill: sourceItem
1203+ anchors.margins: -units.gu(2)
1204+ visible: sourceItem !== null
1205+
1206+ property var sourceItem: null
1207+ property int maskX: 0
1208+ property int maskY: 0
1209+ property int maskWidth: 0
1210+ property int maskHeight: 0
1211+
1212+ property real opacityValue: 1
1213+
1214+ Item {
1215+ id: opacityMask
1216+ anchors.fill: parent
1217+
1218+ Rectangle {
1219+ id: clipRect
1220+ color: "black"
1221+ x: root.maskX - root.anchors.margins
1222+ y: root.maskY - root.anchors.margins
1223+ width: root.maskWidth
1224+ height: root.maskHeight
1225+ opacity: 1 - root.opacityValue
1226+ }
1227+ }
1228+
1229+ ShaderEffect {
1230+ id: opacityEffect
1231+ anchors.fill: parent
1232+
1233+ property variant source: ShaderEffectSource {
1234+ id: shaderEffectSource
1235+ sourceItem: root.sourceItem
1236+ sourceRect: root.sourceItem ? Qt.rect(sourceItem.x + root.anchors.margins,
1237+ sourceItem.y + root.anchors.margins,
1238+ sourceItem.width - root.anchors.margins * 2,
1239+ sourceItem.height - root.anchors.margins * 2)
1240+ : Qt.rect(0,0,0,0)
1241+ hideSource: true
1242+ }
1243+
1244+ property var mask: ShaderEffectSource {
1245+ sourceItem: opacityMask
1246+ hideSource: true
1247+ }
1248+
1249+ fragmentShader: "
1250+ varying highp vec2 qt_TexCoord0;
1251+ uniform sampler2D source;
1252+ uniform sampler2D mask;
1253+ void main(void)
1254+ {
1255+ highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
1256+ highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
1257+
1258+ sourceColor *= 1.0 - maskColor.a;
1259+
1260+ gl_FragColor = sourceColor;
1261+ }"
1262+ }
1263+}
1264
1265=== added file 'qml/Stage/Spread/Spread.qml'
1266--- qml/Stage/Spread/Spread.qml 1970-01-01 00:00:00 +0000
1267+++ qml/Stage/Spread/Spread.qml 2016-10-05 11:22:21 +0000
1268@@ -0,0 +1,162 @@
1269+/*
1270+ * Copyright (C) 2016 Canonical, Ltd.
1271+ *
1272+ * This program is free software; you can redistribute it and/or modify
1273+ * it under the terms of the GNU General Public License as published by
1274+ * the Free Software Foundation; version 3.
1275+ *
1276+ * This program is distributed in the hope that it will be useful,
1277+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1278+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1279+ * GNU General Public License for more details.
1280+ *
1281+ * You should have received a copy of the GNU General Public License
1282+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1283+ */
1284+
1285+import QtQuick 2.4
1286+import Ubuntu.Components 1.3
1287+import "MathUtils.js" as MathUtils
1288+
1289+Item {
1290+ id: root
1291+
1292+ // Information about the environment
1293+ property int highlightedIndex: -1
1294+ property var model: null
1295+ property int leftMargin: 0
1296+ property var spreadFlickable
1297+
1298+ // some config options
1299+ property real contentMargin: 0.16 * root.height
1300+ property real contentTopMargin: contentMargin
1301+ property real contentBottomMargin: 0.35 * contentMargin
1302+ property real windowTitleTopMargin: 3/4 * (contentTopMargin - windowTitle.height)
1303+ property int stackItemCount: 3
1304+ property real leftRotationAngle: 22
1305+ property real rightRotationAngle: 32
1306+ property real leftStackScale: .82
1307+ property real rightStackScale: 1
1308+ property real rightEdgeBreakPoint: Math.min(units.gu(40) / root.width, .35)
1309+
1310+ signal leaveSpread()
1311+
1312+ // Calculated stuff
1313+ readonly property int totalItemCount: model.count
1314+ readonly property real leftStackXPos: 0.03 * root.width + leftMargin
1315+ readonly property real rightStackXPos: root.width - 1.5 * leftStackXPos + leftMargin
1316+
1317+ readonly property real stackHeight: spreadItemHeight - appInfoHeight
1318+ readonly property real stackWidth: Math.min(leftStackXPos/3, units.gu(1.5))
1319+
1320+ readonly property real spreadWidth: rightStackXPos - leftStackXPos
1321+ readonly property real spreadHeight: root.height
1322+ readonly property real spreadItemHeight: spreadHeight - contentTopMargin - contentBottomMargin
1323+ readonly property real spreadItemWidth: stackHeight
1324+
1325+ readonly property real dynamicLeftRotationAngle: leftRotationAngle * rotationAngleFactor
1326+ readonly property real dynamicRightRotationAngle: rightRotationAngle * rotationAngleFactor
1327+
1328+ readonly property real appInfoHeight: {
1329+ var screenHeightReferencePoint = 40 // ref screen height in gu
1330+ var valueAtReferencePoint = 0.17 // of screen height at the reference point
1331+ var appInfoHeightValueChange = -0.0014 // units / gu
1332+ var minAppInfoHeight = 0.08
1333+ var maxAppInfoHeight = 0.2
1334+ var screenHeightInGU = root.height / units.gu(1) // screenHeight in gu
1335+
1336+ return MathUtils.clamp(valueAtReferencePoint + appInfoHeightValueChange * (screenHeightInGU - screenHeightReferencePoint), minAppInfoHeight, maxAppInfoHeight) * root.height
1337+ }
1338+
1339+ property real rotationAngleFactor: {
1340+ var spreadHeightReferencePoint = 28 // reference spread height in gu
1341+ var valueAtReferencePoint = 1.3
1342+ var rotationAngleValueChange = -0.008 // units / gu
1343+ var minRotationAngleFactor = 0.6
1344+ var maxRotationAngleFactor = 1.5
1345+ var spreadHeightInGU = spreadHeight / units.gu(1)
1346+
1347+ return MathUtils.clamp(valueAtReferencePoint + rotationAngleValueChange * (spreadHeightInGU - spreadHeightReferencePoint), minRotationAngleFactor, maxRotationAngleFactor)
1348+ }
1349+ readonly property real itemOverlap: {
1350+ var spreadAspectRatioReferencePoint = 1.0 // ref screen height in gu
1351+ var valueAtReferencePoint = 0.74 // of screen height at the reference point
1352+ var itemOverlapValueChange = -0.068
1353+ var minOverlap = 0.55
1354+ var maxOverlap = 0.82
1355+ var spreadAspectRatio = spreadWidth / stackHeight // spread stack aspect ratio (app info not included)
1356+
1357+ return MathUtils.clamp(valueAtReferencePoint + itemOverlapValueChange * (spreadAspectRatio - spreadAspectRatioReferencePoint), minOverlap, maxOverlap)
1358+ }
1359+
1360+ readonly property real visibleItemCount: (spreadWidth / spreadItemWidth) / (1 - itemOverlap)
1361+
1362+ readonly property real spreadTotalWidth: totalItemCount * spreadWidth / visibleItemCount
1363+
1364+ readonly property real centeringOffset: Math.max(spreadWidth - spreadTotalWidth ,0) / (2 * spreadWidth)
1365+
1366+
1367+ readonly property var curve: BezierCurve {
1368+ controlPoint2: {'x': 0.19, 'y': 0.00}
1369+ controlPoint3: {'x': 0.91, 'y': 1.00}
1370+ }
1371+
1372+ Label {
1373+ id: windowTitle
1374+
1375+ width: Math.min(implicitWidth, 0.5*root.width)
1376+ elide: Qt.ElideMiddle
1377+ anchors.horizontalCenter: parent.horizontalCenter
1378+ y: windowTitleTopMargin
1379+ readonly property var highlightedSurface: root.model ? root.model.surfaceAt(root.highlightedIndex) : null
1380+ readonly property var highlightedApp: root.model ? root.model.applicationAt(root.highlightedIndex) : null
1381+ text: root.highlightedIndex >= 0 && highlightedSurface && highlightedSurface.name != "" ? highlightedSurface.name :
1382+ highlightedApp ? highlightedApp.name : ""
1383+ fontSize: root.height < units.gu(85) ? 'medium' : 'large'
1384+ color: "white"
1385+ opacity: root.highlightedIndex >= 0 ? 1 : 0
1386+ Behavior on opacity { UbuntuNumberAnimation { } }
1387+ }
1388+
1389+ Keys.onPressed: {
1390+ switch (event.key) {
1391+ case Qt.Key_Left:
1392+ case Qt.Key_Backtab:
1393+ selectPrevious(event.isAutoRepeat)
1394+ event.accepted = true;
1395+ break;
1396+ case Qt.Key_Right:
1397+ case Qt.Key_Tab:
1398+ selectNext(event.isAutoRepeat)
1399+ event.accepted = true;
1400+ break;
1401+ case Qt.Key_Escape:
1402+ highlightedIndex = -1
1403+ // Falling through intentionally
1404+ case Qt.Key_Enter:
1405+ case Qt.Key_Return:
1406+ case Qt.Key_Space:
1407+ root.leaveSpread();
1408+ event.accepted = true;
1409+ }
1410+ }
1411+
1412+
1413+ function selectNext(isAutoRepeat) {
1414+ if (isAutoRepeat && highlightedIndex >= totalItemCount -1) {
1415+ return; // AutoRepeat is not allowed to wrap around
1416+ }
1417+
1418+ highlightedIndex = (highlightedIndex + 1) % totalItemCount;
1419+ spreadFlickable.snap(highlightedIndex)
1420+ }
1421+
1422+ function selectPrevious(isAutoRepeat) {
1423+ if (isAutoRepeat && highlightedIndex == 0) {
1424+ return; // AutoRepeat is not allowed to wrap around
1425+ }
1426+
1427+ highlightedIndex = highlightedIndex - 1 >= 0 ? highlightedIndex - 1 : totalItemCount - 1;
1428+ spreadFlickable.snap(highlightedIndex)
1429+ }
1430+}
1431
1432=== added file 'qml/Stage/Spread/SpreadDelegateInputArea.qml'
1433--- qml/Stage/Spread/SpreadDelegateInputArea.qml 1970-01-01 00:00:00 +0000
1434+++ qml/Stage/Spread/SpreadDelegateInputArea.qml 2016-10-05 11:22:21 +0000
1435@@ -0,0 +1,183 @@
1436+/*
1437+ * Copyright (C) 2016 Canonical, Ltd.
1438+ *
1439+ * This program is free software; you can redistribute it and/or modify
1440+ * it under the terms of the GNU General Public License as published by
1441+ * the Free Software Foundation; version 3.
1442+ *
1443+ * This program is distributed in the hope that it will be useful,
1444+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1445+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1446+ * GNU General Public License for more details.
1447+ *
1448+ * You should have received a copy of the GNU General Public License
1449+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1450+ */
1451+
1452+import QtQuick 2.4
1453+import Ubuntu.Components 1.3
1454+import Ubuntu.Gestures 0.1
1455+import "../../Components"
1456+
1457+Item {
1458+ id: root
1459+
1460+ property bool closeable: true
1461+ readonly property real minSpeedToClose: units.gu(40)
1462+ property bool zeroVelocityCounts: false
1463+
1464+ readonly property alias distance: d.distance
1465+
1466+ signal clicked()
1467+ signal close()
1468+
1469+ QtObject {
1470+ id: d
1471+ property real distance: 0
1472+ property bool moving: false
1473+ property var dragEvents: []
1474+ property real dragVelocity: 0
1475+ property int threshold: units.gu(2)
1476+
1477+ // Can be replaced with a fake implementation during tests
1478+ // property var __getCurrentTimeMs: function () { return new Date().getTime() }
1479+ property var __dateTime: new function() {
1480+ this.getCurrentTimeMs = function() {return new Date().getTime()}
1481+ }
1482+
1483+ function pushDragEvent(event) {
1484+ var currentTime = __dateTime.getCurrentTimeMs()
1485+ dragEvents.push([currentTime, event.x, event.y, getEventSpeed(currentTime, event)])
1486+ cullOldDragEvents(currentTime)
1487+ updateSpeed()
1488+ }
1489+
1490+ function cullOldDragEvents(currentTime) {
1491+ // cull events older than 50 ms but always keep the latest 2 events
1492+ for (var numberOfCulledEvents = 0; numberOfCulledEvents < dragEvents.length-2; numberOfCulledEvents++) {
1493+ // dragEvents[numberOfCulledEvents][0] is the dragTime
1494+ if (currentTime - dragEvents[numberOfCulledEvents][0] <= 50) break
1495+ }
1496+
1497+ dragEvents.splice(0, numberOfCulledEvents)
1498+ }
1499+
1500+ function updateSpeed() {
1501+ var totalSpeed = 0
1502+ for (var i = 0; i < dragEvents.length; i++) {
1503+ totalSpeed += dragEvents[i][3]
1504+ }
1505+
1506+ if (zeroVelocityCounts || Math.abs(totalSpeed) > 0.001) {
1507+ dragVelocity = totalSpeed / dragEvents.length * 1000
1508+ }
1509+ }
1510+
1511+ function getEventSpeed(currentTime, event) {
1512+ if (dragEvents.length != 0) {
1513+ var lastDrag = dragEvents[dragEvents.length-1]
1514+ var duration = Math.max(1, currentTime - lastDrag[0])
1515+ return (event.y - lastDrag[2]) / duration
1516+ } else {
1517+ return 0
1518+ }
1519+ }
1520+ }
1521+
1522+ // Event eater
1523+ MouseArea {
1524+ anchors.fill: parent
1525+ onClicked: root.clicked()
1526+ onWheel: wheel.accepted = true
1527+ }
1528+
1529+ MultiPointTouchArea {
1530+ anchors.fill: parent
1531+ mouseEnabled: false
1532+ maximumTouchPoints: 1
1533+ property int offset: 0
1534+
1535+ touchPoints: [
1536+ TouchPoint {
1537+ id: tp
1538+ }
1539+ ]
1540+
1541+ onCanceled: {
1542+ d.moving = false
1543+ animation.animate("center");
1544+ }
1545+
1546+ onTouchUpdated: {
1547+ if (!d.moving) {
1548+ if (Math.abs(tp.startY - tp.y) > d.threshold) {
1549+ d.moving = true;
1550+ d.dragEvents = []
1551+ offset = tp.y - tp.startY;
1552+ } else {
1553+ return;
1554+ }
1555+ }
1556+
1557+ d.distance = tp.y - tp.startY - offset
1558+ d.pushDragEvent(tp);
1559+ }
1560+
1561+ onReleased: {
1562+ if (!d.moving) {
1563+ root.clicked()
1564+ }
1565+
1566+ if (!root.closeable) {
1567+ animation.animate("center")
1568+ return;
1569+ }
1570+
1571+ var touchPoint = touchPoints[0];
1572+
1573+ if ((d.dragVelocity < -root.minSpeedToClose && d.distance < -units.gu(8)) || d.distance < -root.height / 2) {
1574+ animation.animate("up")
1575+ } else if ((d.dragVelocity > root.minSpeedToClose && d.distance > units.gu(8)) || d.distance > root.height / 2) {
1576+ animation.animate("down")
1577+ } else {
1578+ animation.animate("center")
1579+ }
1580+ }
1581+ }
1582+
1583+ UbuntuNumberAnimation {
1584+ id: animation
1585+ objectName: "closeAnimation"
1586+ target: d
1587+ property: "distance"
1588+ property bool requestClose: false
1589+
1590+ function animate(direction) {
1591+ animation.from = dragArea.distance;
1592+ switch (direction) {
1593+ case "up":
1594+ animation.to = -root.height * 1.5;
1595+ requestClose = true;
1596+ break;
1597+ case "down":
1598+ animation.to = root.height * 1.5;
1599+ requestClose = true;
1600+ break;
1601+ default:
1602+ animation.to = 0
1603+ }
1604+ animation.start();
1605+ }
1606+
1607+ onRunningChanged: {
1608+ if (!running) {
1609+ d.moving = false;
1610+ if (requestClose) {
1611+ root.close();
1612+ } else {
1613+ d.distance = 0;
1614+ }
1615+ }
1616+ }
1617+ }
1618+}
1619
1620=== added file 'qml/Stage/Spread/SpreadMaths.qml'
1621--- qml/Stage/Spread/SpreadMaths.qml 1970-01-01 00:00:00 +0000
1622+++ qml/Stage/Spread/SpreadMaths.qml 2016-10-05 11:22:21 +0000
1623@@ -0,0 +1,78 @@
1624+/*
1625+ * Copyright (C) 2016 Canonical, Ltd.
1626+ *
1627+ * This program is free software; you can redistribute it and/or modify
1628+ * it under the terms of the GNU General Public License as published by
1629+ * the Free Software Foundation; version 3.
1630+ *
1631+ * This program is distributed in the hope that it will be useful,
1632+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1633+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1634+ * GNU General Public License for more details.
1635+ *
1636+ * You should have received a copy of the GNU General Public License
1637+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1638+ */
1639+
1640+import QtQuick 2.4
1641+import Ubuntu.Components 1.3
1642+import Utils 0.1
1643+import "MathUtils.js" as MathUtils
1644+
1645+Item {
1646+ id: root
1647+ anchors { left: parent.left; top: parent.top; margins: units.gu(1) }
1648+
1649+ // Information about the environment
1650+ property Item flickable: null
1651+ property Spread spread: null
1652+ property int itemIndex: 0
1653+
1654+ // Internal
1655+ property real spreadPosition: itemIndex/spread.visibleItemCount - flickable.contentX/spread.spreadWidth // 0 -> left stack, 1 -> right stack
1656+ property real leftStackingProgress: MathUtils.clamp(MathUtils.map(spreadPosition, 0, -spread.stackItemCount/spread.visibleItemCount , 0, 1), 0, 1)
1657+ property real rightStackingProgress: MathUtils.clamp(MathUtils.map(spreadPosition, 1, 1 + spread.stackItemCount/spread.visibleItemCount , 0, 1), 0, 1)
1658+ property real stackingX: (MathUtils.easeOutCubic(rightStackingProgress) - MathUtils.easeOutCubic(leftStackingProgress)) * spread.stackWidth
1659+
1660+
1661+ QtObject {
1662+ id: d
1663+ property real spreadScale: MathUtils.clamp(
1664+ MathUtils.map(spreadPosition, 0, 1, spread.leftStackScale, spread.rightStackScale),
1665+ spread.leftStackScale, spread.rightStackScale)
1666+
1667+ property real selectedScale: (spread.highlightedIndex == itemIndex ? 1.01 : 1)
1668+ Behavior on selectedScale { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
1669+
1670+ }
1671+
1672+ // Output
1673+ readonly property int targetX: spread.leftStackXPos +
1674+ spread.spreadWidth * spread.curve.getYFromX(spreadPosition + spread.centeringOffset) +
1675+ stackingX
1676+
1677+ readonly property int targetY: spread.contentTopMargin
1678+
1679+ readonly property real targetAngle: MathUtils.clamp(
1680+ MathUtils.map(targetX, spread.leftStackXPos, spread.rightStackXPos, spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle),
1681+ Math.min(spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle), Math.max(spread.dynamicLeftRotationAngle, spread.dynamicRightRotationAngle))
1682+
1683+
1684+ readonly property real targetScale: d.spreadScale * d.selectedScale
1685+
1686+ readonly property real shadowOpacity: 0.2 * (1 - rightStackingProgress) * (1 - leftStackingProgress)
1687+
1688+
1689+ readonly property real closeIconOffset: (targetScale - 1) * (-spread.stackHeight / 2)
1690+
1691+ readonly property real tileInfoOpacity: Math.min(MathUtils.clamp(MathUtils.map(leftStackingProgress, 0 , 1/(spread.stackItemCount*3), 1, 0), 0 , 1),
1692+ MathUtils.clamp(MathUtils.map(spreadPosition, 0.9 , 1, 1, 0), 0 , 1)) /** MathUtils.map(curvedSwitcherProgress, 0.7, 0.9, 0, 1)*/
1693+
1694+ readonly property bool itemVisible: {
1695+ var leftStackHidden = spreadPosition < -(spread.stackItemCount + 1)/spread.visibleItemCount
1696+ // don't hide the rightmost
1697+ var rightStackHidden = (spreadPosition > 1 + (spread.stackItemCount)/spread.visibleItemCount) && itemIndex !== spread.totalItemCount - 1
1698+ return !leftStackHidden && !rightStackHidden
1699+ }
1700+
1701+}
1702
1703=== added file 'qml/Stage/Spread/StagedRightEdgeMaths.qml'
1704--- qml/Stage/Spread/StagedRightEdgeMaths.qml 1970-01-01 00:00:00 +0000
1705+++ qml/Stage/Spread/StagedRightEdgeMaths.qml 2016-10-05 11:22:21 +0000
1706@@ -0,0 +1,174 @@
1707+/*
1708+ * Copyright (C) 2016 Canonical, Ltd.
1709+ *
1710+ * This program is free software; you can redistribute it and/or modify
1711+ * it under the terms of the GNU General Public License as published by
1712+ * the Free Software Foundation; version 3.
1713+ *
1714+ * This program is distributed in the hope that it will be useful,
1715+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1716+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1717+ * GNU General Public License for more details.
1718+ *
1719+ * You should have received a copy of the GNU General Public License
1720+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1721+ */
1722+
1723+import QtQuick 2.4
1724+import Ubuntu.Components 1.3
1725+import Unity.Application 0.1
1726+import "MathUtils.js" as MathUtils
1727+
1728+QtObject {
1729+ id: root
1730+
1731+ // Input
1732+ property int itemIndex: 0
1733+ property real progress: 0
1734+ property int sceneWidth: 0
1735+ property int sideStageWidth: 0
1736+ property int sceneHeight: 0
1737+ property int targetX: 0
1738+ property int startY: 0
1739+ property int targetY: 0
1740+ property real startAngle: 30
1741+ property real targetAngle: 0
1742+ property int targetHeight: 0
1743+ property real startScale: 1.3
1744+ property real targetScale: 0
1745+ property real breakPoint: units.gu(15) / sceneWidth
1746+
1747+ property bool isMainStageApp: false
1748+ property bool isSideStageApp: false
1749+ property bool sideStageOpen: false
1750+ property int nextInStack: 0
1751+ property int shuffledZ: 0
1752+
1753+
1754+ // Config
1755+ property int tileDistance: units.gu(10)
1756+
1757+ // Output
1758+
1759+ readonly property real scaleToPreviewProgress: {
1760+ return progress < breakPoint ? 0 : MathUtils.clamp(MathUtils.linearAnimation(breakPoint, 1, 0, 1, progress), 0, 1)
1761+ }
1762+ readonly property int animatedWidth: {
1763+ return progress < breakPoint ? root.sceneHeight : MathUtils.linearAnimation(breakPoint, 1, root.sceneWidth, targetHeight, progress)
1764+ }
1765+
1766+ readonly property int animatedHeight: {
1767+ return progress < breakPoint ? root.sceneHeight : MathUtils.linearAnimation(breakPoint, 1, root.sceneHeight, targetHeight, progress)
1768+ }
1769+
1770+
1771+ readonly property int animatedX: {
1772+ var nextStage = appRepeater.itemAt(nextInStack) ? appRepeater.itemAt(nextInStack).stage : ApplicationInfoInterface.MainStage;
1773+
1774+ var startX = 0;
1775+ if (isMainStageApp) {
1776+ if (progress < breakPoint) {
1777+ if (nextStage == ApplicationInfoInterface.MainStage) {
1778+ return MathUtils.linearAnimation(0, breakPoint, 0, -units.gu(4), progress);
1779+ } else {
1780+ return 0;
1781+ }
1782+ } else {
1783+ if (nextStage == ApplicationInfoInterface.MainStage) {
1784+ return MathUtils.linearAnimation(breakPoint, 1, -units.gu(4), targetX, progress);
1785+ } else {
1786+ return MathUtils.linearAnimation(breakPoint, 1, 0, targetX, progress);
1787+ }
1788+ }
1789+ } else if (isSideStageApp) {
1790+ startX = sceneWidth - sideStageWidth;
1791+ } else if (itemIndex == nextInStack && itemIndex <= 2 && priv.sideStageDelegate && nextStage == ApplicationInfoInterface.MainStage) {
1792+ startX = sceneWidth - sideStageWidth;
1793+ } else {
1794+ var stageCount = (priv.mainStageDelegate ? 1 : 0) + (priv.sideStageDelegate ? 1 : 0)
1795+ startX = sceneWidth + Math.max(0, itemIndex - stageCount - 1) * tileDistance;
1796+ }
1797+
1798+ if (itemIndex == nextInStack) {
1799+ if (progress < breakPoint) {
1800+ return MathUtils.linearAnimation(0, breakPoint, startX, startX * (1 - breakPoint), progress)
1801+ }
1802+ return MathUtils.linearAnimation(breakPoint, 1, startX * (1 - breakPoint), targetX, progress)
1803+ }
1804+
1805+ if (progress < breakPoint) {
1806+ return startX;
1807+ }
1808+
1809+ return MathUtils.linearAnimation(breakPoint, 1, startX, targetX, progress)
1810+
1811+ }
1812+
1813+ readonly property int animatedY: progress < breakPoint ? startY : MathUtils.linearAnimation(breakPoint, 1, startY, targetY, progress)
1814+
1815+ readonly property int animatedZ: {
1816+ if (progress < breakPoint + (1 - breakPoint) / 2) {
1817+ return shuffledZ
1818+ }
1819+ return itemIndex;
1820+ }
1821+
1822+ readonly property real animatedAngle: {
1823+ var nextStage = appRepeater.itemAt(nextInStack) ? appRepeater.itemAt(nextInStack).stage : ApplicationInfoInterface.MainStage;
1824+
1825+ var startAngle = 0;
1826+ if (isMainStageApp) {
1827+ startAngle = 0;
1828+ } else if (isSideStageApp) {
1829+ startAngle = 0;
1830+ } else {
1831+ if (stage == ApplicationInfoInterface.SideStage && itemIndex == nextInStack && !sideStageOpen) {
1832+ startAngle = 0;
1833+ } else {
1834+ startAngle = root.startAngle;
1835+ }
1836+ }
1837+
1838+ if ((itemIndex == nextInStack)
1839+ || (isMainStageApp && nextStage === ApplicationInfoInterface.MainStage)
1840+ || (isSideStageApp && nextStage === ApplicationInfoInterface.SideStage)) {
1841+ return MathUtils.linearAnimation(0, 1, startAngle, targetAngle, progress);
1842+ }
1843+
1844+ if (progress < breakPoint) {
1845+ return 0;
1846+ }
1847+ return MathUtils.linearAnimation(breakPoint, 1, startAngle, targetAngle, progress);
1848+ }
1849+
1850+ readonly property real animatedScale: {
1851+ var pullingInSideStage = itemIndex == nextInStack && stage == ApplicationInfoInterface.SideStage && !sideStageOpen;
1852+
1853+ var startScale = 1;
1854+ if (isMainStageApp) {
1855+ startScale = 1;
1856+ } else if (isSideStageApp) {
1857+ startScale = 1;
1858+ } else {
1859+ if (pullingInSideStage) {
1860+ startScale = 1
1861+ } else {
1862+ startScale = root.startScale;
1863+ }
1864+ }
1865+
1866+ if (progress < breakPoint) {
1867+ if (itemIndex == nextInStack && (sideStageOpen || stage == ApplicationInfoInterface.MainStage)) {
1868+ return MathUtils.linearAnimation(0, 1, startScale, targetScale, progress);
1869+ }
1870+ return startScale;
1871+ }
1872+ if (itemIndex == nextInStack) {
1873+ return MathUtils.linearAnimation(0, 1, startScale, targetScale, progress)
1874+ }
1875+
1876+ return MathUtils.linearAnimation(breakPoint, 1, startScale, targetScale, progress)
1877+ }
1878+
1879+ readonly property bool itemVisible: true //animatedX < sceneWidth
1880+}
1881
1882=== added file 'qml/Stage/Spread/WindowedRightEdgeMaths.qml'
1883--- qml/Stage/Spread/WindowedRightEdgeMaths.qml 1970-01-01 00:00:00 +0000
1884+++ qml/Stage/Spread/WindowedRightEdgeMaths.qml 2016-10-05 11:22:21 +0000
1885@@ -0,0 +1,81 @@
1886+/*
1887+ * Copyright (C) 2016 Canonical, Ltd.
1888+ *
1889+ * This program is free software; you can redistribute it and/or modify
1890+ * it under the terms of the GNU General Public License as published by
1891+ * the Free Software Foundation; version 3.
1892+ *
1893+ * This program is distributed in the hope that it will be useful,
1894+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1895+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1896+ * GNU General Public License for more details.
1897+ *
1898+ * You should have received a copy of the GNU General Public License
1899+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1900+ */
1901+
1902+import QtQuick 2.4
1903+import Ubuntu.Components 1.3
1904+import Unity.Application 0.1
1905+import "MathUtils.js" as MathUtils
1906+
1907+QtObject {
1908+ id: root
1909+
1910+ // Input
1911+ property int itemIndex: 0
1912+ property int normalZ: 0
1913+ property real progress: 0
1914+ property int startWidth: 0
1915+ property int startHeight: 0
1916+ property int startX: 0
1917+ property int targetX: 0
1918+ property int startY: 0
1919+ property int targetY: 0
1920+// property real startAngle: 40
1921+ property real targetAngle: 0
1922+ property int targetHeight: 0
1923+ property real targetScale: 0
1924+
1925+ // Config
1926+ property real breakPoint: 0.4
1927+
1928+ // Output
1929+
1930+ readonly property real scaleToPreviewProgress: {
1931+ return progress < breakPoint ? 0 : MathUtils.clamp(MathUtils.linearAnimation(breakPoint, 1, 0, 1, progress), 0, 1)
1932+ }
1933+ readonly property int animatedWidth: {
1934+ return progress < breakPoint ? root.startWidth : MathUtils.linearAnimation(breakPoint, 1, root.startWidth, targetHeight, progress)
1935+ }
1936+
1937+ readonly property int animatedHeight: {
1938+ return progress < breakPoint ? root.startHeight : MathUtils.linearAnimation(breakPoint, 1, root.startHeight, targetHeight, progress)
1939+ }
1940+
1941+ readonly property int animatedX: {
1942+ if (progress < breakPoint) {
1943+ return startX;
1944+ }
1945+ return MathUtils.linearAnimation(breakPoint, 1, startX, targetX, progress)
1946+ }
1947+
1948+ readonly property int animatedY: progress < breakPoint ? startY : MathUtils.linearAnimation(breakPoint, 1, startY, targetY, progress)
1949+
1950+ readonly property real animatedAngle: progress < breakPoint ? 0 : MathUtils.linearAnimation(breakPoint, 1, 0, targetAngle, progress);
1951+
1952+ readonly property real decorationHeight: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, 0, progress);
1953+
1954+ readonly property int animatedZ: {
1955+ if (progress < breakPoint + (1 - breakPoint) / 2) {
1956+ return itemIndex == 1 ? normalZ + 2 : normalZ
1957+ }
1958+ return itemIndex
1959+ }
1960+
1961+ readonly property real opacityMask: itemIndex == 1 ? MathUtils.linearAnimation(0, breakPoint, 0, 1, progress) : 1
1962+
1963+ readonly property real animatedScale: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, targetScale, progress)
1964+
1965+// readonly property bool itemVisible: true //animatedX < sceneWidth
1966+}
1967
1968=== added file 'qml/Stage/Spread/cubic-bezier.js'
1969--- qml/Stage/Spread/cubic-bezier.js 1970-01-01 00:00:00 +0000
1970+++ qml/Stage/Spread/cubic-bezier.js 2016-10-05 11:22:21 +0000
1971@@ -0,0 +1,39 @@
1972+/*
1973+ * Copyright (C) 2016 Canonical, Ltd.
1974+ *
1975+ * This program is free software; you can redistribute it and/or modify
1976+ * it under the terms of the GNU General Public License as published by
1977+ * the Free Software Foundation; version 3.
1978+ *
1979+ * This program is distributed in the hope that it will be useful,
1980+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1981+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1982+ * GNU General Public License for more details.
1983+ *
1984+ * You should have received a copy of the GNU General Public License
1985+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1986+ */
1987+
1988+//====================================\\
1989+// 13thParallel.org Beziér Curve Code \\
1990+// by Dan Pupius (www.pupius.net) \\
1991+//====================================\\
1992+
1993+
1994+var coord = function (x,y) {
1995+ if(!x) var x=0;
1996+ if(!y) var y=0;
1997+ return {x: x, y: y};
1998+}
1999+
2000+function B4(t) { return t*t*t }
2001+function B3(t) { return 3*t*t*(1-t) }
2002+function B2(t) { return 3*t*(1-t)*(1-t) }
2003+function B1(t) { return (1-t)*(1-t)*(1-t) }
2004+
2005+var getBezier = function(percent,C1,C2,C3,C4) {
2006+ var pos = new coord();
2007+ pos.x = C1.x*B1(percent) + C2.x*B2(percent) + C3.x*B3(percent) + C4.x*B4(percent);
2008+ pos.y = C1.y*B1(percent) + C2.y*B2(percent) + C3.y*B3(percent) + C4.y*B4(percent);
2009+ return pos;
2010+}
2011
2012=== renamed file 'qml/Stages/DesktopStage.qml' => 'qml/Stage/Stage.qml'
2013--- qml/Stages/DesktopStage.qml 2016-09-07 08:36:59 +0000
2014+++ qml/Stage/Stage.qml 2016-10-05 11:22:21 +0000
2015@@ -22,75 +22,152 @@
2016 import Utils 0.1
2017 import Ubuntu.Gestures 0.1
2018 import GlobalShortcut 1.0
2019+import GSettings 1.0
2020+import "Spread"
2021+import "Spread/MathUtils.js" as MathUtils
2022
2023-AbstractStage {
2024+FocusScope {
2025 id: root
2026 anchors.fill: parent
2027- paintBackground: false
2028-
2029- // functions to be called from outside
2030- function updateFocusedAppOrientation() { /* TODO */ }
2031- function updateFocusedAppOrientationAnimated() { /* TODO */}
2032- function pushRightEdge(amount) {
2033- if (spread.state === "") {
2034- edgeBarrier.push(amount);
2035- }
2036- }
2037- function closeFocusedDelegate() {
2038- if (priv.focusedAppDelegate && !priv.focusedAppDelegate.isDash) {
2039- priv.focusedAppDelegate.close();
2040- }
2041- }
2042-
2043- // Used by TutorialRight
2044- property bool spreadShown: spread.state == "altTab"
2045+
2046+ property QtObject applicationManager
2047+ property QtObject topLevelSurfaceList
2048+ property bool altTabPressed
2049+ property url background
2050+ property int dragAreaWidth
2051+ property bool interactive
2052+ property bool keepDashRunning: true
2053+ property real nativeHeight
2054+ property real nativeWidth
2055+ property QtObject orientations
2056+ property int shellOrientation
2057+ property int shellOrientationAngle
2058+ property bool spreadEnabled: true // If false, animations and right edge will be disabled
2059+ property bool suspended
2060+ property int leftMargin: 0
2061+ property bool oskEnabled: false
2062+ property rect inputMethodRect
2063+
2064+ // Configuration
2065+ property string mode: "staged"
2066+ property real leftEdgeDragProgress: 0
2067+
2068+ // Used by the tutorial code
2069+ readonly property bool spreadShown: state == "spread"
2070+ readonly property real rightEdgeDragProgress: rightEdgeDragArea.progress // How far left the stage has been dragged
2071
2072 // used by the snap windows (edge maximize) feature
2073 readonly property alias previewRectangle: fakeRectangle
2074
2075- mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
2076+ readonly property var mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
2077
2078 // application windows never rotate independently
2079- mainAppWindowOrientationAngle: shellOrientationAngle
2080-
2081- orientationChangesEnabled: true
2082-
2083-
2084- itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
2085+ property int mainAppWindowOrientationAngle: shellOrientationAngle
2086+
2087+ property bool orientationChangesEnabled: priv.focusedAppDelegate && priv.focusedAppDelegate.orientationChangesEnabled
2088+
2089+ property int supportedOrientations: {
2090+ if (mainApp) {
2091+ switch (mode) {
2092+ case "staged":
2093+ return mainApp.supportedOrientations;
2094+ case "stagedWithSideStage":
2095+ var orientations = mainApp.supportedOrientations;
2096+ orientations |= Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation;
2097+ if (priv.sideStageItemId) {
2098+ // If we have a sidestage app, support Portrait orientation
2099+ // so that it will switch the sidestage app to mainstage on rotate to portrait
2100+ orientations |= Qt.PortraitOrientation|Qt.InvertedPortraitOrientation;
2101+ }
2102+ return orientations;
2103+ }
2104+ }
2105+
2106+ return Qt.PortraitOrientation |
2107+ Qt.LandscapeOrientation |
2108+ Qt.InvertedPortraitOrientation |
2109+ Qt.InvertedLandscapeOrientation;
2110+ }
2111+
2112+
2113+ onAltTabPressedChanged: priv.goneToSpread = altTabPressed
2114+
2115+ property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
2116 priv.focusedAppDelegate.surface.confinesMousePointer ?
2117 priv.focusedAppDelegate.clientAreaItem : null;
2118
2119+ signal itemSnapshotRequested(Item item)
2120+
2121+ // functions to be called from outside
2122+ function updateFocusedAppOrientation() { /* TODO */ }
2123+ function updateFocusedAppOrientationAnimated() { /* TODO */}
2124+ function pushRightEdge(amount) {
2125+ edgeBarrier.push(amount);
2126+ }
2127+
2128+ onSpreadEnabledChanged: {
2129+ if (!spreadEnabled && root.state == "spread") {
2130+ priv.goneToSpread = false;
2131+ }
2132+ }
2133+
2134+ GSettings {
2135+ id: lifecycleExceptions
2136+ schema.id: "com.canonical.qtmir"
2137+ }
2138+
2139+ function isExemptFromLifecycle(appId) {
2140+ var shortAppId = appId.split('_')[0];
2141+ for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
2142+ if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
2143+ return true;
2144+ }
2145+ }
2146+ return false;
2147+ }
2148+
2149+ GlobalShortcut {
2150+ id: closeFocusedShortcut
2151+ shortcut: Qt.AltModifier|Qt.Key_F4
2152+ onTriggered: {
2153+ if (priv.focusedAppDelegate && !priv.focusedAppDelegate.isDash) {
2154+ priv.focusedAppDelegate.close();
2155+ }
2156+ }
2157+ }
2158+
2159 GlobalShortcut {
2160 id: showSpreadShortcut
2161 shortcut: Qt.MetaModifier|Qt.Key_W
2162- onTriggered: spread.state = "altTab"
2163+ onTriggered: priv.goneToSpread = true
2164 }
2165
2166 GlobalShortcut {
2167 id: minimizeAllShortcut
2168 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_D
2169 onTriggered: priv.minimizeAllWindows()
2170+ active: root.state == "windowed"
2171 }
2172
2173 GlobalShortcut {
2174 id: maximizeWindowShortcut
2175 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
2176 onTriggered: priv.focusedAppDelegate.maximize()
2177- active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximized
2178+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximized
2179 }
2180
2181 GlobalShortcut {
2182 id: maximizeWindowLeftShortcut
2183 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
2184 onTriggered: priv.focusedAppDelegate.maximizeLeft()
2185- active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
2186+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
2187 }
2188
2189 GlobalShortcut {
2190 id: maximizeWindowRightShortcut
2191 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
2192 onTriggered: priv.focusedAppDelegate.maximizeRight()
2193- active: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.canBeMaximizedLeftRight
2194+ active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
2195 }
2196
2197 GlobalShortcut {
2198@@ -98,7 +175,7 @@
2199 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
2200 onTriggered: priv.focusedAppDelegate.anyMaximized
2201 ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
2202- active: priv.focusedAppDelegate !== null
2203+ active: root.state == "windowed" && priv.focusedAppDelegate
2204 }
2205
2206 GlobalShortcut {
2207@@ -107,28 +184,17 @@
2208 active: priv.focusedAppDelegate !== null
2209 }
2210
2211- Connections {
2212- target: root.topLevelSurfaceList
2213- onCountChanged: {
2214- if (spread.state == "altTab") {
2215- spread.cancel();
2216- }
2217- }
2218- }
2219-
2220 QtObject {
2221 id: priv
2222 objectName: "DesktopStagePrivate"
2223
2224 property var focusedAppDelegate: null
2225- onFocusedAppDelegateChanged: {
2226- if (spread.state == "altTab") {
2227- spread.state = "";
2228- }
2229- }
2230-
2231 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
2232
2233+ property bool goneToSpread: false
2234+ property int closingIndex: -1
2235+ property int animationDuration: UbuntuAnimation.FastDuration
2236+
2237 function updateForegroundMaximizedApp() {
2238 var found = false;
2239 for (var i = 0; i < appRepeater.count && !found; i++) {
2240@@ -162,11 +228,86 @@
2241 }
2242 }
2243
2244- readonly property real virtualKeyboardHeight: SurfaceManager.inputMethodSurface
2245- ? SurfaceManager.inputMethodSurface.inputBounds.height
2246- : 0
2247+ readonly property bool sideStageEnabled: root.shellOrientation == Qt.LandscapeOrientation ||
2248+ root.shellOrientation == Qt.InvertedLandscapeOrientation
2249+
2250+ property var mainStageDelegate: null
2251+ property var sideStageDelegate: null
2252+ property int mainStageItemId: 0
2253+ property int sideStageItemId: 0
2254+ property string mainStageAppId: ""
2255+ property string sideStageAppId: ""
2256+
2257+ onSideStageDelegateChanged: {
2258+ if (!sideStageDelegate) {
2259+ sideStage.hide();
2260+ }
2261+ }
2262+
2263+ function updateMainAndSideStageIndexes() {
2264+ if (root.mode != "stagedWithSideStage") {
2265+ priv.sideStageDelegate = null;
2266+ priv.sideStageItemId = 0;
2267+ priv.sideStageAppId = "";
2268+ priv.mainStageDelegate = appRepeater.itemAt(0);
2269+ priv.mainStageAppId = topLevelSurfaceList.idAt(0);
2270+ priv.mainStageAppId = topLevelSurfaceList.applicationAt(0) ? topLevelSurfaceList.applicationAt(0).appId : ""
2271+ return;
2272+ }
2273+
2274+ var choseMainStage = false;
2275+ var choseSideStage = false;
2276+
2277+ if (!root.topLevelSurfaceList)
2278+ return;
2279+
2280+ for (var i = 0; i < appRepeater.count && (!choseMainStage || !choseSideStage); ++i) {
2281+ var appDelegate = appRepeater.itemAt(i);
2282+ if (sideStage.shown && appDelegate.stage == ApplicationInfoInterface.SideStage
2283+ && !choseSideStage) {
2284+ priv.sideStageDelegate = appDelegate
2285+ priv.sideStageItemId = root.topLevelSurfaceList.idAt(i);
2286+ priv.sideStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
2287+ choseSideStage = true;
2288+ } else if (!choseMainStage && appDelegate.stage == ApplicationInfoInterface.MainStage) {
2289+ priv.mainStageDelegate = appDelegate;
2290+ priv.mainStageItemId = root.topLevelSurfaceList.idAt(i);
2291+ priv.mainStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
2292+ choseMainStage = true;
2293+ }
2294+ }
2295+ if (!choseMainStage && priv.mainStageDelegate) {
2296+ priv.mainStageDelegate = null;
2297+ priv.mainStageItemId = 0;
2298+ priv.mainStageAppId = "";
2299+ }
2300+ if (!choseSideStage && priv.sideStageDelegate) {
2301+ priv.sideStageDelegate = null;
2302+ priv.sideStageItemId = 0;
2303+ priv.sideStageAppId = "";
2304+ }
2305+ }
2306+
2307+ property int nextInStack: {
2308+ var mainStageIndex = priv.mainStageDelegate ? priv.mainStageDelegate.itemIndex : -1;
2309+ var sideStageIndex = priv.sideStageDelegate ? priv.sideStageDelegate.itemIndex : -1;
2310+ if (sideStageIndex == -1) {
2311+ return topLevelSurfaceList.count > 1 ? 1 : -1;
2312+ }
2313+ if (mainStageIndex == 0 || sideStageIndex == 0) {
2314+ if (mainStageIndex == 1 || sideStageIndex == 1) {
2315+ return topLevelSurfaceList.count > 2 ? 2 : -1;
2316+ }
2317+ return 1;
2318+ }
2319+ return -1;
2320+ }
2321+
2322+ readonly property real virtualKeyboardHeight: root.inputMethodRect.height
2323 }
2324
2325+ Component.onCompleted: priv.updateMainAndSideStageIndexes();
2326+
2327 Connections {
2328 target: PanelState
2329 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
2330@@ -178,14 +319,13 @@
2331 target: PanelState
2332 property: "buttonsVisible"
2333 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
2334- && spread.state == ""
2335 }
2336
2337 Binding {
2338 target: PanelState
2339 property: "title"
2340 value: {
2341- if (priv.focusedAppDelegate !== null && spread.state == "") {
2342+ if (priv.focusedAppDelegate !== null) {
2343 if (priv.focusedAppDelegate.maximized)
2344 return priv.focusedAppDelegate.title
2345 else
2346@@ -199,7 +339,7 @@
2347 Binding {
2348 target: PanelState
2349 property: "dropShadow"
2350- value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null
2351+ value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
2352 }
2353
2354 Binding {
2355@@ -216,16 +356,34 @@
2356
2357 Instantiator {
2358 model: root.applicationManager
2359- delegate: Binding {
2360- target: model.application
2361- property: "requestedState"
2362-
2363- // TODO: figure out some lifecycle policy, like suspending minimized apps
2364- // if running on a tablet or something.
2365- // TODO: If the device has a dozen suspended apps because it was running
2366- // in staged mode, when it switches to Windowed mode it will suddenly
2367- // resume all those apps at once. We might want to avoid that.
2368- value: ApplicationInfoInterface.RequestedRunning // Always running for now
2369+ delegate: QtObject {
2370+ property var stateBinding: Binding {
2371+ readonly property bool isDash: model.application ? model.application.appId == "unity8-dash" : false
2372+ target: model.application
2373+ property: "requestedState"
2374+
2375+ // TODO: figure out some lifecycle policy, like suspending minimized apps
2376+ // or something if running windowed.
2377+ // TODO: If the device has a dozen suspended apps because it was running
2378+ // in staged mode, when it switches to Windowed mode it will suddenly
2379+ // resume all those apps at once. We might want to avoid that.
2380+ value: root.mode === "windowed"
2381+ || (isDash && root.keepDashRunning)
2382+ || (!root.suspended && model.application && priv.focusedAppDelegate &&
2383+ (priv.focusedAppDelegate.appId === model.application.appId ||
2384+ priv.mainStageAppId === model.application.appId ||
2385+ priv.sideStageAppId === model.application.appId))
2386+ ? ApplicationInfoInterface.RequestedRunning
2387+ : ApplicationInfoInterface.RequestedSuspended
2388+ }
2389+
2390+ property var lifecycleBinding: Binding {
2391+ target: model.application
2392+ property: "exemptFromLifecycle"
2393+ value: model.application
2394+ ? (!model.application.isTouchApp || isExemptFromLifecycle(model.application.appId))
2395+ : false
2396+ }
2397 }
2398 }
2399
2400@@ -236,16 +394,203 @@
2401 when: !appRepeater.startingUp && root.parent
2402 }
2403
2404+ states: [
2405+ State {
2406+ name: "spread"; when: priv.goneToSpread
2407+ PropertyChanges { target: floatingFlickable; enabled: true }
2408+ PropertyChanges { target: spreadItem; focus: true }
2409+ PropertyChanges { target: hoverMouseArea; enabled: true }
2410+ PropertyChanges { target: rightEdgeDragArea; enabled: false }
2411+ PropertyChanges { target: cancelSpreadMouseArea; enabled: true }
2412+ },
2413+ State {
2414+ name: "stagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "staged"
2415+ },
2416+ State {
2417+ name: "sideStagedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "stagedWithSideStage"
2418+ PropertyChanges {
2419+ target: sideStage
2420+ opacity: priv.sideStageDelegate.x === sideStage.x ? 1 : 0
2421+ visible: true
2422+ }
2423+ },
2424+ State {
2425+ name: "windowedRightEdge"; when: (rightEdgeDragArea.dragging || edgeBarrier.progress > 0) && root.mode == "windowed"
2426+ },
2427+ State {
2428+ name: "staged"; when: root.mode === "staged"
2429+ },
2430+ State {
2431+ name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
2432+ PropertyChanges { target: triGestureArea; enabled: true }
2433+ PropertyChanges { target: sideStage; visible: true }
2434+ },
2435+ State {
2436+ name: "windowed"; when: root.mode === "windowed"
2437+ }
2438+ ]
2439+ transitions: [
2440+ Transition {
2441+ from: "stagedRightEdge,sideStagedRightEdge,windowedRightEdge"; to: "spread"
2442+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
2443+ },
2444+ Transition {
2445+ to: "spread"
2446+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: appRepeater.count > 1 ? 1 : 0 }
2447+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
2448+ },
2449+ Transition {
2450+ from: "spread"
2451+ SequentialAnimation {
2452+ ScriptAction {
2453+ script: {
2454+ var item = appRepeater.itemAt(Math.max(0, spreadItem.highlightedIndex));
2455+ if (item.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
2456+ sideStage.show();
2457+ }
2458+ item.playFocusAnimation();
2459+ }
2460+ }
2461+ PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
2462+ }
2463+ },
2464+ Transition {
2465+ to: "stagedRightEdge"
2466+ PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
2467+ },
2468+ Transition {
2469+ to: "stagedWithSideStage"
2470+ ScriptAction { script: priv.updateMainAndSideStageIndexes(); }
2471+ }
2472+
2473+ ]
2474+
2475+ MouseArea {
2476+ id: cancelSpreadMouseArea
2477+ anchors.fill: parent
2478+ enabled: false
2479+ onClicked: priv.goneToSpread = false
2480+ }
2481+
2482 FocusScope {
2483 id: appContainer
2484 objectName: "appContainer"
2485 anchors.fill: parent
2486- focus: spread.state !== "altTab"
2487+ focus: true
2488
2489 Wallpaper {
2490 id: wallpaper
2491 anchors.fill: parent
2492 source: root.background
2493+ // Make sure it's the lowest item. Due to the left edge drag we sometimes need
2494+ // to put the dash at -1 and we don't want it behind the Wallpaper
2495+ z: -2
2496+ }
2497+
2498+ Spread {
2499+ id: spreadItem
2500+ objectName: "spreadItem"
2501+ anchors.fill: appContainer
2502+ leftMargin: root.leftMargin
2503+ model: root.topLevelSurfaceList
2504+ spreadFlickable: floatingFlickable
2505+ z: 10
2506+
2507+ onLeaveSpread: {
2508+ priv.goneToSpread = false;
2509+ }
2510+ }
2511+
2512+ Connections {
2513+ target: root.topLevelSurfaceList
2514+ onListChanged: priv.updateMainAndSideStageIndexes()
2515+ }
2516+
2517+
2518+ DropArea {
2519+ objectName: "MainStageDropArea"
2520+ anchors {
2521+ left: parent.left
2522+ top: parent.top
2523+ bottom: parent.bottom
2524+ }
2525+ width: appContainer.width - sideStage.width
2526+ enabled: sideStage.enabled
2527+
2528+ onDropped: {
2529+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.MainStage);
2530+ drop.source.appDelegate.focus = true;
2531+ }
2532+ keys: "SideStage"
2533+ }
2534+
2535+ SideStage {
2536+ id: sideStage
2537+ objectName: "sideStage"
2538+ shown: false
2539+ height: appContainer.height
2540+ x: appContainer.width - width
2541+ visible: false
2542+ Behavior on opacity { UbuntuNumberAnimation {} }
2543+ z: {
2544+ if (!priv.mainStageItemId) return 0;
2545+
2546+ if (priv.sideStageItemId && priv.nextInStack > 0) {
2547+
2548+ // Due the order in which bindings are evaluated, this might be triggered while shuffling
2549+ // the list and index doesn't yet match with itemIndex (even though itemIndex: index)
2550+ // Let's walk the list and compare itemIndex to make sure we have the correct one.
2551+ var nextDelegateInStack = -1;
2552+ for (var i = 0; i < appRepeater.count; i++) {
2553+ if (appRepeater.itemAt(i).itemIndex == priv.nextInStack) {
2554+ nextDelegateInStack = appRepeater.itemAt(i);
2555+ break;
2556+ }
2557+ }
2558+
2559+ if (nextDelegateInStack.stage === ApplicationInfoInterface.MainStage) {
2560+ // if the next app in stack is a main stage app, put the sidestage on top of it.
2561+ return 2;
2562+ }
2563+ return 1;
2564+ }
2565+
2566+ return 1;
2567+ }
2568+
2569+ onShownChanged: {
2570+ if (!shown && priv.mainStageDelegate) {
2571+ priv.mainStageDelegate.claimFocus();
2572+ }
2573+ }
2574+
2575+ DropArea {
2576+ id: sideStageDropArea
2577+ objectName: "SideStageDropArea"
2578+ anchors.fill: parent
2579+
2580+ property bool dropAllowed: true
2581+
2582+ onEntered: {
2583+ dropAllowed = drag.keys != "Disabled";
2584+ }
2585+ onExited: {
2586+ dropAllowed = true;
2587+ }
2588+ onDropped: {
2589+ if (drop.keys == "MainStage") {
2590+ drop.source.appDelegate.saveStage(ApplicationInfoInterface.SideStage);
2591+ drop.source.appDelegate.focus = true;
2592+ }
2593+ }
2594+ drag {
2595+ onSourceChanged: {
2596+ if (!sideStageDropArea.drag.source) {
2597+ dropAllowed = true;
2598+ }
2599+ }
2600+ }
2601+ }
2602 }
2603
2604 TopLevelSurfaceRepeater {
2605@@ -256,6 +601,7 @@
2606 delegate: FocusScope {
2607 id: appDelegate
2608 objectName: "appDelegate_" + model.id
2609+ property int itemIndex: index // We need this from outside the repeater
2610 // z might be overriden in some cases by effects, but we need z ordering
2611 // to calculate occlusion detection
2612 property int normalZ: topLevelSurfaceList.count - index
2613@@ -265,10 +611,33 @@
2614 }
2615 }
2616 z: normalZ
2617- x: requestedX // may be overridden in some states. Do not directly write to this.
2618- y: requestedY // may be overridden in some states. Do not directly write to this.
2619- property real requestedX: priv.focusedAppDelegate ? priv.focusedAppDelegate.x + units.gu(3) : (normalZ - 1) * units.gu(3)
2620- property real requestedY: priv.focusedAppDelegate ? priv.focusedAppDelegate.y + units.gu(3) : normalZ * units.gu(3)
2621+
2622+ // Normally we want x/y where we request it to be. Width/height of our delegate will
2623+ // match what the actual surface size is.
2624+ // Don't write to those, they will be set by states
2625+ x: requestedX
2626+ y: requestedY
2627+ width: decoratedWindow.implicitWidth
2628+ height: decoratedWindow.implicitHeight
2629+
2630+ // requestedX/Y/width/height is what we ask the actual surface to be.
2631+ // Do not write to those, they will be set by states
2632+ property real requestedX: windowedX
2633+ property real requestedY: windowedY
2634+ property real requestedWidth: windowedWidth
2635+ property real requestedHeight: windowedHeight
2636+
2637+ // In those are for windowed mode. Those values basically store the window's properties
2638+ // when having a floating window. If you want to move/resize a window in normal mode, this is what you want to write to.
2639+ property real windowedX
2640+ property real windowedY
2641+ property real windowedWidth
2642+ property real windowedHeight
2643+
2644+ // unlike windowedX/Y, this is the last known grab position before being pushed against edges/corners
2645+ // when restoring, the window should return to these, not to the place where it was dropped near the edge
2646+ property real restoredX
2647+ property real restoredY
2648
2649 Binding {
2650 target: appDelegate
2651@@ -277,27 +646,24 @@
2652 Math.min(appDelegate.requestedY - PanelState.panelHeight,
2653 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
2654 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
2655- && SurfaceManager.inputMethodSurface
2656- && SurfaceManager.inputMethodSurface.state != Mir.HiddenState
2657- && SurfaceManager.inputMethodSurface.state != Mir.MinimizedState
2658+ && root.inputMethodRect.height > 0
2659
2660 }
2661
2662- width: decoratedWindow.width
2663- height: decoratedWindow.height
2664+ Behavior on x { id: xBehavior; enabled: priv.closingIndex >= 0; UbuntuNumberAnimation { onRunningChanged: if (!running) priv.closingIndex = -1} }
2665
2666 Connections {
2667 target: root
2668 onShellOrientationAngleChanged: {
2669 // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
2670 if (application && application.rotatesWindowContents) {
2671- if (state == "normal" || state == "restored") {
2672+ if (root.state == "windowed") {
2673 var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
2674 angleDiff = (360 + angleDiff) % 360;
2675 if (angleDiff === 90 || angleDiff === 270) {
2676 var aux = decoratedWindow.requestedHeight;
2677- decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.visibleDecorationHeight;
2678- decoratedWindow.requestedWidth = aux - decoratedWindow.visibleDecorationHeight;
2679+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
2680+ decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
2681 }
2682 }
2683 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
2684@@ -306,6 +672,10 @@
2685 }
2686 }
2687 }
2688+ Connections {
2689+ target: priv
2690+ onSideStageEnabledChanged: refreshStage()
2691+ }
2692
2693 readonly property alias application: decoratedWindow.application
2694 readonly property alias minimumWidth: decoratedWindow.minimumWidth
2695@@ -314,8 +684,6 @@
2696 readonly property alias maximumHeight: decoratedWindow.maximumHeight
2697 readonly property alias widthIncrement: decoratedWindow.widthIncrement
2698 readonly property alias heightIncrement: decoratedWindow.heightIncrement
2699- property int requestedWidth: -1
2700- property int requestedHeight: -1
2701
2702 readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
2703 readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
2704@@ -330,7 +698,7 @@
2705 maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
2706
2707 readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
2708- readonly property alias fullscreen: decoratedWindow.fullscreen
2709+ readonly property bool fullscreen: surface ? surface.state === Mir.FullscreenState : application.fullscreen
2710
2711 readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
2712 readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
2713@@ -339,6 +707,7 @@
2714 (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
2715 readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
2716 readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
2717+ readonly property alias orientationChangesEnabled: decoratedWindow.orientationChangesEnabled
2718
2719 property int windowState: WindowStateStorage.WindowStateNormal
2720 property bool animationsEnabled: true
2721@@ -347,23 +716,45 @@
2722 property bool visuallyMaximized: false
2723 property bool visuallyMinimized: false
2724
2725+ property int stage: ApplicationInfoInterface.MainStage
2726+ function saveStage(newStage) {
2727+ appDelegate.stage = newStage;
2728+ WindowStateStorage.saveStage(appId, newStage);
2729+ priv.updateMainAndSideStageIndexes()
2730+ }
2731+
2732 readonly property var surface: model.surface
2733 readonly property alias resizeArea: resizeArea
2734 readonly property alias focusedSurface: decoratedWindow.focusedSurface
2735 readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
2736
2737- readonly property bool isDash: model.application.appId == "unity8-dash"
2738+ readonly property string appId: model.application.appId
2739+ readonly property bool isDash: appId == "unity8-dash"
2740 readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
2741
2742 function claimFocus() {
2743- if (spread.state == "altTab") {
2744- spread.cancel();
2745- }
2746- appDelegate.restore(true /* animated */, appDelegate.windowState);
2747+ if (root.state == "spread") {
2748+ spreadItem.highlightedIndex = index
2749+ priv.goneToSpread = false;
2750+ }
2751+ if (root.mode == "stagedWithSideStage") {
2752+ if (appDelegate.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
2753+ sideStage.show();
2754+ }
2755+ priv.updateMainAndSideStageIndexes();
2756+ }
2757+
2758+ if (root.mode == "windowed") {
2759+ appDelegate.restore(true /* animated */, appDelegate.windowState);
2760+ } else {
2761+ appDelegate.focus = true;
2762+ }
2763 }
2764 Connections {
2765 target: model.surface
2766- onFocusRequested: claimFocus();
2767+ onFocusRequested: {
2768+ claimFocus();
2769+ }
2770 }
2771 Connections {
2772 target: model.application
2773@@ -383,14 +774,9 @@
2774 return;
2775
2776 if (focus) {
2777- // If we're orphan (!parent) it means this stage is no longer the current one
2778- // and will be deleted shortly. So we should no longer have a say over the model
2779- if (root.parent) {
2780- topLevelSurfaceList.raiseId(model.id);
2781- }
2782-
2783+ topLevelSurfaceList.raiseId(model.id);
2784 priv.focusedAppDelegate = appDelegate;
2785- } else if (!focus && priv.focusedAppDelegate === appDelegate) {
2786+ } else if (!focus && priv.focusedAppDelegate === appDelegate && root.state != "spread") {
2787 priv.focusedAppDelegate = null;
2788 // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
2789 MirFocusController.focusedSurface = null;
2790@@ -403,13 +789,25 @@
2791 decoratedWindow.surfaceOrientationAngle = 0;
2792 }
2793
2794+ // First, cascade the newly created window, relative to the currently/old focused window.
2795+ windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
2796+ windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
2797+ // Now load any saved state. This needs to happen *after* the cascading!
2798+ resizeArea.loadWindowState();
2799+
2800 // NB: We're differentiating if this delegate was created in response to a new entry in the model
2801 // or if the Repeater is just populating itself with delegates to match the model it received.
2802 if (!appRepeater.startingUp) {
2803 // a top level window is always the focused one when it first appears, unfocusing
2804 // any preexisting one
2805- focus = true;
2806+ if (root.state == "spread") {
2807+ spreadItem.highlightedIndex = index;
2808+ }
2809+ claimFocus();
2810 }
2811+
2812+ refreshStage();
2813+ _constructing = false;
2814 }
2815 Component.onDestruction: {
2816 if (!root.parent) {
2817@@ -435,13 +833,20 @@
2818
2819 onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
2820
2821+ property bool _constructing: true;
2822+ onStageChanged: {
2823+ if (!_constructing) {
2824+ priv.updateMainAndSideStageIndexes();
2825+ }
2826+ }
2827+
2828 visible: (
2829 !visuallyMinimized
2830 && !greeter.fullyShown
2831 && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
2832 )
2833- || decoratedWindow.fullscreen
2834- || (spread.state == "altTab" && index === spread.highlightedIndex)
2835+ || appDelegate.fullscreen
2836+ || focusAnimation.running || rightEdgeFocusAnimation.running || hidingAnimation.running
2837
2838 function close() {
2839 model.surface.close();
2840@@ -499,7 +904,44 @@
2841 }
2842
2843 function playFocusAnimation() {
2844- focusAnimation.start()
2845+ if (state == "stagedRightEdge") {
2846+ // TODO: Can we drop this if and find something that always works?
2847+ if (root.mode == "staged") {
2848+ rightEdgeFocusAnimation.targetX = 0
2849+ rightEdgeFocusAnimation.start()
2850+ } else if (root.mode == "stagedWithSideStage") {
2851+ rightEdgeFocusAnimation.targetX = appDelegate.stage == ApplicationInfoInterface.SideStage ? sideStage.x : 0
2852+ rightEdgeFocusAnimation.start()
2853+ }
2854+ } else if (state == "windowedRightEdge") {
2855+ claimFocus();
2856+ } else {
2857+ focusAnimation.start()
2858+ }
2859+ }
2860+ function playHidingAnimation() {
2861+ if (state != "windowedRightEdge") {
2862+ hidingAnimation.start()
2863+ }
2864+ }
2865+
2866+ function refreshStage() {
2867+ var newStage = ApplicationInfoInterface.MainStage;
2868+ if (priv.sideStageEnabled) { // we're in lanscape rotation.
2869+ if (!isDash && application && application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
2870+ var defaultStage = ApplicationInfoInterface.SideStage; // if application supports portrait, it defaults to sidestage.
2871+ if (application.supportedOrientations & (Qt.LandscapeOrientation|Qt.InvertedLandscapeOrientation)) {
2872+ // if it supports lanscape, it defaults to mainstage.
2873+ defaultStage = ApplicationInfoInterface.MainStage;
2874+ }
2875+ newStage = WindowStateStorage.getStage(application.appId, defaultStage);
2876+ }
2877+ }
2878+
2879+ stage = newStage;
2880+ if (focus && stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
2881+ sideStage.show();
2882+ }
2883 }
2884
2885 UbuntuNumberAnimation {
2886@@ -509,32 +951,255 @@
2887 from: 0.98
2888 to: 1
2889 duration: UbuntuAnimation.SnapDuration
2890- }
2891-
2892- // unlike requestedX/Y, this is the last known grab position before being pushed against edges/corners
2893- // when restoring, the window should return to these, not to the place where it was dropped near the edge
2894- property real restoredX
2895- property real restoredY
2896+ onStarted: {
2897+ topLevelSurfaceList.raiseId(model.id);
2898+ }
2899+ onStopped: {
2900+ appDelegate.claimFocus();
2901+ }
2902+ }
2903+ ParallelAnimation {
2904+ id: rightEdgeFocusAnimation
2905+ property int targetX: 0
2906+ UbuntuNumberAnimation { target: appDelegate; properties: "x"; to: rightEdgeFocusAnimation.targetX; duration: priv.animationDuration }
2907+ UbuntuNumberAnimation { target: decoratedWindow; properties: "angle"; to: 0; duration: priv.animationDuration }
2908+ UbuntuNumberAnimation { target: decoratedWindow; properties: "itemScale"; to: 1; duration: priv.animationDuration }
2909+ onStopped: {
2910+ appDelegate.focus = true
2911+ }
2912+ }
2913+ ParallelAnimation {
2914+ id: hidingAnimation
2915+ UbuntuNumberAnimation { target: appDelegate; property: "opacity"; to: 0; duration: priv.animationDuration }
2916+ onStopped: appDelegate.opacity = 1
2917+ }
2918+
2919+ SpreadMaths {
2920+ id: spreadMaths
2921+ spread: spreadItem
2922+ itemIndex: index
2923+ flickable: floatingFlickable
2924+ }
2925+ StageMaths {
2926+ id: stageMaths
2927+ sceneWidth: root.width
2928+ stage: appDelegate.stage
2929+ thisDelegate: appDelegate
2930+ mainStageDelegate: priv.mainStageDelegate
2931+ sideStageDelegate: priv.sideStageDelegate
2932+ sideStageWidth: sideStage.panelWidth
2933+ sideStageX: sideStage.x
2934+ itemIndex: appDelegate.itemIndex
2935+ nextInStack: priv.nextInStack
2936+ leftEdgeDragProgress: root.leftEdgeDragProgress
2937+ }
2938+
2939+ StagedRightEdgeMaths {
2940+ id: stagedRightEdgeMaths
2941+ sceneWidth: appContainer.width - root.leftMargin
2942+ sceneHeight: appContainer.height
2943+ isMainStageApp: priv.mainStageDelegate == appDelegate
2944+ isSideStageApp: priv.sideStageDelegate == appDelegate
2945+ sideStageWidth: sideStage.width
2946+ sideStageOpen: sideStage.shown
2947+ itemIndex: index
2948+ nextInStack: priv.nextInStack
2949+ progress: 0
2950+ targetHeight: spreadItem.stackHeight
2951+ targetX: spreadMaths.targetX
2952+ startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
2953+ targetY: spreadMaths.targetY
2954+ targetAngle: spreadMaths.targetAngle
2955+ targetScale: spreadMaths.targetScale
2956+ shuffledZ: stageMaths.itemZ
2957+ breakPoint: spreadItem.rightEdgeBreakPoint
2958+ }
2959+
2960+ WindowedRightEdgeMaths {
2961+ id: windowedRightEdgeMaths
2962+ itemIndex: index
2963+ startWidth: appDelegate.requestedWidth
2964+ startHeight: appDelegate.requestedHeight
2965+ targetHeight: spreadItem.stackHeight
2966+ targetX: spreadMaths.targetX
2967+ targetY: spreadMaths.targetY
2968+ normalZ: appDelegate.normalZ
2969+ targetAngle: spreadMaths.targetAngle
2970+ targetScale: spreadMaths.targetScale
2971+ breakPoint: spreadItem.rightEdgeBreakPoint
2972+ }
2973
2974 states: [
2975 State {
2976+ name: "spread"; when: root.state == "spread"
2977+ PropertyChanges {
2978+ target: decoratedWindow;
2979+ showDecoration: false;
2980+ angle: spreadMaths.targetAngle
2981+ itemScale: spreadMaths.targetScale
2982+ scaleToPreviewSize: spreadItem.stackHeight
2983+ scaleToPreviewProgress: 1
2984+ hasDecoration: root.mode === "windowed"
2985+ shadowOpacity: spreadMaths.shadowOpacity
2986+ showHighlight: spreadItem.highlightedIndex === index
2987+ darkening: spreadItem.highlightedIndex >= 0
2988+ anchors.topMargin: dragArea.distance
2989+ }
2990+ PropertyChanges {
2991+ target: appDelegate
2992+ x: spreadMaths.targetX
2993+ y: spreadMaths.targetY
2994+ z: index
2995+ height: spreadItem.spreadItemHeight
2996+ requestedWidth: decoratedWindow.oldRequestedWidth
2997+ requestedHeight: decoratedWindow.oldRequestedHeight
2998+ visible: spreadMaths.itemVisible
2999+ }
3000+ PropertyChanges { target: dragArea; enabled: true }
3001+ PropertyChanges { target: windowInfoItem; opacity: spreadMaths.tileInfoOpacity; visible: spreadMaths.itemVisible }
3002+ },
3003+ State {
3004+ name: "stagedRightEdge"
3005+ when: (root.mode == "staged" || root.mode == "stagedWithSideStage") && (root.state == "sideStagedRightEdge" || root.state == "stagedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running)
3006+ PropertyChanges {
3007+ target: stagedRightEdgeMaths
3008+ progress: Math.max(edgeBarrier.progress, rightEdgeDragArea.draggedProgress)
3009+ }
3010+ PropertyChanges {
3011+ target: appDelegate
3012+ x: stagedRightEdgeMaths.animatedX
3013+ y: stagedRightEdgeMaths.animatedY
3014+ z: stagedRightEdgeMaths.animatedZ
3015+ height: stagedRightEdgeMaths.animatedHeight
3016+ requestedWidth: decoratedWindow.oldRequestedWidth
3017+ requestedHeight: decoratedWindow.oldRequestedHeight
3018+ visible: appDelegate.x < root.width
3019+ }
3020+ PropertyChanges {
3021+ target: decoratedWindow
3022+ hasDecoration: false
3023+ angle: stagedRightEdgeMaths.animatedAngle
3024+ itemScale: stagedRightEdgeMaths.animatedScale
3025+ scaleToPreviewSize: spreadItem.stackHeight
3026+ scaleToPreviewProgress: stagedRightEdgeMaths.scaleToPreviewProgress
3027+ shadowOpacity: .3
3028+ }
3029+ },
3030+ State {
3031+ name: "windowedRightEdge"
3032+ when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
3033+ PropertyChanges {
3034+ target: windowedRightEdgeMaths
3035+ progress: Math.max(rightEdgeDragArea.progress, edgeBarrier.progress)
3036+ }
3037+ PropertyChanges {
3038+ target: appDelegate
3039+ x: windowedRightEdgeMaths.animatedX
3040+ y: windowedRightEdgeMaths.animatedY
3041+ z: windowedRightEdgeMaths.animatedZ
3042+ height: stagedRightEdgeMaths.animatedHeight
3043+ requestedWidth: decoratedWindow.oldRequestedWidth
3044+ requestedHeight: decoratedWindow.oldRequestedHeight
3045+ }
3046+ PropertyChanges {
3047+ target: decoratedWindow
3048+ showDecoration: windowedRightEdgeMaths.decorationHeight
3049+ angle: windowedRightEdgeMaths.animatedAngle
3050+ itemScale: windowedRightEdgeMaths.animatedScale
3051+ scaleToPreviewSize: spreadItem.stackHeight
3052+ scaleToPreviewProgress: windowedRightEdgeMaths.scaleToPreviewProgress
3053+ shadowOpacity: .3
3054+ }
3055+ PropertyChanges {
3056+ target: opacityEffect;
3057+ opacityValue: windowedRightEdgeMaths.opacityMask
3058+ sourceItem: windowedRightEdgeMaths.opacityMask < 1 ? decoratedWindow : null
3059+ }
3060+ },
3061+ State {
3062+ name: "staged"; when: root.state == "staged"
3063+ PropertyChanges {
3064+ target: appDelegate
3065+ x: stageMaths.itemX
3066+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
3067+ requestedWidth: appContainer.width
3068+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
3069+ visuallyMaximized: true
3070+ visible: appDelegate.x < root.width
3071+ }
3072+ PropertyChanges {
3073+ target: decoratedWindow
3074+ hasDecoration: false
3075+ }
3076+ PropertyChanges {
3077+ target: resizeArea
3078+ enabled: false
3079+ }
3080+ PropertyChanges {
3081+ target: stageMaths
3082+ animateX: !focusAnimation.running && itemIndex !== spreadItem.highlightedIndex
3083+ }
3084+ },
3085+ State {
3086+ name: "stagedWithSideStage"; when: root.state == "stagedWithSideStage"
3087+ PropertyChanges {
3088+ target: stageMaths
3089+ itemIndex: index
3090+ }
3091+ PropertyChanges {
3092+ target: appDelegate
3093+ x: stageMaths.itemX
3094+ y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
3095+ z: stageMaths.itemZ
3096+ requestedWidth: stageMaths.itemWidth
3097+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
3098+ visuallyMaximized: true
3099+ visible: appDelegate.x < root.width
3100+ }
3101+ PropertyChanges {
3102+ target: decoratedWindow
3103+ hasDecoration: false
3104+ }
3105+ PropertyChanges {
3106+ target: resizeArea
3107+ enabled: false
3108+ }
3109+ },
3110+ State {
3111+ name: "maximized"; when: appDelegate.windowState == WindowStateStorage.WindowStateMaximized
3112+ PropertyChanges {
3113+ target: appDelegate;
3114+ requestedX: root.leftMargin;
3115+ requestedY: 0;
3116+ visuallyMinimized: false;
3117+ visuallyMaximized: true
3118+ requestedWidth: appContainer.width - root.leftMargin;
3119+ requestedHeight: appContainer.height;
3120+ }
3121+ PropertyChanges { target: touchControls; enabled: true }
3122+ },
3123+ State {
3124 name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
3125 PropertyChanges {
3126 target: appDelegate;
3127- x: rotation == 0 ? 0 : (parent.width - width) / 2 + (shellOrientationAngle == 90 ? -PanelState.panelHeight : PanelState.panelHeight)
3128- y: rotation == 0 ? -PanelState.panelHeight : (parent.height - height) / 2
3129+ requestedX: 0
3130+ requestedY: 0
3131 requestedWidth: appContainer.width;
3132 requestedHeight: appContainer.height;
3133 }
3134+ PropertyChanges { target: decoratedWindow; hasDecoration: false }
3135 },
3136 State {
3137 name: "normal";
3138 when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
3139 PropertyChanges {
3140- target: appDelegate;
3141- visuallyMinimized: false;
3142+ target: appDelegate
3143+ visuallyMinimized: false
3144 visuallyMaximized: false
3145 }
3146+ PropertyChanges { target: touchControls; enabled: true }
3147+ PropertyChanges { target: resizeArea; enabled: true }
3148+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3}
3149 },
3150 State {
3151 name: "restored";
3152@@ -542,30 +1207,25 @@
3153 extend: "normal"
3154 PropertyChanges {
3155 target: appDelegate;
3156- requestedX: restoredX;
3157- requestedY: restoredY;
3158+ windowedX: restoredX;
3159+ windowedY: restoredY;
3160 }
3161 },
3162 State {
3163- name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
3164- PropertyChanges {
3165- target: appDelegate;
3166- requestedX: root.leftMargin;
3167- requestedY: 0;
3168- requestedWidth: appContainer.width - root.leftMargin;
3169- requestedHeight: appContainer.height;
3170- visuallyMinimized: false;
3171- visuallyMaximized: true
3172- }
3173+ name: "semiMaximized"
3174+ PropertyChanges { target: touchControls; enabled: true }
3175+ PropertyChanges { target: resizeArea; enabled: true }
3176+ PropertyChanges { target: decoratedWindow; shadowOpacity: .3 }
3177 },
3178 State {
3179 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
3180+ extend: "semiMaximized"
3181 PropertyChanges {
3182 target: appDelegate
3183- requestedX: root.leftMargin
3184- requestedY: PanelState.panelHeight
3185- requestedWidth: (appContainer.width - root.leftMargin)/2
3186- requestedHeight: appContainer.height - PanelState.panelHeight
3187+ windowedX: root.leftMargin
3188+ windowedY: PanelState.panelHeight
3189+ windowedWidth: (appContainer.width - root.leftMargin)/2
3190+ windowedHeight: appContainer.height - PanelState.panelHeight
3191 }
3192 },
3193 State {
3194@@ -573,17 +1233,18 @@
3195 extend: "maximizedLeft"
3196 PropertyChanges {
3197 target: appDelegate;
3198- requestedX: (appContainer.width + root.leftMargin)/2
3199+ windowedX: (appContainer.width + root.leftMargin)/2
3200 }
3201 },
3202 State {
3203 name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
3204+ extend: "semiMaximized"
3205 PropertyChanges {
3206 target: appDelegate
3207- requestedX: root.leftMargin
3208- requestedY: PanelState.panelHeight
3209- requestedWidth: (appContainer.width - root.leftMargin)/2
3210- requestedHeight: (appContainer.height - PanelState.panelHeight)/2
3211+ windowedX: root.leftMargin
3212+ windowedY: PanelState.panelHeight
3213+ windowedWidth: (appContainer.width - root.leftMargin)/2
3214+ windowedHeight: (appContainer.height - PanelState.panelHeight)/2
3215 }
3216 },
3217 State {
3218@@ -591,17 +1252,18 @@
3219 extend: "maximizedTopLeft"
3220 PropertyChanges {
3221 target: appDelegate
3222- requestedX: (appContainer.width + root.leftMargin)/2
3223+ windowedX: (appContainer.width + root.leftMargin)/2
3224 }
3225 },
3226 State {
3227 name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
3228+ extend: "semiMaximized"
3229 PropertyChanges {
3230 target: appDelegate
3231- requestedX: root.leftMargin
3232- requestedY: (appContainer.height + PanelState.panelHeight)/2
3233- requestedWidth: (appContainer.width - root.leftMargin)/2
3234- requestedHeight: appContainer.height/2
3235+ windowedX: root.leftMargin
3236+ windowedY: (appContainer.height + PanelState.panelHeight)/2
3237+ windowedWidth: (appContainer.width - root.leftMargin)/2
3238+ windowedHeight: appContainer.height/2
3239 }
3240 },
3241 State {
3242@@ -609,35 +1271,52 @@
3243 extend: "maximizedBottomLeft"
3244 PropertyChanges {
3245 target: appDelegate
3246- requestedX: (appContainer.width + root.leftMargin)/2
3247+ windowedX: (appContainer.width + root.leftMargin)/2
3248 }
3249 },
3250 State {
3251 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
3252- PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: requestedY; requestedWidth: appContainer.width - root.leftMargin }
3253+ extend: "semiMaximized"
3254+ PropertyChanges { target: appDelegate; requestedX: root.leftMargin; requestedY: windowedY;
3255+ requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appDelegate.windowedHeight }
3256 },
3257 State {
3258 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
3259- PropertyChanges { target: appDelegate; requestedX: requestedX; requestedY: PanelState.panelHeight; requestedHeight: appContainer.height - PanelState.panelHeight }
3260+ extend: "semiMaximized"
3261+ PropertyChanges { target: appDelegate; requestedX: windowedX; requestedY: PanelState.panelHeight;
3262+ requestedWidth: appDelegate.windowedWidth; requestedHeight: appContainer.height - PanelState.panelHeight }
3263 },
3264 State {
3265 name: "minimized"; when: appDelegate.minimized
3266 PropertyChanges {
3267- target: appDelegate;
3268- requestedX: -appDelegate.width / 2;
3269- scale: units.gu(5) / appDelegate.width;
3270+ target: appDelegate
3271+ requestedX: -appDelegate.width / 2
3272+ scale: units.gu(5) / appDelegate.width
3273 opacity: 0;
3274- visuallyMinimized: true;
3275+ visuallyMinimized: true
3276 visuallyMaximized: false
3277 }
3278 }
3279 ]
3280 transitions: [
3281 Transition {
3282+ from: "staged,stagedWithSideStage"; to: "normal"
3283+ enabled: appDelegate.animationsEnabled
3284+ PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
3285+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,opacity,requestedWidth,requestedHeight,scale"; duration: priv.animationDuration }
3286+ },
3287+ Transition {
3288+ from: "normal,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight";
3289+ to: "staged,stagedWithSideStage"
3290+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,requestedWidth,requestedHeight"; duration: priv.animationDuration}
3291+ },
3292+ Transition {
3293+ from: "maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight,minimized";
3294 to: "normal,restored"
3295 enabled: appDelegate.animationsEnabled
3296 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
3297- UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
3298+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,requestedWidth,requestedHeight,windowedWidth,windowedHeight,scale";
3299+ duration: priv.animationDuration }
3300 },
3301 Transition {
3302 to: "minimized"
3303@@ -657,11 +1336,60 @@
3304 }
3305 },
3306 Transition {
3307- to: "*" //maximized and fullscreen
3308+ to: "spread"
3309+ // DecoratedWindow wants the scaleToPreviewSize set before enabling scaleToPreview
3310+ PropertyAction { target: appDelegate; properties: "z,visible" }
3311+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
3312+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height"; duration: priv.animationDuration }
3313+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
3314+ },
3315+ Transition {
3316+ from: "normal,staged"; to: "stagedWithSideStage"
3317+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y"; duration: priv.animationDuration }
3318+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedWidth,requestedHeight"; duration: priv.animationDuration }
3319+ },
3320+ Transition {
3321+ to: "windowedRightEdge"
3322+ ScriptAction {
3323+ script: {
3324+ windowedRightEdgeMaths.startX = appDelegate.requestedX
3325+ windowedRightEdgeMaths.startY = appDelegate.requestedY
3326+
3327+ if (index == 1) {
3328+ var thisRect = { x: appDelegate.windowedX, y: appDelegate.windowedY, width: appDelegate.requestedWidth, height: appDelegate.requestedHeight }
3329+ var otherDelegate = appRepeater.itemAt(0);
3330+ var otherRect = { x: otherDelegate.windowedX, y: otherDelegate.windowedY, width: otherDelegate.requestedWidth, height: otherDelegate.requestedHeight }
3331+ var intersectionRect = MathUtils.intersectionRect(thisRect, otherRect)
3332+ var mappedInterSectionRect = appDelegate.mapFromItem(root, intersectionRect.x, intersectionRect.y)
3333+ opacityEffect.maskX = mappedInterSectionRect.x
3334+ opacityEffect.maskY = mappedInterSectionRect.y
3335+ opacityEffect.maskWidth = intersectionRect.width
3336+ opacityEffect.maskHeight = intersectionRect.height
3337+ }
3338+ }
3339+ }
3340+ },
3341+ Transition {
3342+ from: "stagedRightEdge"; to: "staged"
3343+ enabled: rightEdgeDragArea.cancelled // only transition back to state if the gesture was cancelled, in the other cases we play the focusAnimations.
3344+ SequentialAnimation {
3345+ ParallelAnimation {
3346+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height,width,scale"; duration: priv.animationDuration }
3347+ UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
3348+ }
3349+ // We need to release scaleToPreviewSize at last
3350+ PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
3351+ PropertyAction { target: appDelegate; property: "visible" }
3352+ }
3353+ },
3354+ Transition {
3355+ from: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
3356+ to: "normal,maximized,maximizedLeft,maximizedRight,maximizedTop,maximizedBottom,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
3357 enabled: appDelegate.animationsEnabled
3358- PropertyAction { target: appDelegate; property: "visuallyMinimized" }
3359 SequentialAnimation {
3360- UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,opacity,scale,requestedWidth,requestedHeight" }
3361+ PropertyAction { target: appDelegate; property: "visuallyMinimized" }
3362+ UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,opacity,scale,requestedWidth,requestedHeight,windowedWidth,windowedHeight";
3363+ duration: priv.animationDuration }
3364 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
3365 ScriptAction { script: { fakeRectangle.stop(); } }
3366 }
3367@@ -669,14 +1397,6 @@
3368 ]
3369
3370 Binding {
3371- id: previewBinding
3372- target: appDelegate
3373- property: "z"
3374- value: topLevelSurfaceList.count + 1
3375- when: index == spread.highlightedIndex && spread.ready
3376- }
3377-
3378- Binding {
3379 target: PanelState
3380 property: "buttonsAlwaysVisible"
3381 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
3382@@ -697,26 +1417,15 @@
3383 screenWidth: appContainer.width
3384 screenHeight: appContainer.height
3385 leftMargin: root.leftMargin
3386-
3387- onPressed: { appDelegate.focus = true; }
3388-
3389- Component.onCompleted: {
3390- loadWindowState();
3391- }
3392-
3393- property bool saveStateOnDestruction: true
3394- Connections {
3395- target: root
3396- onStageAboutToBeUnloaded: {
3397- resizeArea.saveWindowState();
3398- resizeArea.saveStateOnDestruction = false;
3399- fullscreenPolicy.active = false;
3400- }
3401- }
3402+ enabled: false
3403+ visible: enabled
3404+
3405+ onPressed: {
3406+ appDelegate.focus = true;
3407+ }
3408+
3409 Component.onDestruction: {
3410- if (saveStateOnDestruction) {
3411- saveWindowState();
3412- }
3413+ saveWindowState();
3414 }
3415 }
3416
3417@@ -729,14 +1438,25 @@
3418 surface: model.surface
3419 active: appDelegate.focus
3420 focus: true
3421+ interactive: root.interactive
3422+ showDecoration: 1
3423 maximizeButtonShown: appDelegate.canBeMaximized
3424 overlayShown: touchControls.overlayShown
3425+ width: implicitWidth
3426+ height: implicitHeight
3427+ highlightSize: windowInfoItem.iconMargin / 2
3428 stageWidth: appContainer.width
3429 stageHeight: appContainer.height
3430
3431 requestedWidth: appDelegate.requestedWidth
3432 requestedHeight: appDelegate.requestedHeight
3433
3434+ property int oldRequestedWidth: -1
3435+ property int oldRequestedHeight: -1
3436+
3437+ onRequestedWidthChanged: oldRequestedWidth = requestedWidth
3438+ onRequestedHeightChanged: oldRequestedHeight = requestedHeight
3439+
3440 onCloseClicked: { appDelegate.close(); }
3441 onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
3442 onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
3443@@ -744,11 +1464,34 @@
3444 onMinimizeClicked: appDelegate.minimize()
3445 onDecorationPressed: { appDelegate.focus = true; }
3446 onDecorationReleased: fakeRectangle.commit();
3447+
3448+ property real angle: 0
3449+ property real itemScale: 1
3450+ transform: [
3451+ Scale {
3452+ origin.x: 0
3453+ origin.y: decoratedWindow.implicitHeight / 2
3454+ xScale: decoratedWindow.itemScale
3455+ yScale: decoratedWindow.itemScale
3456+ },
3457+ Rotation {
3458+ origin { x: 0; y: (decoratedWindow.height / 2) }
3459+ axis { x: 0; y: 1; z: 0 }
3460+ angle: decoratedWindow.angle
3461+ }
3462+ ]
3463+ }
3464+
3465+ OpacityMask {
3466+ id: opacityEffect
3467+ anchors.fill: decoratedWindow
3468 }
3469
3470 WindowControlsOverlay {
3471 id: touchControls
3472 target: appDelegate
3473+ enabled: false
3474+ visible: enabled
3475 stageWidth: appContainer.width
3476 stageHeight: appContainer.height
3477
3478@@ -764,9 +1507,89 @@
3479 }
3480
3481 WindowedFullscreenPolicy {
3482- id: fullscreenPolicy
3483- active: true
3484- surface: model.surface
3485+ id: windowedFullscreenPolicy
3486+ active: root.mode == "windowed"
3487+ surface: model.surface
3488+ }
3489+ StagedFullscreenPolicy {
3490+ id: stagedFullscreenPolicy
3491+ active: root.mode == "staged" || root.mode == "stagedWithSideStage"
3492+ surface: model.surface
3493+ }
3494+
3495+ SpreadDelegateInputArea {
3496+ id: dragArea
3497+ objectName: "dragArea"
3498+ anchors.fill: decoratedWindow
3499+ enabled: false
3500+ closeable: !appDelegate.isDash
3501+
3502+ onClicked: {
3503+ spreadItem.highlightedIndex = index;
3504+ if (distance == 0) {
3505+ priv.goneToSpread = false;
3506+ }
3507+ }
3508+ onClose: {
3509+ priv.closingIndex = index
3510+ if (model.surface) { // could be stopped by OOM
3511+ model.surface.close()
3512+ } else if (model.application) {
3513+ root.applicationManager.stopApplication(model.application.appId);
3514+ }
3515+ }
3516+ }
3517+
3518+ WindowInfoItem {
3519+ id: windowInfoItem
3520+ objectName: "windowInfoItem"
3521+ anchors { left: parent.left; top: decoratedWindow.bottom; topMargin: units.gu(1) }
3522+ title: model.application.name
3523+ iconSource: model.application.icon
3524+ height: spreadItem.appInfoHeight
3525+ opacity: 0
3526+ z: 1
3527+ visible: opacity > 0
3528+ maxWidth: {
3529+ var nextApp = appRepeater.itemAt(index + 1);
3530+ if (nextApp) {
3531+ return nextApp.x - appDelegate.x - units.gu(1)
3532+ }
3533+ return appDelegate.width;
3534+ }
3535+
3536+ onClicked: {
3537+ spreadItem.highlightedIndex = index;
3538+ priv.goneToSpread = false;
3539+ }
3540+ }
3541+
3542+ Image {
3543+ id: closeImage
3544+ anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
3545+ source: "graphics/window-close.svg"
3546+ readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
3547+ visible: !appDelegate.isDash
3548+ && index == spreadItem.highlightedIndex
3549+ && mousePos.y < (decoratedWindow.height / 3)
3550+ && mousePos.y > -units.gu(4)
3551+ && mousePos.x > -units.gu(4)
3552+ && mousePos.x < (decoratedWindow.width * 2 / 3)
3553+ height: units.gu(2)
3554+ width: height
3555+ sourceSize.width: width
3556+ sourceSize.height: height
3557+
3558+ MouseArea {
3559+ id: closeMouseArea
3560+ objectName: "closeMouseArea"
3561+ anchors.fill: closeImage
3562+ anchors.margins: -units.gu(2)
3563+ onClicked: {
3564+ priv.closingIndex = index;
3565+ appDelegate.close();
3566+ }
3567+ }
3568 }
3569 }
3570 }
3571@@ -786,7 +1609,8 @@
3572 // NB: it does its own positioning according to the specified edge
3573 edge: Qt.RightEdge
3574
3575- onPassed: { spread.show(); }
3576+ onPassed: priv.goneToSpread = true;
3577+
3578 material: Component {
3579 Item {
3580 Rectangle {
3581@@ -803,23 +1627,248 @@
3582 }
3583 }
3584
3585+ MouseArea {
3586+ id: hoverMouseArea
3587+ objectName: "hoverMouseArea"
3588+ anchors.fill: appContainer
3589+ propagateComposedEvents: true
3590+ hoverEnabled: true
3591+ enabled: false
3592+ visible: enabled
3593+
3594+ property int scrollAreaWidth: width / 3
3595+ property bool progressiveScrollingEnabled: false
3596+
3597+ onMouseXChanged: {
3598+ mouse.accepted = false
3599+
3600+ if (hoverMouseArea.pressed) {
3601+ return;
3602+ }
3603+
3604+ // Find the hovered item and mark it active
3605+ var mapped = mapToItem(appContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
3606+ var itemUnder = appContainer.childAt(mapped.x, mapped.y)
3607+ if (itemUnder) {
3608+ mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
3609+ var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
3610+ if (delegateChild && (delegateChild.objectName === "dragArea" || delegateChild.objectName === "windowInfoItem")) {
3611+ spreadItem.highlightedIndex = appRepeater.indexOf(itemUnder)
3612+ }
3613+ }
3614+
3615+ if (floatingFlickable.contentWidth > floatingFlickable.width) {
3616+ var margins = floatingFlickable.width * 0.05;
3617+
3618+ if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
3619+ progressiveScrollingEnabled = true
3620+ }
3621+
3622+ // do we need to scroll?
3623+ if (mouseX < scrollAreaWidth + margins) {
3624+ var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
3625+ var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
3626+ floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
3627+ }
3628+ if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
3629+ var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
3630+ var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
3631+ floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
3632+ }
3633+ }
3634+ }
3635+
3636+ onPressed: mouse.accepted = false
3637+ }
3638+
3639+ FloatingFlickable {
3640+ id: floatingFlickable
3641+ objectName: "spreadFlickable"
3642+ anchors.fill: appContainer
3643+ enabled: false
3644+ contentWidth: spreadItem.spreadTotalWidth
3645+
3646+ function snap(toIndex) {
3647+ var delegate = appRepeater.itemAt(toIndex)
3648+ var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
3649+ if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
3650+ var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
3651+ snapAnimation.to = floatingFlickable.contentX - offset;
3652+ snapAnimation.start();
3653+ } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
3654+ var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
3655+ snapAnimation.to = floatingFlickable.contentX - offset;
3656+ snapAnimation.start();
3657+ }
3658+ }
3659+ UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
3660+ }
3661+
3662+ PropertyAnimation {
3663+ id: shortRightEdgeSwipeAnimation
3664+ property: "x"
3665+ to: 0
3666+ duration: priv.animationDuration
3667+ }
3668+
3669 SwipeArea {
3670+ id: rightEdgeDragArea
3671+ objectName: "rightEdgeDragArea"
3672 direction: Direction.Leftwards
3673 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
3674- width: units.gu(1)
3675- onDraggingChanged: { if (dragging) { spread.show(); } }
3676+ width: root.dragAreaWidth
3677+
3678+ property var gesturePoints: []
3679+ property bool cancelled: false
3680+
3681+ property real progress: dragging ? -touchPosition.x / root.width : 0
3682+ onProgressChanged: {
3683+ if (dragging) {
3684+ draggedProgress = progress;
3685+ }
3686+ }
3687+
3688+ property real draggedProgress: 0
3689+
3690+ onTouchPositionChanged: {
3691+ gesturePoints.push(touchPosition.x);
3692+ if (gesturePoints.length > 10) {
3693+ gesturePoints.splice(0, gesturePoints.length - 10)
3694+ }
3695+ }
3696+
3697+ onDraggingChanged: {
3698+ if (dragging) {
3699+ // A potential edge-drag gesture has started. Start recording it
3700+ gesturePoints = [];
3701+ cancelled = false;
3702+ draggedProgress = 0;
3703+ } else {
3704+ // Ok. The user released. Did he drag far enough to go to full spread?
3705+ if (gesturePoints[gesturePoints.length - 1] < -spreadItem.rightEdgeBreakPoint * spreadItem.width ) {
3706+
3707+ // He dragged far enough, but if the last movement was a flick to the right again, he wants to cancel the spread again.
3708+ var oneWayFlickToRight = true;
3709+ var smallestX = gesturePoints[0]-1;
3710+ for (var i = 0; i < gesturePoints.length; i++) {
3711+ if (gesturePoints[i] <= smallestX) {
3712+ oneWayFlickToRight = false;
3713+ break;
3714+ }
3715+ smallestX = gesturePoints[i];
3716+ }
3717+
3718+ if (!oneWayFlickToRight) {
3719+ // Ok, the user made it, let's go to spread!
3720+ priv.goneToSpread = true;
3721+ } else {
3722+ cancelled = true;
3723+ }
3724+ } else {
3725+ // Ok, the user didn't drag far enough to cross the breakPoint
3726+ // Find out if it was a one-way movement to the left, in which case we just switch directly to next app.
3727+ var oneWayFlick = true;
3728+ var smallestX = rightEdgeDragArea.width;
3729+ for (var i = 0; i < gesturePoints.length; i++) {
3730+ if (gesturePoints[i] >= smallestX) {
3731+ oneWayFlick = false;
3732+ break;
3733+ }
3734+ smallestX = gesturePoints[i];
3735+ }
3736+
3737+ if (appRepeater.count > 1 &&
3738+ (oneWayFlick && rightEdgeDragArea.distance > units.gu(2) || rightEdgeDragArea.distance > spreadItem.rightEdgeBreakPoint * spreadItem.width)) {
3739+ var nextStage = appRepeater.itemAt(priv.nextInStack).stage
3740+ for (var i = 0; i < appRepeater.count; i++) {
3741+ if (i != priv.nextInStack && appRepeater.itemAt(i).stage == nextStage) {
3742+ appRepeater.itemAt(i).playHidingAnimation()
3743+ break;
3744+ }
3745+ }
3746+ appRepeater.itemAt(priv.nextInStack).playFocusAnimation()
3747+ if (appRepeater.itemAt(priv.nextInStack).stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
3748+ sideStage.show();
3749+ }
3750+
3751+ } else {
3752+ cancelled = true;
3753+ }
3754+
3755+ gesturePoints = [];
3756+ }
3757+ }
3758+ }
3759 }
3760
3761- DesktopSpread {
3762- id: spread
3763- objectName: "spread"
3764- anchors.fill: appContainer
3765- workspace: appContainer
3766- focus: state == "altTab"
3767- altTabPressed: root.altTabPressed
3768-
3769- onPlayFocusAnimation: {
3770- appRepeater.itemAt(index).playFocusAnimation();
3771+ TabletSideStageTouchGesture {
3772+ id: triGestureArea
3773+ objectName: "triGestureArea"
3774+ anchors.fill: parent
3775+ enabled: false
3776+ property Item appDelegate
3777+
3778+ dragComponent: dragComponent
3779+ dragComponentProperties: { "appDelegate": appDelegate }
3780+
3781+ onPressed: {
3782+ function matchDelegate(obj) { return String(obj.objectName).indexOf("appDelegate") >= 0; }
3783+
3784+ var delegateAtCenter = Functions.itemAt(appContainer, x, y, matchDelegate);
3785+ if (!delegateAtCenter) return;
3786+
3787+ appDelegate = delegateAtCenter;
3788+ }
3789+
3790+ onClicked: {
3791+ if (sideStage.shown) {
3792+ sideStage.hide();
3793+ } else {
3794+ sideStage.show();
3795+ priv.updateMainAndSideStageIndexes()
3796+ }
3797+ }
3798+
3799+ onDragStarted: {
3800+ // If we're dragging to the sidestage.
3801+ if (!sideStage.shown) {
3802+ sideStage.show();
3803+ }
3804+ }
3805+
3806+ Component {
3807+ id: dragComponent
3808+ SurfaceContainer {
3809+ property Item appDelegate
3810+
3811+ surface: appDelegate ? appDelegate.surface : null
3812+
3813+ consumesInput: false
3814+ interactive: false
3815+ focus: false
3816+ requestedWidth: appDelegate.requestedWidth
3817+ requestedHeight: appDelegate.requestedHeight
3818+
3819+ width: units.gu(40)
3820+ height: units.gu(40)
3821+
3822+ Drag.hotSpot.x: width/2
3823+ Drag.hotSpot.y: height/2
3824+ // only accept opposite stage.
3825+ Drag.keys: {
3826+ if (!surface) return "Disabled";
3827+ if (appDelegate.isDash) return "Disabled";
3828+
3829+ if (appDelegate.stage === ApplicationInfo.MainStage) {
3830+ if (appDelegate.application.supportedOrientations
3831+ & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
3832+ return "MainStage";
3833+ }
3834+ return "Disabled";
3835+ }
3836+ return "SideStage";
3837+ }
3838+ }
3839 }
3840 }
3841 }
3842
3843=== added file 'qml/Stage/StageMaths.qml'
3844--- qml/Stage/StageMaths.qml 1970-01-01 00:00:00 +0000
3845+++ qml/Stage/StageMaths.qml 2016-10-05 11:22:21 +0000
3846@@ -0,0 +1,79 @@
3847+import QtQuick 2.4
3848+import Unity.Application 0.1
3849+import Ubuntu.Components 1.3
3850+
3851+QtObject {
3852+ id: root
3853+
3854+ // input
3855+ property int itemIndex: 0
3856+ property int nextInStack: 0
3857+ property int sceneWidth: 0
3858+ property int sideStageWidth: 0
3859+ property int sideStageX: sceneWidth
3860+ property bool animateX: false
3861+ property int leftEdgeDragProgress: 0
3862+
3863+ property int stage: ApplicationInfoInterface.MainStage
3864+ property var thisDelegate: null
3865+ property var mainStageDelegate: null
3866+ property var sideStageDelegate: null
3867+
3868+ // output
3869+
3870+ // We need to shuffle z ordering a bit in order to keep side stage apps above main stage apps.
3871+ // We don't want to really reorder them in the model because that allows us to keep track
3872+ // of the last focused order.
3873+ readonly property int itemZ: {
3874+ // only shuffle when we've got a main and side stage
3875+ if (thisDelegate.isDash && thisDelegate != mainStageDelegate && leftEdgeDragProgress > 0) {
3876+ return -1; // Keep the dash behind all other apps for the left edge gesture
3877+ }
3878+
3879+ if (!sideStageDelegate) return itemIndex;
3880+
3881+ // don't shuffle indexes greater than "actives or next"
3882+ if (itemIndex > 2) return itemIndex;
3883+
3884+ if (thisDelegate == mainStageDelegate) {
3885+ // Active main stage always at 0
3886+ return 0;
3887+ }
3888+
3889+ if (nextInStack > 0) {
3890+ var stageOfNextInStack = appRepeater.itemAt(nextInStack).stage;
3891+
3892+ if (itemIndex === nextInStack) {
3893+ // this is the next app in stack.
3894+
3895+ if (stage === ApplicationInfoInterface.SideStage) {
3896+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
3897+ return Math.min(2, topLevelSurfaceList.count-1);
3898+ }
3899+ return 1;
3900+ }
3901+ if (stageOfNextInStack === ApplicationInfoInterface.SideStage) {
3902+ // if the next app in stack is a sidestage app, it must order on top of other side stage app
3903+ return 1;
3904+ }
3905+ return Math.min(2, topLevelSurfaceList.count-1);
3906+ }
3907+ return Math.min(index+1, topLevelSurfaceList.count-1);
3908+ }
3909+
3910+
3911+ property int itemX: {
3912+ if (mainStageDelegate == thisDelegate) {
3913+ return thisDelegate.isDash ? 0 : leftEdgeDragProgress;
3914+ }
3915+ if (sideStageDelegate == thisDelegate) {
3916+ return sideStageX;
3917+ }
3918+ return thisDelegate.isDash && leftEdgeDragProgress > 0 ? 0 : sceneWidth;
3919+ }
3920+ Behavior on itemX { enabled: root.animateX; UbuntuNumberAnimation {} }
3921+
3922+ readonly property int itemWidth: stage == ApplicationInfoInterface.MainStage ?
3923+ sideStageDelegate != null ? sideStageX : sceneWidth :
3924+ stage == ApplicationInfoInterface.SideStage ? sideStageWidth : sceneWidth
3925+}
3926
3927=== modified file 'qml/Stage/SurfaceContainer.qml'
3928--- qml/Stages/SurfaceContainer.qml 2016-05-18 21:58:39 +0000
3929+++ qml/Stage/SurfaceContainer.qml 2016-10-05 11:22:21 +0000
3930@@ -23,6 +23,8 @@
3931 FocusScope {
3932 id: root
3933 objectName: "surfaceContainer"
3934+ implicitWidth: surfaceItem.implicitWidth
3935+ implicitHeight: surfaceItem.implicitHeight
3936
3937 // Must be set from outside
3938 property var surface: null
3939@@ -32,7 +34,6 @@
3940 property int requestedHeight: -1
3941 property bool interactive
3942 property int surfaceOrientationAngle: 0
3943- property bool resizeSurface: true
3944 property bool isPromptSurface: false
3945 // FIME - dont export, use interactive property. Need to fix qtmir to handle consumesInputChanged
3946 // to update surface activeFocus. See mock MirSurfaceItem.
3947@@ -58,35 +59,15 @@
3948 MirSurfaceItem {
3949 id: surfaceItem
3950 objectName: "surfaceItem"
3951+ anchors.fill: parent
3952
3953 focus: true
3954
3955 fillMode: MirSurfaceItem.PadOrCrop
3956 consumesInput: true
3957
3958- surfaceWidth: {
3959- if (root.resizeSurface) {
3960- if (root.requestedWidth >= 0) {
3961- return root.requestedWidth;
3962- } else {
3963- return width;
3964- }
3965- } else {
3966- return -1;
3967- }
3968- }
3969-
3970- surfaceHeight: {
3971- if (root.resizeSurface) {
3972- if (root.requestedHeight >= 0) {
3973- return root.requestedHeight;
3974- } else {
3975- return height;
3976- }
3977- } else {
3978- return -1;
3979- }
3980- }
3981+ surfaceWidth: root.requestedWidth
3982+ surfaceHeight: root.requestedHeight
3983
3984 enabled: root.interactive
3985 antialiasing: !root.interactive
3986@@ -99,34 +80,6 @@
3987 enabled: surfaceItem.enabled
3988 }
3989
3990- // MirSurface size drives SurfaceContainer size
3991- Binding {
3992- target: surfaceItem; property: "width"; value: root.surface ? root.surface.size.width : 0
3993- when: root.requestedWidth >= 0 && root.surface
3994- }
3995- Binding {
3996- target: surfaceItem; property: "height"; value: root.surface ? root.surface.size.height : 0
3997- when: root.requestedHeight >= 0 && root.surface
3998- }
3999- Binding {
4000- target: root; property: "width"; value: surfaceItem.width
4001- when: root.requestedWidth >= 0
4002- }
4003- Binding {
4004- target: root; property: "height"; value: surfaceItem.height
4005- when: root.requestedHeight >= 0
4006- }
4007-
4008- // SurfaceContainer size drives MirSurface size
4009- Binding {
4010- target: surfaceItem; property: "width"; value: root.width
4011- when: root.requestedWidth < 0
4012- }
4013- Binding {
4014- target: surfaceItem; property: "height"; value: root.height
4015- when: root.requestedHeight < 0
4016- }
4017-
4018 Loader {
4019 id: animationsLoader
4020 objectName: "animationsLoader"
4021
4022=== modified file 'qml/Stage/TopLevelSurfaceRepeater.qml'
4023--- qml/Stages/TopLevelSurfaceRepeater.qml 2016-09-07 09:48:56 +0000
4024+++ qml/Stage/TopLevelSurfaceRepeater.qml 2016-10-05 11:22:21 +0000
4025@@ -55,4 +55,13 @@
4026 startingUp = false;
4027 }
4028 }
4029+
4030+ function indexOf(delegateItem) {
4031+ for (var i = 0; i < count; i++) {
4032+ if (itemAt(i) === delegateItem) {
4033+ return i;
4034+ }
4035+ }
4036+ return -1;
4037+ }
4038 }
4039
4040=== modified file 'qml/Stage/WindowDecoration.qml'
4041--- qml/Stages/WindowDecoration.qml 2016-09-22 07:42:18 +0000
4042+++ qml/Stage/WindowDecoration.qml 2016-10-05 11:22:21 +0000
4043@@ -79,7 +79,7 @@
4044 onMaximizeClicked: root.maximizeClicked();
4045 onMaximizeHorizontallyClicked: if (root.target.canBeMaximizedHorizontally) root.maximizeHorizontallyClicked();
4046 onMaximizeVerticallyClicked: if (root.target.canBeMaximizedVertically) root.maximizeVerticallyClicked();
4047- closeButtonShown: root.target.application.appId !== "unity8-dash"
4048+ closeButtonShown: root.target.appId !== "unity8-dash"
4049 }
4050
4051 Label {
4052
4053=== added file 'qml/Stage/WindowInfoItem.qml'
4054--- qml/Stage/WindowInfoItem.qml 1970-01-01 00:00:00 +0000
4055+++ qml/Stage/WindowInfoItem.qml 2016-10-05 11:22:21 +0000
4056@@ -0,0 +1,53 @@
4057+import QtQuick 2.4
4058+import Ubuntu.Components 1.3
4059+
4060+Item {
4061+ id: root
4062+ implicitWidth: Math.max(iconShape.width, titleLabel.width)
4063+ implicitHeight: iconShape.height + titleLabel.height + labelMargin + iconMargin
4064+ property alias title: titleLabel.text
4065+ property alias iconSource: icon.source
4066+
4067+ property real iconHeight: (height - titleLabel.height) * 0.65
4068+ property real iconMargin: (height - titleLabel.height) * 0.25
4069+ property real labelMargin: (height - titleLabel.height) * 0.1
4070+ property int maxWidth: units.gu(10)
4071+
4072+ signal clicked()
4073+
4074+ ProportionalShape {
4075+ id: iconShape
4076+ anchors {
4077+ top: parent.top
4078+ topMargin: iconMargin
4079+ left: parent.left
4080+ }
4081+ height: iconHeight
4082+ borderSource: "undefined"
4083+ aspect: UbuntuShape.Flat
4084+ source: Image {
4085+ id: icon
4086+ sourceSize.width: iconShape.width
4087+ sourceSize.height: iconShape.height
4088+ cache: false // see lpbug#1543290 why no cache
4089+ }
4090+ }
4091+
4092+ MouseArea {
4093+ anchors.fill: iconShape
4094+ onClicked: root.clicked()
4095+ }
4096+
4097+ Label {
4098+ id: titleLabel
4099+ anchors {
4100+ left: iconShape.left
4101+ top: iconShape.bottom
4102+ topMargin: labelMargin
4103+ }
4104+ width: root.maxWidth
4105+ fontSize: 'small'
4106+ color: 'white'
4107+ elide: Label.ElideRight
4108+ }
4109+}
4110
4111=== modified file 'qml/Stage/WindowResizeArea.qml'
4112--- qml/Stages/WindowResizeArea.qml 2016-08-31 13:00:26 +0000
4113+++ qml/Stage/WindowResizeArea.qml 2016-10-05 11:22:21 +0000
4114@@ -75,14 +75,15 @@
4115
4116 function loadWindowState() {
4117 var windowGeometry = windowStateStorage.getGeometry(root.windowId,
4118- Qt.rect(target.requestedX, target.requestedY, defaultWidth, defaultHeight));
4119-
4120- target.requestedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
4121- target.requestedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
4122+ Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
4123+
4124+
4125+ target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
4126+ target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
4127 root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
4128- target.requestedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.requestedWidth),
4129+ target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.windowedWidth),
4130 (target.fullscreen ? 0 : root.leftMargin)); });
4131- target.requestedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight); });
4132+ target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.windowedHeight), PanelState.panelHeight); });
4133
4134 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
4135 target.restore(false /* animated */, windowState);
4136@@ -111,28 +112,28 @@
4137
4138 readonly property int minimumWidth: root.target ? Math.max(root.minWidth, root.target.minimumWidth) : root.minWidth
4139 onMinimumWidthChanged: {
4140- if (target.requestedWidth < minimumWidth) {
4141- target.requestedWidth = minimumWidth;
4142+ if (target.windowedWidth < minimumWidth) {
4143+ target.windowedWidth = minimumWidth;
4144 }
4145 }
4146 readonly property int minimumHeight: root.target ? Math.max(root.minHeight, root.target.minimumHeight) : root.minHeight
4147 onMinimumHeightChanged: {
4148- if (target.requestedHeight < minimumHeight) {
4149- target.requestedHeight = minimumHeight;
4150+ if (target.windowedHeight < minimumHeight) {
4151+ target.windowedHeight = minimumHeight;
4152 }
4153 }
4154 readonly property int maximumWidth: root.target && root.target.maximumWidth >= minimumWidth && root.target.maximumWidth > 0
4155 ? root.target.maximumWidth : maxSafeInt
4156 onMaximumWidthChanged: {
4157- if (target.requestedWidth > maximumWidth) {
4158- target.requestedWidth = maximumWidth;
4159+ if (target.windowedWidth > maximumWidth) {
4160+ target.windowedWidth = maximumWidth;
4161 }
4162 }
4163 readonly property int maximumHeight: root.target && root.target.maximumHeight >= minimumHeight && root.target.maximumHeight > 0
4164 ? root.target.maximumHeight : maxSafeInt
4165 onMaximumHeightChanged: {
4166- if (target.requestedHeight > maximumHeight) {
4167- target.requestedHeight = maximumHeight;
4168+ if (target.windowedHeight > maximumHeight) {
4169+ target.windowedHeight = maximumHeight;
4170 }
4171 }
4172 readonly property int widthIncrement: {
4173@@ -247,8 +248,8 @@
4174 var pos = mapToItem(root.target.parent, mouseX, mouseY);
4175 d.startMousePosX = pos.x;
4176 d.startMousePosY = pos.y;
4177- d.startX = target.requestedX;
4178- d.startY = target.requestedY;
4179+ d.startX = target.windowedX;
4180+ d.startY = target.windowedY;
4181 d.startWidth = target.width;
4182 d.startHeight = target.height;
4183 d.currentWidth = target.width;
4184@@ -285,53 +286,53 @@
4185
4186 if (d.leftBorder) {
4187 var newTargetX = d.startX + deltaX;
4188- var rightBorderX = target.requestedX + target.width;
4189+ var rightBorderX = target.windowedX + target.width;
4190 if (rightBorderX > newTargetX + d.minimumWidth) {
4191 if (rightBorderX < newTargetX + d.maximumWidth) {
4192- target.requestedWidth = rightBorderX - newTargetX;
4193+ target.windowedWidth = rightBorderX - newTargetX;
4194 } else {
4195- target.requestedWidth = d.maximumWidth;
4196+ target.windowedWidth = d.maximumWidth;
4197 }
4198 } else {
4199- target.requestedWidth = d.minimumWidth;
4200+ target.windowedWidth = d.minimumWidth;
4201 }
4202
4203 } else if (d.rightBorder) {
4204 var newWidth = d.startWidth + deltaX;
4205 if (newWidth > d.minimumWidth) {
4206 if (newWidth < d.maximumWidth) {
4207- target.requestedWidth = newWidth;
4208+ target.windowedWidth = newWidth;
4209 } else {
4210- target.requestedWidth = d.maximumWidth;
4211+ target.windowedWidth = d.maximumWidth;
4212 }
4213 } else {
4214- target.requestedWidth = d.minimumWidth;
4215+ target.windowedWidth = d.minimumWidth;
4216 }
4217 }
4218
4219 if (d.topBorder) {
4220 var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
4221- var bottomBorderY = target.requestedY + target.height;
4222+ var bottomBorderY = target.windowedY + target.height;
4223 if (bottomBorderY > newTargetY + d.minimumHeight) {
4224 if (bottomBorderY < newTargetY + d.maximumHeight) {
4225- target.requestedHeight = bottomBorderY - newTargetY;
4226+ target.windowedHeight = bottomBorderY - newTargetY;
4227 } else {
4228- target.requestedHeight = d.maximumHeight;
4229+ target.windowedHeight = d.maximumHeight;
4230 }
4231 } else {
4232- target.requestedHeight = d.minimumHeight;
4233+ target.windowedHeight = d.minimumHeight;
4234 }
4235
4236 } else if (d.bottomBorder) {
4237 var newHeight = d.startHeight + deltaY;
4238 if (newHeight > d.minimumHeight) {
4239 if (newHeight < d.maximumHeight) {
4240- target.requestedHeight = newHeight;
4241+ target.windowedHeight = newHeight;
4242 } else {
4243- target.requestedHeight = d.maximumHeight;
4244+ target.windowedHeight = d.maximumHeight;
4245 }
4246 } else {
4247- target.requestedHeight = d.minimumHeight;
4248+ target.windowedHeight = d.minimumHeight;
4249 }
4250 }
4251 }
4252@@ -340,13 +341,13 @@
4253 target: root.target
4254 onWidthChanged: {
4255 if (d.moveLeftBorder) {
4256- target.requestedX += d.currentWidth - target.width;
4257+ target.windowedX += d.currentWidth - target.width;
4258 }
4259 d.currentWidth = target.width;
4260 }
4261 onHeightChanged: {
4262 if (d.moveTopBorder) {
4263- target.requestedY += d.currentHeight - target.height;
4264+ target.windowedY += d.currentHeight - target.height;
4265 }
4266 d.currentHeight = target.height;
4267 }
4268
4269=== removed file 'qml/Stages/AbstractStage.qml'
4270--- qml/Stages/AbstractStage.qml 2016-09-07 08:36:59 +0000
4271+++ qml/Stages/AbstractStage.qml 1970-01-01 00:00:00 +0000
4272@@ -1,93 +0,0 @@
4273-/*
4274- * Copyright (C) 2015-2016 Canonical, Ltd.
4275- *
4276- * This program is free software; you can redistribute it and/or modify
4277- * it under the terms of the GNU General Public License as published by
4278- * the Free Software Foundation; version 3.
4279- *
4280- * This program is distributed in the hope that it will be useful,
4281- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4282- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4283- * GNU General Public License for more details.
4284- *
4285- * You should have received a copy of the GNU General Public License
4286- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4287- */
4288-
4289-import QtQuick 2.4
4290-import Ubuntu.Components 1.3
4291-import GlobalShortcut 1.0
4292-import GSettings 1.0
4293-
4294-FocusScope {
4295- id: root
4296-
4297- // Controls to be set from outside
4298- property QtObject applicationManager
4299- property QtObject topLevelSurfaceList
4300- property bool altTabPressed
4301- property url background
4302- property bool beingResized
4303- property int dragAreaWidth
4304- property real dragProgress // How far left the stage has been dragged, used externally by tutorial code
4305- property bool interactive
4306- property real inverseProgress // This is the progress for left edge drags, in pixels.
4307- property bool keepDashRunning: true
4308- property real maximizedAppTopMargin
4309- property real nativeHeight
4310- property real nativeWidth
4311- property QtObject orientations
4312- property int shellOrientation
4313- property int shellOrientationAngle
4314- property bool spreadEnabled: true // If false, animations and right edge will be disabled
4315- property bool suspended
4316- // A Stage should paint a wallpaper etc over its full size but not use the margins for window placement
4317- property int leftMargin: 0
4318- property alias paintBackground: background.visible
4319- property bool oskEnabled: false
4320-
4321- // To be read from outside
4322- property var mainApp: null
4323- property int mainAppWindowOrientationAngle: 0
4324- property bool orientationChangesEnabled
4325- property int supportedOrientations: Qt.PortraitOrientation
4326- | Qt.LandscapeOrientation
4327- | Qt.InvertedPortraitOrientation
4328- | Qt.InvertedLandscapeOrientation
4329-
4330- property Item itemConfiningMouseCursor: null
4331-
4332-
4333- signal stageAboutToBeUnloaded
4334- signal itemSnapshotRequested(Item item)
4335-
4336- // Shared code for use in stage implementations
4337- GSettings {
4338- id: lifecycleExceptions
4339- schema.id: "com.canonical.qtmir"
4340- }
4341-
4342- function isExemptFromLifecycle(appId) {
4343- var shortAppId = appId.split('_')[0];
4344- for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
4345- if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
4346- return true;
4347- }
4348- }
4349- return false;
4350- }
4351-
4352- Rectangle {
4353- id: background
4354- color: "#060606"
4355- anchors.fill: parent
4356- }
4357-
4358- // shared Alt+F4 functionality
4359- function closeFocusedDelegate() {} // to be implemented by stages
4360-
4361- GlobalShortcut {
4362- shortcut: Qt.AltModifier|Qt.Key_F4
4363- onTriggered: closeFocusedDelegate()
4364- }
4365-}
4366
4367=== removed file 'qml/Stages/DesktopSpread.qml'
4368--- qml/Stages/DesktopSpread.qml 2016-06-15 14:08:18 +0000
4369+++ qml/Stages/DesktopSpread.qml 1970-01-01 00:00:00 +0000
4370@@ -1,576 +0,0 @@
4371-/*
4372- * Copyright (C) 2015-2016 Canonical, Ltd.
4373- *
4374- * This program is free software; you can redistribute it and/or modify
4375- * it under the terms of the GNU General Public License as published by
4376- * the Free Software Foundation; version 3.
4377- *
4378- * This program is distributed in the hope that it will be useful,
4379- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4380- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4381- * GNU General Public License for more details.
4382- *
4383- * You should have received a copy of the GNU General Public License
4384- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4385- */
4386-
4387-import QtQuick 2.4
4388-import QtQuick.Layouts 1.1
4389-import Ubuntu.Components 1.3
4390-import Ubuntu.Gestures 0.1
4391-import Unity.Application 0.1
4392-import "../Components"
4393-import Utils 0.1
4394-
4395-FocusScope {
4396- id: root
4397-
4398- property bool altTabPressed: false
4399- property Item workspace: null
4400-
4401- readonly property alias ready: blurLayer.ready
4402- readonly property alias highlightedIndex: spreadRepeater.highlightedIndex
4403-
4404- signal playFocusAnimation(int index)
4405-
4406- function show() {
4407- spreadContainer.animateIn = true;
4408- root.state = "altTab";
4409- }
4410-
4411- onFocusChanged: {
4412- // When the spread comes active, we want to keep focus to the input handler below
4413- // Make sure nothing inside the ApplicationWindow grabs our focus!
4414- if (focus) {
4415- forceActiveFocus();
4416- }
4417- }
4418-
4419- Keys.onPressed: {
4420- switch (event.key) {
4421- case Qt.Key_Left:
4422- case Qt.Key_Backtab:
4423- selectPrevious(event.isAutoRepeat)
4424- event.accepted = true;
4425- break;
4426- case Qt.Key_Right:
4427- case Qt.Key_Tab:
4428- selectNext(event.isAutoRepeat)
4429- event.accepted = true;
4430- break;
4431- case Qt.Key_Escape:
4432- spreadRepeater.highlightedIndex = -1
4433- // Falling through intentionally
4434- case Qt.Key_Enter:
4435- case Qt.Key_Return:
4436- case Qt.Key_Space:
4437- root.state = ""
4438- event.accepted = true;
4439- }
4440- }
4441-
4442- function selectNext(isAutoRepeat) {
4443- if (isAutoRepeat && spreadRepeater.highlightedIndex >= topLevelSurfaceList.count -1) {
4444- return; // AutoRepeat is not allowed to wrap around
4445- }
4446-
4447- spreadRepeater.highlightedIndex = (spreadRepeater.highlightedIndex + 1) % topLevelSurfaceList.count;
4448- var newContentX = ((spreadFlickable.contentWidth) / (topLevelSurfaceList.count + 1)) * Math.max(0, Math.min(topLevelSurfaceList.count - 5, spreadRepeater.highlightedIndex - 3));
4449- if (spreadFlickable.contentX < newContentX || spreadRepeater.highlightedIndex == 0) {
4450- spreadFlickable.snapTo(newContentX)
4451- }
4452- }
4453-
4454- function selectPrevious(isAutoRepeat) {
4455- if (isAutoRepeat && spreadRepeater.highlightedIndex == 0) {
4456- return; // AutoRepeat is not allowed to wrap around
4457- }
4458-
4459- var newIndex = spreadRepeater.highlightedIndex - 1 >= 0 ? spreadRepeater.highlightedIndex - 1 : topLevelSurfaceList.count - 1;
4460- spreadRepeater.highlightedIndex = newIndex;
4461- var newContentX = ((spreadFlickable.contentWidth) / (topLevelSurfaceList.count + 1)) * Math.max(0, Math.min(topLevelSurfaceList.count - 5, spreadRepeater.highlightedIndex - 1));
4462- if (spreadFlickable.contentX > newContentX || newIndex == topLevelSurfaceList.count -1) {
4463- spreadFlickable.snapTo(newContentX)
4464- }
4465- }
4466-
4467- function focusSelected() {
4468- if (spreadRepeater.highlightedIndex != -1) {
4469- if (spreadContainer.visible) {
4470- root.playFocusAnimation(spreadRepeater.highlightedIndex)
4471- }
4472- var surface = topLevelSurfaceList.surfaceAt(spreadRepeater.highlightedIndex);
4473- surface.requestFocus();
4474- }
4475- }
4476-
4477- function cancel() {
4478- spreadRepeater.highlightedIndex = -1;
4479- state = ""
4480- }
4481-
4482- BlurLayer {
4483- id: blurLayer
4484- anchors.fill: parent
4485- source: root.workspace
4486- visible: false
4487- }
4488-
4489- Rectangle {
4490- id: spreadBackground
4491- anchors.fill: parent
4492- color: "#B2000000"
4493- visible: false
4494- opacity: visible ? 1 : 0
4495- Behavior on opacity {
4496- UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4497- }
4498- }
4499-
4500- MouseArea {
4501- id: eventEater
4502- anchors.fill: parent
4503- visible: spreadBackground.visible
4504- enabled: visible
4505- acceptedButtons: Qt.AllButtons
4506- onWheel: wheel.accepted = true;
4507- }
4508-
4509- Item {
4510- id: spreadContainer
4511- objectName: "spreadContainer"
4512- anchors.fill: parent
4513- visible: false
4514-
4515- property bool animateIn: false
4516-
4517- Repeater {
4518- id: spreadRepeater
4519- objectName: "spreadRepeater"
4520- model: topLevelSurfaceList
4521-
4522- property int highlightedIndex: -1
4523- property int closingIndex: -1
4524-
4525- function indexOf(delegateItem) {
4526- for (var i = 0; i < spreadRepeater.count; i++) {
4527- if (spreadRepeater.itemAt(i) === delegateItem) {
4528- return i;
4529- }
4530- }
4531- return -1;
4532- }
4533-
4534- delegate: Item {
4535- id: spreadDelegate
4536- objectName: "spreadDelegate"
4537- width: units.gu(20)
4538- height: units.gu(20)
4539-
4540- property real angle: 0
4541- property real itemScale: 1
4542- property int itemScaleOriginX: 0
4543- property int itemScaleOriginY: 0
4544-
4545- readonly property string windowTitle: clippedSpreadDelegate.window.title
4546-
4547- Behavior on x {
4548- id: closeBehavior
4549- enabled: spreadRepeater.closingIndex >= 0
4550- UbuntuNumberAnimation {
4551- onRunningChanged: if (!running) spreadRepeater.closingIndex = -1
4552- }
4553- }
4554-
4555- DesktopSpreadDelegate {
4556- id: clippedSpreadDelegate
4557- objectName: "clippedSpreadDelegate"
4558- anchors.left: parent.left
4559- anchors.top: parent.top
4560- application: model.application
4561- surface: model.surface
4562- width: spreadMaths.spreadHeight
4563- height: spreadMaths.spreadHeight
4564-
4565- transform: [
4566- Scale {
4567- origin.x: itemScaleOriginX
4568- origin.y: itemScaleOriginY
4569- xScale: itemScale
4570- yScale: itemScale
4571- },
4572- Rotation {
4573- origin { x: 0; y: (clippedSpreadDelegate.height - (clippedSpreadDelegate.height * itemScale / 2)) }
4574- axis { x: 0; y: 1; z: 0 }
4575- angle: spreadDelegate.angle
4576- }
4577- ]
4578-
4579- MouseArea {
4580- id: spreadSelectArea
4581- anchors.fill: parent
4582- anchors.margins: -units.gu(2)
4583- enabled: false
4584- onClicked: {
4585- spreadRepeater.highlightedIndex = index;
4586- root.state = "";
4587- }
4588- }
4589- }
4590-
4591- SpreadMaths {
4592- id: spreadMaths
4593- flickable: spreadFlickable
4594- itemIndex: index
4595- totalItems: Math.max(6, topLevelSurfaceList.count)
4596- sceneHeight: root.height
4597- itemHeight: spreadDelegate.height
4598- }
4599-
4600- states: [
4601- State {
4602- name: "altTab"; when: root.state == "altTab" && spreadContainer.visible
4603- PropertyChanges {
4604- target: spreadDelegate
4605- x: spreadMaths.animatedX
4606- y: spreadMaths.animatedY + (spreadDelegate.height - clippedSpreadDelegate.height) - units.gu(2)
4607- width: spreadMaths.spreadHeight
4608- height: spreadMaths.sceneHeight
4609- angle: spreadMaths.animatedAngle
4610- itemScale: spreadMaths.scale
4611- itemScaleOriginY: clippedSpreadDelegate.height / 2;
4612- z: index
4613- visible: spreadMaths.itemVisible
4614- }
4615- PropertyChanges {
4616- target: clippedSpreadDelegate
4617- highlightShown: index == spreadRepeater.highlightedIndex
4618- state: "transformed"
4619- shadowOpacity: spreadMaths.shadowOpacity
4620- anchors.topMargin: units.gu(2)
4621- }
4622- PropertyChanges {
4623- target: tileInfo
4624- visible: true
4625- opacity: spreadMaths.tileInfoOpacity
4626- }
4627- PropertyChanges {
4628- target: spreadSelectArea
4629- enabled: true
4630- }
4631- }
4632- ]
4633- transitions: [
4634- Transition {
4635- from: ""
4636- to: "altTab"
4637- SequentialAnimation {
4638- ParallelAnimation {
4639- PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
4640- PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
4641- PropertyAnimation {
4642- target: spreadDelegate; properties: "x"
4643- from: root.width
4644- duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration :0
4645- easing: UbuntuAnimation.StandardEasing
4646- }
4647- UbuntuNumberAnimation { target: clippedSpreadDelegate; property: "shadowOpacity"; from: 0; to: spreadMaths.shadowOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
4648- UbuntuNumberAnimation { target: tileInfo; property: "opacity"; from: 0; to: spreadMaths.tileInfoOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
4649- }
4650- PropertyAction { target: spreadSelectArea; property: "enabled" }
4651- }
4652- }
4653- ]
4654-
4655- MouseArea {
4656- id: tileInfo
4657- objectName: "tileInfo"
4658- anchors {
4659- left: parent.left
4660- top: clippedSpreadDelegate.bottom
4661- topMargin: ((spreadMaths.sceneHeight - spreadDelegate.y) - clippedSpreadDelegate.height) * 0.2
4662- }
4663- property int nextItemX: spreadRepeater.count > index + 1 ? spreadRepeater.itemAt(index + 1).x : spreadDelegate.x + units.gu(30)
4664- width: Math.min(units.gu(30), nextItemX - spreadDelegate.x)
4665- height: titleInfoColumn.height
4666- visible: false
4667- hoverEnabled: true
4668-
4669- onContainsMouseChanged: {
4670- if (containsMouse) {
4671- spreadRepeater.highlightedIndex = index
4672- }
4673- }
4674-
4675- onClicked: {
4676- root.state = ""
4677- }
4678-
4679- ColumnLayout {
4680- id: titleInfoColumn
4681- anchors { left: parent.left; top: parent.top; right: parent.right }
4682- spacing: units.gu(1)
4683-
4684- UbuntuShapeForItem {
4685- Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
4686- Layout.preferredWidth: height * 8 / 7.6
4687- image: Image {
4688- anchors.fill: parent
4689- source: model.application.icon
4690- Rectangle {
4691- anchors.fill: parent
4692- color: "black"
4693- opacity: clippedSpreadDelegate.highlightShown ? 0 : .1
4694- Behavior on opacity {
4695- UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4696- }
4697- }
4698- }
4699- }
4700- Label {
4701- Layout.fillWidth: true
4702- Layout.preferredHeight: units.gu(6)
4703- text: model.application ? model.application.name : spreadDelegate.windowTitle
4704- wrapMode: Text.WordWrap
4705- elide: Text.ElideRight
4706- maximumLineCount: 2
4707- }
4708- }
4709- }
4710-
4711- Image {
4712- id: closeImage
4713- anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset + units.gu(2) }
4714- source: "graphics/window-close.svg"
4715- readonly property var mousePos: hoverMouseArea.mapToItem(spreadDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
4716- visible: index == spreadRepeater.highlightedIndex
4717- && mousePos.y < (clippedSpreadDelegate.height / 3)
4718- && mousePos.y > -units.gu(4)
4719- && mousePos.x > -units.gu(4)
4720- && mousePos.x < (clippedSpreadDelegate.width * 2 / 3)
4721- height: units.gu(1.5)
4722- width: height
4723- sourceSize.width: width
4724- sourceSize.height: height
4725-
4726- MouseArea {
4727- id: closeMouseArea
4728- objectName: "closeMouseArea"
4729- anchors.fill: closeImage
4730- anchors.margins: -units.gu(2)
4731- onClicked: {
4732- spreadRepeater.closingIndex = index;
4733- model.surface.close();
4734- }
4735- }
4736- }
4737- }
4738- }
4739- }
4740-
4741-
4742- MouseArea {
4743- id: hoverMouseArea
4744- objectName: "hoverMouseArea"
4745- anchors.fill: spreadContainer
4746- propagateComposedEvents: true
4747- hoverEnabled: true
4748- enabled: false
4749- visible: enabled
4750-
4751- property int scrollAreaWidth: root.width / 3
4752- property bool progressiveScrollingEnabled: false
4753-
4754- onMouseXChanged: {
4755- mouse.accepted = false
4756-
4757- if (hoverMouseArea.pressed) {
4758- return;
4759- }
4760-
4761- // Find the hovered item and mark it active
4762- var mapped = mapToItem(spreadContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
4763- var itemUnder = spreadContainer.childAt(mapped.x, mapped.y)
4764- if (itemUnder) {
4765- mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
4766- var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
4767- if (delegateChild && (delegateChild.objectName === "clippedSpreadDelegate" || delegateChild.objectName === "tileInfo")) {
4768- spreadRepeater.highlightedIndex = spreadRepeater.indexOf(itemUnder)
4769- }
4770- }
4771-
4772- if (spreadFlickable.contentWidth > spreadFlickable.minContentWidth) {
4773- var margins = spreadFlickable.width * 0.05;
4774-
4775- if (!progressiveScrollingEnabled && mouseX < spreadFlickable.width - scrollAreaWidth) {
4776- progressiveScrollingEnabled = true
4777- }
4778-
4779- // do we need to scroll?
4780- if (mouseX < scrollAreaWidth + margins) {
4781- var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
4782- var contentX = (1 - progress) * (spreadFlickable.contentWidth - spreadFlickable.width)
4783- spreadFlickable.contentX = Math.max(0, Math.min(spreadFlickable.contentX, contentX))
4784- }
4785- if (mouseX > spreadFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
4786- var progress = Math.min(1, (mouseX - (spreadFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
4787- var contentX = progress * (spreadFlickable.contentWidth - spreadFlickable.width)
4788- spreadFlickable.contentX = Math.min(spreadFlickable.contentWidth - spreadFlickable.width, Math.max(spreadFlickable.contentX, contentX))
4789- }
4790- }
4791- }
4792- onPressed: mouse.accepted = false
4793- }
4794-
4795- FloatingFlickable {
4796- id: spreadFlickable
4797- objectName: "spreadFlickable"
4798- anchors.fill: parent
4799- property int minContentWidth: 6 * Math.min(height / 4, width / 5)
4800- contentWidth: Math.max(6, topLevelSurfaceList.count) * Math.min(height / 4, width / 5)
4801- enabled: false
4802-
4803- function snapTo(contentX) {
4804- snapAnimation.stop();
4805- snapAnimation.to = contentX
4806- snapAnimation.start();
4807- }
4808-
4809- UbuntuNumberAnimation {
4810- id: snapAnimation
4811- target: spreadFlickable
4812- property: "contentX"
4813- }
4814- }
4815-
4816- Item {
4817- id: workspaceSelector
4818- anchors {
4819- left: parent.left
4820- top: parent.top
4821- right: parent.right
4822- topMargin: units.gu(3.5)
4823- }
4824- height: root.height * 0.25
4825- visible: false
4826-
4827- RowLayout {
4828- anchors.fill: parent
4829- spacing: units.gu(1)
4830- Item { Layout.fillWidth: true }
4831- Repeater {
4832- model: 1 // TODO: will be a workspacemodel in the future
4833- Item {
4834- Layout.fillHeight: true
4835- Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
4836- Image {
4837- source: root.background
4838- anchors {
4839- left: parent.left
4840- right: parent.right
4841- verticalCenter: parent.verticalCenter
4842- }
4843- height: parent.height * 0.75
4844-
4845- ShaderEffect {
4846- anchors.fill: parent
4847-
4848- property var source: ShaderEffectSource {
4849- id: shaderEffectSource
4850- sourceItem: root.workspace
4851- }
4852-
4853- fragmentShader: "
4854- varying highp vec2 qt_TexCoord0;
4855- uniform sampler2D source;
4856- void main(void)
4857- {
4858- highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
4859- gl_FragColor = sourceColor;
4860- }"
4861- }
4862- }
4863-
4864- // TODO: This is the bar for the currently selected workspace
4865- // Enable this once the workspace stuff is implemented
4866- // Rectangle {
4867- // anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
4868- // height: units.dp(2)
4869- // color: theme.palette.normal.focus
4870- // visible: index == 0 // TODO: should be active workspace index
4871- // }
4872- }
4873-
4874- }
4875- // TODO: This is the "new workspace" button. Enable this once workspaces are implemented
4876- // Item {
4877- // Layout.fillHeight: true
4878- // Layout.preferredWidth: ((height - units.gu(6)) * root.width / root.height)
4879- // Rectangle {
4880- // anchors {
4881- // left: parent.left
4882- // right: parent.right
4883- // verticalCenter: parent.verticalCenter
4884- // }
4885- // height: parent.height * 0.75
4886- // color: "#22ffffff"
4887-
4888- // Label {
4889- // anchors.centerIn: parent
4890- // font.pixelSize: parent.height / 2
4891- // text: "+"
4892- // }
4893- // }
4894- // }
4895- Item { Layout.fillWidth: true }
4896- }
4897- }
4898-
4899- Label {
4900- id: currentSelectedLabel
4901- anchors { bottom: parent.bottom; bottomMargin: root.height * 0.625; horizontalCenter: parent.horizontalCenter }
4902- text: spreadRepeater.highlightedIndex >= 0 ? spreadRepeater.itemAt(spreadRepeater.highlightedIndex).windowTitle: ""
4903- visible: false
4904- fontSize: "large"
4905- }
4906-
4907- states: [
4908- State {
4909- name: "altTab"; when: root.altTabPressed
4910- PropertyChanges { target: blurLayer; saturation: 0.8; blurRadius: 60; visible: true }
4911- PropertyChanges { target: workspaceSelector; visible: true }
4912- PropertyChanges { target: spreadContainer; visible: true }
4913- PropertyChanges { target: spreadFlickable; enabled: spreadFlickable.contentWidth > spreadFlickable.minContentWidth }
4914- PropertyChanges { target: currentSelectedLabel; visible: true }
4915- PropertyChanges { target: spreadBackground; visible: true }
4916- PropertyChanges { target: hoverMouseArea; enabled: true }
4917- }
4918- ]
4919- transitions: [
4920- Transition {
4921- from: "*"
4922- to: "altTab"
4923- SequentialAnimation {
4924- PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: Math.min(topLevelSurfaceList.count - 1, 1) }
4925- PauseAnimation { duration: spreadContainer.animateIn ? 0 : 140 }
4926- PropertyAction { target: workspaceSelector; property: "visible" }
4927- PropertyAction { target: spreadContainer; property: "visible" }
4928- ParallelAnimation {
4929- UbuntuNumberAnimation { target: blurLayer; properties: "saturation,blurRadius"; duration: UbuntuAnimation.SnapDuration }
4930- PropertyAction { target: spreadFlickable; property: "visible" }
4931- PropertyAction { targets: [currentSelectedLabel,spreadBackground]; property: "visible" }
4932- PropertyAction { target: spreadFlickable; property: "contentX"; value: 0 }
4933- }
4934- PropertyAction { target: hoverMouseArea; properties: "enabled,progressiveScrollingEnabled"; value: false }
4935- }
4936- },
4937- Transition {
4938- from: "*"
4939- to: "*"
4940- PropertyAnimation { property: "opacity" }
4941- ScriptAction { script: { root.focusSelected() } }
4942- PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: -1 }
4943- PropertyAction { target: spreadContainer; property: "animateIn"; value: false }
4944- }
4945- ]
4946-}
4947
4948=== removed file 'qml/Stages/DesktopSpreadDelegate.qml'
4949--- qml/Stages/DesktopSpreadDelegate.qml 2016-05-17 20:46:51 +0000
4950+++ qml/Stages/DesktopSpreadDelegate.qml 1970-01-01 00:00:00 +0000
4951@@ -1,126 +0,0 @@
4952-/*
4953- * Copyright (C) 2014-2016 Canonical, Ltd.
4954- *
4955- * This program is free software; you can redistribute it and/or modify
4956- * it under the terms of the GNU General Public License as published by
4957- * the Free Software Foundation; version 3.
4958- *
4959- * This program is distributed in the hope that it will be useful,
4960- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4961- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4962- * GNU General Public License for more details.
4963- *
4964- * You should have received a copy of the GNU General Public License
4965- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4966- *
4967- * Authors: Michael Zanetti <michael.zanetti@canonical.com>
4968- */
4969-
4970-import QtQuick 2.4
4971-import Ubuntu.Components 1.3
4972-import Unity.Application 0.1
4973-
4974-Item {
4975- id: root
4976-
4977- property alias window: applicationWindow
4978- property alias application: applicationWindow.application
4979- property alias surface: applicationWindow.surface
4980-
4981- property bool highlightShown: false
4982- property real shadowOpacity: 1
4983-
4984- property int windowWidth: surface ? surface.size.width : 0
4985- property int windowHeight: surface ? surface.size.height : 0
4986-
4987- state: "normal"
4988- states: [
4989- State {
4990- name: "normal"
4991- PropertyChanges {
4992- target: root
4993- width: windowWidth
4994- height: windowHeight
4995- }
4996- },
4997- State {
4998- name: "transformed"
4999- PropertyChanges {
5000- target: applicationWindow
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches