Commit 79f3c50e authored by Fushan Wen's avatar Fushan Wen 💬
Browse files

applets/fifteenPuzzle: add keyboard navigation support

Up/Down/Left/Right: move focus to the adjacent item.
Space/Enter/Return: Click the item
parent c159899c
......@@ -21,14 +21,92 @@ Item {
readonly property int boardSize: Plasmoid.configuration.boardSize
property Component piece: Piece {}
property var pieces: []
property int currentPosition: -1
property int seconds: 0
Keys.onPressed: {
let newPosition = main.currentPosition;
switch (event.key) {
case Qt.Key_Up: {
if (main.currentPosition < 0) {
newPosition = (main.boardSize - 1) * main.boardSize; // Start from bottom
} else if (main.currentPosition >= main.boardSize) {
newPosition = main.currentPosition - main.boardSize;
}
if (pieces[newPosition].empty) {
if (main.currentPosition < 0) {
newPosition = (main.boardSize - 2) * main.boardSize;
} else if (newPosition >= main.boardSize) {
newPosition -= main.boardSize;
}
}
break;
}
case Qt.Key_Down: {
if (main.currentPosition < 0) {
newPosition = 0; // Start from top
} else if (main.currentPosition < main.boardSize * (main.boardSize - 1)) {
newPosition = main.currentPosition + main.boardSize;
}
if (pieces[newPosition].empty) {
if (main.currentPosition < 0) {
newPosition = main.boardSize;
} else if (newPosition < main.boardSize * (main.boardSize - 1)) {
newPosition += main.boardSize;
}
}
break;
}
case Qt.Key_Left: {
if (main.currentPosition < 0) {
newPosition = main.boardSize - 1; // Start from right
} else if (main.currentPosition % main.boardSize) {
newPosition = main.currentPosition - 1;
}
if (pieces[newPosition].empty) {
if (main.currentPosition < 0) {
newPosition = main.boardSize - 2;
} else if (newPosition % main.boardSize) {
newPosition -= 1;
}
}
break;
}
case Qt.Key_Right: {
if (main.currentPosition < 0) {
newPosition = 0; // Start from left
} else if ((main.currentPosition + 1) % main.boardSize) {
newPosition = main.currentPosition + 1;
}
if (pieces[newPosition].empty) {
if (main.currentPosition < 0) {
newPosition = 1;
} else if ((newPosition + 1) % main.boardSize) {
newPosition += 1;
}
}
break;
}
default:
return;
}
// Edge empty case: don't move
if (pieces[newPosition].empty) {
newPosition = main.currentPosition;
}
pieces[newPosition].forceActiveFocus();
event.accepted = true;
}
function fillBoard() {
// Clear out old board
for (const piece of pieces) {
piece.destroy();
}
main.currentPosition = -1;
pieces = [];
const count = boardSize * boardSize;
......@@ -36,6 +114,11 @@ Item {
for (let i = 0; i < count; ++i) {
const newPiece = piece.createObject(mainGrid, {"number": i, "position": i });
pieces[i] = newPiece;
newPiece.activeFocusChanged.connect(() => {
if (newPiece.activeFocus) {
main.currentPosition = newPiece.position;
}
});
newPiece.activated.connect(pieceClicked);
}
shuffleBoard();
......@@ -46,6 +129,7 @@ Item {
// Hide the solved rectangle in case it was visible
solvedRect.visible = false;
main.seconds = 0;
main.currentPosition = -1;
const count = boardSize * boardSize;
for (let i = count - 1; i >= 0; --i) {
......@@ -131,6 +215,7 @@ Item {
for (const [row, col] of [[-1, 0], [1, 0], [0, -1], [0, 1]]) {
// stop at first direction that has (or rather "had" at this point) the empty piece
if (swapWithEmptyPiece(position, row, col)) {
main.currentPosition += col + main.boardSize * row;
break;
}
}
......@@ -183,6 +268,23 @@ Item {
bottom: controlsRow.top
bottomMargin: PlasmaCore.Units.smallSpacing
}
activeFocusOnTab: true
onActiveFocusChanged: {
// Move focus to the first non-empty piece
if (activeFocus) {
if (main.currentPosition < 0) {
if (main.pieces[0].empty) {
main.pieces[1].forceActiveFocus();
} else {
main.pieces[0].forceActiveFocus();
}
} else {
main.pieces[main.currentPosition].forceActiveFocus();
}
}
}
}
RowLayout {
......
......@@ -9,6 +9,7 @@ import QtQuick.Layouts 1.15
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.plasmoid 2.0
Rectangle {
......@@ -43,6 +44,17 @@ Rectangle {
property int number
property int position
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Space:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Select:
tapHandler.tapped(null);
break;
}
}
Behavior on x {
NumberAnimation {
duration: PlasmaCore.Units.longDuration
......@@ -56,6 +68,17 @@ Rectangle {
}
}
Loader {
anchors.fill: parent
active: parent.activeFocus
asynchronous: true
z: 0
sourceComponent: PlasmaExtras.Highlight {
hovered: true
}
}
PlasmaComponents3.Label {
id: pieceNumeral
anchors.centerIn: parent
......@@ -80,6 +103,11 @@ Rectangle {
}
TapHandler {
onTapped: piece.activated(position)
id: tapHandler
onTapped: {
piece.forceActiveFocus();
piece.activated(position);
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment