Skip to content

Commit

Permalink
Add steam games model (#25)
Browse files Browse the repository at this point in the history
* Add SteamGamesModel

* Add basic game list view

* rollback mainwindow.qml
  • Loading branch information
zhulik authored Jul 13, 2023
1 parent 6eabcd6 commit 76006df
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 2 deletions.
30 changes: 30 additions & 0 deletions resources/qml/GamesView/GameDelegate.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

import "../" as Core

ItemDelegate {
id: root

clip: true

ColumnLayout {
anchors.margins: 5
anchors.fill: parent

Core.AsyncImage {
Layout.alignment: Qt.AlignHCenter
width: parent.width * 0.9
height: parent.height * 0.8
source: libraryImagePath
}

Label {
Layout.fillWidth: parent
text: name
elide: Text.ElideMiddle
horizontalAlignment: "AlignHCenter"
}
}
}
47 changes: 47 additions & 0 deletions resources/qml/GamesView/GamesView.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import Qt.labs.platform 1.1

import QtQuick.Controls.Material 2.12

import DeckFM 1.0
import Steamworks.SteamInput 1.0

import "../MDI" as MDI
import ".." as Core

import "../QSteamworks" as Steamworks

Item {
id: root

property bool showFooter: true
property var hintActions: ["scroll", "file_manager_open", "file_manager_go_back", "file_manager_go_home"]

GridView {
id: view
anchors.fill: parent

model: SteamGamesModel {
id: fames_model
onModelReset: view.currentIndex = 0
}

cellWidth: 150
cellHeight: 210
clip: true
keyNavigationWraps: false

ScrollBar.vertical: ScrollBar {}

delegate: GameDelegate {
width: view.cellWidth
height: view.cellHeight
}

highlight: Rectangle {
color: Material.primary
}
}
}
4 changes: 4 additions & 0 deletions resources/qml/MainWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Steamworks 1.0
import Steamworks.SteamInput 1.0

import "./DirectoryView" as DirView
import "./GamesView" as GamesView

import "MainWindow.js" as JS

Expand Down Expand Up @@ -125,6 +126,9 @@ ApplicationWindow {

onFileOpened: JS.openFile(path)
}
GamesView.GamesView {
id: gamesView
}
}

GlobalMenu {
Expand Down
6 changes: 5 additions & 1 deletion src/QSteamworks/QSteamInput/qmlsteaminputscope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ void QMLSteamInputScope::rebuildInputStack() {
i++;
}

setActiveControls(stack.last() + globals);
if (stack.count() > 0) {
setActiveControls(stack.last() + globals);
} else {
setActiveControls(globals);
}
}

QList<QSteamworks::QSteamInput::QMLSteamInputControl *> QMLSteamInputScope::activeControls() const {
Expand Down
2 changes: 1 addition & 1 deletion src/QSteamworks/steaminput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static const QMap<ESteamInputType, QString> controllerNames{
{k_ESteamInputType_SwitchProController, "Switch Pro"},
{k_ESteamInputType_MobileTouch, "Mobile Touch"}};

QString readFile(QString const &path) {
static QString readFile(QString const &path) {
QFile f(path);

if (!f.open(QFile::ReadOnly | QFile::Text)) {
Expand Down
2 changes: 2 additions & 0 deletions src/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "QSteamworks/errors.h"
#include "QSteamworks/steamapi.h"
#include "qnetworkaccessmanager.h"
#include "steamgamesmodel.h"

Application::Application(int &argc, char **argv) : QGuiApplication{argc, argv} {
setOrganizationName("zhulik");
Expand All @@ -28,6 +29,7 @@ Application::Application(int &argc, char **argv) : QGuiApplication{argc, argv} {
cacheThumbnailImageProvider->setCache(new DiskCache(m_engine));

qmlRegisterType<FolderListModel>("DeckFM", 1, 0, "FolderListModel");
qmlRegisterType<SteamGamesModel>("DeckFM", 1, 0, "SteamGamesModel");

// TODO: move to an init function in QSteamworks
QSteamworks::registerTypes();
Expand Down
68 changes: 68 additions & 0 deletions src/steamgamesmodel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include "steamgamesmodel.h"
#include "QSteamInput/vdfparser.h"
#include "qglobal.h"
#include "steam/steamtypes.h"

#include <QDebug>
#include <QStandardPaths>

static QString readFile(QString const &path) {
QFile f(path);

if (!f.open(QFile::ReadOnly | QFile::Text)) {
throw std::runtime_error(QString("Cannot read file %1").arg(path).toLocal8Bit());
}

return QTextStream(&f).readAll();
}

SteamGamesModel::SteamGamesModel(QObject *parent) : QAbstractListModel{parent} {
m_root = QDir(QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0]);
m_root.cd(".local/share/Steam");

refresh();
}

int SteamGamesModel::rowCount(const QModelIndex &parent) const { return m_games.count(); }

QVariant SteamGamesModel::data(const QModelIndex &index, int role) const {
auto game = m_games.values()[index.row()];
switch (role) {
case Id:
return game.id;
case Name:
return game.name;
case LibraryImagePath:
return game.libraryImagePath;
default:
return QVariant();
}
}

QHash<int, QByteArray> SteamGamesModel::roleNames() const {
return QHash<int, QByteArray>{{Id, "id"}, {Name, "name"}, {LibraryImagePath, "libraryImagePath"}};
}

void SteamGamesModel::refresh() {
VDFParser parser;

auto libraryFolders =
parser.parse(readFile(m_root.absoluteFilePath("config/libraryfolders.vdf")))["libraryfolders"].toObject();

beginResetModel();
m_games.clear();
foreach (auto k, libraryFolders.keys()) {
auto folderObj = libraryFolders[k].toObject();
auto dir = QDir(folderObj["path"].toString());
dir.cd("steamapps");
Q_ASSERT(dir.exists());

foreach (auto gameId, folderObj["apps"].toObject().keys()) {
auto id = gameId.toUInt();
auto manifest = parser.parse(readFile(dir.absoluteFilePath(QString("appmanifest_%1.acf").arg(gameId))));
m_games[id] = SteamGame{id, manifest["AppState"].toObject()["name"].toString(),
m_root.absoluteFilePath(QString("appcache/librarycache/%1_library_600x900.jpg").arg(id))};
}
}
endResetModel();
}
29 changes: 29 additions & 0 deletions src/steamgamesmodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include "qobjectdefs.h"
#include <QAbstractListModel>
#include <QDir>

struct SteamGame {
uint id = -1;
QString name;
QString libraryImagePath;
};

class SteamGamesModel : public QAbstractListModel {
Q_OBJECT
public:
enum Role { Id = Qt::UserRole, Name, LibraryImagePath };

explicit SteamGamesModel(QObject *parent = nullptr);

Q_INVOKABLE void refresh();

virtual int rowCount(const QModelIndex &parent) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
virtual QHash<int, QByteArray> roleNames() const override;

private:
QDir m_root;
QHash<uint, SteamGame> m_games;
};

0 comments on commit 76006df

Please sign in to comment.