diff --git a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp index 852fbb74ca..8ec6278aae 100644 --- a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp +++ b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp @@ -44,6 +44,11 @@ bool IsSettingSaveable(const Config::Location& config_location) &Config::RA_ENABLED.GetLocation(), &Config::RA_USERNAME.GetLocation(), &Config::RA_API_TOKEN.GetLocation(), + &Config::RA_ACHIEVEMENTS_ENABLED.GetLocation(), + &Config::RA_LEADERBOARDS_ENABLED.GetLocation(), + &Config::RA_RICH_PRESENCE_ENABLED.GetLocation(), + &Config::RA_UNOFFICIAL_ENABLED.GetLocation(), + &Config::RA_ENCORE_ENABLED.GetLocation(), }; return std::any_of(begin(s_setting_saveable), end(s_setting_saveable), diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp new file mode 100644 index 0000000000..d2b8f63b6f --- /dev/null +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp @@ -0,0 +1,239 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef USE_RETRO_ACHIEVEMENTS +#include "DolphinQt/Achievements/AchievementSettingsWidget.h" + +#include +#include +#include +#include +#include +#include + +#include "Core/AchievementManager.h" +#include "Core/Config/AchievementSettings.h" +#include "Core/Config/MainSettings.h" +#include "Core/Core.h" + +#include "DolphinQt/Achievements/AchievementsWindow.h" +#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h" +#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" +#include "DolphinQt/QtUtils/ModalMessageBox.h" +#include "DolphinQt/QtUtils/NonDefaultQPushButton.h" +#include "DolphinQt/QtUtils/SignalBlocking.h" +#include "DolphinQt/Settings.h" + +static constexpr bool hardcore_mode_enabled = false; + +AchievementSettingsWidget::AchievementSettingsWidget(QWidget* parent, + AchievementsWindow* parent_window) + : QWidget(parent), parent_window(parent_window) +{ + CreateLayout(); + LoadSettings(); + ConnectWidgets(); + + connect(&Settings::Instance(), &Settings::ConfigChanged, this, + &AchievementSettingsWidget::LoadSettings); +} + +void AchievementSettingsWidget::CreateLayout() +{ + m_common_layout = new QVBoxLayout(); + m_common_integration_enabled_input = + new ToolTipCheckBox(tr("Enable RetroAchievements.org Integration")); + m_common_integration_enabled_input->SetDescription( + tr("Enable integration with RetroAchievements for earning achievements and competing in " + "leaderboards.

Must log in with a RetroAchievements account to use. Dolphin does " + "not save your password locally and uses an API token to maintain login.")); + m_common_username_label = new QLabel(tr("Username")); + m_common_username_input = new QLineEdit(QStringLiteral("")); + m_common_password_label = new QLabel(tr("Password")); + m_common_password_input = new QLineEdit(QStringLiteral("")); + m_common_password_input->setEchoMode(QLineEdit::Password); + m_common_login_button = new QPushButton(tr("Login")); + m_common_logout_button = new QPushButton(tr("Logout")); + m_common_login_failed = new QLabel(tr("Login Failed")); + m_common_login_failed->setStyleSheet(QStringLiteral("QLabel { color : red; }")); + m_common_login_failed->setVisible(false); + m_common_achievements_enabled_input = new ToolTipCheckBox(tr("Enable Achievements")); + m_common_achievements_enabled_input->SetDescription(tr("Enable unlocking achievements.
")); + m_common_leaderboards_enabled_input = new ToolTipCheckBox(tr("Enable Leaderboards")); + m_common_leaderboards_enabled_input->SetDescription( + tr("Enable competing in RetroAchievements leaderboards.

Hardcore Mode must be enabled " + "to use.")); + m_common_rich_presence_enabled_input = new ToolTipCheckBox(tr("Enable Rich Presence")); + m_common_rich_presence_enabled_input->SetDescription( + tr("Enable detailed rich presence on the RetroAchievements website.

This provides a " + "detailed description of what the player is doing in game to the website. If this is " + "disabled, the website will only report what game is being played.

This has no " + "bearing on Discord rich presence.")); + m_common_unofficial_enabled_input = new ToolTipCheckBox(tr("Enable Unofficial Achievements")); + m_common_unofficial_enabled_input->SetDescription( + tr("Enable unlocking unofficial achievements as well as official " + "achievements.

Unofficial achievements may be optional or unfinished achievements " + "that have not been deemed official by RetroAchievements and may be useful for testing or " + "simply for fun.")); + m_common_encore_enabled_input = new ToolTipCheckBox(tr("Enable Encore Achievements")); + m_common_encore_enabled_input->SetDescription(tr( + "Enable unlocking achievements in Encore Mode.

Encore Mode re-enables achievements " + "the player has already unlocked on the site so that the player will be notified if they " + "meet the unlock conditions again, useful for custom speedrun criteria or simply for fun.")); + + m_common_layout->addWidget(m_common_integration_enabled_input); + m_common_layout->addWidget(m_common_username_label); + m_common_layout->addWidget(m_common_username_input); + m_common_layout->addWidget(m_common_password_label); + m_common_layout->addWidget(m_common_password_input); + m_common_layout->addWidget(m_common_login_button); + m_common_layout->addWidget(m_common_logout_button); + m_common_layout->addWidget(m_common_login_failed); + m_common_layout->addWidget(m_common_achievements_enabled_input); + m_common_layout->addWidget(m_common_leaderboards_enabled_input); + m_common_layout->addWidget(m_common_rich_presence_enabled_input); + m_common_layout->addWidget(m_common_unofficial_enabled_input); + m_common_layout->addWidget(m_common_encore_enabled_input); + + m_common_layout->setAlignment(Qt::AlignTop); + setLayout(m_common_layout); +} + +void AchievementSettingsWidget::ConnectWidgets() +{ + connect(m_common_integration_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleRAIntegration); + connect(m_common_login_button, &QPushButton::pressed, this, &AchievementSettingsWidget::Login); + connect(m_common_logout_button, &QPushButton::pressed, this, &AchievementSettingsWidget::Logout); + connect(m_common_achievements_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleAchievements); + connect(m_common_leaderboards_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleLeaderboards); + connect(m_common_rich_presence_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleRichPresence); + connect(m_common_unofficial_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleUnofficial); + connect(m_common_encore_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleEncore); +} + +void AchievementSettingsWidget::OnControllerInterfaceConfigure() +{ + ControllerInterfaceWindow* window = new ControllerInterfaceWindow(this); + window->setAttribute(Qt::WA_DeleteOnClose, true); + window->setWindowModality(Qt::WindowModality::WindowModal); + window->show(); +} + +void AchievementSettingsWidget::LoadSettings() +{ + bool enabled = Config::Get(Config::RA_ENABLED); + bool achievements_enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED); + bool logged_out = Config::Get(Config::RA_API_TOKEN).empty(); + std::string username = Config::Get(Config::RA_USERNAME); + + SignalBlocking(m_common_integration_enabled_input)->setChecked(enabled); + SignalBlocking(m_common_username_label)->setEnabled(enabled); + if (!username.empty()) + SignalBlocking(m_common_username_input)->setText(QString::fromStdString(username)); + SignalBlocking(m_common_username_input)->setEnabled(enabled && logged_out); + SignalBlocking(m_common_password_label)->setVisible(logged_out); + SignalBlocking(m_common_password_label)->setEnabled(enabled); + SignalBlocking(m_common_password_input)->setVisible(logged_out); + SignalBlocking(m_common_password_input)->setEnabled(enabled); + SignalBlocking(m_common_login_button)->setVisible(logged_out); + SignalBlocking(m_common_login_button)->setEnabled(enabled && !Core::IsRunning()); + SignalBlocking(m_common_logout_button)->setVisible(!logged_out); + SignalBlocking(m_common_logout_button)->setEnabled(enabled); + + SignalBlocking(m_common_achievements_enabled_input)->setChecked(achievements_enabled); + SignalBlocking(m_common_achievements_enabled_input)->setEnabled(enabled); + + SignalBlocking(m_common_leaderboards_enabled_input) + ->setChecked(Config::Get(Config::RA_LEADERBOARDS_ENABLED)); + SignalBlocking(m_common_leaderboards_enabled_input)->setEnabled(enabled && hardcore_mode_enabled); + + SignalBlocking(m_common_rich_presence_enabled_input) + ->setChecked(Config::Get(Config::RA_RICH_PRESENCE_ENABLED)); + SignalBlocking(m_common_rich_presence_enabled_input)->setEnabled(enabled); + + SignalBlocking(m_common_unofficial_enabled_input) + ->setChecked(Config::Get(Config::RA_UNOFFICIAL_ENABLED)); + SignalBlocking(m_common_unofficial_enabled_input)->setEnabled(enabled && achievements_enabled); + + SignalBlocking(m_common_encore_enabled_input)->setChecked(Config::Get(Config::RA_ENCORE_ENABLED)); + SignalBlocking(m_common_encore_enabled_input)->setEnabled(enabled && achievements_enabled); +} + +void AchievementSettingsWidget::SaveSettings() +{ + Config::ConfigChangeCallbackGuard config_guard; + + Config::SetBaseOrCurrent(Config::RA_ENABLED, m_common_integration_enabled_input->isChecked()); + Config::SetBaseOrCurrent(Config::RA_ACHIEVEMENTS_ENABLED, + m_common_achievements_enabled_input->isChecked()); + Config::SetBaseOrCurrent(Config::RA_LEADERBOARDS_ENABLED, + m_common_leaderboards_enabled_input->isChecked()); + Config::SetBaseOrCurrent(Config::RA_RICH_PRESENCE_ENABLED, + m_common_rich_presence_enabled_input->isChecked()); + Config::SetBaseOrCurrent(Config::RA_UNOFFICIAL_ENABLED, + m_common_unofficial_enabled_input->isChecked()); + Config::SetBaseOrCurrent(Config::RA_ENCORE_ENABLED, m_common_encore_enabled_input->isChecked()); + Config::Save(); +} + +void AchievementSettingsWidget::ToggleRAIntegration() +{ + SaveSettings(); + if (Config::Get(Config::RA_ENABLED)) + AchievementManager::GetInstance()->Init(); + else + AchievementManager::GetInstance()->Shutdown(); +} + +void AchievementSettingsWidget::Login() +{ + Config::SetBaseOrCurrent(Config::RA_USERNAME, m_common_username_input->text().toStdString()); + AchievementManager::GetInstance()->Login(m_common_password_input->text().toStdString()); + m_common_password_input->setText(QString()); + m_common_login_failed->setVisible(Config::Get(Config::RA_API_TOKEN).empty()); + SaveSettings(); +} + +void AchievementSettingsWidget::Logout() +{ + AchievementManager::GetInstance()->Logout(); + SaveSettings(); +} + +void AchievementSettingsWidget::ToggleAchievements() +{ + SaveSettings(); + AchievementManager::GetInstance()->ActivateDeactivateAchievements(); +} + +void AchievementSettingsWidget::ToggleLeaderboards() +{ + SaveSettings(); + AchievementManager::GetInstance()->ActivateDeactivateLeaderboards(); +} + +void AchievementSettingsWidget::ToggleRichPresence() +{ + SaveSettings(); + AchievementManager::GetInstance()->ActivateDeactivateRichPresence(); +} + +void AchievementSettingsWidget::ToggleUnofficial() +{ + SaveSettings(); + AchievementManager::GetInstance()->ActivateDeactivateAchievements(); +} + +void AchievementSettingsWidget::ToggleEncore() +{ + SaveSettings(); + AchievementManager::GetInstance()->ActivateDeactivateAchievements(); +} + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h new file mode 100644 index 0000000000..ed23c53e7a --- /dev/null +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h @@ -0,0 +1,62 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef USE_RETRO_ACHIEVEMENTS +#include + +class AchievementsWindow; +class QGroupBox; +class QVBoxLayout; +class QLabel; +class QLineEdit; +class QPushButton; +class ToolTipCheckBox; + +class AchievementSettingsWidget final : public QWidget +{ + Q_OBJECT +public: + explicit AchievementSettingsWidget(QWidget* parent, AchievementsWindow* parent_window); + +private: + void OnControllerInterfaceConfigure(); + + void CreateLayout(); + void ConnectWidgets(); + + void LoadSettings(); + void SaveSettings(); + + void ToggleRAIntegration(); + void Login(); + void Logout(); + void ToggleAchievements(); + void ToggleLeaderboards(); + void ToggleRichPresence(); + void ToggleHardcore(); + void ToggleBadgeIcons(); + void ToggleUnofficial(); + void ToggleEncore(); + + AchievementsWindow* parent_window; + + QGroupBox* m_common_box; + QVBoxLayout* m_common_layout; + ToolTipCheckBox* m_common_integration_enabled_input; + QLabel* m_common_login_failed; + QLabel* m_common_username_label; + QLineEdit* m_common_username_input; + QLabel* m_common_password_label; + QLineEdit* m_common_password_input; + QPushButton* m_common_login_button; + QPushButton* m_common_logout_button; + ToolTipCheckBox* m_common_achievements_enabled_input; + ToolTipCheckBox* m_common_leaderboards_enabled_input; + ToolTipCheckBox* m_common_rich_presence_enabled_input; + ToolTipCheckBox* m_common_unofficial_enabled_input; + ToolTipCheckBox* m_common_encore_enabled_input; +}; + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index b3b9616dcb..b23843f75b 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -4,9 +4,11 @@ #ifdef USE_RETRO_ACHIEVEMENTS #include "DolphinQt/Achievements/AchievementsWindow.h" -#include #include +#include +#include +#include "DolphinQt/Achievements/AchievementSettingsWidget.h" #include "DolphinQt/QtUtils/WrapInScrollArea.h" AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent) @@ -28,8 +30,14 @@ void AchievementsWindow::CreateMainLayout() { auto* layout = new QVBoxLayout(); + m_tab_widget = new QTabWidget(); + m_tab_widget->addTab( + GetWrappedWidget(new AchievementSettingsWidget(m_tab_widget, this), this, 125, 100), + tr("Settings")); + m_button_box = new QDialogButtonBox(QDialogButtonBox::Close); + layout->addWidget(m_tab_widget); layout->addWidget(m_button_box); WrapInScrollArea(this, layout); diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h index 3ac28c6a17..9570e8127f 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h @@ -6,6 +6,7 @@ #ifdef USE_RETRO_ACHIEVEMENTS #include +class QTabWidget; class QDialogButtonBox; class AchievementsWindow : public QDialog @@ -20,6 +21,7 @@ private: void showEvent(QShowEvent* event); void ConnectWidgets(); + QTabWidget* m_tab_widget; QDialogButtonBox* m_button_box; }; diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 4c774831c8..573a3236a0 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -27,6 +27,8 @@ add_executable(dolphin-emu CheatSearchWidget.h CheatsManager.cpp CheatsManager.h + Achievements/AchievementSettingsWidget.cpp + Achievements/AchievementSettingsWidget.h Achievements/AchievementsWindow.cpp Achievements/AchievementsWindow.h Config/ARCodeWidget.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index a9de3f8a14..896bde5458 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -50,6 +50,7 @@ + @@ -253,6 +254,7 @@ +