Merge pull request #12027 from LillyJadeKatrin/retroachievements-leaderboards-tab
RetroAchievements - Leaderboards Tab
This commit is contained in:
commit
bbf3fed93c
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <rcheevos/include/rc_api_info.h>
|
||||||
#include <rcheevos/include/rc_hash.h>
|
#include <rcheevos/include/rc_hash.h>
|
||||||
|
|
||||||
#include "Common/HttpRequest.h"
|
#include "Common/HttpRequest.h"
|
||||||
|
@ -268,9 +269,15 @@ void AchievementManager::ActivateDeactivateLeaderboards()
|
||||||
for (u32 ix = 0; ix < m_game_data.num_leaderboards; ix++)
|
for (u32 ix = 0; ix < m_game_data.num_leaderboards; ix++)
|
||||||
{
|
{
|
||||||
auto leaderboard = m_game_data.leaderboards[ix];
|
auto leaderboard = m_game_data.leaderboards[ix];
|
||||||
|
u32 leaderboard_id = leaderboard.id;
|
||||||
if (m_is_game_loaded && leaderboards_enabled && hardcore_mode_enabled)
|
if (m_is_game_loaded && leaderboards_enabled && hardcore_mode_enabled)
|
||||||
{
|
{
|
||||||
rc_runtime_activate_lboard(&m_runtime, leaderboard.id, leaderboard.definition, nullptr, 0);
|
rc_runtime_activate_lboard(&m_runtime, leaderboard_id, leaderboard.definition, nullptr, 0);
|
||||||
|
m_queue.EmplaceItem([this, leaderboard_id] {
|
||||||
|
FetchBoardInfo(leaderboard_id);
|
||||||
|
if (m_update_callback)
|
||||||
|
m_update_callback();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -712,6 +719,12 @@ AchievementManager::GetAchievementProgress(AchievementId achievement_id, u32* va
|
||||||
return ResponseType::SUCCESS;
|
return ResponseType::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::unordered_map<AchievementManager::AchievementId, AchievementManager::LeaderboardStatus>&
|
||||||
|
AchievementManager::GetLeaderboardsInfo() const
|
||||||
|
{
|
||||||
|
return m_leaderboard_map;
|
||||||
|
}
|
||||||
|
|
||||||
AchievementManager::RichPresence AchievementManager::GetRichPresence()
|
AchievementManager::RichPresence AchievementManager::GetRichPresence()
|
||||||
{
|
{
|
||||||
std::lock_guard lg{m_lock};
|
std::lock_guard lg{m_lock};
|
||||||
|
@ -732,6 +745,7 @@ void AchievementManager::CloseGame()
|
||||||
m_game_id = 0;
|
m_game_id = 0;
|
||||||
m_game_badge.name = "";
|
m_game_badge.name = "";
|
||||||
m_unlock_map.clear();
|
m_unlock_map.clear();
|
||||||
|
m_leaderboard_map.clear();
|
||||||
rc_api_destroy_fetch_game_data_response(&m_game_data);
|
rc_api_destroy_fetch_game_data_response(&m_game_data);
|
||||||
std::memset(&m_game_data, 0, sizeof(m_game_data));
|
std::memset(&m_game_data, 0, sizeof(m_game_data));
|
||||||
m_queue.Cancel();
|
m_queue.Cancel();
|
||||||
|
@ -955,6 +969,90 @@ AchievementManager::ResponseType AchievementManager::FetchUnlockData(bool hardco
|
||||||
return r_type;
|
return r_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AchievementManager::ResponseType AchievementManager::FetchBoardInfo(AchievementId leaderboard_id)
|
||||||
|
{
|
||||||
|
std::string username = Config::Get(Config::RA_USERNAME);
|
||||||
|
LeaderboardStatus lboard{};
|
||||||
|
|
||||||
|
{
|
||||||
|
rc_api_fetch_leaderboard_info_response_t board_info{};
|
||||||
|
const rc_api_fetch_leaderboard_info_request_t fetch_board_request = {
|
||||||
|
.leaderboard_id = leaderboard_id, .count = 4, .first_entry = 1, .username = nullptr};
|
||||||
|
const ResponseType r_type =
|
||||||
|
Request<rc_api_fetch_leaderboard_info_request_t, rc_api_fetch_leaderboard_info_response_t>(
|
||||||
|
fetch_board_request, &board_info, rc_api_init_fetch_leaderboard_info_request,
|
||||||
|
rc_api_process_fetch_leaderboard_info_response);
|
||||||
|
if (r_type != ResponseType::SUCCESS)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to fetch info for leaderboard ID {}.", leaderboard_id);
|
||||||
|
rc_api_destroy_fetch_leaderboard_info_response(&board_info);
|
||||||
|
return r_type;
|
||||||
|
}
|
||||||
|
lboard.name = board_info.title;
|
||||||
|
lboard.description = board_info.description;
|
||||||
|
lboard.entries.clear();
|
||||||
|
for (u32 i = 0; i < board_info.num_entries; ++i)
|
||||||
|
{
|
||||||
|
const auto& org_entry = board_info.entries[i];
|
||||||
|
LeaderboardEntry dest_entry =
|
||||||
|
LeaderboardEntry{.username = org_entry.username, .rank = org_entry.rank};
|
||||||
|
if (rc_runtime_format_lboard_value(dest_entry.score.data(), FORMAT_SIZE, org_entry.score,
|
||||||
|
board_info.format) == 0)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to format leaderboard score {}.", org_entry.score);
|
||||||
|
strncpy(dest_entry.score.data(), fmt::format("{}", org_entry.score).c_str(), FORMAT_SIZE);
|
||||||
|
}
|
||||||
|
lboard.entries[org_entry.index] = dest_entry;
|
||||||
|
}
|
||||||
|
rc_api_destroy_fetch_leaderboard_info_response(&board_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Retrieve, if exists, the player's entry, the two entries above the player, and the two
|
||||||
|
// entries below the player, for a total of five entries. Technically I only need one entry
|
||||||
|
// below, but the API is ambiguous what happens if an even number and a username are provided.
|
||||||
|
rc_api_fetch_leaderboard_info_response_t board_info{};
|
||||||
|
const rc_api_fetch_leaderboard_info_request_t fetch_board_request = {
|
||||||
|
.leaderboard_id = leaderboard_id,
|
||||||
|
.count = 5,
|
||||||
|
.first_entry = 0,
|
||||||
|
.username = username.c_str()};
|
||||||
|
const ResponseType r_type =
|
||||||
|
Request<rc_api_fetch_leaderboard_info_request_t, rc_api_fetch_leaderboard_info_response_t>(
|
||||||
|
fetch_board_request, &board_info, rc_api_init_fetch_leaderboard_info_request,
|
||||||
|
rc_api_process_fetch_leaderboard_info_response);
|
||||||
|
if (r_type != ResponseType::SUCCESS)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to fetch info for leaderboard ID {}.", leaderboard_id);
|
||||||
|
rc_api_destroy_fetch_leaderboard_info_response(&board_info);
|
||||||
|
return r_type;
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < board_info.num_entries; ++i)
|
||||||
|
{
|
||||||
|
const auto& org_entry = board_info.entries[i];
|
||||||
|
LeaderboardEntry dest_entry =
|
||||||
|
LeaderboardEntry{.username = org_entry.username, .rank = org_entry.rank};
|
||||||
|
if (rc_runtime_format_lboard_value(dest_entry.score.data(), FORMAT_SIZE, org_entry.score,
|
||||||
|
board_info.format) == 0)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to format leaderboard score {}.", org_entry.score);
|
||||||
|
strncpy(dest_entry.score.data(), fmt::format("{}", org_entry.score).c_str(), FORMAT_SIZE);
|
||||||
|
}
|
||||||
|
lboard.entries[org_entry.index] = dest_entry;
|
||||||
|
if (org_entry.username == username)
|
||||||
|
lboard.player_index = org_entry.index;
|
||||||
|
}
|
||||||
|
rc_api_destroy_fetch_leaderboard_info_response(&board_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lg{m_lock};
|
||||||
|
m_leaderboard_map[leaderboard_id] = lboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseType::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void AchievementManager::ActivateDeactivateAchievement(AchievementId id, bool enabled,
|
void AchievementManager::ActivateDeactivateAchievement(AchievementId id, bool enabled,
|
||||||
bool unofficial, bool encore)
|
bool unofficial, bool encore)
|
||||||
{
|
{
|
||||||
|
@ -1198,7 +1296,12 @@ void AchievementManager::HandleLeaderboardTriggeredEvent(const rc_runtime_event_
|
||||||
m_game_data.leaderboards[ix].title),
|
m_game_data.leaderboards[ix].title),
|
||||||
OSD::Duration::VERY_LONG, OSD::Color::YELLOW);
|
OSD::Duration::VERY_LONG, OSD::Color::YELLOW);
|
||||||
}
|
}
|
||||||
return;
|
m_queue.EmplaceItem([this, event_id] {
|
||||||
|
FetchBoardInfo(event_id);
|
||||||
|
if (m_update_callback)
|
||||||
|
m_update_callback();
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid leaderboard triggered event with id {}.", event_id);
|
ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid leaderboard triggered event with id {}.", event_id);
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
using AchievementId = u32;
|
using AchievementId = u32;
|
||||||
static constexpr size_t FORMAT_SIZE = 24;
|
static constexpr size_t FORMAT_SIZE = 24;
|
||||||
using FormattedValue = std::array<char, FORMAT_SIZE>;
|
using FormattedValue = std::array<char, FORMAT_SIZE>;
|
||||||
|
using LeaderboardRank = u32;
|
||||||
static constexpr size_t RP_SIZE = 256;
|
static constexpr size_t RP_SIZE = 256;
|
||||||
using RichPresence = std::array<char, RP_SIZE>;
|
using RichPresence = std::array<char, RP_SIZE>;
|
||||||
using Badge = std::vector<u8>;
|
using Badge = std::vector<u8>;
|
||||||
|
@ -83,6 +84,21 @@ public:
|
||||||
static constexpr std::string_view GOLD = "#FFD700";
|
static constexpr std::string_view GOLD = "#FFD700";
|
||||||
static constexpr std::string_view BLUE = "#0B71C1";
|
static constexpr std::string_view BLUE = "#0B71C1";
|
||||||
|
|
||||||
|
struct LeaderboardEntry
|
||||||
|
{
|
||||||
|
std::string username;
|
||||||
|
FormattedValue score;
|
||||||
|
LeaderboardRank rank;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LeaderboardStatus
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string description;
|
||||||
|
u32 player_index = 0;
|
||||||
|
std::unordered_map<u32, LeaderboardEntry> entries;
|
||||||
|
};
|
||||||
|
|
||||||
static AchievementManager* GetInstance();
|
static AchievementManager* GetInstance();
|
||||||
void Init();
|
void Init();
|
||||||
void SetUpdateCallback(UpdateCallback callback);
|
void SetUpdateCallback(UpdateCallback callback);
|
||||||
|
@ -113,6 +129,7 @@ public:
|
||||||
const UnlockStatus& GetUnlockStatus(AchievementId achievement_id) const;
|
const UnlockStatus& GetUnlockStatus(AchievementId achievement_id) const;
|
||||||
AchievementManager::ResponseType GetAchievementProgress(AchievementId achievement_id, u32* value,
|
AchievementManager::ResponseType GetAchievementProgress(AchievementId achievement_id, u32* value,
|
||||||
u32* target);
|
u32* target);
|
||||||
|
const std::unordered_map<AchievementId, LeaderboardStatus>& GetLeaderboardsInfo() const;
|
||||||
RichPresence GetRichPresence();
|
RichPresence GetRichPresence();
|
||||||
|
|
||||||
void CloseGame();
|
void CloseGame();
|
||||||
|
@ -129,6 +146,7 @@ private:
|
||||||
ResponseType StartRASession();
|
ResponseType StartRASession();
|
||||||
ResponseType FetchGameData();
|
ResponseType FetchGameData();
|
||||||
ResponseType FetchUnlockData(bool hardcore);
|
ResponseType FetchUnlockData(bool hardcore);
|
||||||
|
ResponseType FetchBoardInfo(AchievementId leaderboard_id);
|
||||||
|
|
||||||
void ActivateDeactivateAchievement(AchievementId id, bool enabled, bool unofficial, bool encore);
|
void ActivateDeactivateAchievement(AchievementId id, bool enabled, bool unofficial, bool encore);
|
||||||
void GenerateRichPresence();
|
void GenerateRichPresence();
|
||||||
|
@ -165,6 +183,7 @@ private:
|
||||||
time_t m_last_ping_time = 0;
|
time_t m_last_ping_time = 0;
|
||||||
|
|
||||||
std::unordered_map<AchievementId, UnlockStatus> m_unlock_map;
|
std::unordered_map<AchievementId, UnlockStatus> m_unlock_map;
|
||||||
|
std::unordered_map<AchievementId, LeaderboardStatus> m_leaderboard_map;
|
||||||
|
|
||||||
Common::WorkQueueThread<std::function<void()>> m_queue;
|
Common::WorkQueueThread<std::function<void()>> m_queue;
|
||||||
Common::WorkQueueThread<std::function<void()>> m_image_queue;
|
Common::WorkQueueThread<std::function<void()>> m_image_queue;
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "DolphinQt/Achievements/AchievementHeaderWidget.h"
|
#include "DolphinQt/Achievements/AchievementHeaderWidget.h"
|
||||||
|
#include "DolphinQt/Achievements/AchievementLeaderboardWidget.h"
|
||||||
#include "DolphinQt/Achievements/AchievementProgressWidget.h"
|
#include "DolphinQt/Achievements/AchievementProgressWidget.h"
|
||||||
#include "DolphinQt/Achievements/AchievementSettingsWidget.h"
|
#include "DolphinQt/Achievements/AchievementSettingsWidget.h"
|
||||||
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
||||||
|
@ -42,10 +43,14 @@ void AchievementsWindow::CreateMainLayout()
|
||||||
m_header_widget = new AchievementHeaderWidget(this);
|
m_header_widget = new AchievementHeaderWidget(this);
|
||||||
m_tab_widget = new QTabWidget();
|
m_tab_widget = new QTabWidget();
|
||||||
m_progress_widget = new AchievementProgressWidget(m_tab_widget);
|
m_progress_widget = new AchievementProgressWidget(m_tab_widget);
|
||||||
|
m_leaderboard_widget = new AchievementLeaderboardWidget(m_tab_widget);
|
||||||
m_tab_widget->addTab(
|
m_tab_widget->addTab(
|
||||||
GetWrappedWidget(new AchievementSettingsWidget(m_tab_widget, this), this, 125, 100),
|
GetWrappedWidget(new AchievementSettingsWidget(m_tab_widget, this), this, 125, 100),
|
||||||
tr("Settings"));
|
tr("Settings"));
|
||||||
m_tab_widget->addTab(GetWrappedWidget(m_progress_widget, this, 125, 100), tr("Progress"));
|
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);
|
m_button_box = new QDialogButtonBox(QDialogButtonBox::Close);
|
||||||
|
|
||||||
|
@ -70,6 +75,8 @@ void AchievementsWindow::UpdateData()
|
||||||
// Settings tab handles its own updates ... indeed, that calls this
|
// Settings tab handles its own updates ... indeed, that calls this
|
||||||
m_progress_widget->UpdateData();
|
m_progress_widget->UpdateData();
|
||||||
m_tab_widget->setTabVisible(1, AchievementManager::GetInstance()->IsGameLoaded());
|
m_tab_widget->setTabVisible(1, AchievementManager::GetInstance()->IsGameLoaded());
|
||||||
|
m_leaderboard_widget->UpdateData();
|
||||||
|
m_tab_widget->setTabVisible(2, AchievementManager::GetInstance()->IsGameLoaded());
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
||||||
|
|
||||||
class AchievementHeaderWidget;
|
class AchievementHeaderWidget;
|
||||||
|
class AchievementLeaderboardWidget;
|
||||||
class AchievementProgressWidget;
|
class AchievementProgressWidget;
|
||||||
class QDialogButtonBox;
|
class QDialogButtonBox;
|
||||||
class QTabWidget;
|
class QTabWidget;
|
||||||
|
@ -30,6 +31,7 @@ private:
|
||||||
AchievementHeaderWidget* m_header_widget;
|
AchievementHeaderWidget* m_header_widget;
|
||||||
QTabWidget* m_tab_widget;
|
QTabWidget* m_tab_widget;
|
||||||
AchievementProgressWidget* m_progress_widget;
|
AchievementProgressWidget* m_progress_widget;
|
||||||
|
AchievementLeaderboardWidget* m_leaderboard_widget;
|
||||||
QDialogButtonBox* m_button_box;
|
QDialogButtonBox* m_button_box;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ add_executable(dolphin-emu
|
||||||
CheatsManager.h
|
CheatsManager.h
|
||||||
Achievements/AchievementHeaderWidget.cpp
|
Achievements/AchievementHeaderWidget.cpp
|
||||||
Achievements/AchievementHeaderWidget.h
|
Achievements/AchievementHeaderWidget.h
|
||||||
|
Achievements/AchievementLeaderboardWidget.cpp
|
||||||
|
Achievements/AchievementLeaderboardWidget.h
|
||||||
Achievements/AchievementProgressWidget.cpp
|
Achievements/AchievementProgressWidget.cpp
|
||||||
Achievements/AchievementProgressWidget.h
|
Achievements/AchievementProgressWidget.h
|
||||||
Achievements/AchievementSettingsWidget.cpp
|
Achievements/AchievementSettingsWidget.cpp
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
<ClCompile Include="CheatSearchWidget.cpp" />
|
<ClCompile Include="CheatSearchWidget.cpp" />
|
||||||
<ClCompile Include="CheatsManager.cpp" />
|
<ClCompile Include="CheatsManager.cpp" />
|
||||||
<ClCompile Include="Achievements\AchievementHeaderWidget.cpp" />
|
<ClCompile Include="Achievements\AchievementHeaderWidget.cpp" />
|
||||||
|
<ClCompile Include="Achievements\AchievementLeaderboardWidget.cpp" />
|
||||||
<ClCompile Include="Achievements\AchievementProgressWidget.cpp" />
|
<ClCompile Include="Achievements\AchievementProgressWidget.cpp" />
|
||||||
<ClCompile Include="Achievements\AchievementSettingsWidget.cpp" />
|
<ClCompile Include="Achievements\AchievementSettingsWidget.cpp" />
|
||||||
<ClCompile Include="Achievements\AchievementsWindow.cpp" />
|
<ClCompile Include="Achievements\AchievementsWindow.cpp" />
|
||||||
|
@ -261,6 +262,7 @@
|
||||||
<QtMoc Include="CheatSearchWidget.h" />
|
<QtMoc Include="CheatSearchWidget.h" />
|
||||||
<QtMoc Include="CheatsManager.h" />
|
<QtMoc Include="CheatsManager.h" />
|
||||||
<QtMoc Include="Achievements\AchievementHeaderWidget.h" />
|
<QtMoc Include="Achievements\AchievementHeaderWidget.h" />
|
||||||
|
<QtMoc Include="Achievements\AchievementLeaderboardWidget.h" />
|
||||||
<QtMoc Include="Achievements\AchievementProgressWidget.h" />
|
<QtMoc Include="Achievements\AchievementProgressWidget.h" />
|
||||||
<QtMoc Include="Achievements\AchievementSettingsWidget.h" />
|
<QtMoc Include="Achievements\AchievementSettingsWidget.h" />
|
||||||
<QtMoc Include="Achievements\AchievementsWindow.h" />
|
<QtMoc Include="Achievements\AchievementsWindow.h" />
|
||||||
|
|
Loading…
Reference in New Issue