diff --git a/src/launcher/forms/configuration_edit_dialog.ui b/src/launcher/forms/configuration_edit_dialog.ui
index 82fdd0072..5b5feb5d9 100644
--- a/src/launcher/forms/configuration_edit_dialog.ui
+++ b/src/launcher/forms/configuration_edit_dialog.ui
@@ -6,7 +6,7 @@
0
0
- 840
+ 900
620
@@ -400,6 +400,13 @@ To use your own sound, replace the emulator's assets/sounds/trophy-unlock.wav wi
Restore default settings
+ -
+
+ 8025
+ Game Configs
+ Import or export game configs
+
+
-
Qt::Horizontal
diff --git a/src/launcher/forms/configuration_list_widget.ui b/src/launcher/forms/configuration_list_widget.ui
index c49cf6830..e41f1b51d 100644
--- a/src/launcher/forms/configuration_list_widget.ui
+++ b/src/launcher/forms/configuration_list_widget.ui
@@ -125,7 +125,7 @@
- <html><head/><body><p>Edit configuration</p></body></html>
+ Edit game config
@@ -150,7 +150,7 @@
- <html><head/><body><p>Delete configuration</p></body></html>
+ Clear game config
diff --git a/src/launcher/include/configuration.h b/src/launcher/include/configuration.h
index 5b88a28e6..fc7568d50 100644
--- a/src/launcher/include/configuration.h
+++ b/src/launcher/include/configuration.h
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -14,9 +15,6 @@
#include
#include
-#define KYTY_CFG_SET(n) s->setValue(#n, QVariant::fromValue(n).toString());
-#define KYTY_CFG_GET(n) n = s->value(#n).value();
-
template
inline QStringList EnumToList() {
QStringList ret;
@@ -126,7 +124,7 @@ public:
int vblank_frequency = 60;
int console_language = DEFAULT_CONSOLE_LANGUAGE;
bool vulkan_validation_enabled = false;
- bool shader_validation_enabled = true;
+ bool shader_validation_enabled = false;
ShaderOptimizationType shader_optimization_type = ShaderOptimizationType::Performance;
LogDirection shader_log_direction = LogDirection::Silent;
QString shader_log_folder = "_Shaders";
@@ -188,90 +186,16 @@ public:
game_comment = other.game_comment;
}
- void WriteSettings(QSettings* s) const {
- KYTY_CFG_SET(name);
- KYTY_CFG_SET(basedir);
- KYTY_CFG_SET(game_path);
- KYTY_CFG_SET(custom_settings);
- KYTY_CFG_SET(screen_resolution);
- KYTY_CFG_SET(user_name);
- KYTY_CFG_SET(user_id);
- KYTY_CFG_SET(audio_input_device);
- KYTY_CFG_SET(present_mode);
- KYTY_CFG_SET(gpu_index);
- KYTY_CFG_SET(fullscreen_enabled);
- KYTY_CFG_SET(hide_cursor_enabled);
- KYTY_CFG_SET(readback_linear_images);
- KYTY_CFG_SET(tessellation_enabled);
- KYTY_CFG_SET(trophy_enabled);
- KYTY_CFG_SET(vblank_frequency);
- KYTY_CFG_SET(console_language);
- KYTY_CFG_SET(vulkan_validation_enabled);
- KYTY_CFG_SET(shader_validation_enabled);
- KYTY_CFG_SET(shader_optimization_type);
- KYTY_CFG_SET(shader_log_direction);
- KYTY_CFG_SET(shader_log_folder);
- KYTY_CFG_SET(command_buffer_dump_enabled);
- KYTY_CFG_SET(command_buffer_dump_folder);
- KYTY_CFG_SET(printf_direction);
- KYTY_CFG_SET(printf_output_file);
- KYTY_CFG_SET(profiler_enabled);
- KYTY_CFG_SET(renderdoc_enabled);
- KYTY_CFG_SET(amd_cpu_enabled);
-#if defined(_WIN32)
- KYTY_CFG_SET(red_zone_protection_enabled);
-#endif
- s->setValue("host_input_mapping", host_input_mapping);
- KYTY_CFG_SET(elf);
- }
+ void WriteSettings(QSettings* s) const;
+ void ReadSettings(QSettings* s);
- void ReadSettings(QSettings* s) {
- KYTY_CFG_GET(name);
- KYTY_CFG_GET(basedir);
- KYTY_CFG_GET(game_path);
- KYTY_CFG_GET(custom_settings);
- KYTY_CFG_GET(screen_resolution);
- user_name = s->value("user_name", user_name).toString();
- bool user_id_ok = false;
- auto saved_user_id = s->value("user_id", user_id).toInt(&user_id_ok);
- user_id = user_id_ok && Config::IsConfiguredUserIdValid(saved_user_id)
- ? saved_user_id
- : Config::DEFAULT_USER_ID;
- audio_input_device = s->value("audio_input_device", audio_input_device).toString();
- KYTY_CFG_GET(present_mode);
- gpu_index = s->value("gpu_index", -1).toInt();
- if (EnumToText(present_mode).isEmpty()) {
- present_mode = PresentMode::Mailbox;
- }
- KYTY_CFG_GET(fullscreen_enabled);
- KYTY_CFG_GET(hide_cursor_enabled);
- KYTY_CFG_GET(readback_linear_images);
- KYTY_CFG_GET(tessellation_enabled);
- trophy_enabled = s->value("trophy_enabled", trophy_enabled).toBool();
- vblank_frequency = s->value("vblank_frequency", vblank_frequency).toInt();
- console_language = s->value("console_language", console_language).toInt();
- if (console_language < 0 || console_language > MAX_CONSOLE_LANGUAGE) {
- console_language = DEFAULT_CONSOLE_LANGUAGE;
- }
- KYTY_CFG_GET(vulkan_validation_enabled);
- KYTY_CFG_GET(shader_validation_enabled);
- KYTY_CFG_GET(shader_optimization_type);
- KYTY_CFG_GET(shader_log_direction);
- KYTY_CFG_GET(shader_log_folder);
- KYTY_CFG_GET(command_buffer_dump_enabled);
- KYTY_CFG_GET(command_buffer_dump_folder);
- KYTY_CFG_GET(printf_direction);
- KYTY_CFG_GET(printf_output_file);
- KYTY_CFG_GET(profiler_enabled);
- KYTY_CFG_GET(renderdoc_enabled);
- amd_cpu_enabled = s->value("amd_cpu_enabled", false).toBool();
-#if defined(_WIN32)
- red_zone_protection_enabled =
- s->value("red_zone_protection_enabled", red_zone_protection_enabled).toBool();
-#endif
- host_input_mapping = s->value("host_input_mapping", host_input_mapping).toStringList();
- elf = s->value("elf", elf).toString();
- }
+ [[nodiscard]] QVariantMap GameSettings() const;
+ // Call on a temporary configuration: validation can fail after loading values.
+ bool SetGameSettings(const QJsonObject& settings, QString& error);
+
+private:
+ template
+ void ReadGameSettingsValues(const Settings& s);
};
Q_DECLARE_METATYPE(Configuration*)
diff --git a/src/launcher/include/configurationEditDialog.h b/src/launcher/include/configurationEditDialog.h
index cc441243f..c9292d4e7 100644
--- a/src/launcher/include/configurationEditDialog.h
+++ b/src/launcher/include/configurationEditDialog.h
@@ -33,6 +33,8 @@ public:
signals:
void PreviewControllerColor(const QString& color);
+ void ImportGameSettings();
+ void ExportGameSettings();
private:
Ui::ConfigurationEditDialog* m_ui = nullptr;
diff --git a/src/launcher/include/configurationListWidget.h b/src/launcher/include/configurationListWidget.h
index de0bee954..2adf4052a 100644
--- a/src/launcher/include/configurationListWidget.h
+++ b/src/launcher/include/configurationListWidget.h
@@ -74,6 +74,8 @@ private:
void SelectItem(QTreeWidgetItem* witem);
void ApplyCompatibility();
void UpdateToolbarIcons();
+ void ImportGameSettings(QWidget* parent);
+ void ExportGameSettings(QWidget* parent) const;
[[nodiscard]] bool HasValidGameDirectory() const;
ConfigurationItem* m_selected_item = nullptr;
diff --git a/src/launcher/src/configuration.cpp b/src/launcher/src/configuration.cpp
new file mode 100644
index 000000000..d5c6bc703
--- /dev/null
+++ b/src/launcher/src/configuration.cpp
@@ -0,0 +1,145 @@
+#include "configuration.h"
+
+QVariantMap Configuration::GameSettings() const {
+ QVariantMap values;
+#define KYTY_CFG_SET(n) values.insert(QStringLiteral(#n), QVariant::fromValue(n).toString())
+ KYTY_CFG_SET(screen_resolution);
+ KYTY_CFG_SET(user_name);
+ KYTY_CFG_SET(user_id);
+ KYTY_CFG_SET(audio_input_device);
+ KYTY_CFG_SET(present_mode);
+ KYTY_CFG_SET(gpu_index);
+ KYTY_CFG_SET(fullscreen_enabled);
+ KYTY_CFG_SET(hide_cursor_enabled);
+ KYTY_CFG_SET(readback_linear_images);
+ KYTY_CFG_SET(tessellation_enabled);
+ KYTY_CFG_SET(trophy_enabled);
+ KYTY_CFG_SET(vblank_frequency);
+ KYTY_CFG_SET(console_language);
+ KYTY_CFG_SET(vulkan_validation_enabled);
+ KYTY_CFG_SET(shader_validation_enabled);
+ KYTY_CFG_SET(shader_optimization_type);
+ KYTY_CFG_SET(shader_log_direction);
+ KYTY_CFG_SET(shader_log_folder);
+ KYTY_CFG_SET(command_buffer_dump_enabled);
+ KYTY_CFG_SET(command_buffer_dump_folder);
+ KYTY_CFG_SET(printf_direction);
+ KYTY_CFG_SET(printf_output_file);
+ KYTY_CFG_SET(profiler_enabled);
+ KYTY_CFG_SET(renderdoc_enabled);
+ KYTY_CFG_SET(amd_cpu_enabled);
+#if defined(_WIN32)
+ KYTY_CFG_SET(red_zone_protection_enabled);
+#endif
+ KYTY_CFG_SET(elf);
+#undef KYTY_CFG_SET
+ return values;
+}
+
+template
+void Configuration::ReadGameSettingsValues(const Settings& s) {
+#define KYTY_CFG_GET(n) n = s.value(QStringLiteral(#n)).template value()
+ KYTY_CFG_GET(screen_resolution);
+ user_name = s.value("user_name", user_name).toString();
+ bool user_id_ok = false;
+ auto saved_user_id = s.value("user_id", user_id).toInt(&user_id_ok);
+ user_id = user_id_ok && Config::IsConfiguredUserIdValid(saved_user_id)
+ ? saved_user_id
+ : Config::DEFAULT_USER_ID;
+ audio_input_device = s.value("audio_input_device", audio_input_device).toString();
+ KYTY_CFG_GET(present_mode);
+ gpu_index = s.value("gpu_index", -1).toInt();
+ if (EnumToText(present_mode).isEmpty()) {
+ present_mode = PresentMode::Mailbox;
+ }
+ KYTY_CFG_GET(fullscreen_enabled);
+ KYTY_CFG_GET(hide_cursor_enabled);
+ KYTY_CFG_GET(readback_linear_images);
+ KYTY_CFG_GET(tessellation_enabled);
+ trophy_enabled = s.value("trophy_enabled", trophy_enabled).toBool();
+ vblank_frequency = s.value("vblank_frequency", vblank_frequency).toInt();
+ console_language = s.value("console_language", console_language).toInt();
+ if (console_language < 0 || console_language > MAX_CONSOLE_LANGUAGE) {
+ console_language = DEFAULT_CONSOLE_LANGUAGE;
+ }
+ KYTY_CFG_GET(vulkan_validation_enabled);
+ KYTY_CFG_GET(shader_validation_enabled);
+ KYTY_CFG_GET(shader_optimization_type);
+ KYTY_CFG_GET(shader_log_direction);
+ KYTY_CFG_GET(shader_log_folder);
+ KYTY_CFG_GET(command_buffer_dump_enabled);
+ KYTY_CFG_GET(command_buffer_dump_folder);
+ KYTY_CFG_GET(printf_direction);
+ KYTY_CFG_GET(printf_output_file);
+ KYTY_CFG_GET(profiler_enabled);
+ KYTY_CFG_GET(renderdoc_enabled);
+ amd_cpu_enabled = s.value("amd_cpu_enabled", false).toBool();
+#if defined(_WIN32)
+ red_zone_protection_enabled =
+ s.value("red_zone_protection_enabled", red_zone_protection_enabled).toBool();
+#endif
+ elf = s.value("elf", elf).toString();
+#undef KYTY_CFG_GET
+}
+
+void Configuration::WriteSettings(QSettings* s) const {
+ const auto values = GameSettings();
+ for (auto it = values.constBegin(); it != values.constEnd(); ++it) {
+ s->setValue(it.key(), it.value());
+ }
+ s->setValue("name", name);
+ s->setValue("basedir", basedir);
+ s->setValue("game_path", game_path);
+ s->setValue("custom_settings", QVariant::fromValue(custom_settings).toString());
+ s->setValue("host_input_mapping", host_input_mapping);
+}
+
+void Configuration::ReadSettings(QSettings* s) {
+ ReadGameSettingsValues(*s);
+ name = s->value("name").toString();
+ basedir = s->value("basedir").toString();
+ game_path = s->value("game_path").toString();
+ custom_settings = s->value("custom_settings").toBool();
+ host_input_mapping = s->value("host_input_mapping", host_input_mapping).toStringList();
+}
+
+bool Configuration::SetGameSettings(const QJsonObject& settings, QString& error) {
+ const auto fail = [&error](const QString& message) {
+ error = message;
+ return false;
+ };
+ auto values = GameSettings();
+ for (auto it = settings.constBegin(); it != settings.constEnd(); ++it) {
+ if (!values.contains(it.key())) {
+ return fail(tr("Unknown game setting: %1").arg(it.key()));
+ }
+ if (!it.value().isString()) {
+ return fail(tr("Game setting %1 must be a string.").arg(it.key()));
+ }
+ values.insert(it.key(), it.value().toString());
+ }
+
+ ReadGameSettingsValues(values);
+ const auto canonical = GameSettings();
+ for (auto it = settings.constBegin(); it != settings.constEnd(); ++it) {
+ if (canonical.value(it.key()) != values.value(it.key())) {
+ return fail(tr("Invalid value for game setting: %1").arg(it.key()));
+ }
+ }
+ if (user_name.trimmed().isEmpty() || user_name.toUtf8().size() > Config::MAX_USER_NAME_LENGTH) {
+ return fail(tr("User name must contain 1-16 UTF-8 bytes."));
+ }
+ if (gpu_index < -1) {
+ return fail(tr("GPU index must be -1 or greater."));
+ }
+ if (vblank_frequency < 30 || vblank_frequency > 360) {
+ return fail(tr("Vblank frequency must be between 30 and 360."));
+ }
+ if ((shader_log_direction == LogDirection::File && shader_log_folder.isEmpty()) ||
+ (printf_direction == LogDirection::File && printf_output_file.isEmpty()) ||
+ (command_buffer_dump_enabled && command_buffer_dump_folder.isEmpty())) {
+ return fail(tr("Enabled logging and command buffer dumps require an output path."));
+ }
+
+ return true;
+}
diff --git a/src/launcher/src/configurationEditDialog.cpp b/src/launcher/src/configurationEditDialog.cpp
index 140f881a1..882a60f07 100644
--- a/src/launcher/src/configurationEditDialog.cpp
+++ b/src/launcher/src/configurationEditDialog.cpp
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -126,6 +127,7 @@ ConfigurationEditDialog::ConfigurationEditDialog(Configuration& info, QWidget* p
setMinimumWidth(width());
InitGameDirectories();
m_ui->controller_group->setVisible(false);
+ m_ui->settings_button->setVisible(false);
connect(m_ui->ok_button, &QPushButton::clicked, this, &ConfigurationEditDialog::save);
connect(m_ui->cancel_button, &QPushButton::clicked, this, &QDialog::reject);
@@ -354,6 +356,11 @@ void ConfigurationEditDialog::InitGameDirectories() {
void ConfigurationEditDialog::SetGlobalSettings(const QStringList& dirs) {
m_global_settings = true;
+ auto* menu = new QMenu(m_ui->settings_button);
+ menu->addAction(tr("Import..."), this, &ConfigurationEditDialog::ImportGameSettings);
+ menu->addAction(tr("Export..."), this, &ConfigurationEditDialog::ExportGameSettings);
+ m_ui->settings_button->setMenu(menu);
+ m_ui->settings_button->setVisible(true);
m_game_dirs_list->clear();
m_game_dirs_group->setMinimumWidth(GLOBAL_SETTINGS_GAME_DIRS_MIN_WIDTH);
diff --git a/src/launcher/src/configurationListWidget.cpp b/src/launcher/src/configurationListWidget.cpp
index 05555835d..66ffc1031 100644
--- a/src/launcher/src/configurationListWidget.cpp
+++ b/src/launcher/src/configurationListWidget.cpp
@@ -24,9 +24,11 @@
#include
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -40,6 +42,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -765,7 +768,7 @@ void ConfigurationListWidget::edit_configuration() {
auto info = CreateConfiguration(*item);
ConfigurationEditDialog dlg(*info, this);
- dlg.setWindowTitle(tr("Edit game settings"));
+ dlg.setWindowTitle(tr("Edit game config"));
connect(&dlg, &ConfigurationEditDialog::PreviewControllerColor, this,
&ConfigurationListWidget::PreviewControllerColor);
@@ -789,8 +792,8 @@ void ConfigurationListWidget::delete_configuartion() {
return;
}
- if (QMessageBox::Yes == QMessageBox::question(this, tr("Clear custom settings"),
- tr("Do you want to clear custom settings?"))) {
+ if (QMessageBox::Yes == QMessageBox::question(this, tr("Clear game config"),
+ tr("Clear this game's config and use global settings?"))) {
delete m_custom_infos.take(item->GetInfo().game_path);
item->GetInfo().custom_settings = false;
WriteSettings();
@@ -810,6 +813,10 @@ void ConfigurationListWidget::edit_global_settings() {
dlg.SetGlobalSettings(m_game_dirs);
connect(&dlg, &ConfigurationEditDialog::PreviewControllerColor, this,
&ConfigurationListWidget::PreviewControllerColor);
+ connect(&dlg, &ConfigurationEditDialog::ImportGameSettings, this,
+ [this, &dlg]() { ImportGameSettings(&dlg); });
+ connect(&dlg, &ConfigurationEditDialog::ExportGameSettings, this,
+ [this, &dlg]() { ExportGameSettings(&dlg); });
if (dlg.exec() == QDialog::Accepted) {
m_global_info.CopyEmulatorSettingsFrom(info);
@@ -822,7 +829,133 @@ void ConfigurationListWidget::edit_global_settings() {
ScanGameDirectory();
}
}
- emit Select();
+ SelectItem(m_ui->cfgs_list->currentItem());
+}
+
+static bool IsGameSettingsTitleId(const QString& title_id) {
+ static const QRegularExpression pattern(QStringLiteral("\\APPSA[0-9]{5}\\z"));
+ return pattern.match(title_id).hasMatch();
+}
+
+void ConfigurationListWidget::ImportGameSettings(QWidget* parent) {
+ const auto path = QFileDialog::getOpenFileName(parent, tr("Import game configs"), {},
+ tr("JSON files (*.json)"));
+ if (path.isEmpty()) {
+ return;
+ }
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly)) {
+ QMessageBox::warning(parent, tr("Import failed"), file.errorString());
+ return;
+ }
+ const auto document = QJsonDocument::fromJson(file.readAll());
+ if (!document.isObject() || document.object().isEmpty()) {
+ QMessageBox::warning(
+ parent, tr("Import failed"),
+ tr("Expected a JSON object containing game configs keyed by PPSA code."));
+ return;
+ }
+ const auto settings = document.object();
+ for (auto it = settings.constBegin(); it != settings.constEnd(); ++it) {
+ Configuration info;
+ QString error;
+ if (!IsGameSettingsTitleId(it.key()) || !it.value().isObject() ||
+ it.value().toObject().isEmpty() ||
+ !info.SetGameSettings(it.value().toObject(), error)) {
+ QMessageBox::warning(parent, tr("Import failed"),
+ tr("Invalid game config for %1. %2").arg(it.key(), error));
+ return;
+ }
+ }
+ struct ImportedGame {
+ ConfigurationItem* item;
+ std::unique_ptr info;
+ };
+ std::vector imported;
+ auto unmatched = settings.keys();
+ for (int index = 0; index < m_ui->cfgs_list->topLevelItemCount(); ++index) {
+ auto* item = static_cast(m_ui->cfgs_list->topLevelItem(index));
+ const auto title_id = item->GetInfo().title_id.trimmed().toUpper();
+ if (!settings.contains(title_id)) {
+ continue;
+ }
+ auto info = CreateConfiguration(*item);
+ QString error;
+ if (!info->SetGameSettings(settings.value(title_id).toObject(), error)) {
+ QMessageBox::warning(parent, tr("Import failed"),
+ tr("Invalid game config for %1. %2").arg(title_id, error));
+ return;
+ }
+ info->custom_settings = true;
+ imported.push_back({item, std::move(info)});
+ unmatched.removeAll(title_id);
+ }
+ auto message = imported.empty() ? tr("No matching games found in the library.")
+ : tr("Configs will be updated for the following games:\n");
+ for (const auto& game: imported) {
+ message += tr("\n%1 — %2").arg(game.info->title_id.trimmed().toUpper(), game.info->name);
+ }
+ if (!unmatched.isEmpty()) {
+ message += tr("\nGames not found: %1").arg(unmatched.join(QStringLiteral(", ")));
+ }
+ if (imported.empty()) {
+ QMessageBox::information(parent, tr("Import game configs"), message);
+ return;
+ }
+ QMessageBox confirmation(QMessageBox::Question, tr("Import game configs"), message,
+ QMessageBox::Apply | QMessageBox::Cancel, parent);
+ confirmation.setTextFormat(Qt::PlainText);
+ confirmation.setDefaultButton(QMessageBox::Cancel);
+ if (confirmation.exec() != QMessageBox::Apply) {
+ return;
+ }
+ for (auto& [item, info]: imported) {
+ const auto game_path = info->game_path;
+ delete m_custom_infos.take(game_path);
+ m_custom_infos.insert(game_path, info.release());
+ item->GetInfo().custom_settings = true;
+ item->Update();
+ }
+ WriteSettings();
+}
+
+void ConfigurationListWidget::ExportGameSettings(QWidget* parent) const {
+ QMap games;
+ for (int index = 0; index < m_ui->cfgs_list->topLevelItemCount(); ++index) {
+ const auto* item = static_cast(m_ui->cfgs_list->topLevelItem(index));
+ const auto& game = item->GetInfo();
+ const auto title_id = game.title_id.trimmed().toUpper();
+ if (m_custom_infos.contains(game.game_path) && IsGameSettingsTitleId(title_id)) {
+ games.insert(tr("%1 — %2 (%3)").arg(title_id, game.name, game.game_path), item);
+ }
+ }
+ if (games.isEmpty()) {
+ QMessageBox::information(parent, tr("Export game config"),
+ tr("No game configs with a PPSA code were found."));
+ return;
+ }
+ bool accepted = false;
+ const auto selected = QInputDialog::getItem(parent, tr("Export game config"), tr("Game:"),
+ games.keys(), 0, false, &accepted);
+ if (!accepted) {
+ return;
+ }
+ const auto& game = games.value(selected)->GetInfo();
+ const auto title_id = game.title_id.trimmed().toUpper();
+ const auto path =
+ QFileDialog::getSaveFileName(parent, tr("Export game config"),
+ title_id + QStringLiteral(".json"), tr("JSON files (*.json)"));
+ if (path.isEmpty()) {
+ return;
+ }
+ const auto settings =
+ QJsonObject::fromVariantMap(m_custom_infos.value(game.game_path)->GameSettings());
+ const auto data =
+ QJsonDocument(QJsonObject {{title_id, settings}}).toJson(QJsonDocument::Indented);
+ QSaveFile file(path);
+ if (!file.open(QIODevice::WriteOnly) || file.write(data) != data.size() || !file.commit()) {
+ QMessageBox::warning(parent, tr("Export failed"), file.errorString());
+ }
}
void ConfigurationListWidget::edit_input_mapping() {
@@ -1040,11 +1173,11 @@ void ConfigurationListWidget::show_context_menu(const QPoint& pos) {
tr("Remove save data..."), this, SLOT(remove_save_data()));
menu.addSeparator();
QAction* action_edit =
- menu.addAction(style()->standardIcon(QStyle::SP_FileIcon), tr("Edit game settings..."),
+ menu.addAction(style()->standardIcon(QStyle::SP_FileIcon), tr("Edit game config..."),
this, SLOT(edit_configuration()));
QAction* action_delete =
menu.addAction(style()->standardIcon(QStyle::SP_DialogDiscardButton),
- tr("Clear custom settings"), this, SLOT(delete_configuartion()));
+ tr("Clear game config"), this, SLOT(delete_configuartion()));
if (item == nullptr) {
menu.addSeparator();