mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-02-09 21:13:08 +00:00
QML: fix couch focus/menu scoping and overlays
This commit is contained in:
parent
444ef65a78
commit
5b993cff6b
9 changed files with 1143 additions and 122 deletions
|
|
@ -54,10 +54,37 @@ Kirigami.OverlaySheet {
|
|||
|
||||
onOpened: playButton.forceActiveFocus()
|
||||
|
||||
Shortcut {
|
||||
enabled: detailsSheet.opened
|
||||
sequence: "E"
|
||||
onActivated: {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
detailsSheet.editRequested()
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
enabled: detailsSheet.opened
|
||||
sequence: "F"
|
||||
onActivated: {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (game) game.favorite = !game.favorite
|
||||
}
|
||||
}
|
||||
|
||||
function isDescendant(item, ancestor) {
|
||||
let p = item
|
||||
while (p) {
|
||||
if (p === ancestor) return true
|
||||
if (ancestor.contentItem && p === ancestor.contentItem) return true
|
||||
if (ancestor.header && p === ancestor.header) return true
|
||||
if (p.visualParent !== undefined && p.visualParent !== null) {
|
||||
if (detailsSheet.isDescendant(p.visualParent, ancestor)) return true
|
||||
} else if (p.popup !== undefined && p.popup !== null && p.popup.visualParent !== undefined && p.popup.visualParent !== null) {
|
||||
if (detailsSheet.isDescendant(p.popup.visualParent, ancestor)) return true
|
||||
}
|
||||
p = p.parent
|
||||
}
|
||||
return false
|
||||
|
|
@ -81,6 +108,8 @@ Kirigami.OverlaySheet {
|
|||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateLeft() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!detailsSheet.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -88,6 +117,8 @@ Kirigami.OverlaySheet {
|
|||
detailsSheet.focusNextInChain(false)
|
||||
}
|
||||
function onNavigateRight() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!detailsSheet.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -95,6 +126,8 @@ Kirigami.OverlaySheet {
|
|||
detailsSheet.focusNextInChain(true)
|
||||
}
|
||||
function onNavigateUp() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!detailsSheet.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -102,6 +135,8 @@ Kirigami.OverlaySheet {
|
|||
detailsSheet.focusNextInChain(false)
|
||||
}
|
||||
function onNavigateDown() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!detailsSheet.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -109,6 +144,8 @@ Kirigami.OverlaySheet {
|
|||
detailsSheet.focusNextInChain(true)
|
||||
}
|
||||
function onSelectPressed() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!detailsSheet.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
|
|||
|
|
@ -86,10 +86,23 @@ Kirigami.Dialog {
|
|||
|
||||
property string selectedCoverPath: ""
|
||||
|
||||
readonly property bool anyMenuOpen: runnerCombo && runnerCombo.popup && runnerCombo.popup.visible
|
||||
|
||||
function closeCurrentMenu() {
|
||||
if (runnerCombo && runnerCombo.popup && runnerCombo.popup.visible) {
|
||||
runnerCombo.popup.close()
|
||||
}
|
||||
}
|
||||
|
||||
function isDescendant(item, ancestor) {
|
||||
let p = item
|
||||
while (p) {
|
||||
if (p === ancestor || (ancestor.contentItem && p === ancestor.contentItem)) return true
|
||||
if (p.visualParent !== undefined && p.visualParent !== null) {
|
||||
if (dialog.isDescendant(p.visualParent, ancestor)) return true
|
||||
} else if (p.popup !== undefined && p.popup !== null && p.popup.visualParent !== undefined && p.popup.visualParent !== null) {
|
||||
if (dialog.isDescendant(p.popup.visualParent, ancestor)) return true
|
||||
}
|
||||
p = p.parent
|
||||
}
|
||||
return false
|
||||
|
|
@ -118,7 +131,7 @@ Kirigami.Dialog {
|
|||
item.toggle()
|
||||
return
|
||||
}
|
||||
if (item.hasOwnProperty("checked")) {
|
||||
if (item.checkable !== undefined && item.checkable && item.checked !== undefined) {
|
||||
item.checked = !item.checked
|
||||
return
|
||||
}
|
||||
|
|
@ -203,6 +216,8 @@ Kirigami.Dialog {
|
|||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateUp() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!dialog.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -210,6 +225,8 @@ Kirigami.Dialog {
|
|||
dialog.focusNextInChain(false)
|
||||
}
|
||||
function onNavigateDown() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!dialog.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -217,6 +234,8 @@ Kirigami.Dialog {
|
|||
dialog.focusNextInChain(true)
|
||||
}
|
||||
function onNavigateLeft() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!dialog.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -224,6 +243,8 @@ Kirigami.Dialog {
|
|||
dialog.focusNextInChain(false)
|
||||
}
|
||||
function onNavigateRight() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!dialog.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
@ -231,6 +252,8 @@ Kirigami.Dialog {
|
|||
dialog.focusNextInChain(true)
|
||||
}
|
||||
function onSelectPressed() {
|
||||
let app = applicationWindow()
|
||||
if (app && app.currentConfirmDialog && app.currentConfirmDialog()) return
|
||||
if (!dialog.opened) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ FocusScope {
|
|||
readonly property int gameCount: proxyModel.count
|
||||
property url focusedCoverUrl: ""
|
||||
|
||||
readonly property bool anyMenuOpen: searchHeader.anyMenuOpen
|
||||
|
||||
function closeCurrentMenu() {
|
||||
searchHeader.closeCurrentMenu()
|
||||
}
|
||||
|
||||
function focusSearch() {
|
||||
searchField.forceActiveFocus()
|
||||
}
|
||||
|
|
@ -35,6 +41,14 @@ FocusScope {
|
|||
}
|
||||
|
||||
function restoreFocus() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.hasOwnProperty("pendingSidebarOpen") && w.pendingSidebarOpen) {
|
||||
w.pendingSidebarOpen = false
|
||||
if (w.globalDrawer && typeof w.globalDrawer.open === "function") {
|
||||
w.globalDrawer.open()
|
||||
return
|
||||
}
|
||||
}
|
||||
if (libraryRoot.searchActive) {
|
||||
libraryRoot.focusSearch()
|
||||
} else {
|
||||
|
|
@ -176,6 +190,16 @@ FocusScope {
|
|||
}
|
||||
|
||||
Keys.onDownPressed: gameGrid.forceActiveFocus()
|
||||
|
||||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateDown() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (!searchField.activeFocus) return
|
||||
gameGrid.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
739
src/qml/Main.qml
739
src/qml/Main.qml
File diff suppressed because it is too large
Load diff
|
|
@ -20,6 +20,96 @@ ColumnLayout {
|
|||
property var pendingDisableImportApply: null
|
||||
property string pendingDisableImportName: ""
|
||||
|
||||
readonly property bool anyConfirmOpen: disableImportConfirmDialog.opened
|
||||
|| fetchAllCoversConfirmDialog.opened
|
||||
|| removeMissingConfirmDialog.opened
|
||||
|| clearConfirmDialog.opened
|
||||
|| resetConfirmDialog.opened
|
||||
|
||||
readonly property bool anyMenuOpen: uiModeMenu.visible
|
||||
|
||||
function currentConfirmDialog() {
|
||||
if (disableImportConfirmDialog.opened) return disableImportConfirmDialog
|
||||
if (fetchAllCoversConfirmDialog.opened) return fetchAllCoversConfirmDialog
|
||||
if (removeMissingConfirmDialog.opened) return removeMissingConfirmDialog
|
||||
if (clearConfirmDialog.opened) return clearConfirmDialog
|
||||
if (resetConfirmDialog.opened) return resetConfirmDialog
|
||||
return null
|
||||
}
|
||||
|
||||
function closeCurrentConfirmDialog() {
|
||||
let d = currentConfirmDialog()
|
||||
if (!d) return
|
||||
if (typeof d.reject === "function") {
|
||||
d.reject()
|
||||
} else {
|
||||
d.close()
|
||||
}
|
||||
}
|
||||
|
||||
function closeCurrentMenu() {
|
||||
if (uiModeMenu.visible) {
|
||||
uiModeMenu.close()
|
||||
}
|
||||
}
|
||||
|
||||
function isDescendant(item, ancestor) {
|
||||
let p = item
|
||||
while (p) {
|
||||
if (p === ancestor) return true
|
||||
if (ancestor.contentItem && p === ancestor.contentItem) return true
|
||||
if (p.visualParent !== undefined && p.visualParent !== null) {
|
||||
if (settingsPage.isDescendant(p.visualParent, ancestor)) return true
|
||||
} else if (p.popup !== undefined && p.popup !== null && p.popup.visualParent !== undefined && p.popup.visualParent !== null) {
|
||||
if (settingsPage.isDescendant(p.popup.visualParent, ancestor)) return true
|
||||
}
|
||||
p = p.parent
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function focusNextInMenu(forward) {
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
let next = w.activeFocusItem
|
||||
for (let i = 0; i < 50; i++) {
|
||||
next = next.nextItemInFocusChain(forward)
|
||||
if (!next) return
|
||||
if (settingsPage.isDescendant(next, uiModeMenu)) {
|
||||
next.forceActiveFocus()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function activateFocusedInMenu() {
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
let item = w.activeFocusItem
|
||||
if (typeof item.triggered === "function") {
|
||||
item.triggered()
|
||||
return
|
||||
}
|
||||
if (typeof item.clicked === "function") {
|
||||
item.clicked()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function focusNoButton(dialog) {
|
||||
Qt.callLater(function() {
|
||||
if (!dialog) return
|
||||
if (typeof dialog.standardButton === "function") {
|
||||
let noButton = dialog.standardButton(Kirigami.Dialog.No)
|
||||
if (noButton) {
|
||||
noButton.forceActiveFocus()
|
||||
return
|
||||
}
|
||||
}
|
||||
dialog.forceActiveFocus()
|
||||
})
|
||||
}
|
||||
|
||||
function requestDisableImport(sourceName, applyFn) {
|
||||
pendingDisableImportName = sourceName
|
||||
pendingDisableImportApply = applyFn
|
||||
|
|
@ -48,7 +138,7 @@ ColumnLayout {
|
|||
text: i18n("UI mode")
|
||||
description: {
|
||||
if (App.config.uiMode === Config.Desktop) return i18n("Desktop")
|
||||
if (App.config.uiMode === Config.Handheld) return i18n("Handheld")
|
||||
if (App.config.uiMode === Config.Couch) return i18n("Couch")
|
||||
return i18n("Automatic")
|
||||
}
|
||||
icon.name: "view-fullscreen"
|
||||
|
|
@ -56,8 +146,12 @@ ColumnLayout {
|
|||
|
||||
QQC2.Menu {
|
||||
id: uiModeMenu
|
||||
focus: true
|
||||
|
||||
onOpened: Qt.callLater(function() { uiModeAuto.forceActiveFocus() })
|
||||
|
||||
QQC2.MenuItem {
|
||||
id: uiModeAuto
|
||||
text: i18n("Automatic")
|
||||
checkable: true
|
||||
checked: App.config.uiMode === Config.Auto
|
||||
|
|
@ -65,6 +159,7 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
QQC2.MenuItem {
|
||||
id: uiModeDesktop
|
||||
text: i18n("Desktop")
|
||||
checkable: true
|
||||
checked: App.config.uiMode === Config.Desktop
|
||||
|
|
@ -72,15 +167,55 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
QQC2.MenuItem {
|
||||
text: i18n("Handheld")
|
||||
id: uiModeCouch
|
||||
text: i18n("Couch")
|
||||
checkable: true
|
||||
checked: App.config.uiMode === Config.Handheld
|
||||
onTriggered: App.config.uiMode = Config.Handheld
|
||||
checked: App.config.uiMode === Config.Couch
|
||||
onTriggered: App.config.uiMode = Config.Couch
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateUp() {
|
||||
if (!uiModeMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!settingsPage.isDescendant(w.activeFocusItem, uiModeMenu)) return
|
||||
settingsPage.focusNextInMenu(false)
|
||||
}
|
||||
function onNavigateDown() {
|
||||
if (!uiModeMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!settingsPage.isDescendant(w.activeFocusItem, uiModeMenu)) return
|
||||
settingsPage.focusNextInMenu(true)
|
||||
}
|
||||
function onNavigateLeft() {
|
||||
if (!uiModeMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!settingsPage.isDescendant(w.activeFocusItem, uiModeMenu)) return
|
||||
settingsPage.focusNextInMenu(false)
|
||||
}
|
||||
function onNavigateRight() {
|
||||
if (!uiModeMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!settingsPage.isDescendant(w.activeFocusItem, uiModeMenu)) return
|
||||
settingsPage.focusNextInMenu(true)
|
||||
}
|
||||
function onSelectPressed() {
|
||||
if (!uiModeMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!settingsPage.isDescendant(w.activeFocusItem, uiModeMenu)) return
|
||||
settingsPage.activateFocusedInMenu()
|
||||
}
|
||||
}
|
||||
|
||||
FormCard.FormHeader {
|
||||
Layout.topMargin: Kirigami.Units.mediumSpacing
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -553,6 +688,7 @@ FormCard.FormHeader {
|
|||
title: i18n("Disable Import Source")
|
||||
subtitle: i18n("Disabling %1 will remove all games imported from that source. Are you sure?", settingsPage.pendingDisableImportName)
|
||||
standardButtons: Kirigami.Dialog.Yes | Kirigami.Dialog.No
|
||||
onOpened: settingsPage.focusNoButton(disableImportConfirmDialog)
|
||||
onAccepted: {
|
||||
if (settingsPage.pendingDisableImportApply) {
|
||||
settingsPage.pendingDisableImportApply()
|
||||
|
|
@ -573,6 +709,7 @@ FormCard.FormHeader {
|
|||
? i18n("This will download cover art for all games and may replace existing covers. Continue?")
|
||||
: i18n("This will download cover art for games that are missing covers. Continue?")
|
||||
standardButtons: Kirigami.Dialog.Yes | Kirigami.Dialog.No
|
||||
onOpened: settingsPage.focusNoButton(fetchAllCoversConfirmDialog)
|
||||
onAccepted: App.steamGridDB.fetchAllCovers()
|
||||
}
|
||||
|
||||
|
|
@ -581,6 +718,7 @@ FormCard.FormHeader {
|
|||
title: i18n("Remove Missing Games")
|
||||
subtitle: i18n("This will remove games whose executables cannot be found. This cannot be undone. Continue?")
|
||||
standardButtons: Kirigami.Dialog.Yes | Kirigami.Dialog.No
|
||||
onOpened: settingsPage.focusNoButton(removeMissingConfirmDialog)
|
||||
onAccepted: App.removeMissingGames()
|
||||
}
|
||||
|
||||
|
|
@ -589,6 +727,7 @@ FormCard.FormHeader {
|
|||
title: i18n("Clear Library")
|
||||
subtitle: i18n("Are you sure you want to remove all games?")
|
||||
standardButtons: Kirigami.Dialog.Yes | Kirigami.Dialog.No
|
||||
onOpened: settingsPage.focusNoButton(clearConfirmDialog)
|
||||
onAccepted: App.clearLibrary()
|
||||
}
|
||||
|
||||
|
|
@ -597,6 +736,7 @@ FormCard.FormHeader {
|
|||
title: i18n("Reset Application")
|
||||
subtitle: i18n("This will remove all games and reset all settings to defaults. Are you sure?")
|
||||
standardButtons: Kirigami.Dialog.Yes | Kirigami.Dialog.No
|
||||
onOpened: settingsPage.focusNoButton(resetConfirmDialog)
|
||||
onAccepted: {
|
||||
App.clearLibrary()
|
||||
App.config.resetToDefaults()
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ ColumnLayout {
|
|||
property string currentSourceName: i18n("All Games")
|
||||
property bool suppressAutoClose: false
|
||||
|
||||
readonly property bool hasSidebarFocus: sourceList.activeFocus || importAction.activeFocus || settingsAction.activeFocus || aboutAction.activeFocus
|
||||
|
||||
readonly property int adaptiveFocusRingWidth: 1
|
||||
|
||||
signal sourceSelected(string source)
|
||||
|
|
@ -45,6 +47,17 @@ ColumnLayout {
|
|||
sourceList.positionViewAtIndex(i, ListView.Contain)
|
||||
}
|
||||
|
||||
function applySourceById(sourceId) {
|
||||
for (let i = 0; i < sourceModel.count; i++) {
|
||||
let item = sourceModel.get(i)
|
||||
if (item && item.sourceId === sourceId) {
|
||||
applySourceAtIndex(i)
|
||||
return
|
||||
}
|
||||
}
|
||||
applySourceAtIndex(0)
|
||||
}
|
||||
|
||||
function cycleSource(delta) {
|
||||
if (sourceModel.count <= 0) return
|
||||
let i = sourceList.currentIndex
|
||||
|
|
@ -97,9 +110,31 @@ ColumnLayout {
|
|||
|
||||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateUp() { if (sourceList.activeFocus) sourceList.decrementCurrentIndex() }
|
||||
function onNavigateDown() { if (sourceList.activeFocus) sourceList.incrementCurrentIndex() }
|
||||
function onSelectPressed() { if (sourceList.activeFocus) sidebarRoot.activateCurrentItem() }
|
||||
function onNavigateUp() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (!sourceList.activeFocus) return
|
||||
if (sourceList.count > 0 && sourceList.currentIndex <= 0) {
|
||||
aboutAction.forceActiveFocus()
|
||||
} else {
|
||||
sourceList.decrementCurrentIndex()
|
||||
}
|
||||
}
|
||||
function onNavigateDown() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (!sourceList.activeFocus) return
|
||||
if (sourceList.count > 0 && sourceList.currentIndex >= sourceList.count - 1) {
|
||||
importAction.forceActiveFocus()
|
||||
} else {
|
||||
sourceList.incrementCurrentIndex()
|
||||
}
|
||||
}
|
||||
function onSelectPressed() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (sourceList.activeFocus) sidebarRoot.activateCurrentItem()
|
||||
}
|
||||
}
|
||||
|
||||
delegate: QQC2.ItemDelegate {
|
||||
|
|
@ -294,6 +329,8 @@ ColumnLayout {
|
|||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateUp() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (aboutAction.activeFocus) {
|
||||
settingsAction.forceActiveFocus()
|
||||
} else if (settingsAction.activeFocus) {
|
||||
|
|
@ -304,13 +341,20 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
function onNavigateDown() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (importAction.activeFocus) {
|
||||
settingsAction.forceActiveFocus()
|
||||
} else if (settingsAction.activeFocus) {
|
||||
aboutAction.forceActiveFocus()
|
||||
} else if (aboutAction.activeFocus) {
|
||||
sourceList.forceActiveFocus()
|
||||
sourceList.currentIndex = 0
|
||||
}
|
||||
}
|
||||
function onSelectPressed() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (importAction.activeFocus) {
|
||||
importAction.clicked()
|
||||
} else if (settingsAction.activeFocus) {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,19 @@ import org.kde.alakarte
|
|||
RowLayout {
|
||||
id: root
|
||||
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
spacing: uiMode === Config.Couch ? Kirigami.Units.largeSpacing * 1.25 : Kirigami.Units.largeSpacing
|
||||
|
||||
readonly property bool useGamepadHints: GamepadManager.connected
|
||||
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
|
||||
}
|
||||
readonly property int style: GamepadManager.controllerStyle
|
||||
property string context: "library"
|
||||
|
||||
|
|
@ -49,6 +59,9 @@ RowLayout {
|
|||
function iconForAux(action) {
|
||||
if (!useGamepadHints) return ""
|
||||
|
||||
if (action === "dpad") {
|
||||
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/generic/dpad.svg"
|
||||
}
|
||||
if (action === "lb") {
|
||||
return "qrc:/qt/qml/org/kde/alakarte/qml/icons/gamepad/generic/lb.svg"
|
||||
}
|
||||
|
|
@ -72,12 +85,25 @@ RowLayout {
|
|||
}
|
||||
|
||||
function keyboardLabel(action) {
|
||||
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 ""
|
||||
}
|
||||
}
|
||||
|
||||
if (root.context === "library") {
|
||||
switch (action) {
|
||||
case "navigate": return i18n("Arrows")
|
||||
case "confirm": return "Space"
|
||||
case "back": return "Esc"
|
||||
case "back": return ""
|
||||
case "details": return "Enter"
|
||||
case "search": return "Ctrl+F"
|
||||
case "lb": return "Ctrl+PgUp"
|
||||
case "rb": return "Ctrl+PgDown"
|
||||
case "menu": return "Ctrl+,"
|
||||
default: return ""
|
||||
}
|
||||
|
|
@ -85,6 +111,7 @@ RowLayout {
|
|||
|
||||
if (root.context === "edit") {
|
||||
switch (action) {
|
||||
case "navigate": return "Tab"
|
||||
case "confirm": return "Enter"
|
||||
case "back": return "Esc"
|
||||
default: return ""
|
||||
|
|
@ -93,8 +120,11 @@ RowLayout {
|
|||
|
||||
if (root.context === "details") {
|
||||
switch (action) {
|
||||
case "navigate": return "Tab"
|
||||
case "confirm": return "Enter"
|
||||
case "back": return "Esc"
|
||||
case "details": return "F"
|
||||
case "search": return "E"
|
||||
case "menu": return "Ctrl+,"
|
||||
default: return ""
|
||||
}
|
||||
|
|
@ -102,6 +132,19 @@ RowLayout {
|
|||
|
||||
if (root.context === "sidebar") {
|
||||
switch (action) {
|
||||
case "navigate": return i18n("Arrows/Tab")
|
||||
case "confirm": return "Enter"
|
||||
case "back": return "Esc"
|
||||
case "lb": return "Ctrl+PgUp"
|
||||
case "rb": return "Ctrl+PgDown"
|
||||
case "menu": return "Ctrl+,"
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
if (root.context === "settings") {
|
||||
switch (action) {
|
||||
case "navigate": return "Tab"
|
||||
case "confirm": return "Enter"
|
||||
case "back": return "Esc"
|
||||
case "menu": return "Ctrl+,"
|
||||
|
|
@ -109,8 +152,9 @@ RowLayout {
|
|||
}
|
||||
}
|
||||
|
||||
if (root.context === "settings" || root.context === "import" || root.context === "sidebar") {
|
||||
if (root.context === "settings" || root.context === "import" || root.context === "sidebar" || root.context === "about") {
|
||||
switch (action) {
|
||||
case "navigate": return "Tab"
|
||||
case "confirm": return "Enter"
|
||||
case "back": return "Esc"
|
||||
default: return ""
|
||||
|
|
@ -121,53 +165,90 @@ RowLayout {
|
|||
}
|
||||
|
||||
function actionLabel(action) {
|
||||
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 ""
|
||||
}
|
||||
}
|
||||
|
||||
if (root.context === "library") {
|
||||
switch (action) {
|
||||
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
||||
case "confirm": return i18n("Play")
|
||||
case "back": return i18n("Back")
|
||||
case "back": return ""
|
||||
case "details": return i18n("Details")
|
||||
case "search": return i18n("Search")
|
||||
case "lb": return i18n("Prev Source")
|
||||
case "rb": return i18n("Next Source")
|
||||
case "menu": return i18n("Settings")
|
||||
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")
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
if (root.context === "edit") {
|
||||
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") : ""
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
if (root.context === "details") {
|
||||
switch (action) {
|
||||
case "confirm": return i18n("Play")
|
||||
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
||||
case "confirm": return i18n("Select")
|
||||
case "back": return i18n("Back")
|
||||
case "details": return i18n("Favorite")
|
||||
case "search": return i18n("Edit")
|
||||
case "menu": return i18n("Settings")
|
||||
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Menu") : i18n("Settings")
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
if (root.context === "sidebar") {
|
||||
switch (action) {
|
||||
case "navigate": return (useGamepadHints || keyboardLabel("navigate") !== "") ? i18n("Navigate") : ""
|
||||
case "confirm": return i18n("Select")
|
||||
case "back": return i18n("Back")
|
||||
case "lb": return i18n("Prev Source")
|
||||
case "rb": return i18n("Next Source")
|
||||
case "menu": return i18n("Settings")
|
||||
case "menu": return (useGamepadHints && uiMode === Config.Couch) ? i18n("Close") : i18n("Settings")
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
||||
if (root.context === "settings" || root.context === "import" || root.context === "sidebar") {
|
||||
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") : ""
|
||||
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") : ""
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
|
|
@ -195,7 +276,7 @@ RowLayout {
|
|||
border.width: 1
|
||||
border.color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.2)
|
||||
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 1.4
|
||||
Layout.preferredHeight: uiMode === Config.Couch ? Kirigami.Units.gridUnit * 1.8 : Kirigami.Units.gridUnit * 1.4
|
||||
Layout.preferredWidth: useGamepadHints
|
||||
? Layout.preferredHeight
|
||||
: Math.max(keyText.implicitWidth + Kirigami.Units.mediumSpacing * 2, Layout.preferredHeight)
|
||||
|
|
@ -215,7 +296,7 @@ RowLayout {
|
|||
anchors.centerIn: parent
|
||||
text: parent.parent.keyLabel
|
||||
font.bold: true
|
||||
font.pointSize: Kirigami.Theme.smallFont.pointSize
|
||||
font.pointSize: uiMode === Config.Couch ? Kirigami.Theme.defaultFont.pointSize : Kirigami.Theme.smallFont.pointSize
|
||||
color: Kirigami.Theme.textColor
|
||||
visible: !useGamepadHints
|
||||
}
|
||||
|
|
@ -224,11 +305,18 @@ RowLayout {
|
|||
QQC2.Label {
|
||||
text: parent.label
|
||||
color: Kirigami.Theme.textColor
|
||||
font.pointSize: Kirigami.Theme.smallFont.pointSize
|
||||
font.pointSize: uiMode === Config.Couch ? Kirigami.Theme.defaultFont.pointSize : Kirigami.Theme.smallFont.pointSize
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
HintItem {
|
||||
action: "navigate"
|
||||
label: actionLabel("navigate")
|
||||
iconSource: iconForAux("dpad")
|
||||
keyLabel: keyboardLabel("navigate")
|
||||
}
|
||||
|
||||
HintItem {
|
||||
action: "confirm"
|
||||
label: actionLabel("confirm")
|
||||
|
|
@ -261,20 +349,22 @@ RowLayout {
|
|||
action: "lb"
|
||||
label: actionLabel("lb")
|
||||
iconSource: (root.context === "library" || root.context === "sidebar") ? iconForAux("lb") : ""
|
||||
keyLabel: ""
|
||||
keyLabel: keyboardLabel("lb")
|
||||
}
|
||||
|
||||
HintItem {
|
||||
action: "rb"
|
||||
label: actionLabel("rb")
|
||||
iconSource: (root.context === "library" || root.context === "sidebar") ? iconForAux("rb") : ""
|
||||
keyLabel: ""
|
||||
keyLabel: keyboardLabel("rb")
|
||||
}
|
||||
|
||||
HintItem {
|
||||
action: "menu"
|
||||
label: actionLabel("menu")
|
||||
iconSource: (root.context === "library" || root.context === "details" || root.context === "sidebar") ? iconForAux("menu") : ""
|
||||
iconSource: (useGamepadHints && uiMode === Config.Couch)
|
||||
? iconForAux("menu")
|
||||
: ((root.context === "library" || root.context === "details" || root.context === "sidebar" || root.context === "settings") ? iconForAux("menu") : "")
|
||||
keyLabel: keyboardLabel("menu")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,11 +74,29 @@ GridView {
|
|||
|
||||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateUp() { if (gridView.activeFocus) gridView.navigateUp() }
|
||||
function onNavigateDown() { if (gridView.activeFocus) gridView.navigateDown() }
|
||||
function onNavigateLeft() { if (gridView.activeFocus) gridView.navigateLeft() }
|
||||
function onNavigateRight() { if (gridView.activeFocus) gridView.navigateRight() }
|
||||
function onNavigateUp() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (gridView.activeFocus) gridView.navigateUp()
|
||||
}
|
||||
function onNavigateDown() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (gridView.activeFocus) gridView.navigateDown()
|
||||
}
|
||||
function onNavigateLeft() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (gridView.activeFocus) gridView.navigateLeft()
|
||||
}
|
||||
function onNavigateRight() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (gridView.activeFocus) gridView.navigateRight()
|
||||
}
|
||||
function onSelectPressed() {
|
||||
let w = applicationWindow()
|
||||
if (w && w.currentConfirmDialog && w.currentConfirmDialog()) return
|
||||
if (!gridView.activeFocus) {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,57 @@ QQC2.ToolBar {
|
|||
property alias searchField: searchFieldContainer.data
|
||||
property int currentSortMode: 0
|
||||
|
||||
readonly property bool anyMenuOpen: sortMenu.visible
|
||||
|
||||
function closeCurrentMenu() {
|
||||
if (sortMenu.visible) {
|
||||
sortMenu.close()
|
||||
}
|
||||
}
|
||||
|
||||
function isDescendant(item, ancestor) {
|
||||
let p = item
|
||||
while (p) {
|
||||
if (p === ancestor) return true
|
||||
if (ancestor.contentItem && p === ancestor.contentItem) return true
|
||||
if (p.visualParent !== undefined && p.visualParent !== null) {
|
||||
if (searchHeader.isDescendant(p.visualParent, ancestor)) return true
|
||||
} else if (p.popup !== undefined && p.popup !== null && p.popup.visualParent !== undefined && p.popup.visualParent !== null) {
|
||||
if (searchHeader.isDescendant(p.popup.visualParent, ancestor)) return true
|
||||
}
|
||||
p = p.parent
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function focusNextInMenu(forward) {
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
let next = w.activeFocusItem
|
||||
for (let i = 0; i < 50; i++) {
|
||||
next = next.nextItemInFocusChain(forward)
|
||||
if (!next) return
|
||||
if (searchHeader.isDescendant(next, sortMenu)) {
|
||||
next.forceActiveFocus()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function activateFocusedInMenu() {
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
let item = w.activeFocusItem
|
||||
if (typeof item.triggered === "function") {
|
||||
item.triggered()
|
||||
return
|
||||
}
|
||||
if (typeof item.clicked === "function") {
|
||||
item.clicked()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
signal searchChanged(string text)
|
||||
signal sortChanged(int mode)
|
||||
|
||||
|
|
@ -47,8 +98,12 @@ QQC2.ToolBar {
|
|||
|
||||
QQC2.Menu {
|
||||
id: sortMenu
|
||||
focus: true
|
||||
|
||||
onOpened: Qt.callLater(function() { sortModeLastPlayed.forceActiveFocus() })
|
||||
|
||||
QQC2.MenuItem {
|
||||
id: sortModeLastPlayed
|
||||
text: i18n("Last Played")
|
||||
checkable: true
|
||||
checked: searchHeader.currentSortMode === 0
|
||||
|
|
@ -59,6 +114,7 @@ QQC2.ToolBar {
|
|||
}
|
||||
|
||||
QQC2.MenuItem {
|
||||
id: sortModeName
|
||||
text: i18n("Name")
|
||||
checkable: true
|
||||
checked: searchHeader.currentSortMode === 1
|
||||
|
|
@ -69,6 +125,7 @@ QQC2.ToolBar {
|
|||
}
|
||||
|
||||
QQC2.MenuItem {
|
||||
id: sortModePlayTime
|
||||
text: i18n("Play Time")
|
||||
checkable: true
|
||||
checked: searchHeader.currentSortMode === 2
|
||||
|
|
@ -80,4 +137,43 @@ QQC2.ToolBar {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: GamepadManager
|
||||
function onNavigateUp() {
|
||||
if (!sortMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!searchHeader.isDescendant(w.activeFocusItem, sortMenu)) return
|
||||
searchHeader.focusNextInMenu(false)
|
||||
}
|
||||
function onNavigateDown() {
|
||||
if (!sortMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!searchHeader.isDescendant(w.activeFocusItem, sortMenu)) return
|
||||
searchHeader.focusNextInMenu(true)
|
||||
}
|
||||
function onNavigateLeft() {
|
||||
if (!sortMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!searchHeader.isDescendant(w.activeFocusItem, sortMenu)) return
|
||||
searchHeader.focusNextInMenu(false)
|
||||
}
|
||||
function onNavigateRight() {
|
||||
if (!sortMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!searchHeader.isDescendant(w.activeFocusItem, sortMenu)) return
|
||||
searchHeader.focusNextInMenu(true)
|
||||
}
|
||||
function onSelectPressed() {
|
||||
if (!sortMenu.visible) return
|
||||
let w = applicationWindow()
|
||||
if (!w || !w.activeFocusItem) return
|
||||
if (!searchHeader.isDescendant(w.activeFocusItem, sortMenu)) return
|
||||
searchHeader.activateFocusedInMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue