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