2026-01-24 12:27:30 +00:00
|
|
|
import QtQuick
|
|
|
|
|
import QtQuick.Controls as QQC2
|
|
|
|
|
import QtQuick.Layouts
|
|
|
|
|
import org.kde.kirigami as Kirigami
|
|
|
|
|
import org.kde.alakarte
|
|
|
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
|
id: root
|
|
|
|
|
|
2026-01-29 18:49:45 +00:00
|
|
|
spacing: uiMode === Config.Couch ? Kirigami.Units.largeSpacing * 1.25 : Kirigami.Units.largeSpacing
|
2026-01-24 12:27:30 +00:00
|
|
|
|
2026-01-29 18:49:45 +00:00
|
|
|
property int uiMode: Config.Auto
|
|
|
|
|
property int activeInput: InputManager.KeyboardMouse
|
|
|
|
|
|
|
|
|
|
readonly property bool useGamepadHints: {
|
|
|
|
|
if (!GamepadManager.connected) return false
|
|
|
|
|
if (uiMode === Config.Couch) {
|
|
|
|
|
if (activeInput === InputManager.KeyboardMouse && InputManager.hasSeenKeyboardMouse) return false
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return activeInput === InputManager.Gamepad
|
|
|
|
|
}
|
2026-01-24 12:27:30 +00:00
|
|
|
readonly property int style: GamepadManager.controllerStyle
|
|
|
|
|
property string context: "library"
|
|
|
|
|
|
|
|
|
|
function iconBasePath() {
|
|
|
|
|
if (!useGamepadHints) return ""
|
|
|
|
|
switch (style) {
|
|
|
|
|
case GamepadManager.PlayStationController:
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/playstation/"
|
|
|
|
|
case GamepadManager.XboxController:
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/xbox/"
|
|
|
|
|
case GamepadManager.NintendoController:
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/nintendo/"
|
|
|
|
|
default:
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/generic/"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function iconForButton(buttonLabel) {
|
|
|
|
|
if (!useGamepadHints) return ""
|
|
|
|
|
const base = iconBasePath()
|
|
|
|
|
if (style === GamepadManager.PlayStationController) {
|
|
|
|
|
if (buttonLabel === "Cross") return base + "cross.svg"
|
|
|
|
|
if (buttonLabel === "Circle") return base + "circle.svg"
|
|
|
|
|
if (buttonLabel === "Square") return base + "square.svg"
|
|
|
|
|
if (buttonLabel === "Triangle") return base + "triangle.svg"
|
|
|
|
|
}
|
|
|
|
|
if (style === GamepadManager.XboxController || style === GamepadManager.NintendoController) {
|
|
|
|
|
return base + buttonLabel.toLowerCase() + ".svg"
|
|
|
|
|
}
|
|
|
|
|
if (buttonLabel === "A") return base + "south.svg"
|
|
|
|
|
if (buttonLabel === "B") return base + "east.svg"
|
|
|
|
|
if (buttonLabel === "X") return base + "west.svg"
|
|
|
|
|
if (buttonLabel === "Y") return base + "north.svg"
|
|
|
|
|
return base + "south.svg"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function iconForAux(action) {
|
|
|
|
|
if (!useGamepadHints) return ""
|
|
|
|
|
|
2026-01-29 18:49:45 +00:00
|
|
|
if (action === "dpad") {
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/generic/dpad.svg"
|
|
|
|
|
}
|
2026-01-24 12:27:30 +00:00
|
|
|
if (action === "lb") {
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/generic/lb.svg"
|
|
|
|
|
}
|
|
|
|
|
if (action === "rb") {
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/generic/rb.svg"
|
|
|
|
|
}
|
|
|
|
|
if (action === "menu") {
|
|
|
|
|
if (style === GamepadManager.PlayStationController) {
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/playstation/options.svg"
|
|
|
|
|
}
|
|
|
|
|
if (style === GamepadManager.NintendoController) {
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/nintendo/plus.svg"
|
|
|
|
|
}
|
|
|
|
|
if (style === GamepadManager.XboxController) {
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/xbox/menu.svg"
|
|
|
|
|
}
|
|
|
|
|
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/generic/menu.svg"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function keyboardLabel(action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
if (root.context === "confirm" || root.context === "confirm_remove") {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case "navigate": return "Tab"
|
|
|
|
|
case "confirm": return "Enter"
|
|
|
|
|
case "back": return "Esc"
|
|
|
|
|
case "menu": return ""
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 12:27:30 +00:00
|
|
|
if (root.context === "library") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return i18n("Arrows")
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return "Space"
|
2026-01-29 18:49:45 +00:00
|
|
|
case "back": return ""
|
2026-01-24 12:27:30 +00:00
|
|
|
case "details": return "Enter"
|
|
|
|
|
case "search": return "Ctrl+F"
|
2026-01-29 18:49:45 +00:00
|
|
|
case "lb": return "Ctrl+PgUp"
|
|
|
|
|
case "rb": return "Ctrl+PgDown"
|
2026-01-24 12:27:30 +00:00
|
|
|
case "menu": return "Ctrl+,"
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "edit") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return "Tab"
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return "Enter"
|
|
|
|
|
case "back": return "Esc"
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "details") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return "Tab"
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return "Enter"
|
|
|
|
|
case "back": return "Esc"
|
2026-01-29 18:49:45 +00:00
|
|
|
case "details": return "F"
|
|
|
|
|
case "search": return "E"
|
2026-01-24 12:27:30 +00:00
|
|
|
case "menu": return "Ctrl+,"
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "sidebar") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return i18n("Arrows/Tab")
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return "Enter"
|
|
|
|
|
case "back": return "Esc"
|
2026-01-29 18:49:45 +00:00
|
|
|
case "lb": return "Ctrl+PgUp"
|
|
|
|
|
case "rb": return "Ctrl+PgDown"
|
2026-01-24 12:27:30 +00:00
|
|
|
case "menu": return "Ctrl+,"
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-29 18:49:45 +00:00
|
|
|
if (root.context === "settings") {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case "navigate": return "Tab"
|
|
|
|
|
case "confirm": return "Enter"
|
|
|
|
|
case "back": return "Esc"
|
|
|
|
|
case "menu": return "Ctrl+,"
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "settings" || root.context === "import" || root.context === "sidebar" || root.context === "about") {
|
2026-01-24 12:27:30 +00:00
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return "Tab"
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return "Enter"
|
|
|
|
|
case "back": return "Esc"
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function actionLabel(action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
if (root.context === "confirm" || root.context === "confirm_remove") {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
|
|
|
|
case "confirm": return i18n("Select")
|
|
|
|
|
case "back": return i18n("Cancel")
|
|
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : ""
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 12:27:30 +00:00
|
|
|
if (root.context === "library") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return i18n("Play")
|
2026-01-29 18:49:45 +00:00
|
|
|
case "back": return ""
|
2026-01-24 12:27:30 +00:00
|
|
|
case "details": return i18n("Details")
|
|
|
|
|
case "search": return i18n("Search")
|
|
|
|
|
case "lb": return i18n("Prev Source")
|
|
|
|
|
case "rb": return i18n("Next Source")
|
2026-01-29 18:49:45 +00:00
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : i18n("Settings")
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "settings") {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
|
|
|
|
case "confirm": return i18n("Select")
|
|
|
|
|
case "back": return i18n("Back")
|
|
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : i18n("Close")
|
2026-01-24 12:27:30 +00:00
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "edit") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return i18n("Select")
|
|
|
|
|
case "back": return i18n("Back")
|
2026-01-29 18:49:45 +00:00
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : ""
|
2026-01-24 12:27:30 +00:00
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "details") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
|
|
|
|
case "confirm": return i18n("Select")
|
2026-01-24 12:27:30 +00:00
|
|
|
case "back": return i18n("Back")
|
|
|
|
|
case "details": return i18n("Favorite")
|
|
|
|
|
case "search": return i18n("Edit")
|
2026-01-29 18:49:45 +00:00
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : i18n("Settings")
|
2026-01-24 12:27:30 +00:00
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "sidebar") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return i18n("Select")
|
|
|
|
|
case "back": return i18n("Back")
|
|
|
|
|
case "lb": return i18n("Prev Source")
|
|
|
|
|
case "rb": return i18n("Next Source")
|
2026-01-29 18:49:45 +00:00
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Close") : i18n("Settings")
|
2026-01-24 12:27:30 +00:00
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "settings" || root.context === "import" || root.context === "sidebar") {
|
|
|
|
|
switch (action) {
|
2026-01-29 18:49:45 +00:00
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
2026-01-24 12:27:30 +00:00
|
|
|
case "confirm": return i18n("Select")
|
|
|
|
|
case "back": return i18n("Back")
|
2026-01-29 18:49:45 +00:00
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : ""
|
|
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (root.context === "about") {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
|
|
|
|
case "confirm": return i18n("Select")
|
|
|
|
|
case "back": return i18n("Back")
|
|
|
|
|
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : ""
|
2026-01-24 12:27:30 +00:00
|
|
|
default: return ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
component HintItem: RowLayout {
|
|
|
|
|
required property string action
|
|
|
|
|
property string label: ""
|
|
|
|
|
property string iconSource: ""
|
|
|
|
|
property string keyLabel: ""
|
|
|
|
|
|
|
|
|
|
visible: {
|
|
|
|
|
if (root.useGamepadHints) return iconSource != "" && label.length > 0
|
|
|
|
|
return keyLabel.length > 0 && label.length > 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spacing: Kirigami.Units.smallSpacing
|
|
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
|
id: buttonFrame
|
|
|
|
|
radius: Kirigami.Units.smallSpacing
|
|
|
|
|
color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.08)
|
|
|
|
|
border.width: 1
|
|
|
|
|
border.color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.2)
|
|
|
|
|
|
2026-01-29 18:49:45 +00:00
|
|
|
Layout.preferredHeight: uiMode === Config.Couch ? Kirigami.Units.gridUnit * 1.8 : Kirigami.Units.gridUnit * 1.4
|
2026-01-24 12:27:30 +00:00
|
|
|
Layout.preferredWidth: useGamepadHints
|
|
|
|
|
? Layout.preferredHeight
|
|
|
|
|
: Math.max(keyText.implicitWidth + Kirigami.Units.mediumSpacing * 2, Layout.preferredHeight)
|
|
|
|
|
|
|
|
|
|
Image {
|
|
|
|
|
id: buttonIcon
|
|
|
|
|
anchors.centerIn: parent
|
|
|
|
|
width: parent.height * 0.7
|
|
|
|
|
height: width
|
|
|
|
|
source: parent.parent.iconSource
|
|
|
|
|
visible: useGamepadHints && source != ""
|
|
|
|
|
sourceSize: Qt.size(width * 2, height * 2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QQC2.Label {
|
|
|
|
|
id: keyText
|
|
|
|
|
anchors.centerIn: parent
|
|
|
|
|
text: parent.parent.keyLabel
|
|
|
|
|
font.bold: true
|
2026-01-29 18:49:45 +00:00
|
|
|
font.pointSize: uiMode === Config.Couch ? Kirigami.Theme.defaultFont.pointSize : Kirigami.Theme.smallFont.pointSize
|
2026-01-24 12:27:30 +00:00
|
|
|
color: Kirigami.Theme.textColor
|
|
|
|
|
visible: !useGamepadHints
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QQC2.Label {
|
|
|
|
|
text: parent.label
|
|
|
|
|
color: Kirigami.Theme.textColor
|
2026-01-29 18:49:45 +00:00
|
|
|
font.pointSize: uiMode === Config.Couch ? Kirigami.Theme.defaultFont.pointSize : Kirigami.Theme.smallFont.pointSize
|
2026-01-24 12:27:30 +00:00
|
|
|
Layout.alignment: Qt.AlignVCenter
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-29 18:49:45 +00:00
|
|
|
HintItem {
|
|
|
|
|
action: "navigate"
|
|
|
|
|
label: actionLabel("navigate")
|
|
|
|
|
iconSource: iconForAux("dpad")
|
|
|
|
|
keyLabel: keyboardLabel("navigate")
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 12:27:30 +00:00
|
|
|
HintItem {
|
|
|
|
|
action: "confirm"
|
|
|
|
|
label: actionLabel("confirm")
|
|
|
|
|
iconSource: iconForButton(GamepadManager.confirmButtonLabel)
|
|
|
|
|
keyLabel: keyboardLabel("confirm")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HintItem {
|
|
|
|
|
action: "back"
|
|
|
|
|
label: actionLabel("back")
|
|
|
|
|
iconSource: iconForButton(GamepadManager.backButtonLabel)
|
|
|
|
|
keyLabel: keyboardLabel("back")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HintItem {
|
|
|
|
|
action: "details"
|
|
|
|
|
label: actionLabel("details")
|
|
|
|
|
iconSource: iconForButton(GamepadManager.detailsButtonLabel)
|
|
|
|
|
keyLabel: keyboardLabel("details")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HintItem {
|
|
|
|
|
action: "search"
|
|
|
|
|
label: actionLabel("search")
|
|
|
|
|
iconSource: iconForButton(GamepadManager.searchButtonLabel)
|
|
|
|
|
keyLabel: keyboardLabel("search")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HintItem {
|
|
|
|
|
action: "lb"
|
|
|
|
|
label: actionLabel("lb")
|
|
|
|
|
iconSource: (root.context === "library" || root.context === "sidebar") ? iconForAux("lb") : ""
|
2026-01-29 18:49:45 +00:00
|
|
|
keyLabel: keyboardLabel("lb")
|
2026-01-24 12:27:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HintItem {
|
|
|
|
|
action: "rb"
|
|
|
|
|
label: actionLabel("rb")
|
|
|
|
|
iconSource: (root.context === "library" || root.context === "sidebar") ? iconForAux("rb") : ""
|
2026-01-29 18:49:45 +00:00
|
|
|
keyLabel: keyboardLabel("rb")
|
2026-01-24 12:27:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HintItem {
|
|
|
|
|
action: "menu"
|
|
|
|
|
label: actionLabel("menu")
|
2026-01-29 18:49:45 +00:00
|
|
|
iconSource: (useGamepadHints && uiMode === Config.Couch)
|
|
|
|
|
? iconForAux("menu")
|
|
|
|
|
: ((root.context === "library" || root.context === "details" || root.context === "sidebar" || root.context === "settings") ? iconForAux("menu") : "")
|
2026-01-24 12:27:30 +00:00
|
|
|
keyLabel: keyboardLabel("menu")
|
|
|
|
|
}
|
|
|
|
|
}
|