Qt: Add copy/clear game settings

This commit is contained in:
Stenzek 2024-03-21 00:41:54 +10:00
parent 3085172ffd
commit 604dd5df40
No known key found for this signature in database
10 changed files with 263 additions and 82 deletions

View file

@ -2431,7 +2431,7 @@ void FullscreenUI::DoCopyGameSettings()
Settings temp_settings;
temp_settings.Load(*GetEditingSettingsInterface(false));
temp_settings.Save(*s_game_settings_interface);
temp_settings.Save(*s_game_settings_interface, true);
SetSettingsChanged(s_game_settings_interface.get());
ShowToast("Game Settings Copied", fmt::format(FSUI_FSTR("Game settings initialized with global settings for '{}'."),

View file

@ -428,7 +428,7 @@ void Settings::Load(SettingsInterface& si)
#endif
}
void Settings::Save(SettingsInterface& si) const
void Settings::Save(SettingsInterface& si, bool ignore_base) const
{
si.SetStringValue("Console", "Region", GetConsoleRegionName(region));
si.SetBoolValue("Console", "Enable8MBRAM", enable_8mb_ram);
@ -436,6 +436,9 @@ void Settings::Save(SettingsInterface& si) const
si.SetFloatValue("Main", "EmulationSpeed", emulation_speed);
si.SetFloatValue("Main", "FastForwardSpeed", fast_forward_speed);
si.SetFloatValue("Main", "TurboSpeed", turbo_speed);
if (!ignore_base)
{
si.SetBoolValue("Main", "SyncToHostRefreshRate", sync_to_host_refresh_rate);
si.SetBoolValue("Main", "IncreaseTimerResolution", increase_timer_resolution);
si.SetBoolValue("Main", "InhibitScreensaver", inhibit_screensaver);
@ -446,12 +449,14 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Main", "CreateSaveStateBackups", create_save_state_backups);
si.SetBoolValue("Main", "CompressSaveStates", compress_save_states);
si.SetBoolValue("Main", "ConfirmPowerOff", confim_power_off);
si.SetBoolValue("Main", "LoadDevicesFromSaveStates", load_devices_from_save_states);
si.SetBoolValue("Main", "ApplyCompatibilitySettings", apply_compatibility_settings);
si.SetBoolValue("Main", "ApplyGameSettings", apply_game_settings);
si.SetBoolValue("Main", "EnableDiscordPresence", enable_discord_presence);
}
si.SetBoolValue("Main", "LoadDevicesFromSaveStates", load_devices_from_save_states);
si.SetBoolValue("Console", "EnableCheats", enable_cheats);
si.SetBoolValue("Main", "DisableAllEnhancements", disable_all_enhancements);
si.SetBoolValue("Main", "EnableDiscordPresence", enable_discord_presence);
si.SetBoolValue("Main", "RewindEnable", rewind_enable);
si.SetFloatValue("Main", "RewindFrequency", rewind_save_frequency);
si.SetIntValue("Main", "RewindSaveSlots", rewind_save_slots);
@ -470,12 +475,17 @@ void Settings::Save(SettingsInterface& si) const
si.SetStringValue("GPU", "Adapter", gpu_adapter.c_str());
si.SetIntValue("GPU", "ResolutionScale", static_cast<long>(gpu_resolution_scale));
si.SetIntValue("GPU", "Multisamples", static_cast<long>(gpu_multisamples));
if (!ignore_base)
{
si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device);
si.SetBoolValue("GPU", "DisableShaderCache", gpu_disable_shader_cache);
si.SetBoolValue("GPU", "DisableDualSourceBlend", gpu_disable_dual_source_blend);
si.SetBoolValue("GPU", "DisableFramebufferFetch", gpu_disable_framebuffer_fetch);
si.SetBoolValue("GPU", "DisableTextureBuffers", gpu_disable_texture_buffers);
si.SetBoolValue("GPU", "DisableTextureCopyToSelf", gpu_disable_texture_copy_to_self);
}
si.SetBoolValue("GPU", "PerSampleShading", gpu_per_sample_shading);
si.SetBoolValue("GPU", "UseThread", gpu_use_thread);
si.SetBoolValue("GPU", "ThreadedPresentation", gpu_threaded_presentation);
@ -521,6 +531,8 @@ void Settings::Save(SettingsInterface& si) const
si.SetUIntValue("Display", "ScreenshotQuality", display_screenshot_quality);
si.SetIntValue("Display", "CustomAspectRatioNumerator", display_aspect_ratio_custom_numerator);
si.GetIntValue("Display", "CustomAspectRatioDenominator", display_aspect_ratio_custom_denominator);
if (!ignore_base)
{
si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages);
si.SetBoolValue("Display", "ShowFPS", display_show_fps);
si.SetBoolValue("Display", "ShowSpeed", display_show_speed);
@ -532,10 +544,12 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Display", "ShowStatusIndicators", display_show_status_indicators);
si.SetBoolValue("Display", "ShowInputs", display_show_inputs);
si.SetBoolValue("Display", "ShowEnhancements", display_show_enhancements);
si.SetFloatValue("Display", "OSDScale", display_osd_scale);
}
si.SetBoolValue("Display", "DisplayAllFrames", display_all_frames);
si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically);
si.SetFloatValue("Display", "MaxFPS", display_max_fps);
si.SetFloatValue("Display", "OSDScale", display_osd_scale);
si.SetIntValue("CDROM", "ReadaheadSectors", cdrom_readahead_sectors);
si.SetStringValue("CDROM", "MechaconVersion", GetCDROMMechVersionName(cdrom_mechacon_version));
@ -558,10 +572,14 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Audio", "DumpOnBoot", audio_dump_on_boot);
si.SetBoolValue("Hacks", "UseOldMDECRoutines", use_old_mdec_routines);
if (!ignore_base)
{
si.SetIntValue("Hacks", "DMAMaxSliceTicks", dma_max_slice_ticks);
si.SetIntValue("Hacks", "DMAHaltTicks", dma_halt_ticks);
si.SetIntValue("Hacks", "GPUFIFOSize", gpu_fifo_size);
si.SetIntValue("Hacks", "GPUMaxRunAhead", gpu_max_run_ahead);
}
si.SetBoolValue("PCDrv", "Enabled", pcdrv_enable);
si.SetBoolValue("PCDrv", "EnableWrites", pcdrv_enable_writes);
@ -603,6 +621,8 @@ void Settings::Save(SettingsInterface& si) const
si.SetIntValue("Cheevos", "NotificationsDuration", achievements_notification_duration);
si.SetIntValue("Cheevos", "LeaderboardsDuration", achievements_leaderboard_duration);
if (!ignore_base)
{
si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level));
si.SetStringValue("Logging", "LogFilter", log_filter.c_str());
si.SetBoolValue("Logging", "LogTimestamps", log_timestamps);
@ -620,6 +640,7 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Debug", "ShowTimersState", debugging.show_timers_state);
si.SetBoolValue("Debug", "ShowMDECState", debugging.show_mdec_state);
si.SetBoolValue("Debug", "ShowDMAState", debugging.show_dma_state);
}
si.SetBoolValue("TextureReplacements", "EnableVRAMWriteReplacements",
texture_replacements.enable_vram_write_replacements);
@ -633,6 +654,33 @@ void Settings::Save(SettingsInterface& si) const
texture_replacements.dump_vram_write_height_threshold);
}
void Settings::Clear(SettingsInterface& si)
{
si.ClearSection("Main");
si.ClearSection("Console");
si.ClearSection("CPU");
si.ClearSection("GPU");
si.ClearSection("Display");
si.ClearSection("CDROM");
si.ClearSection("Audio");
si.ClearSection("Hacks");
si.ClearSection("PCDrv");
si.ClearSection("BIOS");
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
si.ClearSection(Controller::GetSettingsSection(i).c_str());
si.ClearSection("MemoryCards");
// Can't wipe out this section, because input profiles.
si.DeleteValue("ControllerPorts", "MultitapMode");
si.ClearSection("Cheevos");
si.ClearSection("Logging");
si.ClearSection("Debug");
si.ClearSection("TextureReplacements");
}
void Settings::FixIncompatibleSettings(bool display_osd_messages)
{
if (g_settings.disable_all_enhancements)

View file

@ -341,7 +341,8 @@ struct Settings
};
void Load(SettingsInterface& si);
void Save(SettingsInterface& si) const;
void Save(SettingsInterface& si, bool ignore_base) const;
static void Clear(SettingsInterface& si);
void FixIncompatibleSettings(bool display_osd_messages);

