Skip to content

Commit

Permalink
Add Leaderboards tab to Achievement dialog
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
LillyJadeKatrin committed Sep 26, 2023
1 parent cae8ead commit 6747957
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 0 deletions.
113 changes: 113 additions & 0 deletions Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp
@@ -0,0 +1,113 @@
// 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/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();

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()
{
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);
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<AchievementManager::Rank, 4> to_display{};
for (size_t ix = 0; ix < to_display.size(); ix++)
{
to_display[ix] = (board.entries.size() > ix) ? static_cast<AchievementManager::Rank>(ix) : 0;
}
if (board.player_rank > to_display.size() - 1)
{
// If the rank one below than the player is found, offset = 1.
AchievementManager::Rank offset =
static_cast<AchievementManager::Rank>(board.entries.count(board.player_rank + 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 ix = 1; ix < to_display.size(); ix++)
to_display[ix] = board.player_rank - 3 + offset + static_cast<AchievementManager::Rank>(ix);
}
for (size_t ix = 0; ix < to_display.size(); ix++)
{
AchievementManager::Rank rank = to_display[ix];
QLabel* a_rank = new QLabel(QStringLiteral("---"));
QLabel* a_username = new QLabel(QStringLiteral("---"));
QLabel* a_score = new QLabel(QStringLiteral("---"));
if (board.entries.count(rank) > 0)
{
a_rank->setText(tr("Rank %1").arg(rank));
a_username->setText(QString::fromStdString(board.entries.at(rank).username));
a_score->setText(QString::fromUtf8(board.entries.at(rank).score.data()));
}
QVBoxLayout* a_col = new QVBoxLayout();
a_col->addWidget(a_rank);
a_col->addWidget(a_username);
a_col->addWidget(a_score);
m_common_layout->addLayout(a_col, row, static_cast<int>(ix) + 1);
}
row++;
}
}

#endif // USE_RETRO_ACHIEVEMENTS
24 changes: 24 additions & 0 deletions 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
6 changes: 6 additions & 0 deletions Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -40,11 +41,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);

Expand All @@ -69,6 +73,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();
}
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/Achievements/AchievementsWindow.h
Expand Up @@ -10,6 +10,7 @@
#include "DolphinQt/QtUtils/QueueOnObject.h"

class AchievementHeaderWidget;
class AchievementLeaderboardWidget;
class AchievementProgressWidget;
class QDialogButtonBox;
class QTabWidget;
Expand All @@ -30,6 +31,7 @@ class AchievementsWindow : public QDialog
AchievementHeaderWidget* m_header_widget;
QTabWidget* m_tab_widget;
AchievementProgressWidget* m_progress_widget;
AchievementLeaderboardWidget* m_leaderboard_widget;
QDialogButtonBox* m_button_box;
};

Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/CMakeLists.txt
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/DolphinQt.vcxproj
Expand Up @@ -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" />
Expand Down Expand Up @@ -259,6 +260,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" />
Expand Down

0 comments on commit 6747957

Please sign in to comment.