on xenial help sign in
allow navigating the staged spreads with keyboard too
commitea5f0a6ec05a763b1e5126d81f4ea36e070b37b0 authorMichael Zanetti <michael.zanetti@canonical.com> dateThu 10 Mar 2016, 10:19 (11 years ago) parentc6b1db8
5 files changed+139−24
qml/Stages/PhoneStage.qml+47−6 qml/Stages/SpreadDelegate.qml+20 qml/Stages/TabletStage.qml+53−6 tests/qmltests/Stages/tst_SpreadDelegate.qml+7 tests/qmltests/tst_Shell.qml+12−12
qml/Stages/PhoneStage.qml+47−6
@@ -44,6 +44,33 @@ AbstractStage {
4444 }
4545 }
4646
47+ onAltTabPressedChanged: {
48+ if (!spreadEnabled || !altTabEnabled) {
49+ return;
50+ }
51+ if (altTabPressed) {
52+ spreadView.snapToSpread();
53+ priv.highlightIndex = Math.min(spreadRepeater.count - 1, 1);
54+ } else {
55+ spreadView.snapTo(priv.highlightIndex)
56+ }
57+ }
58+
59+ FocusScope {
60+ focus: root.altTabPressed
61+
62+ Keys.onPressed: {
63+ switch (event.key) {
64+ case Qt.Key_Tab:
65+ priv.highlightIndex = (priv.highlightIndex + 1) % spreadRepeater.count
66+ break;
67+ case Qt.Key_Backtab:
68+ priv.highlightIndex = (priv.highlightIndex + spreadRepeater.count - 1) % spreadRepeater.count
69+ break;
70+ }
71+ }
72+ }
73+
4774 // Functions to be called from outside
4875 function updateFocusedAppOrientation() {
4976 if (spreadRepeater.count > 0) {
@@ -186,6 +213,7 @@ AbstractStage {
186213
187214 property real oldInverseProgress: 0
188215 property bool animateX: false
216+ property int highlightIndex: 0
189217
190218 onFocusedAppDelegateChanged: {
191219 if (focusedAppDelegate) {
@@ -220,6 +248,10 @@ AbstractStage {
220248 spreadView.phase = 0;
221249 spreadView.contentX = -spreadView.shift;
222250 }
251+
252+ onHighlightIndexChanged: {
253+ spreadView.contentX = highlightIndex * spreadView.contentWidth / (spreadRepeater.count + 2)
254+ }
223255 }
224256 Timer {
225257 id: fullyShowingFocusedAppUpdateTimer
@@ -287,6 +319,11 @@ AbstractStage {
287319 }
288320 }
289321
322+ Behavior on contentX {
323+ enabled: root.altTabPressed
324+ UbuntuNumberAnimation {}
325+ }
326+
290327 onShiftedContentXChanged: {
291328 if (root.beingResized) {
292329 // Flickabe.contentX wiggles during resizes. Don't react to it.
@@ -325,12 +362,17 @@ AbstractStage {
325362 } else if (shiftedContentX < positionMarker3 * width) {
326363 snapTo(1);
327364 } else if (phase < 2){
328− // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
329− snapAnimation.targetContentX = width * positionMarker4 + 1 - shift;
330− snapAnimation.start();
365+ snapToSpread();
331366 root.opened();
332367 }
333368 }
369+
370+ function snapToSpread() {
371+ // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
372+ snapAnimation.targetContentX = (root.width * spreadView.positionMarker4) + 1 - spreadView.shift;
373+ snapAnimation.start();
374+ }
375+
334376 function snapTo(index) {
335377 if (!root.altTabEnabled) {
336378 // Reset to start instead
@@ -433,6 +475,7 @@ AbstractStage {
433475 maximizedAppTopMargin: root.maximizedAppTopMargin
434476 dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
435477 focusFirstApp: root.focusFirstApp
478+ highlightShown: root.altTabPressed && index === priv.highlightIndex
436479
437480 readonly property bool isDash: model.appId == "unity8-dash"
438481
@@ -665,9 +708,7 @@ AbstractStage {
665708 edge: Qt.RightEdge
666709
667710 onPassed: {
668− // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
669− snapAnimation.targetContentX = (root.width * spreadView.positionMarker4) + 1 - spreadView.shift;
670− snapAnimation.start();
711+ spreadView.snapToSpread();
671712 }
672713 material: Component {
673714 Item {
qml/Stages/SpreadDelegate.qml+20
@@ -43,6 +43,7 @@ FocusScope {
4343 property int shellOrientationAngle
4444 property int shellOrientation
4545 property QtObject orientations
46+ property bool highlightShown: false
4647
4748 function matchShellOrientation() {
4849 if (!root.application)
@@ -261,6 +262,25 @@ FocusScope {
261262 Behavior on opacity { UbuntuNumberAnimation {} }
262263 }
263264
265+ Rectangle {
266+ id: selectionHighlight
267+ objectName: "selectionHighlight"
268+ anchors.fill: appWindow
269+ anchors.margins: -units.gu(1)
270+ color: "white"
271+ opacity: root.highlightShown ? 0.15 : 0
272+ antialiasing: true
273+ visible: opacity > 0
274+ }
275+
276+ Rectangle {
277+ anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
278+ height: units.dp(2)
279+ color: UbuntuColors.orange
280+ visible: root.highlightShown
281+ antialiasing: true
282+ }
283+
264284 ApplicationWindow {
265285 id: appWindow
266286 objectName: application ? "appWindow_" + application.appId : "appWindow_null"
qml/Stages/TabletStage.qml+53−6
@@ -108,6 +108,38 @@ AbstractStage {
108108 priv.oldInverseProgress = inverseProgress;
109109 }
110110
111+ onAltTabPressedChanged: {
112+ if (!spreadEnabled) {
113+ return;
114+ }
115+ if (altTabPressed) {
116+ priv.highlightIndex = Math.min(spreadRepeater.count - 1, 1);
117+ spreadView.snapToSpread();
118+ } else {
119+ for (var i = 0; i < spreadRepeater.count; i++) {
120+ if (spreadRepeater.itemAt(i).zIndex === priv.highlightIndex) {
121+ spreadView.snapTo(i);
122+ return;
123+ }
124+ }
125+ }
126+ }
127+
128+ FocusScope {
129+ focus: root.altTabPressed
130+
131+ Keys.onPressed: {
132+ switch (event.key) {
133+ case Qt.Key_Tab:
134+ priv.highlightIndex = (priv.highlightIndex + 1) % spreadRepeater.count
135+ break;
136+ case Qt.Key_Backtab:
137+ priv.highlightIndex = (priv.highlightIndex + spreadRepeater.count - 1) % spreadRepeater.count
138+ break;
139+ }
140+ }
141+ }
142+
111143 QtObject {
112144 id: priv
113145 objectName: "stagesPriv"
@@ -136,6 +168,8 @@ AbstractStage {
136168
137169 property int oldInverseProgress: 0
138170
171+ property int highlightIndex: 0
172+
139173 onFocusedAppIdChanged: {
140174 if (priv.focusedAppId.length > 0) {
141175 var focusedApp = ApplicationManager.findApplication(focusedAppId);
@@ -191,6 +225,10 @@ AbstractStage {
191225 }
192226 return oneWayFlick;
193227 }
228+
229+ onHighlightIndexChanged: {
230+ spreadView.contentX = highlightIndex * spreadView.contentWidth / (spreadRepeater.count + 2)
231+ }
194232 }
195233
196234 Connections {
@@ -397,11 +435,16 @@ AbstractStage {
397435 } else if (shiftedContentX < phase1Width) {
398436 snapTo(1);
399437 } else {
400− // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
401− snapAnimation.targetContentX = spreadView.width * spreadView.positionMarker4 + 1 - shift;
402− snapAnimation.start();
438+ snapToSpread();
403439 }
404440 }
441+
442+ function snapToSpread() {
443+ // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
444+ snapAnimation.targetContentX = (spreadView.width * spreadView.positionMarker4) + 1 - shift;
445+ snapAnimation.start();
446+ }
447+
405448 function snapTo(index) {
406449 spreadView.selectedIndex = index;
407450 snapAnimation.targetContentX = -shift;
@@ -487,6 +530,11 @@ AbstractStage {
487530 }
488531 }
489532
533+ Behavior on contentX {
534+ enabled: root.altTabPressed
535+ UbuntuNumberAnimation {}
536+ }
537+
490538 MouseArea {
491539 id: spreadRow
492540 x: spreadView.contentX
@@ -617,6 +665,7 @@ AbstractStage {
617665 dragOffset: !isDash && model.appId == priv.mainStageAppId && root.inverseProgress > 0 && spreadView.phase === 0 ? root.inverseProgress : 0
618666 application: ApplicationManager.get(index)
619667 closeable: !isDash
668+ highlightShown: root.altTabPressed && priv.highlightIndex == zIndex
620669
621670 readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage
622671
@@ -819,9 +868,7 @@ AbstractStage {
819868 edge: Qt.RightEdge
820869
821870 onPassed: {
822− // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
823− snapAnimation.targetContentX = (root.width * spreadView.positionMarker4) + 1 - spreadView.shift;
824− snapAnimation.start();
871+ spreadView.snapToSpread();
825872 }
826873 material: Component {
827874 Item {
tests/qmltests/Stages/tst_SpreadDelegate.qml+7
@@ -308,5 +308,12 @@ Rectangle {
308308 tryCompare(closeAnimation, "running", false);
309309 }
310310
311+ function test_showHighLight() {
312+ loadWithGalleryApp.clicked();
313+ var highlightRect = findChild(spreadDelegateLoader.item, "selectionHighlight")
314+ tryCompare(highlightRect, "visible", false)
315+ spreadDelegateLoader.item.highlightShown = true;
316+ tryCompare(highlightRect, "visible", true)
317+ }
311318 }
312319}
tests/qmltests/tst_Shell.qml+12−12
@@ -1424,9 +1424,17 @@ Rectangle {
14241424 tryCompare(galleryApp, "requestedState", ApplicationInfoInterface.RequestedRunning);
14251425 }
14261426
1427− function test_altTabSwitchesFocus() {
1428− loadShell("desktop");
1429− shell.usageScenario = "desktop"
1427+ function test_altTabSwitchesFocus_data() {
1428+ return [
1429+ { tag: "windowed", shellType: "desktop" },
1430+ { tag: "staged", shellType: "phone" },
1431+ { tag: "sidestaged", shellType: "tablet" }
1432+ ];
1433+ }
1434+
1435+ function test_altTabSwitchesFocus(data) {
1436+ loadShell(data.shellType);
1437+ shell.usageScenario = data.shellType;
14301438 waitForRendering(root)
14311439
14321440 var desktopStage = findChild(shell, "stage");
@@ -1444,18 +1452,10 @@ Rectangle {
14441452 keyClick(Qt.Key_Tab, Qt.ControlModifier)
14451453 tryCompare(app2.session.lastSurface, "activeFocus", true)
14461454
1447− var desktopSpread = findChild(shell, "spread")
1448−
1449− tryCompare(desktopSpread, "state", "")
1450−
1451− // Just press Alt, make sure the spread comes up
1455+ // Press Alt+Tab
14521456 keyPress(Qt.Key_Control);
14531457 keyClick(Qt.Key_Tab);
1454− tryCompare(desktopSpread, "state", "altTab")
1455−
1456− // Release control, check if spread disappears
14571458 keyRelease(Qt.Key_Control)
1458− tryCompare(desktopSpread, "state", "")
14591459
14601460 // Focus should have switched back now
14611461 tryCompare(app3.session.lastSurface, "activeFocus", true)