mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-06-11 00:47:22 +00:00
Rework Game Center into console-style capsule rails
Restructure the overlay around landscape 16:9 media capsules, clearer focus borders, tighter search/filter rails, and stronger handheld vs big-screen spacing hierarchy.
This commit is contained in:
parent
434f46403c
commit
75a0f7a21e
1 changed files with 145 additions and 135 deletions
|
|
@ -41,6 +41,15 @@ Window {
|
||||||
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
|
readonly property int shortAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsFast)
|
||||||
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
|
readonly property int longAnimationDuration: MobileShell.Motion.duration(MobileShell.Motion.EffectsDefault)
|
||||||
readonly property int launchFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.StandardAccel)
|
readonly property int launchFadeDuration: MobileShell.Motion.duration(MobileShell.Motion.StandardAccel)
|
||||||
|
readonly property int shortestSide: Math.min(width, height)
|
||||||
|
readonly property bool compactMode: !ShellSettings.Settings.convergenceModeEnabled && shortestSide <= Kirigami.Units.gridUnit * 50
|
||||||
|
readonly property bool bigScreenMode: !compactMode
|
||||||
|
readonly property int horizontalPadding: compactMode ? Kirigami.Units.largeSpacing : Kirigami.Units.largeSpacing * 2
|
||||||
|
readonly property int verticalPadding: compactMode ? Kirigami.Units.largeSpacing : Kirigami.Units.largeSpacing * 2
|
||||||
|
readonly property real gridMinCellSize: compactMode ? Kirigami.Units.gridUnit * 6.8 : Kirigami.Units.gridUnit * 8.8
|
||||||
|
// Steam library assets heavily favor wide capsules and 16:9 media surfaces.
|
||||||
|
// Keep game tiles landscape-first to avoid mobile-style portrait cards.
|
||||||
|
readonly property real capsuleArtAspect: 16 / 9
|
||||||
|
|
||||||
function controlLegendText() {
|
function controlLegendText() {
|
||||||
if (GamingShell.GamepadManager.hasGamepad) {
|
if (GamingShell.GamepadManager.hasGamepad) {
|
||||||
|
|
@ -508,7 +517,7 @@ Window {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||||
color: MobileShell.SurfaceColors.withAlpha(MobileShell.SurfaceColors.accentSurface(Kirigami.Theme.backgroundColor, 0.24, 0.12), 0.92)
|
color: MobileShell.SurfaceColors.withAlpha(MobileShell.SurfaceColors.accentSurface(Kirigami.Theme.backgroundColor, 0.24, 0.12), root.bigScreenMode ? 0.94 : 0.9)
|
||||||
}
|
}
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
|
|
@ -521,8 +530,11 @@ Window {
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Kirigami.Units.largeSpacing * 2
|
anchors.leftMargin: root.horizontalPadding
|
||||||
spacing: Kirigami.Units.largeSpacing
|
anchors.rightMargin: root.horizontalPadding
|
||||||
|
anchors.topMargin: root.verticalPadding
|
||||||
|
anchors.bottomMargin: root.verticalPadding
|
||||||
|
spacing: root.compactMode ? Kirigami.Units.smallSpacing : Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
// ---- header ----
|
// ---- header ----
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|
@ -531,7 +543,7 @@ Window {
|
||||||
|
|
||||||
Kirigami.Heading {
|
Kirigami.Heading {
|
||||||
text: i18n("Game Center")
|
text: i18n("Game Center")
|
||||||
level: 1
|
level: root.compactMode ? 2 : 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { Layout.fillWidth: true }
|
Item { Layout.fillWidth: true }
|
||||||
|
|
@ -586,7 +598,7 @@ Window {
|
||||||
|
|
||||||
QQC2.ToolButton {
|
QQC2.ToolButton {
|
||||||
icon.name: "window-close"
|
icon.name: "window-close"
|
||||||
text: i18n("Exit Gaming Mode")
|
text: root.compactMode ? i18n("Exit") : i18n("Exit Gaming Mode")
|
||||||
display: QQC2.AbstractButton.TextBesideIcon
|
display: QQC2.AbstractButton.TextBesideIcon
|
||||||
Keys.onReturnPressed: clicked()
|
Keys.onReturnPressed: clicked()
|
||||||
Keys.onEnterPressed: clicked()
|
Keys.onEnterPressed: clicked()
|
||||||
|
|
@ -598,6 +610,7 @@ Window {
|
||||||
RunningGamesView {
|
RunningGamesView {
|
||||||
id: runningGames
|
id: runningGames
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
compactMode: root.compactMode
|
||||||
onTaskActivated: {
|
onTaskActivated: {
|
||||||
GamingShell.GameLauncherProvider.clearPendingLaunch()
|
GamingShell.GameLauncherProvider.clearPendingLaunch()
|
||||||
root.gameStarted()
|
root.gameStarted()
|
||||||
|
|
@ -652,7 +665,9 @@ Window {
|
||||||
ListView {
|
ListView {
|
||||||
id: recentList
|
id: recentList
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 5
|
readonly property int cardWidth: root.compactMode ? Kirigami.Units.gridUnit * 8 : Kirigami.Units.gridUnit * 10
|
||||||
|
readonly property int artHeight: Math.round(cardWidth / root.capsuleArtAspect)
|
||||||
|
Layout.preferredHeight: artHeight + Kirigami.Units.gridUnit * 1.7
|
||||||
orientation: ListView.Horizontal
|
orientation: ListView.Horizontal
|
||||||
spacing: Kirigami.Units.largeSpacing
|
spacing: Kirigami.Units.largeSpacing
|
||||||
clip: true
|
clip: true
|
||||||
|
|
@ -690,7 +705,7 @@ Window {
|
||||||
Keys.onDownPressed: grid.forceActiveFocus()
|
Keys.onDownPressed: grid.forceActiveFocus()
|
||||||
|
|
||||||
delegate: QQC2.ItemDelegate {
|
delegate: QQC2.ItemDelegate {
|
||||||
width: Kirigami.Units.gridUnit * 7
|
width: recentList.cardWidth
|
||||||
height: recentList.height
|
height: recentList.height
|
||||||
|
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
@ -704,16 +719,26 @@ Window {
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
radius: Kirigami.Units.cornerRadius
|
radius: Kirigami.Units.cornerRadius
|
||||||
color: parent.isCurrent
|
color: parent.isCurrent
|
||||||
? Kirigami.Theme.highlightColor
|
? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.22)
|
||||||
: (parent.hovered ? Kirigami.Theme.hoverColor : "transparent")
|
: (parent.hovered
|
||||||
|
? Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.08)
|
||||||
|
: "transparent")
|
||||||
|
border.color: parent.isCurrent ? Kirigami.Theme.highlightColor : "transparent"
|
||||||
|
border.width: parent.isCurrent ? 2 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
Image {
|
Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.preferredHeight: recentList.artHeight
|
||||||
|
radius: Kirigami.Units.cornerRadius
|
||||||
|
clip: true
|
||||||
|
color: Qt.rgba(Kirigami.Theme.alternateBackgroundColor.r, Kirigami.Theme.alternateBackgroundColor.g, Kirigami.Theme.alternateBackgroundColor.b, 0.8)
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
source: hasArt ? "file://" + modelData.artwork : ""
|
source: hasArt ? "file://" + modelData.artwork : ""
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
visible: hasArt
|
visible: hasArt
|
||||||
|
|
@ -721,19 +746,20 @@ Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.Icon {
|
Kirigami.Icon {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
anchors.centerIn: parent
|
||||||
implicitWidth: Kirigami.Units.iconSizes.large
|
implicitWidth: Kirigami.Units.iconSizes.large
|
||||||
implicitHeight: Kirigami.Units.iconSizes.large
|
implicitHeight: Kirigami.Units.iconSizes.large
|
||||||
source: modelData.icon
|
source: modelData.icon
|
||||||
visible: !hasArt
|
visible: !hasArt
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PC3.Label {
|
PC3.Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: modelData.name
|
text: modelData.name
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignLeft
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.85
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.85
|
||||||
color: parent.parent.isCurrent
|
color: parent.parent.isCurrent
|
||||||
? Kirigami.Theme.highlightedTextColor
|
? Kirigami.Theme.highlightedTextColor
|
||||||
|
|
@ -761,9 +787,14 @@ Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- search + filter ----
|
// ---- search + filter ----
|
||||||
RowLayout {
|
Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: Kirigami.Units.largeSpacing
|
implicitHeight: searchFilterStack.implicitHeight
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: searchFilterStack
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
Kirigami.SearchField {
|
Kirigami.SearchField {
|
||||||
id: searchField
|
id: searchField
|
||||||
|
|
@ -783,6 +814,7 @@ Window {
|
||||||
|
|
||||||
QQC2.TabBar {
|
QQC2.TabBar {
|
||||||
id: sourceFilterBar
|
id: sourceFilterBar
|
||||||
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
|
@ -808,6 +840,7 @@ Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---- game grid ----
|
// ---- game grid ----
|
||||||
|
|
||||||
|
|
@ -819,11 +852,12 @@ Window {
|
||||||
|
|
||||||
model: GamingShell.GameLauncherProvider
|
model: GamingShell.GameLauncherProvider
|
||||||
|
|
||||||
readonly property real minCellSize: Kirigami.Units.gridUnit * 8
|
readonly property real minCellSize: root.gridMinCellSize
|
||||||
readonly property int columns: Math.max(2, Math.floor(width / minCellSize))
|
readonly property int columns: Math.max(2, Math.floor(width / minCellSize))
|
||||||
|
|
||||||
cellWidth: Math.floor(width / columns)
|
cellWidth: Math.floor(width / columns)
|
||||||
cellHeight: Math.floor(cellWidth * 1.5) + Kirigami.Units.gridUnit * 2
|
readonly property int artHeight: Math.round(cellWidth / root.capsuleArtAspect)
|
||||||
|
cellHeight: artHeight + (root.compactMode ? Kirigami.Units.gridUnit * 1.9 : Kirigami.Units.gridUnit * 2.2)
|
||||||
|
|
||||||
keyNavigationEnabled: true
|
keyNavigationEnabled: true
|
||||||
highlightMoveDuration: 0
|
highlightMoveDuration: 0
|
||||||
|
|
@ -898,7 +932,7 @@ Window {
|
||||||
|
|
||||||
QQC2.ItemDelegate {
|
QQC2.ItemDelegate {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Kirigami.Units.smallSpacing
|
anchors.margins: root.compactMode ? 0 : Kirigami.Units.smallSpacing
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
readonly property bool isCurrent: GridView.isCurrentItem && grid.activeFocus
|
readonly property bool isCurrent: GridView.isCurrentItem && grid.activeFocus
|
||||||
|
|
@ -906,24 +940,30 @@ Window {
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
||||||
color: parent.isCurrent
|
color: parent.isCurrent
|
||||||
? Kirigami.Theme.highlightColor
|
? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g,
|
||||||
: (parent.hovered ? Kirigami.Theme.hoverColor : "transparent")
|
Kirigami.Theme.highlightColor.b, 0.22)
|
||||||
|
: (parent.hovered
|
||||||
|
? Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g,
|
||||||
|
Kirigami.Theme.textColor.b, 0.08)
|
||||||
|
: "transparent")
|
||||||
radius: Kirigami.Units.cornerRadius
|
radius: Kirigami.Units.cornerRadius
|
||||||
|
border.color: parent.isCurrent ? Kirigami.Theme.highlightColor : "transparent"
|
||||||
|
border.width: parent.isCurrent ? 2 : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
// ---- cover art tile ----
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: Kirigami.Units.smallSpacing
|
||||||
visible: hasArt
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.preferredHeight: grid.artHeight
|
||||||
radius: Kirigami.Units.cornerRadius
|
radius: Kirigami.Units.cornerRadius
|
||||||
clip: true
|
clip: true
|
||||||
color: "transparent"
|
color: Qt.rgba(Kirigami.Theme.alternateBackgroundColor.r,
|
||||||
|
Kirigami.Theme.alternateBackgroundColor.g,
|
||||||
|
Kirigami.Theme.alternateBackgroundColor.b, 0.85)
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -931,6 +971,15 @@ Window {
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
smooth: true
|
smooth: true
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
visible: hasArt
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.Icon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
implicitWidth: root.compactMode ? Kirigami.Units.iconSizes.large : Kirigami.Units.iconSizes.huge
|
||||||
|
implicitHeight: implicitWidth
|
||||||
|
source: icon
|
||||||
|
visible: !hasArt
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -954,76 +1003,35 @@ Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title beneath artwork
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
PC3.Label {
|
PC3.Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 2
|
|
||||||
text: name
|
text: name
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignLeft
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
leftPadding: Kirigami.Units.smallSpacing
|
leftPadding: Kirigami.Units.smallSpacing
|
||||||
rightPadding: Kirigami.Units.smallSpacing
|
rightPadding: Kirigami.Units.smallSpacing
|
||||||
color: parent.parent.parent.isCurrent
|
color: parent.parent.parent.isCurrent
|
||||||
? Kirigami.Theme.highlightedTextColor
|
? Kirigami.Theme.highlightedTextColor
|
||||||
: Kirigami.Theme.textColor
|
: Kirigami.Theme.textColor
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ---- fallback icon tile ----
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Kirigami.Units.smallSpacing
|
|
||||||
visible: !hasArt
|
|
||||||
spacing: Kirigami.Units.smallSpacing
|
|
||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
|
||||||
|
|
||||||
Kirigami.Icon {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
implicitWidth: Kirigami.Units.iconSizes.huge
|
|
||||||
implicitHeight: Kirigami.Units.iconSizes.huge
|
|
||||||
source: icon
|
|
||||||
|
|
||||||
scale: parent.parent.parent.isCurrent ? 1.08 : 1.0
|
|
||||||
Behavior on scale {
|
|
||||||
MobileShell.MotionNumberAnimation { type: MobileShell.Motion.EffectsFast; duration: root.shortAnimationDuration }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PC3.Label {
|
PC3.Label {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: name
|
visible: lastPlayedText.length > 0
|
||||||
maximumLineCount: 2
|
text: lastPlayedText
|
||||||
wrapMode: Text.Wrap
|
maximumLineCount: 1
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
color: parent.parent.parent.isCurrent
|
leftPadding: Kirigami.Units.smallSpacing
|
||||||
? Kirigami.Theme.highlightedTextColor
|
rightPadding: Kirigami.Units.smallSpacing
|
||||||
: Kirigami.Theme.textColor
|
opacity: 0.65
|
||||||
}
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.78
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
visible: source !== "desktop"
|
|
||||||
radius: height / 2
|
|
||||||
color: root.sourceChipColor(source)
|
|
||||||
implicitHeight: sourceChipLabel.implicitHeight + Kirigami.Units.smallSpacing
|
|
||||||
implicitWidth: sourceChipLabel.implicitWidth + Kirigami.Units.largeSpacing
|
|
||||||
|
|
||||||
PC3.Label {
|
|
||||||
id: sourceChipLabel
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: root.sourceLabel(source)
|
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.72
|
|
||||||
font.weight: Font.DemiBold
|
|
||||||
color: "white"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { Layout.fillHeight: true }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1074,6 +1082,7 @@ Window {
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: GamingShell.GamepadManager
|
model: GamingShell.GamepadManager
|
||||||
|
visible: root.bigScreenMode
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: Kirigami.Units.smallSpacing
|
spacing: Kirigami.Units.smallSpacing
|
||||||
|
|
@ -1113,7 +1122,7 @@ Window {
|
||||||
PC3.Label {
|
PC3.Label {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: root.controlLegendText()
|
text: root.controlLegendText()
|
||||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.75
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * (root.compactMode ? 0.7 : 0.75)
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
horizontalAlignment: Text.AlignRight
|
horizontalAlignment: Text.AlignRight
|
||||||
|
|
@ -1126,6 +1135,7 @@ Window {
|
||||||
GamingQuickSettings {
|
GamingQuickSettings {
|
||||||
id: quickSettings
|
id: quickSettings
|
||||||
z: 50
|
z: 50
|
||||||
|
compactMode: root.compactMode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Launch transition: brief fade to black, then dismiss
|
// Launch transition: brief fade to black, then dismiss
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue