diff --git a/pcsx2-qt/SettingWidgetBinder.h b/pcsx2-qt/SettingWidgetBinder.h index 4240ccb2e3..602ae9ca77 100644 --- a/pcsx2-qt/SettingWidgetBinder.h +++ b/pcsx2-qt/SettingWidgetBinder.h @@ -1261,6 +1261,102 @@ namespace SettingWidgetBinder widget->connect(widget, &QLineEdit::editingFinished, widget, std::move(value_changed)); } + static inline void BindWidgetToFileSetting(SettingsInterface* sif, QLineEdit* widget, QAbstractButton* browse_button, + QAbstractButton* open_button, QAbstractButton* reset_button, std::string section, std::string key, std::string default_value, + const char* filter, bool allow_pergame = false, bool use_relative = true) + { + using Accessor = SettingAccessor; + + std::string current_path(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())); + if (current_path.empty()) + current_path = default_value; + else if (use_relative && !Path::IsAbsolute(current_path)) + current_path = Path::Canonicalize(Path::Combine(EmuFolders::DataRoot, current_path)); + + const QString value(QString::fromStdString(current_path)); + Accessor::setStringValue(widget, value); + + if (!allow_pergame) + { + widget->setEnabled(false); + if (browse_button) + browse_button->setEnabled(false); + if (reset_button) + reset_button->setEnabled(false); + return; + } + + auto value_changed = [widget, section = std::move(section), key = std::move(key), default_value, use_relative]() { + const std::string new_value(widget->text().toStdString()); + if (!new_value.empty()) + { + if (use_relative) + { + const std::string relative_path(Path::MakeRelative(new_value, EmuFolders::DataRoot)); + Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), relative_path.c_str()); + } + else + { + Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.c_str()); + } + + if (!FileSystem::FileExists(new_value.c_str())) + { + QMessageBox::critical(QtUtils::GetRootWidget(widget), qApp->translate("SettingWidgetBinder", "Error"), + qApp->translate("SettingWidgetBinder", "File cannot be found.")); + } + + Host::CommitBaseSettingChanges(); + return; + } + else + { + QMessageBox::critical(QtUtils::GetRootWidget(widget), qApp->translate("SettingWidgetBinder", "Error"), + qApp->translate("SettingWidgetBinder", "File path cannot be empty.")); + } + + // reset to old value + std::string current_path(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())); + if (current_path.empty()) + current_path = default_value; + else if (use_relative && !Path::IsAbsolute(current_path)) + current_path = Path::Canonicalize(Path::Combine(EmuFolders::DataRoot, current_path)); + + widget->setText(QString::fromStdString(current_path)); + }; + + if (browse_button) + { + QObject::connect(browse_button, &QAbstractButton::clicked, browse_button, [widget, key, value_changed, filter]() { + const QString path(QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(widget), + qApp->translate("SettingWidgetBinder", "Select File"), QString(), filter))); + if (path.isEmpty()) + return; + + widget->setText(path); + value_changed(); + }); + } + if (open_button) + { + QObject::connect(open_button, &QAbstractButton::clicked, open_button, [widget]() { + QString path(Accessor::getStringValue(widget)); + if (!path.isEmpty()) + QtUtils::OpenURL(QtUtils::GetRootWidget(widget), QUrl::fromLocalFile(path)); + }); + } + if (reset_button) + { + QObject::connect( + reset_button, &QAbstractButton::clicked, reset_button, [widget, default_value = std::move(default_value), value_changed]() { + widget->setText(QString::fromStdString(default_value)); + value_changed(); + }); + } + + widget->connect(widget, &QLineEdit::editingFinished, widget, std::move(value_changed)); + } + // No need to pass a section or key since this is only used once and has six keys associated with it static inline void BindWidgetToDateTimeSetting(SettingsInterface* sif, QDateTimeEdit* widget, std::string section) { diff --git a/pcsx2-qt/Settings/AchievementSettingsWidget.cpp b/pcsx2-qt/Settings/AchievementSettingsWidget.cpp index d0e83748f2..d6595d7048 100644 --- a/pcsx2-qt/Settings/AchievementSettingsWidget.cpp +++ b/pcsx2-qt/Settings/AchievementSettingsWidget.cpp @@ -16,6 +16,8 @@ #include #include +const char* AUDIO_FILE_FILTER = QT_TRANSLATE_NOOP("MainWindow", "Audio Files (*.wav)"); + AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWidget* parent) : QWidget(parent) , m_dialog(dialog) @@ -29,6 +31,9 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.achievementNotifications, "Achievements", "Notifications", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboardNotifications, "Achievements", "LeaderboardNotifications", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Achievements", "SoundEffects", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.notificationSound, "Achievements", "InfoSound", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unlockSound, "Achievements", "UnlockSound", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.lbSound, "Achievements", "LBSubmitSound", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.overlays, "Achievements", "Overlays", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.encoreMode, "Achievements", "EncoreMode", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.spectatorMode, "Achievements", "SpectatorMode", false); @@ -36,11 +41,16 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.achievementNotificationsDuration, "Achievements", "NotificationsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_NOTIFICATION_DURATION); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.leaderboardNotificationsDuration, "Achievements", "LeaderboardsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_LEADERBOARD_DURATION); + SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.notificationSoundPath, m_ui.notificationSoundBrowse, m_ui.notificationSoundOpen, m_ui.notificationSoundReset, "Achievements", "InfoSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_INFO_SOUND_NAME), AUDIO_FILE_FILTER, true, false); + SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.unlockSoundPath, m_ui.unlockSoundBrowse, m_ui.unlockSoundOpen, m_ui.unlockSoundReset, "Achievements", "UnlockSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_UNLOCK_SOUND_NAME), AUDIO_FILE_FILTER, true, false); + SettingWidgetBinder::BindWidgetToFileSetting(sif, m_ui.lbSoundPath, m_ui.lbSoundBrowse, m_ui.lbSoundOpen, m_ui.lbSoundReset, "Achievements", "LBSubmitSoundName", Path::Combine(EmuFolders::Resources, EmuConfig.Achievements.DEFAULT_LBSUBMIT_SOUND_NAME), AUDIO_FILE_FILTER, true, false); + dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"), tr("When enabled and logged in, PCSX2 will scan for achievements on startup.")); dialog->registerWidgetHelp(m_ui.hardcoreMode, tr("Enable Hardcore Mode"), tr("Unchecked"), tr("\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions.")); dialog->registerWidgetHelp(m_ui.achievementNotifications, tr("Show Achievement Notifications"), tr("Checked"), tr("Displays popup messages on events such as achievement unlocks and game completion.")); dialog->registerWidgetHelp(m_ui.leaderboardNotifications, tr("Show Leaderboard Notifications"), tr("Checked"), tr("Displays popup messages when starting, submitting, or failing a leaderboard challenge.")); dialog->registerWidgetHelp(m_ui.soundEffects, tr("Enable Sound Effects"), tr("Checked"), tr("Plays sound effects for events such as achievement unlocks and leaderboard submissions.")); + dialog->registerWidgetHelp(m_ui.soundEffectsBox, tr("Custom Sound Effect"), tr("Any"), tr("Customize the sound effect that are played whenever you received a notification, earned an achievement or submitted an entry to the leaderboard.")); dialog->registerWidgetHelp(m_ui.overlays, tr("Enable In-Game Overlays"), tr("Checked"), tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active.")); dialog->registerWidgetHelp(m_ui.encoreMode, tr("Enable Encore Mode"), tr("Unchecked"),tr("When enabled, each session will behave as if no achievements have been unlocked.")); dialog->registerWidgetHelp(m_ui.spectatorMode, tr("Enable Spectator Mode"), tr("Unchecked"), tr("When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server.")); @@ -51,6 +61,10 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi connect(m_ui.hardcoreMode, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::onHardcoreModeStateChanged); connect(m_ui.achievementNotifications, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState); connect(m_ui.leaderboardNotifications, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState); + connect(m_ui.soundEffects, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState); + connect(m_ui.notificationSound, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState); + connect(m_ui.unlockSound, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState); + connect(m_ui.lbSound, &QCheckBox::checkStateChanged, this, &AchievementSettingsWidget::updateEnableState); connect(m_ui.achievementNotificationsDuration, &QSlider::valueChanged, this, &AchievementSettingsWidget::onAchievementsNotificationDurationSliderChanged); connect(m_ui.leaderboardNotificationsDuration, &QSlider::valueChanged, this, &AchievementSettingsWidget::onLeaderboardsNotificationDurationSliderChanged); @@ -73,6 +87,11 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi m_ui.verticalLayout->removeWidget(m_ui.loginBox); m_ui.loginBox->deleteLater(); m_ui.loginBox = nullptr; + + // sound effects + m_ui.verticalLayout->removeWidget(m_ui.soundEffectsBox); + m_ui.soundEffectsBox->deleteLater(); + m_ui.soundEffectsBox = nullptr; } updateEnableState(); @@ -87,6 +106,10 @@ void AchievementSettingsWidget::updateEnableState() const bool enabled = m_dialog->getEffectiveBoolValue("Achievements", "Enabled", false); const bool notifications = enabled && m_dialog->getEffectiveBoolValue("Achievements", "Notifications", true); const bool lb_notifications = enabled && m_dialog->getEffectiveBoolValue("Achievements", "LeaderboardNotifications", true); + const bool sound = m_dialog->getEffectiveBoolValue("Achievements", "SoundEffects", true); + const bool info = enabled && sound && m_dialog->getEffectiveBoolValue("Achievements", "InfoSound", true); + const bool unlock = enabled && sound && m_dialog->getEffectiveBoolValue("Achievements", "UnlockSound", true); + const bool lbsound = enabled && sound && m_dialog->getEffectiveBoolValue("Achievements", "LBSubmitSound", true); m_ui.hardcoreMode->setEnabled(enabled); m_ui.achievementNotifications->setEnabled(enabled); m_ui.leaderboardNotifications->setEnabled(enabled); @@ -94,6 +117,21 @@ void AchievementSettingsWidget::updateEnableState() m_ui.achievementNotificationsDurationLabel->setEnabled(notifications); m_ui.leaderboardNotificationsDuration->setEnabled(lb_notifications); m_ui.leaderboardNotificationsDurationLabel->setEnabled(lb_notifications); + m_ui.notificationSoundPath->setEnabled(info); + m_ui.notificationSoundBrowse->setEnabled(info); + m_ui.notificationSoundOpen->setEnabled(info); + m_ui.notificationSoundReset->setEnabled(info); + m_ui.notificationSound->setEnabled(enabled); + m_ui.unlockSoundPath->setEnabled(unlock); + m_ui.unlockSoundBrowse->setEnabled(unlock); + m_ui.unlockSoundOpen->setEnabled(unlock); + m_ui.unlockSoundReset->setEnabled(unlock); + m_ui.unlockSound->setEnabled(enabled); + m_ui.lbSoundPath->setEnabled(lbsound); + m_ui.lbSoundOpen->setEnabled(lbsound); + m_ui.lbSoundBrowse->setEnabled(lbsound); + m_ui.lbSoundReset->setEnabled(lbsound); + m_ui.lbSound->setEnabled(enabled); m_ui.soundEffects->setEnabled(enabled); m_ui.overlays->setEnabled(enabled); m_ui.encoreMode->setEnabled(enabled); diff --git a/pcsx2-qt/Settings/AchievementSettingsWidget.ui b/pcsx2-qt/Settings/AchievementSettingsWidget.ui index a45e6c9b5d..1163cfbd9b 100644 --- a/pcsx2-qt/Settings/AchievementSettingsWidget.ui +++ b/pcsx2-qt/Settings/AchievementSettingsWidget.ui @@ -24,256 +24,364 @@ 0 - - - Settings + + + true - - - - - Enable Spectator Mode - - - - - - - Enable Achievements - - - - - - - Test Unofficial Achievements - - - - - - - Enable Encore Mode - - - - - - - Enable Hardcore Mode - - - - - - - - - - Notifications - - - - - - - - 3 - - - 30 - - - 1 - - - 5 - - - Qt::Horizontal - - - false - - - QSlider::TicksBelow - - - 1 - - - - - - - 5 seconds - - - - - - - - - Show Achievement Notifications - - - - - - - - - 3 - - - 30 - - - 1 - - - 5 - - - Qt::Horizontal - - - false - - - QSlider::TicksBelow - - - 1 - - - - - - - 5 seconds - - - - - - - - - Show Leaderboard Notifications - - - - - - - Enable Sound Effects - - - - - - - Enable In-Game Overlays - - - - - - - - - - Account - - - - - - Username: + + + + 0 + -2 + 655 + 739 + + + + + + + Settings + + + + + + Test Unofficial Achievements + + + + + + + Enable Hardcore Mode + + + + + + + Enable Achievements + + + + + + + Enable Spectator Mode + + + + + + + Enable Encore Mode + + + + + + + + + + Notifications + + + + + + + + 3 + + + 30 + + + 1 + + + 5 + + + Qt::Orientation::Horizontal + + + false + + + QSlider::TickPosition::TicksBelow + + + 1 + + + + + + + 5 seconds + + + + + + + + + Show Achievement Notifications + + + + + + + + + 3 + + + 30 + + + 1 + + + 5 + + + Qt::Orientation::Horizontal + + + false + + + QSlider::TickPosition::TicksBelow + + + 1 + + + + + + + 5 seconds + + + + + + + + + Show Leaderboard Notifications + + + + + + + Enable Sound Effects + + + + + + + Enable In-Game Overlays + + + + + + + + + + Sound Effects + + + + + + + + + + + + Browse... + + + + + + + Reset + + + + + + + Achievement Unlock Sound + + + + + + + Browse... + + + + + + + + + + Browse... + + + + + + + Preview + + + + + + + Preview + + + + + + + Notification Sound + + + + + + + Preview + + + + + + + Reset + + + + + + + Reset + + + + + + + Leaderboard Submit Sound + + + + + + + + + + Account + + + + + + Username: Login token generated at: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - View Profile... - - - - - - - Login... - - - - - - + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop + + + + + + + + + View Profile... + + + + + + + Login... + + + + + + + + + + + + + 0 + 75 + + + + Game Info + + + + + + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop + + + + + + + + + + <html><head/><body><p align="justify">PCSX2 uses RetroAchievements as an achievement database and for tracking progress. To use achievements, please sign up for an account at <a href="https://retroachievements.org/">retroachievements.org</a>.</p><p align="justify">To view the achievement list in-game, press the hotkey for <span style=" font-weight:600;">Open Pause Menu</span> and select <span style=" font-weight:600;">Achievements</span> from the menu.</p></body></html> + + + Qt::TextFormat::RichText + + + true + + + 8 + + + true + + + + + - - - - - 0 - 75 - - - - Game Info - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - <html><head/><body><p align="justify">PCSX2 uses RetroAchievements as an achievement database and for tracking progress. To use achievements, please sign up for an account at <a href="https://retroachievements.org/">retroachievements.org</a>.</p><p align="justify">To view the achievement list in-game, press the hotkey for <span style=" font-weight:600;">Open Pause Menu</span> and select <span style=" font-weight:600;">Achievements</span> from the menu.</p></body></html> - - - Qt::RichText - - - true - - - 8 - - - true - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui index 197fda8c7c..1db2da7dab 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui @@ -32,9 +32,9 @@ 0 - -447 + -449 790 - 1049 + 1051 diff --git a/pcsx2/Achievements.cpp b/pcsx2/Achievements.cpp index 7f621e5533..80a2ae28bc 100644 --- a/pcsx2/Achievements.cpp +++ b/pcsx2/Achievements.cpp @@ -74,10 +74,6 @@ namespace Achievements // Chrome uses 10 server calls per domain, seems reasonable. static constexpr u32 MAX_CONCURRENT_SERVER_CALLS = 10; - static constexpr const char* INFO_SOUND_NAME = "sounds/achievements/message.wav"; - static constexpr const char* UNLOCK_SOUND_NAME = "sounds/achievements/unlock.wav"; - static constexpr const char* LBSUBMIT_SOUND_NAME = "sounds/achievements/lbsubmit.wav"; - namespace { struct LoginWithPasswordParameters @@ -1050,9 +1046,8 @@ void Achievements::DisplayAchievementSummary() }); } - // Technically not going through the resource API, but since we're passing this to something else, we can't. - if (EmuConfig.Achievements.SoundEffects) - Common::PlaySoundAsync(EmuFolders::GetOverridableResourcePath(INFO_SOUND_NAME).c_str()); + if (EmuConfig.Achievements.SoundEffects && EmuConfig.Achievements.InfoSound) + Common::PlaySoundAsync(EmuConfig.Achievements.InfoSoundName.c_str()); } void Achievements::DisplayHardcoreDeferredMessage() @@ -1103,8 +1098,8 @@ void Achievements::HandleUnlockEvent(const rc_client_event_t* event) }); } - if (EmuConfig.Achievements.SoundEffects) - Common::PlaySoundAsync(EmuFolders::GetOverridableResourcePath(UNLOCK_SOUND_NAME).c_str()); + if (EmuConfig.Achievements.SoundEffects && EmuConfig.Achievements.UnlockSound) + Common::PlaySoundAsync(EmuConfig.Achievements.UnlockSoundName.c_str()); } void Achievements::HandleGameCompleteEvent(const rc_client_event_t* event) @@ -1197,8 +1192,8 @@ void Achievements::HandleLeaderboardSubmittedEvent(const rc_client_event_t* even }); } - if (EmuConfig.Achievements.SoundEffects) - Common::PlaySoundAsync(EmuFolders::GetOverridableResourcePath(LBSUBMIT_SOUND_NAME).c_str()); + if (EmuConfig.Achievements.SoundEffects && EmuConfig.Achievements.LBSubmitSound) + Common::PlaySoundAsync(EmuConfig.Achievements.LBSubmitSoundName.c_str()); } void Achievements::HandleLeaderboardScoreboardEvent(const rc_client_event_t* event) diff --git a/pcsx2/Config.h b/pcsx2/Config.h index fc1253d220..e879aada39 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -1209,6 +1209,9 @@ struct Pcsx2Config static constexpr u32 MAXIMUM_NOTIFICATION_DURATION = 30; static constexpr u32 DEFAULT_NOTIFICATION_DURATION = 5; static constexpr u32 DEFAULT_LEADERBOARD_DURATION = 10; + static constexpr const char* DEFAULT_INFO_SOUND_NAME = "sounds/achievements/message.wav"; + static constexpr const char* DEFAULT_UNLOCK_SOUND_NAME = "sounds/achievements/unlock.wav"; + static constexpr const char* DEFAULT_LBSUBMIT_SOUND_NAME = "sounds/achievements/lbsubmit.wav"; BITFIELD32() bool @@ -1220,12 +1223,19 @@ struct Pcsx2Config Notifications : 1, LeaderboardNotifications : 1, SoundEffects : 1, + InfoSound : 1, + UnlockSound : 1, + LBSubmitSound : 1, Overlays : 1; BITFIELD_END u32 NotificationsDuration = DEFAULT_NOTIFICATION_DURATION; u32 LeaderboardsDuration = DEFAULT_LEADERBOARD_DURATION; + std::string InfoSoundName; + std::string UnlockSoundName; + std::string LBSubmitSoundName; + AchievementsOptions(); void LoadSave(SettingsWrapper& wrap); diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index f41316f4a5..d676dd8a5a 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -272,6 +272,7 @@ namespace FullscreenUI static void SwitchToLanding(); static ImGuiFullscreen::FileSelectorFilters GetOpenFileFilters(); static ImGuiFullscreen::FileSelectorFilters GetDiscImageFilters(); + static ImGuiFullscreen::FileSelectorFilters GetAudioFileFilters(); static void DoStartPath( const std::string& path, std::optional state_index = std::nullopt, std::optional fast_boot = std::nullopt); static void DoStartFile(); @@ -1059,6 +1060,11 @@ ImGuiFullscreen::FileSelectorFilters FullscreenUI::GetDiscImageFilters() return {"*.bin", "*.iso", "*.cue", "*.mdf", "*.chd", "*.cso", "*.zso", "*.gz"}; } +ImGuiFullscreen::FileSelectorFilters FullscreenUI::GetAudioFileFilters() +{ + return {"*.wav"}; +} + void FullscreenUI::DoStartPath(const std::string& path, std::optional state_index, std::optional fast_boot) { VMBootParameters params; @@ -7129,6 +7135,46 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock& se if (!IsEditingGameSettings(bsi)) { + MenuHeading(FSUI_CSTR("Sound Effects")); + if (MenuButton(FSUI_ICONSTR(ICON_FA_MUSIC, "Notification Sound"), bsi->GetTinyStringValue("Achievements", "InfoSoundName"))) + { + auto callback = [bsi](const std::string& path) { + if (!path.empty()) + { + bsi->SetStringValue("Achievements", "InfoSoundName", path.c_str()); + SetSettingsChanged(bsi); + } + CloseFileSelector(); + }; + OpenFileSelector(FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Select Notification Sound"), false, std::move(callback), GetAudioFileFilters()); + } + + if (MenuButton(FSUI_ICONSTR(ICON_FA_MUSIC, "Unlock Sound"), bsi->GetTinyStringValue("Achievements", "UnlockSoundName"))) + { + auto callback = [bsi](const std::string& path) { + if (!path.empty()) + { + bsi->SetStringValue("Achievements", "UnlockSoundName", path.c_str()); + SetSettingsChanged(bsi); + } + CloseFileSelector(); + }; + OpenFileSelector(FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Select Unlock Sound"), false, std::move(callback), GetAudioFileFilters()); + } + + if (MenuButton(FSUI_ICONSTR(ICON_FA_MUSIC, "Leaderboard Submit Sound"), bsi->GetTinyStringValue("Achievements", "LBSubmitSoundName"))) + { + auto callback = [bsi](const std::string& path) { + if (!path.empty()) + { + bsi->SetStringValue("Achievements", "LBSubmitSoundName", path.c_str()); + SetSettingsChanged(bsi); + } + CloseFileSelector(); + }; + OpenFileSelector(FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Select Leaderboard Submit Sound"), false, std::move(callback), GetAudioFileFilters()); + } + MenuHeading(FSUI_CSTR("Account")); if (bsi->ContainsValue("Achievements", "Token")) { diff --git a/pcsx2/ImGui/ImGuiManager.cpp b/pcsx2/ImGui/ImGuiManager.cpp index eaa1c7e93f..b1eaae3890 100644 --- a/pcsx2/ImGui/ImGuiManager.cpp +++ b/pcsx2/ImGui/ImGuiManager.cpp @@ -488,7 +488,7 @@ ImFont* ImGuiManager::AddFixedFont(float size) bool ImGuiManager::AddIconFonts(float size) { // clang-format off - static constexpr ImWchar range_fa[] = { 0xe06f,0xe06f,0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf023,0xf025,0xf028,0xf02b,0xf02b,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03e,0xf04b,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf05a,0xf05a,0xf05e,0xf05e,0xf063,0xf063,0xf067,0xf067,0xf06a,0xf06a,0xf06e,0xf06e,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf084,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c8,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf11b,0xf11c,0xf120,0xf121,0xf129,0xf12a,0xf140,0xf140,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf187,0xf188,0xf191,0xf192,0xf1b3,0xf1b3,0xf1de,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf21e,0xf21e,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2bd,0xf2bd,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf462,0xf462,0xf466,0xf466,0xf4e2,0xf4e2,0xf51f,0xf51f,0xf545,0xf545,0xf54c,0xf54c,0xf553,0xf553,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf70e,0xf70e,0xf756,0xf756,0xf780,0xf780,0xf794,0xf794,0xf815,0xf815,0xf84c,0xf84c,0xf8cc,0xf8cc,0x0,0x0 }; + static constexpr ImWchar range_fa[] = { 0xe06f,0xe06f,0xf001,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf023,0xf025,0xf028,0xf02b,0xf02b,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03e,0xf04b,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf05a,0xf05a,0xf05e,0xf05e,0xf063,0xf063,0xf067,0xf067,0xf06a,0xf06a,0xf06e,0xf06e,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf084,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c8,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf11b,0xf11c,0xf120,0xf121,0xf129,0xf12a,0xf140,0xf140,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf187,0xf188,0xf191,0xf192,0xf1b3,0xf1b3,0xf1de,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf21e,0xf21e,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2bd,0xf2bd,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf462,0xf462,0xf466,0xf466,0xf4e2,0xf4e2,0xf51f,0xf51f,0xf545,0xf545,0xf54c,0xf54c,0xf553,0xf553,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf70e,0xf70e,0xf756,0xf756,0xf780,0xf780,0xf794,0xf794,0xf815,0xf815,0xf84c,0xf84c,0xf8cc,0xf8cc,0x0,0x0 }; static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a7,0x21b0,0x21b3,0x21ba,0x21c3,0x21ce,0x21ce,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21e6,0x21e8,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x2206,0x2208,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x235e,0x2360,0x2361,0x2364,0x2367,0x237a,0x237b,0x237d,0x237d,0x237f,0x237f,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243d,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24fd,0x24ff,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xe000,0xe001,0xff21,0xff3a,0x0,0x0 }; // clang-format on diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index c70f1e9480..9d9a816b22 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -1830,6 +1830,9 @@ Pcsx2Config::AchievementsOptions::AchievementsOptions() Notifications = true; LeaderboardNotifications = true; SoundEffects = true; + InfoSound = true; + UnlockSound = true; + LBSubmitSound = true; Overlays = true; } @@ -1837,6 +1840,15 @@ void Pcsx2Config::AchievementsOptions::LoadSave(SettingsWrapper& wrap) { SettingsWrapSection("Achievements"); + if (InfoSoundName.empty()) + InfoSoundName = Path::Combine(EmuFolders::Resources, DEFAULT_INFO_SOUND_NAME); + + if (UnlockSoundName.empty()) + UnlockSoundName = Path::Combine(EmuFolders::Resources, DEFAULT_UNLOCK_SOUND_NAME); + + if (LBSubmitSoundName.empty()) + LBSubmitSoundName = Path::Combine(EmuFolders::Resources, DEFAULT_LBSUBMIT_SOUND_NAME); + SettingsWrapBitBool(Enabled); SettingsWrapBitBoolEx(HardcoreMode, "ChallengeMode"); SettingsWrapBitBool(EncoreMode); @@ -1845,9 +1857,15 @@ void Pcsx2Config::AchievementsOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapBitBool(Notifications); SettingsWrapBitBool(LeaderboardNotifications); SettingsWrapBitBool(SoundEffects); + SettingsWrapBitBool(InfoSound); + SettingsWrapBitBool(UnlockSound); + SettingsWrapBitBool(LBSubmitSound); SettingsWrapBitBool(Overlays); SettingsWrapEntry(NotificationsDuration); SettingsWrapEntry(LeaderboardsDuration); + SettingsWrapEntry(InfoSoundName); + SettingsWrapEntry(UnlockSoundName); + SettingsWrapEntry(LBSubmitSoundName); if (wrap.IsLoading()) {