View file

@ -975,7 +975,7 @@ void System::SetDefaultSettings(SettingsInterface& si)
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
temp.controller_types[i] = g_settings.controller_types[i];
temp.Save(si);
temp.Save(si, false);
}
void System::ApplySettings(bool display_osd_messages)

View file

@ -724,7 +724,7 @@ void NoGUIHost::CPUThreadMainLoop()
Host::PumpMessagesOnCPUThread();
System::Internal::IdlePollUpdate();
System::PresentDisplay(false);
if (!g_gpu_device->IsVsyncEnabled())
if (!g_gpu_device->IsVSyncActive())
g_gpu_device->ThrottlePresentation();
}
}

View file

@ -2737,7 +2737,7 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
save_state &= allow_save_to_state;
// Only confirm on UI thread because we need to display a msgbox.
if (!m_is_closing && allow_confirm && g_settings.confim_power_off)
if (!m_is_closing && allow_confirm && Host::GetBaseBoolSettingValue("Main", "ConfirmPowerOff", true))
{
SystemLock lock(pauseAndLockSystem());

View file

@ -43,10 +43,11 @@ SettingsWindow::SettingsWindow() : QWidget()
m_ui.setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
addPages();
connectUi();
}
SettingsWindow::SettingsWindow(const std::string& path, const std::string& serial, DiscRegion region,
const GameDatabase::Entry* entry, std::unique_ptr<SettingsInterface> sif)
const GameDatabase::Entry* entry, std::unique_ptr<INISettingsInterface> sif)
: QWidget(), m_sif(std::move(sif))
{
m_ui.setupUi(this);
@ -57,6 +58,7 @@ SettingsWindow::SettingsWindow(const std::string& path, const std::string& seria
tr("<strong>Summary</strong><hr>This page shows information about the selected game, and allows you to "
"validate your disc was dumped correctly."));
addPages();
connectUi();
s_open_game_properties_dialogs.push_back(this);
}
@ -167,10 +169,41 @@ void SettingsWindow::addPages()
connect(m_advanced_settings, &AdvancedSettingsWidget::onShowDebugOptionsChanged, m_graphics_settings,
&GraphicsSettingsWidget::onShowDebugSettingsChanged);
}
void SettingsWindow::reloadPages()
{
const int min_count = isPerGameSettings() ? 1 : 0;
while (m_ui.settingsContainer->count() > min_count)
{
const int row = m_ui.settingsContainer->count() - 1;
delete m_ui.settingsCategory->takeItem(row);
QWidget* widget = m_ui.settingsContainer->widget(row);
m_ui.settingsContainer->removeWidget(widget);
delete widget;
}
addPages();
}
void SettingsWindow::connectUi()
{
if (isPerGameSettings())
{
m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults)->setVisible(false);
m_ui.footerLayout->removeWidget(m_ui.restoreDefaults);
m_ui.restoreDefaults->deleteLater();
m_ui.restoreDefaults = nullptr;
}
else
{
m_ui.footerLayout->removeWidget(m_ui.copyGlobalSettings);
m_ui.copyGlobalSettings->deleteLater();
m_ui.copyGlobalSettings = nullptr;
m_ui.footerLayout->removeWidget(m_ui.clearGameSettings);
m_ui.clearGameSettings->deleteLater();
m_ui.clearGameSettings = nullptr;
}
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
@ -178,9 +211,13 @@ void SettingsWindow::addPages()
m_ui.settingsContainer->setCurrentIndex(0);
m_ui.helpText->setText(m_category_help_text[0]);
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsWindow::onCategoryCurrentRowChanged);
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &SettingsWindow::close);
connect(m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this,
&SettingsWindow::onRestoreDefaultsClicked);
connect(m_ui.close, &QPushButton::clicked, this, &SettingsWindow::close);
if (m_ui.restoreDefaults)
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &SettingsWindow::onRestoreDefaultsClicked);
if (m_ui.copyGlobalSettings)
connect(m_ui.copyGlobalSettings, &QPushButton::clicked, this, &SettingsWindow::onCopyGlobalSettingsClicked);
if (m_ui.clearGameSettings)
connect(m_ui.clearGameSettings, &QPushButton::clicked, this, &SettingsWindow::onClearSettingsClicked);
}
void SettingsWindow::addWidget(QWidget* widget, QString title, QString icon, QString help_text)
@ -232,6 +269,56 @@ void SettingsWindow::onRestoreDefaultsClicked()
g_emu_thread->setDefaultSettings(true, false);
}
void SettingsWindow::onCopyGlobalSettingsClicked()
{
if (!isPerGameSettings())
return;
if (QMessageBox::question(
this, tr("DuckStation Settings"),
tr("The configuration for this game will be replaced by the current global settings.\n\nAny current setting "
"values will be overwritten.\n\nDo you want to continue?"),
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
{
return;
}
{
auto lock = Host::GetSettingsLock();
Settings temp;
temp.Load(*Host::Internal::GetBaseSettingsLayer());
temp.Save(*m_sif.get(), true);
}
m_sif->Save();
g_emu_thread->reloadGameSettings();
reloadPages();
QMessageBox::information(this, tr("DuckStation Settings"), tr("Per-game configuration copied from global settings."));
}
void SettingsWindow::onClearSettingsClicked()
{
if (!isPerGameSettings())
return;
if (QMessageBox::question(this, tr("DuckStation Settings"),
tr("The configuration for this game will be cleared.\n\nAny current setting values will be "
"lost.\n\nDo you want to continue?"),
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
{
return;
}
Settings::Clear(*m_sif.get());
m_sif->Save();
g_emu_thread->reloadGameSettings();
reloadPages();
QMessageBox::information(this, tr("DuckStation Settings"), tr("Per-game configuration cleared."));
}
void SettingsWindow::registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text)
{
// construct rich text with formatted description

View file

@ -4,6 +4,8 @@
#pragma once
#include "ui_settingswindow.h"
#include "util/ini_settings_interface.h"
#include "common/types.h"
#include <QtCore/QMap>
@ -13,8 +15,6 @@
class QWheelEvent;
class SettingsInterface;
enum class DiscRegion : u8;
namespace GameDatabase {
@ -41,7 +41,7 @@ class SettingsWindow final : public QWidget
public:
SettingsWindow();
SettingsWindow(const std::string& path, const std::string& serial, DiscRegion region,
const GameDatabase::Entry* entry, std::unique_ptr<SettingsInterface> sif);
const GameDatabase::Entry* entry, std::unique_ptr<INISettingsInterface> sif);
~SettingsWindow();
static void openGamePropertiesDialog(const std::string& path, const std::string& serial, DiscRegion region);
@ -51,7 +51,7 @@ public:
static bool setGameSettingsBoolForSerial(const std::string& serial, const char* section, const char* key, bool value);
ALWAYS_INLINE bool isPerGameSettings() const { return static_cast<bool>(m_sif); }
ALWAYS_INLINE SettingsInterface* getSettingsInterface() const { return m_sif.get(); }
ALWAYS_INLINE INISettingsInterface* getSettingsInterface() const { return m_sif.get(); }
ALWAYS_INLINE InterfaceSettingsWidget* getGeneralSettingsWidget() const { return m_general_settings; }
ALWAYS_INLINE BIOSSettingsWidget* getBIOSSettingsWidget() const { return m_bios_settings; }
@ -98,6 +98,8 @@ public Q_SLOTS:
private Q_SLOTS:
void onCategoryCurrentRowChanged(int row);
void onRestoreDefaultsClicked();
void onCopyGlobalSettingsClicked();
void onClearSettingsClicked();
protected:
void closeEvent(QCloseEvent* event) override;
@ -109,13 +111,16 @@ private:
MAX_SETTINGS_WIDGETS = 12
};
void connectUi();
void addPages();
void reloadPages();
void addWidget(QWidget* widget, QString title, QString icon, QString help_text);
bool handleWheelEvent(QWheelEvent* event);
Ui::SettingsWindow m_ui;
std::unique_ptr<SettingsInterface> m_sif;
std::unique_ptr<INISettingsInterface> m_sif;
InterfaceSettingsWidget* m_general_settings = nullptr;
BIOSSettingsWidget* m_bios_settings = nullptr;
@ -134,4 +139,6 @@ private:
QObject* m_current_help_widget = nullptr;
QMap<QObject*, QString> m_widget_help_text_map;
std::string m_game_list_filename;
};

View file

@ -24,16 +24,6 @@
<normaloff>:/icons/duck.png</normaloff>:/icons/duck.png</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QStackedWidget" name="settingsContainer">
<property name="minimumSize">
<size>
<width>500</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QListWidget" name="settingsCategory">
<property name="sizePolicy">
@ -62,10 +52,13 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::RestoreDefaults</set>
<item row="0" column="1">
<widget class="QStackedWidget" name="settingsContainer">
<property name="minimumSize">
<size>
<width>500</width>
<height>0</height>
</size>
</property>
</widget>
</item>
@ -88,6 +81,51 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="footerLayout">
<item>
<widget class="QPushButton" name="restoreDefaults">
<property name="text">
<string>Restore Defaults</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="copyGlobalSettings">
<property name="text">
<string>Copy Global Settings</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearGameSettings">
<property name="text">
<string>Clear Settings</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>

View file

@ -91,7 +91,7 @@ bool RegTestHost::InitializeConfig()
// default settings for runner
SettingsInterface& si = *s_base_settings_interface.get();
g_settings.Save(si);
g_settings.Save(si, false);
si.SetStringValue("GPU", "Renderer", Settings::GetRendererName(GPURenderer::Software));
si.SetBoolValue("GPU", "DisableShaderCache", true);
si.SetStringValue("Pad1", "Type", Settings::GetControllerTypeName(ControllerType::AnalogController));