shift-shell/containments/homescreens/folio/qml/gaming/GameCenterOverlay.qml

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

197 lines
6.4 KiB
QML
Raw Normal View History

// SPDX-FileCopyrightText: 2026 Marco Allegretti
// SPDX-License-Identifier: EUPL-1.2
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as QQC2
import QtQuick.Window
import org.kde.kirigami as Kirigami
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
import org.kde.layershell 1.0 as LayerShell
import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
Window {
id: root
required property var folio
signal gameStarted()
signal dismissRequested()
function requestExitGamingMode() {
exitGamingDialog.active = true
exitGamingDialog.item.open()
}
width: Screen.width
height: Screen.height
color: "transparent"
flags: Qt.FramelessWindowHint
LayerShell.Window.scope: "gaming-overlay"
LayerShell.Window.layer: LayerShell.Window.LayerTop
LayerShell.Window.anchors: LayerShell.Window.AnchorTop | LayerShell.Window.AnchorBottom
| LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
LayerShell.Window.exclusionZone: -1
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityOnDemand
// Animate opacity on show/hide
opacity: visible ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
}
onVisibleChanged: {
if (visible) {
root.folio.ApplicationListSearchModel.categoryFilter = "Game"
if (runningGames.hasTasks) {
runningGames.focusFirstTask()
} else {
grid.forceActiveFocus()
}
}
}
Rectangle {
anchors.fill: parent
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.Window
color: Qt.rgba(Kirigami.Theme.backgroundColor.r,
Kirigami.Theme.backgroundColor.g,
Kirigami.Theme.backgroundColor.b, 0.92)
}
FocusScope {
id: contentRoot
anchors.fill: parent
focus: root.visible
// Escape only dismisses the overlay; exiting gaming mode is explicit.
Keys.onEscapePressed: root.dismissRequested()
ColumnLayout {
anchors.fill: parent
anchors.margins: Kirigami.Units.largeSpacing * 2
spacing: Kirigami.Units.largeSpacing
// ---- header ----
RowLayout {
Layout.fillWidth: true
Kirigami.Heading {
Layout.fillWidth: true
text: i18n("Game Center")
level: 1
}
QQC2.ToolButton {
icon.name: "window-close"
text: i18n("Exit Gaming Mode")
display: QQC2.AbstractButton.TextBesideIcon
Keys.onReturnPressed: clicked()
Keys.onEnterPressed: clicked()
onClicked: root.requestExitGamingMode()
}
}
// ---- running games ----
RunningGamesView {
id: runningGames
Layout.fillWidth: true
onTaskActivated: root.gameStarted()
onMoveDownRequested: grid.forceActiveFocus()
}
// ---- game grid ----
Kirigami.Heading {
level: 2
text: i18n("Library")
}
GridView {
id: grid
Layout.fillWidth: true
Layout.fillHeight: true
// Filter the app list to the Games XDG category.
// ApplicationListSearchModel.categoryFilter is declared in
// applicationlistmodel.h and filters on the CategoriesRole of
// ApplicationListModel.
model: root.folio.ApplicationListSearchModel
readonly property real minCellSize: Kirigami.Units.gridUnit * 7
readonly property int columns: Math.max(2, Math.floor(width / minCellSize))
cellWidth: Math.floor(width / columns)
cellHeight: cellWidth + Kirigami.Units.gridUnit * 2
keyNavigationEnabled: true
highlightMoveDuration: 0
highlight: null
onActiveFocusChanged: {
if (activeFocus && count > 0 && currentIndex < 0) {
currentIndex = 0
}
}
Keys.onUpPressed: {
if (runningGames.hasTasks) {
runningGames.focusFirstTask()
}
}
Keys.onReturnPressed: currentItem && currentItem.launch()
Keys.onEnterPressed: currentItem && currentItem.launch()
Keys.onEscapePressed: root.dismissRequested()
delegate: Item {
width: grid.cellWidth
height: grid.cellHeight
GameTile {
anchors.fill: parent
folio: root.folio
application: model.delegate ? model.delegate.application : null
isCurrent: GridView.isCurrentItem && grid.activeFocus
onLaunchRequested: root.gameStarted()
}
}
}
}
}
Loader {
id: exitGamingDialog
active: false
anchors.fill: parent
sourceComponent: Kirigami.PromptDialog {
id: theExitDialog
title: i18n("Leave gaming mode?")
subtitle: i18n("Your games will keep running in the background.")
standardButtons: Kirigami.Dialog.NoButton
customFooterActions: [
Kirigami.Action {
text: i18n("Keep Playing")
onTriggered: theExitDialog.close()
},
Kirigami.Action {
text: i18n("Leave")
onTriggered: {
ShellSettings.Settings.gamingModeEnabled = false
theExitDialog.close()
}
}
]
onClosed: exitGamingDialog.active = false
}
}
}