mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-02-09 21:13:08 +00:00
Add launch profiles MVP
Store per-game launch profile overrides and active profile selection in library.json. Add a quick profile toggle in the details sheet and minimal editing in the edit dialog. Apply the effective profile config in both launching and diagnostics.
This commit is contained in:
parent
1889f9cf81
commit
ec7d61e5b9
5 changed files with 356 additions and 28 deletions
227
src/game.cpp
227
src/game.cpp
|
|
@ -185,6 +185,129 @@ void Game::setLaunchPrefixPath(const QString &path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Game::activeLaunchProfile() const
|
||||||
|
{
|
||||||
|
return m_activeLaunchProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::setActiveLaunchProfile(const QString &profileId)
|
||||||
|
{
|
||||||
|
const QString normalized = profileId.trimmed().isEmpty() ? QStringLiteral("default") : profileId.trimmed();
|
||||||
|
if (m_activeLaunchProfile != normalized) {
|
||||||
|
m_activeLaunchProfile = normalized;
|
||||||
|
Q_EMIT activeLaunchProfileChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap Game::launchProfileConfig(const QString &profileId) const
|
||||||
|
{
|
||||||
|
const QString id = profileId.trimmed();
|
||||||
|
if (id.isEmpty() || id == QLatin1String("default")) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariant value = m_launchProfiles.value(id);
|
||||||
|
if (!value.isValid()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.toMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::setLaunchProfileConfig(const QString &profileId, const QVariantMap &config)
|
||||||
|
{
|
||||||
|
const QString id = profileId.trimmed();
|
||||||
|
if (id.isEmpty() || id == QLatin1String("default")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap cleaned;
|
||||||
|
|
||||||
|
const QString runner = config.value(QStringLiteral("runner")).toString().trimmed();
|
||||||
|
if (!runner.isEmpty()) {
|
||||||
|
cleaned.insert(QStringLiteral("runner"), runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString runnerPath = config.value(QStringLiteral("runnerPath")).toString().trimmed();
|
||||||
|
if (!runnerPath.isEmpty()) {
|
||||||
|
cleaned.insert(QStringLiteral("runnerPath"), runnerPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString prefixPath = config.value(QStringLiteral("prefixPath")).toString().trimmed();
|
||||||
|
if (!prefixPath.isEmpty()) {
|
||||||
|
cleaned.insert(QStringLiteral("prefixPath"), prefixPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariantMap env = config.value(QStringLiteral("env")).toMap();
|
||||||
|
if (!env.isEmpty()) {
|
||||||
|
cleaned.insert(QStringLiteral("env"), env);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cleaned.isEmpty()) {
|
||||||
|
m_launchProfiles.remove(id);
|
||||||
|
} else {
|
||||||
|
m_launchProfiles.insert(id, cleaned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap Game::effectiveLaunchConfig() const
|
||||||
|
{
|
||||||
|
QVariantMap result;
|
||||||
|
|
||||||
|
if (!m_launchRunner.isEmpty()) {
|
||||||
|
result.insert(QStringLiteral("runner"), m_launchRunner);
|
||||||
|
}
|
||||||
|
if (!m_launchRunnerPath.isEmpty()) {
|
||||||
|
result.insert(QStringLiteral("runnerPath"), m_launchRunnerPath);
|
||||||
|
}
|
||||||
|
if (!m_launchPrefixPath.isEmpty()) {
|
||||||
|
result.insert(QStringLiteral("prefixPath"), m_launchPrefixPath);
|
||||||
|
}
|
||||||
|
if (!m_launchEnv.isEmpty()) {
|
||||||
|
result.insert(QStringLiteral("env"), m_launchEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString profileId = m_activeLaunchProfile.trimmed();
|
||||||
|
if (profileId.isEmpty() || profileId == QLatin1String("default")) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariantMap profileConfig = launchProfileConfig(profileId);
|
||||||
|
if (profileConfig.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString runner = profileConfig.value(QStringLiteral("runner")).toString().trimmed();
|
||||||
|
if (!runner.isEmpty()) {
|
||||||
|
result.insert(QStringLiteral("runner"), runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString runnerPath = profileConfig.value(QStringLiteral("runnerPath")).toString().trimmed();
|
||||||
|
if (!runnerPath.isEmpty()) {
|
||||||
|
result.insert(QStringLiteral("runnerPath"), runnerPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString prefixPath = profileConfig.value(QStringLiteral("prefixPath")).toString().trimmed();
|
||||||
|
if (!prefixPath.isEmpty()) {
|
||||||
|
result.insert(QStringLiteral("prefixPath"), prefixPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariantMap profileEnv = profileConfig.value(QStringLiteral("env")).toMap();
|
||||||
|
if (!profileEnv.isEmpty()) {
|
||||||
|
QVariantMap mergedEnv;
|
||||||
|
const QVariantMap baseEnv = result.value(QStringLiteral("env")).toMap();
|
||||||
|
for (auto it = baseEnv.constBegin(); it != baseEnv.constEnd(); ++it) {
|
||||||
|
mergedEnv.insert(it.key(), it.value());
|
||||||
|
}
|
||||||
|
for (auto it = profileEnv.constBegin(); it != profileEnv.constEnd(); ++it) {
|
||||||
|
mergedEnv.insert(it.key(), it.value());
|
||||||
|
}
|
||||||
|
result.insert(QStringLiteral("env"), mergedEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QString Game::platform() const
|
QString Game::platform() const
|
||||||
{
|
{
|
||||||
return m_platform;
|
return m_platform;
|
||||||
|
|
@ -323,7 +446,8 @@ QJsonObject Game::toJson() const
|
||||||
obj[QStringLiteral("hidden")] = m_hidden;
|
obj[QStringLiteral("hidden")] = m_hidden;
|
||||||
obj[QStringLiteral("installed")] = m_installed;
|
obj[QStringLiteral("installed")] = m_installed;
|
||||||
|
|
||||||
const bool hasLaunchConfig = !m_launchEnv.isEmpty() || !m_launchRunner.isEmpty() || !m_launchRunnerPath.isEmpty() || !m_launchPrefixPath.isEmpty();
|
const bool hasLaunchConfig = !m_launchEnv.isEmpty() || !m_launchRunner.isEmpty() || !m_launchRunnerPath.isEmpty() || !m_launchPrefixPath.isEmpty()
|
||||||
|
|| !m_launchProfiles.isEmpty() || (!m_activeLaunchProfile.isEmpty() && m_activeLaunchProfile != QLatin1String("default"));
|
||||||
if (hasLaunchConfig) {
|
if (hasLaunchConfig) {
|
||||||
QJsonObject launchObj;
|
QJsonObject launchObj;
|
||||||
|
|
||||||
|
|
@ -345,6 +469,57 @@ QJsonObject Game::toJson() const
|
||||||
launchObj.insert(QStringLiteral("prefixPath"), m_launchPrefixPath);
|
launchObj.insert(QStringLiteral("prefixPath"), m_launchPrefixPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_activeLaunchProfile.isEmpty() && m_activeLaunchProfile != QLatin1String("default")) {
|
||||||
|
launchObj.insert(QStringLiteral("activeProfile"), m_activeLaunchProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_launchProfiles.isEmpty()) {
|
||||||
|
QJsonObject profilesObj;
|
||||||
|
for (auto it = m_launchProfiles.constBegin(); it != m_launchProfiles.constEnd(); ++it) {
|
||||||
|
const QString profileId = it.key();
|
||||||
|
if (profileId.isEmpty() || profileId == QLatin1String("default")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariantMap profileConfig = it.value().toMap();
|
||||||
|
if (profileConfig.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject profileObj;
|
||||||
|
|
||||||
|
const QString runner = profileConfig.value(QStringLiteral("runner")).toString();
|
||||||
|
if (!runner.isEmpty()) {
|
||||||
|
profileObj.insert(QStringLiteral("runner"), runner);
|
||||||
|
}
|
||||||
|
const QString runnerPath = profileConfig.value(QStringLiteral("runnerPath")).toString();
|
||||||
|
if (!runnerPath.isEmpty()) {
|
||||||
|
profileObj.insert(QStringLiteral("runnerPath"), runnerPath);
|
||||||
|
}
|
||||||
|
const QString prefixPath = profileConfig.value(QStringLiteral("prefixPath")).toString();
|
||||||
|
if (!prefixPath.isEmpty()) {
|
||||||
|
profileObj.insert(QStringLiteral("prefixPath"), prefixPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariantMap env = profileConfig.value(QStringLiteral("env")).toMap();
|
||||||
|
if (!env.isEmpty()) {
|
||||||
|
QJsonObject envObj;
|
||||||
|
for (auto envIt = env.constBegin(); envIt != env.constEnd(); ++envIt) {
|
||||||
|
envObj.insert(envIt.key(), QJsonValue::fromVariant(envIt.value()));
|
||||||
|
}
|
||||||
|
profileObj.insert(QStringLiteral("env"), envObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!profileObj.isEmpty()) {
|
||||||
|
profilesObj.insert(profileId, profileObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!profilesObj.isEmpty()) {
|
||||||
|
launchObj.insert(QStringLiteral("profiles"), profilesObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
obj.insert(QStringLiteral("launch"), launchObj);
|
obj.insert(QStringLiteral("launch"), launchObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,6 +568,7 @@ Game *Game::fromJson(const QJsonObject &json, QObject *parent)
|
||||||
QString runner;
|
QString runner;
|
||||||
QString runnerPath;
|
QString runnerPath;
|
||||||
QString prefixPath;
|
QString prefixPath;
|
||||||
|
QString activeProfile;
|
||||||
const QJsonValue launchValue = json.value(QStringLiteral("launch"));
|
const QJsonValue launchValue = json.value(QStringLiteral("launch"));
|
||||||
if (launchValue.isObject()) {
|
if (launchValue.isObject()) {
|
||||||
const QJsonObject launchObj = launchValue.toObject();
|
const QJsonObject launchObj = launchValue.toObject();
|
||||||
|
|
@ -404,6 +580,51 @@ Game *Game::fromJson(const QJsonObject &json, QObject *parent)
|
||||||
runner = launchObj.value(QStringLiteral("runner")).toString();
|
runner = launchObj.value(QStringLiteral("runner")).toString();
|
||||||
runnerPath = launchObj.value(QStringLiteral("runnerPath")).toString();
|
runnerPath = launchObj.value(QStringLiteral("runnerPath")).toString();
|
||||||
prefixPath = launchObj.value(QStringLiteral("prefixPath")).toString();
|
prefixPath = launchObj.value(QStringLiteral("prefixPath")).toString();
|
||||||
|
|
||||||
|
activeProfile = launchObj.value(QStringLiteral("activeProfile")).toString();
|
||||||
|
|
||||||
|
const QJsonValue profilesValue = launchObj.value(QStringLiteral("profiles"));
|
||||||
|
if (profilesValue.isObject()) {
|
||||||
|
const QJsonObject profilesObj = profilesValue.toObject();
|
||||||
|
for (auto it = profilesObj.constBegin(); it != profilesObj.constEnd(); ++it) {
|
||||||
|
if (!it.value().isObject()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString profileId = it.key();
|
||||||
|
if (profileId.isEmpty() || profileId == QLatin1String("default")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QJsonObject profileObj = it.value().toObject();
|
||||||
|
QVariantMap profileConfig;
|
||||||
|
|
||||||
|
const QString pRunner = profileObj.value(QStringLiteral("runner")).toString();
|
||||||
|
if (!pRunner.isEmpty()) {
|
||||||
|
profileConfig.insert(QStringLiteral("runner"), pRunner);
|
||||||
|
}
|
||||||
|
const QString pRunnerPath = profileObj.value(QStringLiteral("runnerPath")).toString();
|
||||||
|
if (!pRunnerPath.isEmpty()) {
|
||||||
|
profileConfig.insert(QStringLiteral("runnerPath"), pRunnerPath);
|
||||||
|
}
|
||||||
|
const QString pPrefixPath = profileObj.value(QStringLiteral("prefixPath")).toString();
|
||||||
|
if (!pPrefixPath.isEmpty()) {
|
||||||
|
profileConfig.insert(QStringLiteral("prefixPath"), pPrefixPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QJsonValue pEnvValue = profileObj.value(QStringLiteral("env"));
|
||||||
|
if (pEnvValue.isObject()) {
|
||||||
|
const QVariantMap pEnv = pEnvValue.toObject().toVariantMap();
|
||||||
|
if (!pEnv.isEmpty()) {
|
||||||
|
profileConfig.insert(QStringLiteral("env"), pEnv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!profileConfig.isEmpty()) {
|
||||||
|
game->setLaunchProfileConfig(profileId, profileConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QJsonValue legacyEnvValue = json.value(QStringLiteral("launchEnv"));
|
const QJsonValue legacyEnvValue = json.value(QStringLiteral("launchEnv"));
|
||||||
|
|
@ -435,6 +656,10 @@ Game *Game::fromJson(const QJsonObject &json, QObject *parent)
|
||||||
game->setLaunchPrefixPath(prefixPath);
|
game->setLaunchPrefixPath(prefixPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!activeProfile.isEmpty()) {
|
||||||
|
game->setActiveLaunchProfile(activeProfile);
|
||||||
|
}
|
||||||
|
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
11
src/game.h
11
src/game.h
|
|
@ -30,6 +30,7 @@ class Game : public QObject
|
||||||
Q_PROPERTY(QString launchRunner READ launchRunner WRITE setLaunchRunner NOTIFY launchRunnerChanged)
|
Q_PROPERTY(QString launchRunner READ launchRunner WRITE setLaunchRunner NOTIFY launchRunnerChanged)
|
||||||
Q_PROPERTY(QString launchRunnerPath READ launchRunnerPath WRITE setLaunchRunnerPath NOTIFY launchRunnerPathChanged)
|
Q_PROPERTY(QString launchRunnerPath READ launchRunnerPath WRITE setLaunchRunnerPath NOTIFY launchRunnerPathChanged)
|
||||||
Q_PROPERTY(QString launchPrefixPath READ launchPrefixPath WRITE setLaunchPrefixPath NOTIFY launchPrefixPathChanged)
|
Q_PROPERTY(QString launchPrefixPath READ launchPrefixPath WRITE setLaunchPrefixPath NOTIFY launchPrefixPathChanged)
|
||||||
|
Q_PROPERTY(QString activeLaunchProfile READ activeLaunchProfile WRITE setActiveLaunchProfile NOTIFY activeLaunchProfileChanged)
|
||||||
Q_PROPERTY(QString platform READ platform WRITE setPlatform NOTIFY platformChanged)
|
Q_PROPERTY(QString platform READ platform WRITE setPlatform NOTIFY platformChanged)
|
||||||
Q_PROPERTY(QString platformId READ platformId WRITE setPlatformId NOTIFY platformIdChanged)
|
Q_PROPERTY(QString platformId READ platformId WRITE setPlatformId NOTIFY platformIdChanged)
|
||||||
Q_PROPERTY(QDateTime dateAdded READ dateAdded WRITE setDateAdded NOTIFY dateAddedChanged)
|
Q_PROPERTY(QDateTime dateAdded READ dateAdded WRITE setDateAdded NOTIFY dateAddedChanged)
|
||||||
|
|
@ -82,6 +83,13 @@ public:
|
||||||
QString launchPrefixPath() const;
|
QString launchPrefixPath() const;
|
||||||
void setLaunchPrefixPath(const QString &path);
|
void setLaunchPrefixPath(const QString &path);
|
||||||
|
|
||||||
|
QString activeLaunchProfile() const;
|
||||||
|
void setActiveLaunchProfile(const QString &profileId);
|
||||||
|
|
||||||
|
Q_INVOKABLE QVariantMap launchProfileConfig(const QString &profileId) const;
|
||||||
|
Q_INVOKABLE void setLaunchProfileConfig(const QString &profileId, const QVariantMap &config);
|
||||||
|
QVariantMap effectiveLaunchConfig() const;
|
||||||
|
|
||||||
QString platform() const;
|
QString platform() const;
|
||||||
void setPlatform(const QString &platform);
|
void setPlatform(const QString &platform);
|
||||||
|
|
||||||
|
|
@ -129,6 +137,7 @@ Q_SIGNALS:
|
||||||
void launchRunnerChanged();
|
void launchRunnerChanged();
|
||||||
void launchRunnerPathChanged();
|
void launchRunnerPathChanged();
|
||||||
void launchPrefixPathChanged();
|
void launchPrefixPathChanged();
|
||||||
|
void activeLaunchProfileChanged();
|
||||||
void platformChanged();
|
void platformChanged();
|
||||||
void platformIdChanged();
|
void platformIdChanged();
|
||||||
void dateAddedChanged();
|
void dateAddedChanged();
|
||||||
|
|
@ -153,6 +162,8 @@ private:
|
||||||
QString m_launchRunner;
|
QString m_launchRunner;
|
||||||
QString m_launchRunnerPath;
|
QString m_launchRunnerPath;
|
||||||
QString m_launchPrefixPath;
|
QString m_launchPrefixPath;
|
||||||
|
QString m_activeLaunchProfile = QStringLiteral("default");
|
||||||
|
QVariantMap m_launchProfiles;
|
||||||
QString m_platform;
|
QString m_platform;
|
||||||
QString m_platformId;
|
QString m_platformId;
|
||||||
QDateTime m_dateAdded;
|
QDateTime m_dateAdded;
|
||||||
|
|
|
||||||
|
|
@ -153,10 +153,11 @@ QVariantMap GameLauncher::resolveLaunchInfo(Game *game) const
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString runner = game->launchRunner().trimmed();
|
const QVariantMap effectiveLaunchConfig = game->effectiveLaunchConfig();
|
||||||
const QString runnerPath = game->launchRunnerPath().trimmed();
|
const QString runner = effectiveLaunchConfig.value(QStringLiteral("runner")).toString().trimmed();
|
||||||
const QString prefixPath = game->launchPrefixPath().trimmed();
|
const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed();
|
||||||
const QVariantMap launchEnv = game->launchEnv();
|
const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed();
|
||||||
|
const QVariantMap launchEnv = effectiveLaunchConfig.value(QStringLiteral("env")).toMap();
|
||||||
const bool hasLaunchOverrides = !runner.isEmpty() || !runnerPath.isEmpty() || !prefixPath.isEmpty() || !launchEnv.isEmpty();
|
const bool hasLaunchOverrides = !runner.isEmpty() || !runnerPath.isEmpty() || !prefixPath.isEmpty() || !launchEnv.isEmpty();
|
||||||
|
|
||||||
info.insert(QStringLiteral("runner"), runner);
|
info.insert(QStringLiteral("runner"), runner);
|
||||||
|
|
@ -297,10 +298,11 @@ void GameLauncher::launchGame(Game *game)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString runner = game->launchRunner().trimmed();
|
const QVariantMap effectiveLaunchConfig = game->effectiveLaunchConfig();
|
||||||
const QString runnerPath = game->launchRunnerPath().trimmed();
|
const QString runner = effectiveLaunchConfig.value(QStringLiteral("runner")).toString().trimmed();
|
||||||
const QString prefixPath = game->launchPrefixPath().trimmed();
|
const QString runnerPath = effectiveLaunchConfig.value(QStringLiteral("runnerPath")).toString().trimmed();
|
||||||
const QVariantMap launchEnv = game->launchEnv();
|
const QString prefixPath = effectiveLaunchConfig.value(QStringLiteral("prefixPath")).toString().trimmed();
|
||||||
|
const QVariantMap launchEnv = effectiveLaunchConfig.value(QStringLiteral("env")).toMap();
|
||||||
const bool hasLaunchOverrides = !runner.isEmpty() || !runnerPath.isEmpty() || !prefixPath.isEmpty() || !launchEnv.isEmpty();
|
const bool hasLaunchOverrides = !runner.isEmpty() || !runnerPath.isEmpty() || !prefixPath.isEmpty() || !launchEnv.isEmpty();
|
||||||
|
|
||||||
// Check if already running
|
// Check if already running
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,17 @@ Kirigami.OverlaySheet {
|
||||||
onClicked: detailsSheet.editRequested()
|
onClicked: detailsSheet.editRequested()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QQC2.Button {
|
||||||
|
icon.name: "preferences-other"
|
||||||
|
text: game && game.activeLaunchProfile === "couch" ? i18n("Profile: Couch") : i18n("Profile: Default")
|
||||||
|
display: detailsSheet.useCompactLayout ? QQC2.AbstractButton.TextUnderIcon : QQC2.AbstractButton.TextBesideIcon
|
||||||
|
enabled: !!game
|
||||||
|
onClicked: if (game) {
|
||||||
|
game.activeLaunchProfile = (game.activeLaunchProfile === "couch") ? "default" : "couch"
|
||||||
|
App.saveLibrary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QQC2.Button {
|
QQC2.Button {
|
||||||
icon.name: "dialog-information"
|
icon.name: "dialog-information"
|
||||||
text: i18n("Diagnostics")
|
text: i18n("Diagnostics")
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ Kirigami.Dialog {
|
||||||
|
|
||||||
property var game: null
|
property var game: null
|
||||||
property bool isEditing: game !== null
|
property bool isEditing: game !== null
|
||||||
|
property string editProfileId: "default"
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: envModel
|
id: envModel
|
||||||
|
|
@ -49,10 +50,19 @@ Kirigami.Dialog {
|
||||||
game.developer = developerField.text.trim()
|
game.developer = developerField.text.trim()
|
||||||
game.launchCommand = executableField.text.trim()
|
game.launchCommand = executableField.text.trim()
|
||||||
game.workingDirectory = workingDirField.text.trim()
|
game.workingDirectory = workingDirField.text.trim()
|
||||||
|
if (dialog.editProfileId === "couch") {
|
||||||
|
game.setLaunchProfileConfig("couch", {
|
||||||
|
"runner": runnerValue,
|
||||||
|
"runnerPath": runnerPathValue,
|
||||||
|
"prefixPath": prefixPathValue,
|
||||||
|
"env": dialog.envModelToMap()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
game.launchEnv = dialog.envModelToMap()
|
game.launchEnv = dialog.envModelToMap()
|
||||||
game.launchRunner = runnerValue
|
game.launchRunner = runnerValue
|
||||||
game.launchRunnerPath = runnerPathValue
|
game.launchRunnerPath = runnerPathValue
|
||||||
game.launchPrefixPath = prefixPathValue
|
game.launchPrefixPath = prefixPathValue
|
||||||
|
}
|
||||||
if (selectedCoverPath !== "") {
|
if (selectedCoverPath !== "") {
|
||||||
App.setCoverFromFile(game, selectedCoverPath)
|
App.setCoverFromFile(game, selectedCoverPath)
|
||||||
}
|
}
|
||||||
|
|
@ -86,12 +96,15 @@ Kirigami.Dialog {
|
||||||
|
|
||||||
property string selectedCoverPath: ""
|
property string selectedCoverPath: ""
|
||||||
|
|
||||||
readonly property bool anyMenuOpen: runnerCombo && runnerCombo.popup && runnerCombo.popup.visible
|
readonly property bool anyMenuOpen: (runnerCombo && runnerCombo.popup && runnerCombo.popup.visible) || (profileCombo && profileCombo.popup && profileCombo.popup.visible)
|
||||||
|
|
||||||
function closeCurrentMenu() {
|
function closeCurrentMenu() {
|
||||||
if (runnerCombo && runnerCombo.popup && runnerCombo.popup.visible) {
|
if (runnerCombo && runnerCombo.popup && runnerCombo.popup.visible) {
|
||||||
runnerCombo.popup.close()
|
runnerCombo.popup.close()
|
||||||
}
|
}
|
||||||
|
if (profileCombo && profileCombo.popup && profileCombo.popup.visible) {
|
||||||
|
profileCombo.popup.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDescendant(item, ancestor) {
|
function isDescendant(item, ancestor) {
|
||||||
|
|
@ -181,35 +194,72 @@ Kirigami.Dialog {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFields() {
|
function profileIdFromIndex(idx) {
|
||||||
selectedCoverPath = ""
|
if (idx === 1) return "couch"
|
||||||
|
return "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
function profileIndexFromId(profileId) {
|
||||||
|
if ((profileId || "").trim() === "couch") return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadProfileFields() {
|
||||||
envModel.clear()
|
envModel.clear()
|
||||||
if (isEditing && game) {
|
|
||||||
nameField.text = game.name || ""
|
|
||||||
developerField.text = game.developer || ""
|
|
||||||
executableField.text = game.launchCommand || ""
|
|
||||||
workingDirField.text = game.workingDirectory || ""
|
|
||||||
|
|
||||||
runnerCombo.currentIndex = dialog.runnerToIndex(game.launchRunner)
|
if (!isEditing || !game) {
|
||||||
runnerPathField.text = game.launchRunnerPath || ""
|
runnerCombo.currentIndex = 0
|
||||||
prefixPathField.text = game.launchPrefixPath || ""
|
runnerPathField.text = ""
|
||||||
|
prefixPathField.text = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let env = game.launchEnv || ({})
|
if (dialog.editProfileId === "couch") {
|
||||||
|
let cfg = game.launchProfileConfig("couch") || ({})
|
||||||
|
runnerCombo.currentIndex = dialog.runnerToIndex(cfg.runner)
|
||||||
|
runnerPathField.text = cfg.runnerPath || ""
|
||||||
|
prefixPathField.text = cfg.prefixPath || ""
|
||||||
|
let env = cfg.env || ({})
|
||||||
let keys = Object.keys(env)
|
let keys = Object.keys(env)
|
||||||
keys.sort()
|
keys.sort()
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
let k = keys[i]
|
let k = keys[i]
|
||||||
envModel.append({ key: k, value: String(env[k]) })
|
envModel.append({ key: k, value: String(env[k]) })
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
runnerCombo.currentIndex = dialog.runnerToIndex(game.launchRunner)
|
||||||
|
runnerPathField.text = game.launchRunnerPath || ""
|
||||||
|
prefixPathField.text = game.launchPrefixPath || ""
|
||||||
|
let env = game.launchEnv || ({})
|
||||||
|
let keys = Object.keys(env)
|
||||||
|
keys.sort()
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
let k = keys[i]
|
||||||
|
envModel.append({ key: k, value: String(env[k]) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadFields() {
|
||||||
|
selectedCoverPath = ""
|
||||||
|
if (isEditing && game) {
|
||||||
|
nameField.text = game.name || ""
|
||||||
|
developerField.text = game.developer || ""
|
||||||
|
executableField.text = game.launchCommand || ""
|
||||||
|
workingDirField.text = game.workingDirectory || ""
|
||||||
|
|
||||||
|
dialog.editProfileId = game.activeLaunchProfile === "couch" ? "couch" : "default"
|
||||||
|
profileCombo.currentIndex = dialog.profileIndexFromId(dialog.editProfileId)
|
||||||
|
dialog.loadProfileFields()
|
||||||
} else {
|
} else {
|
||||||
nameField.text = ""
|
nameField.text = ""
|
||||||
developerField.text = ""
|
developerField.text = ""
|
||||||
executableField.text = ""
|
executableField.text = ""
|
||||||
workingDirField.text = ""
|
workingDirField.text = ""
|
||||||
|
|
||||||
runnerCombo.currentIndex = 0
|
dialog.editProfileId = "default"
|
||||||
runnerPathField.text = ""
|
profileCombo.currentIndex = 0
|
||||||
prefixPathField.text = ""
|
dialog.loadProfileFields()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,6 +375,35 @@ Kirigami.Dialog {
|
||||||
title: i18n("Compatibility")
|
title: i18n("Compatibility")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: Kirigami.Units.largeSpacing
|
||||||
|
visible: isEditing
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
spacing: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
QQC2.Label {
|
||||||
|
text: i18n("Profile")
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ComboBox {
|
||||||
|
id: profileCombo
|
||||||
|
Layout.fillWidth: true
|
||||||
|
model: [i18n("Default"), i18n("Couch")]
|
||||||
|
onCurrentIndexChanged: if (dialog.isEditing) {
|
||||||
|
dialog.editProfileId = dialog.profileIdFromIndex(currentIndex)
|
||||||
|
dialog.loadProfileFields()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormCard.FormDelegateSeparator { visible: isEditing }
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.margins: Kirigami.Units.largeSpacing
|
Layout.margins: Kirigami.Units.largeSpacing
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue