@@ -0,0 +1,360 @@
1+import QtQuick 2.0
2+import Ubuntu.Components 0.1
3+import "../Components"
4+import "../SideStage"
5+import Unity.Application 0.1
6+import Ubuntu.Gestures 0.1
7+
8+Item {
9+ id: root
10+ objectName: "stages"
11+ anchors.fill: parent
12+
13+ // Controls to be set from outside
14+ property bool shown: false
15+ property bool moving: false
16+ property int dragAreaWidth
17+
18+ // State information propagated to the outside
19+ readonly property bool painting: mainStageImage.visible || sideStageImage.visible || sideStageSnapAnimation.running
20+ property bool fullscreen: priv.focusedApplication ? priv.focusedApplication.fullscreen : false
21+ property bool overlayMode: (sideStageImage.shown && priv.mainStageAppId.length == 0) || priv.overlayOverride
22+
23+ readonly property int overlayWidth: priv.overlayOverride ? 0 : priv.sideStageWidth
24+
25+
26+ onShownChanged: {
27+// print("shown", shown)
28+ if (!shown) {
29+ priv.mainStageAppId = "";
30+ }
31+ }
32+
33+ onMovingChanged: {
34+// print("moving", moving, priv.haveMainStageApp, priv.haveSideStageApp)
35+ if (moving) {
36+ if (!priv.mainStageAppId && !priv.sideStageAppId) {
37+ // Pulling in from the right, make the last used (topmost) app visible
38+ var application = ApplicationManager.get(0);
39+ if (application.stage == ApplicationInfoInterface.SideStage) {
40+ sideStageImage.application = application;
41+ sideStageImage.x = root.width - sideStageImage.width
42+ sideStageImage.visible = true;
43+ } else {
44+ mainStageImage.application = application;
45+ mainStageImage.visible = true;
46+ }
47+ } else {
48+ priv.requestNewScreenshot(ApplicationInfoInterface.MainStage)
49+ if (priv.focusedApplicationId == priv.sideStageAppId) {
50+ priv.requestNewScreenshot(ApplicationInfoInterface.SideStage)
51+ }
52+ }
53+ } else {
54+ mainStageImage.visible = false;
55+ sideStageImage.visible = false;
56+ }
57+ }
58+
59+// Rectangle { anchors.fill: parent; color: "blue"; opacity: 0.5 }
60+
61+ QtObject {
62+ id: priv
63+
64+ property int sideStageWidth: units.gu(40)
65+
66+
67+ property string sideStageAppId
68+ property string mainStageAppId
69+
70+
71+ property var sideStageApp: ApplicationManager.findApplication(sideStageAppId)
72+ property var mainStageApp: ApplicationManager.findApplication(mainStageAppId)
73+
74+ property string sideStageScreenshot: sideStageApp ? sideStageApp.screenshot : ""
75+ property string mainStageScreenshot: mainStageApp ? mainStageApp.screenshot : ""
76+
77+ property string focusedApplicationId: ApplicationManager.focusedApplicationId
78+ property var focusedApplication: ApplicationManager.findApplication(focusedApplicationId)
79+ property url focusedScreenshot: focusedApplication ? focusedApplication.screenshot : ""
80+
81+ property bool waitingForMainScreenshot: false
82+ property bool waitingForSideScreenshot: false
83+ property bool waitingForScreenshots: waitingForMainScreenshot || waitingForSideScreenshot
84+
85+
86+ // Keep overlayMode even if there is no focused app (to allow pulling in the sidestage from the right)
87+ property bool overlayOverride: false
88+
89+ onFocusedApplicationChanged: {
90+ if (focusedApplication) {
91+ if (focusedApplication.stage == ApplicationInfoInterface.MainStage) {
92+ mainStageAppId = focusedApplicationId;
93+ } else if (focusedApplication.stage == ApplicationInfoInterface.SideStage) {
94+ sideStageAppId = focusedApplicationId;
95+ }
96+ }
97+ }
98+
99+ onMainStageScreenshotChanged: {
100+ print("------------------------------------------0")
101+ waitingForMainScreenshot = false;
102+ }
103+
104+ onSideStageScreenshotChanged: {
105+ print("------------------------------------------1")
106+ waitingForSideScreenshot = false;
107+ }
108+
109+ onFocusedScreenshotChanged: {
110+ print("##########################################", root.overlayMode)
111+ waitingForSideScreenshot = false;
112+ }
113+
114+ onWaitingForScreenshotsChanged: {
115+ print("********************++ waitingForScreenshotsChanged:", waitingForScreenshots);
116+ if (waitingForScreenshots) {
117+ return;
118+ }
119+
120+ if (root.moving) {
121+ if (mainStageAppId) {
122+ mainStageImage.application = mainStageApp
123+ mainStageImage.visible = true;
124+ }
125+ if (sideStageAppId && focusedApplicationId == sideStageAppId) {
126+ sideStageImage.application = sideStageApp;
127+ sideStageImage.x = root.width - sideStageImage.width
128+ print("setting side stage screenshot visiblr")
129+ sideStageImage.visible = true;
130+ }
131+ }
132+ if (sideStageHandleMouseArea.pressed) {
133+ if (sideStageAppId) {
134+ print("setting side stage screenshot to", sideStageAppId)
135+ sideStageImage.application = sideStageApp;
136+ sideStageImage.x = root.width - sideStageImage.width
137+ print("setting side stage screenshot visiblr")
138+ sideStageImage.visible = true;
139+ }
140+ if (mainStageAppId) {
141+ mainStageImage.application = mainStageApp
142+ mainStageImage.visible = true;
143+ }
144+ }
145+ }
146+
147+ function requestNewScreenshot(stage) {
148+ print("** requestNewScreenshot called for stage", stage, mainStageAppId, sideStageAppId)
149+ if (stage == ApplicationInfoInterface.MainStage && mainStageAppId) {
150+ print("requesting new MainStage screenshot")
151+ waitingForMainScreenshot = true;
152+ ApplicationManager.updateScreenshot(mainStageAppId);
153+ } else if (stage == ApplicationInfoInterface.SideStage && sideStageAppId) {
154+ print("requesting new SideStage screenshot")
155+ waitingForSideScreenshot = true;
156+ ApplicationManager.updateScreenshot(sideStageAppId);
157+ }
158+ }
159+
160+ }
161+ // FIXME: the signal connection seems to get lost with the fake application manager.
162+ // Check with Qt 5.2, see if we can remove this Connections object
163+ Connections {
164+ target: priv.sideStageApp
165+ onScreenshotChanged: priv.sideStageScreenshot = priv.sideStageApp.screenshot
166+ }
167+ Connections {
168+ target: priv.mainStageApp
169+ onScreenshotChanged: priv.mainStageScreenshot = priv.mainStageApp.screenshot
170+ }
171+
172+ Connections {
173+ target: ApplicationManager
174+
175+// onApplicationAdded: {
176+// var application = ApplicationManager.findApplication(appId)
177+// print("Application added:", appId, application.state)
178+// if (application.stage == ApplicationInfoInterface.SideStage) {
179+// priv.sideStageAppId = appId;
180+// mainStageImage.switchTo(application)
181+// mainStageImage.visible = true;
182+// } else if (application.stage == ApplicationInfoInterface.MainStage) {
183+// priv.mainStageAppId = appId;
184+// sideStageImage.switchTo(application)
185+// sideStageImage.visible = true;
186+// }
187+// }
188+
189+ onFocusRequested: {
190+ print("focus requested by", appId)
191+
192+ var application = ApplicationManager.findApplication(appId)
193+ if (application.stage == ApplicationInfoInterface.SideStage) {
194+ if (sideStageImage.shown) {
195+ print("switching to:", appId)
196+ sideStageImage.switchTo(application)
197+ mainStageImage.visible = true;
198+ ApplicationManager.focusApplication(appId)
199+ } else {
200+ sideStageImage.application = application
201+ sideStageImage.snapToApp(application)
202+ }
203+ } else if (application.stage == ApplicationInfoInterface.MainStage) {
204+ if (root.shown) {
205+ priv.mainStageAppId = application.appId;
206+ mainStageImage.switchTo(application)
207+ if (sideStageImage.shown) {
208+ sideStageImage.snapTo(root.width)
209+ } else {
210+ ApplicationManager.focusApplication(appId)
211+ }
212+ } else {
213+ ApplicationManager.focusApplication(appId)
214+ }
215+ }
216+ priv.overlayOverride = false;
217+ }
218+
219+ onApplicationRemoved: {
220+ if (priv.mainStageAppId == appId) {
221+ priv.mainStageAppId = "";
222+ }
223+ if (priv.sideStageAppId == appId) {
224+ priv.sideStageAppId = "";
225+ }
226+ }
227+
228+ }
229+
230+ SwitchingApplicationImage {
231+ id: mainStageImage
232+ height: parent.height
233+ width: parent.width
234+ visible: false
235+
236+ onSwitched: {
237+ sideStageImage.visible = false;
238+ }
239+
240+// Rectangle { anchors.fill: parent; color: "red"; opacity: 0.5 }
241+ }
242+
243+ SidestageHandle {
244+ id: sideStageHandle
245+ anchors { top: parent.top; right: sideStageImage.left; bottom: parent.bottom }
246+ width: root.dragAreaWidth
247+ visible: root.shown && priv.sideStageAppId
248+
249+ }
250+ MouseArea {
251+ id: sideStageHandleMouseArea
252+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom; rightMargin: sideStageImage.shown ? sideStageImage.width : 0}
253+ width: root.dragAreaWidth
254+ visible: priv.sideStageAppId
255+
256+ property var dragPoints: new Array()
257+
258+ onPressed: {
259+ print("sidestagehandle pressed. shown:", shown, "sidestageAppId:", priv.sideStageAppId)
260+ priv.requestNewScreenshot(ApplicationInfoInterface.SideStage)
261+ }
262+
263+ onMouseXChanged: {
264+ dragPoints.push(mouseX)
265+ var dragPoint = root.width + mouseX;
266+ if (sideStageImage.shown) {
267+ dragPoint -= sideStageImage.width
268+ }
269+ sideStageImage.x = Math.max(root.width - sideStageImage.width, dragPoint)
270+ }
271+
272+ onReleased: {
273+ var distance = 0;
274+ var lastX = dragPoints[0];
275+ var oneWayFlick = true;
276+ for (var i = 0; i < dragPoints.length; ++i) {
277+ if (dragPoints[i] < lastX) {
278+ oneWayFlick = false;
279+ }
280+ distance += dragPoints[i] - lastX;
281+ lastX = dragPoints[i];
282+ }
283+ dragPoints = [];
284+
285+ if (oneWayFlick || distance > sideStageImage.width / 2) {
286+ sideStageImage.snapTo(root.width)
287+ } else {
288+ print("should snap to:", priv.sideStageAppId)
289+ sideStageImage.snapToApp(priv.sideStageApp)
290+ }
291+ }
292+// Rectangle { anchors.fill: parent; color: "purple"; opacity: .5 }
293+ }
294+
295+
296+ SwitchingApplicationImage {
297+ id: sideStageImage
298+ width: priv.sideStageWidth
299+// height: root.height
300+ x: root.width - width
301+ anchors.bottom: parent.bottom
302+ visible: true
303+ property bool shown: false
304+
305+// Rectangle { anchors.fill: parent; color: "green"; opacity: 0.5 }
306+
307+ onSwitched: {
308+ mainStageImage.visible = false;
309+ }
310+
311+ function snapTo(targetX) {
312+ print("snapping to... app:", sideStageImage.application.appId)
313+ sideStageSnapAnimation.targetX = targetX
314+ sideStageImage.visible = true;
315+ if (priv.mainStageAppId) {
316+ mainStageImage.application = priv.mainStageApp
317+ mainStageImage.visible = true;
318+ }
319+ sideStageSnapAnimation.start();
320+ }
321+
322+ function snapToApp(application) {
323+ sideStageImage.application = application
324+ sideStageSnapAnimation.snapToId = application.appId;
325+ snapTo(root.width - sideStageImage.width);
326+ }
327+
328+ SequentialAnimation {
329+ id: sideStageSnapAnimation
330+ property int targetX: root.width
331+ property string snapToId
332+
333+ UbuntuNumberAnimation { target: sideStageImage; property: "x"; to: sideStageSnapAnimation.targetX; duration: UbuntuAnimation.SlowDuration }
334+ ScriptAction {
335+ script: {
336+ if (sideStageSnapAnimation.targetX == root.width) {
337+ if (priv.mainStageAppId) {
338+ ApplicationManager.focusApplication(priv.mainStageAppId)
339+ } else {
340+ print("unfocusing current app")
341+ priv.overlayOverride = true;
342+ ApplicationManager.unfocusCurrentApplication();
343+ }
344+ sideStageImage.shown = false;
345+ }
346+ print("snapped sidestage to app", sideStageSnapAnimation.snapToId)
347+ if (sideStageSnapAnimation.snapToId) {
348+ print("focusing id", sideStageSnapAnimation.snapToId)
349+ ApplicationManager.focusApplication(sideStageSnapAnimation.snapToId)
350+ sideStageSnapAnimation.snapToId = "";
351+ sideStageImage.shown = true;
352+ }
353+ sideStageImage.visible = false;
354+ mainStageImage.visible = false;
355+ print("snapped sidestage")
356+ }
357+ }
358+ }
359+ }
360+}