diff options
| author | LillyJadeKatrin <lilly.kitty.1988@gmail.com> | 2023-06-17 11:47:56 -0400 |
|---|---|---|
| committer | Admiral H. Curtiss <pikachu025@gmail.com> | 2023-10-15 21:28:40 +0200 |
| commit | b824d55093a961efbdcdfd4f330d96306e835070 (patch) | |
| tree | 9223a25ece5e0945fe3b0e99a701cd5d7f2e577e /Source | |
| parent | 04df930e0d0e3b9cec91664350ae63848cad8e41 (diff) | |
Add Leaderboards tab to Achievement dialog
A new tab is added to the Achievements dialog to chart out the leaderboards in a table. Each row of the table contains the leaderboard information and up to four relevant entries, varying based on how many entries are in the leaderboard, whether or not the player has a submitted score, and where in the leaderboard the player's score is.
Diffstat (limited to 'Source')
6 files changed, 164 insertions, 0 deletions
diff --git a/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp new file mode 100644 index 0000000000..243bc4453c --- /dev/null +++ b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp @@ -0,0 +1,127 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef USE_RETRO_ACHIEVEMENTS +#include "DolphinQt/Achievements/AchievementLeaderboardWidget.h" + +#include <QCheckBox> +#include <QGroupBox> +#include <QLabel> +#include <QLineEdit> +#include <QPushButton> +#include <QString> +#include <QVBoxLayout> + +#include <fmt/format.h> + +#include <rcheevos/include/rc_api_runtime.h> +#include <rcheevos/include/rc_api_user.h> +#include <rcheevos/include/rc_runtime.h> + +#include "Common/CommonTypes.h" +#include "Core/AchievementManager.h" +#include "Core/Config/AchievementSettings.h" +#include "Core/Config/MainSettings.h" +#include "Core/Core.h" + +#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h" +#include "DolphinQt/QtUtils/ClearLayoutRecursively.h" +#include "DolphinQt/QtUtils/ModalMessageBox.h" +#include "DolphinQt/QtUtils/NonDefaultQPushButton.h" +#include "DolphinQt/QtUtils/SignalBlocking.h" +#include "DolphinQt/Settings.h" + +AchievementLeaderboardWidget::AchievementLeaderboardWidget(QWidget* parent) : QWidget(parent) +{ + m_common_box = new QGroupBox(); + m_common_layout = new QGridLayout(); + + { + std::lock_guard lg{*AchievementManager::GetInstance()->GetLock()}; + UpdateData(); + } + + m_common_box->setLayout(m_common_layout); + + auto* layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setAlignment(Qt::AlignTop); + layout->addWidget(m_common_box); + setLayout(layout); +} + +void AchievementLeaderboardWidget::UpdateData() +{ + ClearLayoutRecursively(m_common_layout); + + if (!AchievementManager::GetInstance()->IsGameLoaded()) + return; + const auto& leaderboards = AchievementManager::GetInstance()->GetLeaderboardsInfo(); + int row = 0; + for (const auto& board_row : leaderboards) + { + const AchievementManager::LeaderboardStatus& board = board_row.second; + QLabel* a_title = new QLabel(QString::fromStdString(board.name)); + QLabel* a_description = new QLabel(QString::fromStdString(board.description)); + QVBoxLayout* a_col_left = new QVBoxLayout(); + a_col_left->addWidget(a_title); + a_col_left->addWidget(a_description); + if (row > 0) + { + QFrame* a_divider = new QFrame(); + a_divider->setFrameShape(QFrame::HLine); + m_common_layout->addWidget(a_divider, row - 1, 0); + } + m_common_layout->addLayout(a_col_left, row, 0); + // Each leaderboard entry is displayed with four values. These are *generally* intended to be, + // in order, the first place entry, the entry one above the player, the player's entry, and + // the entry one below the player. + // Edge cases: + // * If there are fewer than four entries in the leaderboard, all entries will be shown in + // order and the remainder of the list will be padded with empty values. + // * If the player does not currently have a score in the leaderboard, or is in the top 3, + // the four slots will be the top four players in order. + // * If the player is last place, the player will be in the fourth slot, and the second and + // third slots will be the two players above them. The first slot will always be first place. + std::array<u32, 4> to_display{1, 2, 3, 4}; + if (board.player_index > to_display.size() - 1) + { + // If the rank one below than the player is found, offset = 1. + u32 offset = static_cast<u32>(board.entries.count(board.player_index + 1)); + // Example: player is 10th place but not last + // to_display = {1, 10-3+1+1, 10-3+1+2, 10-3+1+3} = {1, 9, 10, 11} + // Example: player is 15th place and is last + // to_display = {1, 15-3+0+1, 15-3+0+2, 15-3+0+3} = {1, 13, 14, 15} + for (size_t i = 1; i < to_display.size(); ++i) + to_display[i] = board.player_index - 3 + offset + static_cast<u32>(i); + } + for (size_t i = 0; i < to_display.size(); ++i) + { + u32 index = to_display[i]; + QLabel* a_rank = new QLabel(QStringLiteral("---")); + QLabel* a_username = new QLabel(QStringLiteral("---")); + QLabel* a_score = new QLabel(QStringLiteral("---")); + const auto it = board.entries.find(index); + if (it != board.entries.end()) + { + a_rank->setText(tr("Rank %1").arg(it->second.rank)); + a_username->setText(QString::fromStdString(it->second.username)); + a_score->setText(QString::fromUtf8(it->second.score.data())); + } + QVBoxLayout* a_col = new QVBoxLayout(); + a_col->addWidget(a_rank); + a_col->addWidget(a_username); + a_col->addWidget(a_score); + if (row > 0) + { + QFrame* a_divider = new QFrame(); + a_divider->setFrameShape(QFrame::HLine); + m_common_layout->addWidget(a_divider, row - 1, static_cast<int>(i) + 1); + } + m_common_layout->addLayout(a_col, row, static_cast<int>(i) + 1); + } + row += 2; + } +} + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.h b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.h new file mode 100644 index 0000000000..055ea6ab3f --- /dev/null +++ b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.h @@ -0,0 +1,24 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef USE_RETRO_ACHIEVEMENTS +#include <QWidget> + +class QGroupBox; +class QGridLayout; + +class AchievementLeaderboardWidget final : public QWidget +{ + Q_OBJECT +public: + explicit AchievementLeaderboardWidget(QWidget* parent); + void UpdateData(); + +private: + QGroupBox* m_common_box; + QGridLayout* m_common_layout; +}; + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index d376da6109..8d01663c87 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -11,6 +11,7 @@ #include <QVBoxLayout> #include "DolphinQt/Achievements/AchievementHeaderWidget.h" +#include "DolphinQt/Achievements/AchievementLeaderboardWidget.h" #include "DolphinQt/Achievements/AchievementProgressWidget.h" #include "DolphinQt/Achievements/AchievementSettingsWidget.h" #include "DolphinQt/QtUtils/QueueOnObject.h" @@ -42,10 +43,14 @@ void AchievementsWindow::CreateMainLayout() m_header_widget = new AchievementHeaderWidget(this); m_tab_widget = new QTabWidget(); m_progress_widget = new AchievementProgressWidget(m_tab_widget); + m_leaderboard_widget = new AchievementLeaderboardWidget(m_tab_widget); m_tab_widget->addTab( GetWrappedWidget(new AchievementSettingsWidget(m_tab_widget, this), this, 125, 100), tr("Settings")); m_tab_widget->addTab(GetWrappedWidget(m_progress_widget, this, 125, 100), tr("Progress")); + m_tab_widget->setTabVisible(1, AchievementManager::GetInstance()->IsGameLoaded()); + m_tab_widget->addTab(GetWrappedWidget(m_leaderboard_widget, this, 125, 100), tr("Leaderboards")); + m_tab_widget->setTabVisible(2, AchievementManager::GetInstance()->IsGameLoaded()); m_button_box = new QDialogButtonBox(QDialogButtonBox::Close); @@ -70,6 +75,8 @@ void AchievementsWindow::UpdateData() // Settings tab handles its own updates ... indeed, that calls this m_progress_widget->UpdateData(); m_tab_widget->setTabVisible(1, AchievementManager::GetInstance()->IsGameLoaded()); + m_leaderboard_widget->UpdateData(); + m_tab_widget->setTabVisible(2, AchievementManager::GetInstance()->IsGameLoaded()); } update(); } diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h index d8407a3a17..6fd7165e1f 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h @@ -10,6 +10,7 @@ #include "DolphinQt/QtUtils/QueueOnObject.h" class AchievementHeaderWidget; +class AchievementLeaderboardWidget; class AchievementProgressWidget; class QDialogButtonBox; class QTabWidget; @@ -30,6 +31,7 @@ private: AchievementHeaderWidget* m_header_widget; QTabWidget* m_tab_widget; AchievementProgressWidget* m_progress_widget; + AchievementLeaderboardWidget* m_leaderboard_widget; QDialogButtonBox* m_button_box; }; diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 87fc14c766..b271fab7fb 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -30,6 +30,8 @@ add_executable(dolphin-emu CheatsManager.h Achievements/AchievementHeaderWidget.cpp Achievements/AchievementHeaderWidget.h + Achievements/AchievementLeaderboardWidget.cpp + Achievements/AchievementLeaderboardWidget.h Achievements/AchievementProgressWidget.cpp Achievements/AchievementProgressWidget.h Achievements/AchievementSettingsWidget.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index f73ea5c1cc..35f1110e4c 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -51,6 +51,7 @@ <ClCompile Include="CheatSearchWidget.cpp" /> <ClCompile Include="CheatsManager.cpp" /> <ClCompile Include="Achievements\AchievementHeaderWidget.cpp" /> + <ClCompile Include="Achievements\AchievementLeaderboardWidget.cpp" /> <ClCompile Include="Achievements\AchievementProgressWidget.cpp" /> <ClCompile Include="Achievements\AchievementSettingsWidget.cpp" /> <ClCompile Include="Achievements\AchievementsWindow.cpp" /> @@ -261,6 +262,7 @@ <QtMoc Include="CheatSearchWidget.h" /> <QtMoc Include="CheatsManager.h" /> <QtMoc Include="Achievements\AchievementHeaderWidget.h" /> + <QtMoc Include="Achievements\AchievementLeaderboardWidget.h" /> <QtMoc Include="Achievements\AchievementProgressWidget.h" /> <QtMoc Include="Achievements\AchievementSettingsWidget.h" /> <QtMoc Include="Achievements\AchievementsWindow.h" /> |
