mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-08 18:45:48 +00:00
meh
This commit is contained in:
parent
2c393d35f0
commit
98c174edc4
520 changed files with 74815 additions and 58942 deletions
|
@ -17,6 +17,16 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
|
|||
setWindowTitle(tr("About Dolphin"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
QString branch_str = QString::fromStdString(Common::GetScmBranchStr());
|
||||
const int commits_ahead = Common::GetScmCommitsAheadMaster();
|
||||
if (commits_ahead > 0)
|
||||
{
|
||||
branch_str = tr("%1 (%2)").arg(
|
||||
branch_str,
|
||||
// i18n: A positive number of version control commits made compared to some named branch
|
||||
tr("%1 commit(s) ahead of %2").arg(commits_ahead).arg(QStringLiteral("master")));
|
||||
}
|
||||
|
||||
const QString text =
|
||||
QStringLiteral(R"(
|
||||
<p style='font-size:38pt; font-weight:400;'>Dolphin MPN</p>
|
||||
|
@ -50,7 +60,7 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
|
|||
QString::fromUtf8(Common::GetScmDescStr().c_str()))
|
||||
.replace(QStringLiteral("%BRANCH%"),
|
||||
// i18n: "Branch" means the version control term, not a literal tree branch.
|
||||
tr("Branch: %1").arg(QString::fromUtf8(Common::GetScmBranchStr().c_str())))
|
||||
tr("Branch: %1").arg(branch_str))
|
||||
.replace(QStringLiteral("%REVISION%"),
|
||||
tr("Revision: %1").arg(QString::fromUtf8(Common::GetScmRevGitStr().c_str())))
|
||||
.replace(QStringLiteral("%QT_VERSION%"),
|
||||
|
|
104
Source/Core/DolphinQt/Achievements/AchievementBox.cpp
Normal file
104
Source/Core/DolphinQt/Achievements/AchievementBox.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2024 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include "DolphinQt/Achievements/AchievementBox.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include <rcheevos/include/rc_api_runtime.h>
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
|
||||
#include "DolphinQt/QtUtils/FromStdString.h"
|
||||
|
||||
AchievementBox::AchievementBox(QWidget* parent, rc_client_achievement_t* achievement)
|
||||
: QGroupBox(parent), m_achievement(achievement)
|
||||
{
|
||||
const auto& instance = AchievementManager::GetInstance();
|
||||
if (!instance.IsGameLoaded())
|
||||
return;
|
||||
|
||||
m_badge = new QLabel();
|
||||
QLabel* title = new QLabel(QString::fromUtf8(achievement->title, strlen(achievement->title)));
|
||||
QLabel* description =
|
||||
new QLabel(QString::fromUtf8(achievement->description, strlen(achievement->description)));
|
||||
QLabel* points = new QLabel(tr("%1 points").arg(achievement->points));
|
||||
m_status = new QLabel();
|
||||
m_progress_bar = new QProgressBar();
|
||||
QSizePolicy sp_retain = m_progress_bar->sizePolicy();
|
||||
sp_retain.setRetainSizeWhenHidden(true);
|
||||
m_progress_bar->setSizePolicy(sp_retain);
|
||||
|
||||
QVBoxLayout* a_col_right = new QVBoxLayout();
|
||||
a_col_right->addWidget(title);
|
||||
a_col_right->addWidget(description);
|
||||
a_col_right->addWidget(points);
|
||||
a_col_right->addWidget(m_status);
|
||||
a_col_right->addWidget(m_progress_bar);
|
||||
QHBoxLayout* a_total = new QHBoxLayout();
|
||||
a_total->addWidget(m_badge);
|
||||
a_total->addLayout(a_col_right);
|
||||
setLayout(a_total);
|
||||
|
||||
UpdateData();
|
||||
}
|
||||
|
||||
void AchievementBox::UpdateData()
|
||||
{
|
||||
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
|
||||
|
||||
const auto& badge = AchievementManager::GetInstance().GetAchievementBadge(
|
||||
m_achievement->id, m_achievement->state != RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED);
|
||||
std::string_view color = AchievementManager::GRAY;
|
||||
if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE)
|
||||
color = AchievementManager::GOLD;
|
||||
else if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE)
|
||||
color = AchievementManager::BLUE;
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED) && badge.name != "")
|
||||
{
|
||||
QImage i_badge{};
|
||||
if (i_badge.loadFromData(&badge.badge.front(), static_cast<int>(badge.badge.size())))
|
||||
{
|
||||
m_badge->setPixmap(QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
m_badge->adjustSize();
|
||||
m_badge->setStyleSheet(
|
||||
QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_badge->setText({});
|
||||
}
|
||||
|
||||
if (m_achievement->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED)
|
||||
{
|
||||
m_status->setText(
|
||||
tr("Unlocked at %1")
|
||||
.arg(QDateTime::fromSecsSinceEpoch(m_achievement->unlock_time).toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_status->setText(tr("Locked"));
|
||||
}
|
||||
|
||||
if (m_achievement->measured_percent > 0.000)
|
||||
{
|
||||
m_progress_bar->setRange(0, 100);
|
||||
m_progress_bar->setValue(m_achievement->measured_percent);
|
||||
m_progress_bar->setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_progress_bar->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
32
Source/Core/DolphinQt/Achievements/AchievementBox.h
Normal file
32
Source/Core/DolphinQt/Achievements/AchievementBox.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2024 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include <QGroupBox>
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
|
||||
class QLabel;
|
||||
class QProgressBar;
|
||||
class QWidget;
|
||||
|
||||
struct rc_api_achievement_definition_t;
|
||||
|
||||
class AchievementBox final : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AchievementBox(QWidget* parent, rc_client_achievement_t* achievement);
|
||||
void UpdateData();
|
||||
|
||||
private:
|
||||
QLabel* m_badge;
|
||||
QLabel* m_status;
|
||||
QProgressBar* m_progress_bar;
|
||||
|
||||
rc_client_achievement_t* m_achievement;
|
||||
};
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
|
@ -11,10 +11,13 @@
|
|||
#include <QString>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <rcheevos/include/rc_client.h>
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/Core.h"
|
||||
|
||||
#include "DolphinQt/QtUtils/FromStdString.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
AchievementHeaderWidget::AchievementHeaderWidget(QWidget* parent) : QWidget(parent)
|
||||
|
@ -23,21 +26,12 @@ AchievementHeaderWidget::AchievementHeaderWidget(QWidget* parent) : QWidget(pare
|
|||
m_game_icon = new QLabel();
|
||||
m_name = new QLabel();
|
||||
m_points = new QLabel();
|
||||
m_game_progress_hard = new QProgressBar();
|
||||
m_game_progress_soft = new QProgressBar();
|
||||
m_game_progress = new QProgressBar();
|
||||
m_rich_presence = new QLabel();
|
||||
m_locked_warning = new QLabel();
|
||||
|
||||
m_locked_warning->setText(tr("Achievements have been disabled.<br>Please close all running "
|
||||
"games to re-enable achievements."));
|
||||
m_locked_warning->setStyleSheet(QStringLiteral("QLabel { color : red; }"));
|
||||
|
||||
QSizePolicy sp_retain = m_game_progress_hard->sizePolicy();
|
||||
QSizePolicy sp_retain = m_game_progress->sizePolicy();
|
||||
sp_retain.setRetainSizeWhenHidden(true);
|
||||
m_game_progress_hard->setSizePolicy(sp_retain);
|
||||
sp_retain = m_game_progress_soft->sizePolicy();
|
||||
sp_retain.setRetainSizeWhenHidden(true);
|
||||
m_game_progress_soft->setSizePolicy(sp_retain);
|
||||
m_game_progress->setSizePolicy(sp_retain);
|
||||
|
||||
QVBoxLayout* icon_col = new QVBoxLayout();
|
||||
icon_col->addWidget(m_user_icon);
|
||||
|
@ -45,10 +39,8 @@ AchievementHeaderWidget::AchievementHeaderWidget(QWidget* parent) : QWidget(pare
|
|||
QVBoxLayout* text_col = new QVBoxLayout();
|
||||
text_col->addWidget(m_name);
|
||||
text_col->addWidget(m_points);
|
||||
text_col->addWidget(m_game_progress_hard);
|
||||
text_col->addWidget(m_game_progress_soft);
|
||||
text_col->addWidget(m_game_progress);
|
||||
text_col->addWidget(m_rich_presence);
|
||||
text_col->addWidget(m_locked_warning);
|
||||
QHBoxLayout* header_layout = new QHBoxLayout();
|
||||
header_layout->addLayout(icon_col);
|
||||
header_layout->addLayout(text_col);
|
||||
|
@ -61,50 +53,49 @@ AchievementHeaderWidget::AchievementHeaderWidget(QWidget* parent) : QWidget(pare
|
|||
m_total->setContentsMargins(0, 0, 0, 0);
|
||||
m_total->setAlignment(Qt::AlignTop);
|
||||
setLayout(m_total);
|
||||
|
||||
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
|
||||
UpdateData();
|
||||
}
|
||||
|
||||
void AchievementHeaderWidget::UpdateData()
|
||||
{
|
||||
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
if (!instance.IsLoggedIn())
|
||||
if (!Config::Get(Config::RA_ENABLED) || !instance.HasAPIToken())
|
||||
{
|
||||
m_header_box->setVisible(false);
|
||||
return;
|
||||
}
|
||||
m_header_box->setVisible(true);
|
||||
|
||||
AchievementManager::PointSpread point_spread = instance.TallyScore();
|
||||
QString user_name = QString::fromStdString(instance.GetPlayerDisplayName());
|
||||
QString game_name = QString::fromStdString(instance.GetGameDisplayName());
|
||||
QString user_name = QtUtils::FromStdString(instance.GetPlayerDisplayName());
|
||||
QString game_name = QtUtils::FromStdString(instance.GetGameDisplayName());
|
||||
AchievementManager::BadgeStatus player_badge = instance.GetPlayerBadge();
|
||||
AchievementManager::BadgeStatus game_badge = instance.GetGameBadge();
|
||||
|
||||
m_user_icon->setVisible(false);
|
||||
m_user_icon->clear();
|
||||
m_user_icon->setText({});
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED))
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED) && !player_badge.name.empty())
|
||||
{
|
||||
if (!player_badge.name.empty())
|
||||
QImage i_user_icon{};
|
||||
if (i_user_icon.loadFromData(&player_badge.badge.front(), (int)player_badge.badge.size()))
|
||||
{
|
||||
QImage i_user_icon{};
|
||||
if (i_user_icon.loadFromData(&player_badge.badge.front(), (int)player_badge.badge.size()))
|
||||
{
|
||||
m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon)
|
||||
.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
m_user_icon->adjustSize();
|
||||
m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent"));
|
||||
m_user_icon->setVisible(true);
|
||||
}
|
||||
m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon)
|
||||
.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
m_user_icon->adjustSize();
|
||||
m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent"));
|
||||
m_user_icon->setVisible(true);
|
||||
}
|
||||
}
|
||||
m_game_icon->setVisible(false);
|
||||
m_game_icon->clear();
|
||||
m_game_icon->setText({});
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED))
|
||||
|
||||
if (instance.IsGameLoaded())
|
||||
{
|
||||
if (!game_badge.name.empty())
|
||||
rc_client_user_game_summary_t game_summary;
|
||||
rc_client_get_user_game_summary(instance.GetClient(), &game_summary);
|
||||
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED) && !game_badge.name.empty())
|
||||
{
|
||||
QImage i_game_icon{};
|
||||
if (i_game_icon.loadFromData(&game_badge.badge.front(), (int)game_badge.badge.size()))
|
||||
|
@ -113,70 +104,39 @@ void AchievementHeaderWidget::UpdateData()
|
|||
.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
m_game_icon->adjustSize();
|
||||
std::string_view color = AchievementManager::GRAY;
|
||||
if (point_spread.hard_unlocks == point_spread.total_count)
|
||||
color = AchievementManager::GOLD;
|
||||
else if (point_spread.hard_unlocks + point_spread.soft_unlocks == point_spread.total_count)
|
||||
color = AchievementManager::BLUE;
|
||||
if (game_summary.num_core_achievements == game_summary.num_unlocked_achievements)
|
||||
{
|
||||
color =
|
||||
instance.IsHardcoreModeActive() ? AchievementManager::GOLD : AchievementManager::BLUE;
|
||||
}
|
||||
m_game_icon->setStyleSheet(
|
||||
QStringLiteral("border: 4px solid %1").arg(QString::fromStdString(std::string(color))));
|
||||
QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color)));
|
||||
m_game_icon->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!game_name.isEmpty())
|
||||
{
|
||||
m_name->setText(tr("%1 is playing %2").arg(user_name).arg(game_name));
|
||||
m_points->setText(GetPointsString(user_name, point_spread));
|
||||
m_points->setText(tr("%1 has unlocked %2/%3 achievements worth %4/%5 points")
|
||||
.arg(user_name)
|
||||
.arg(game_summary.num_unlocked_achievements)
|
||||
.arg(game_summary.num_core_achievements)
|
||||
.arg(game_summary.points_unlocked)
|
||||
.arg(game_summary.points_core));
|
||||
|
||||
m_game_progress_hard->setRange(0, point_spread.total_count);
|
||||
if (!m_game_progress_hard->isVisible())
|
||||
m_game_progress_hard->setVisible(true);
|
||||
m_game_progress_hard->setValue(point_spread.hard_unlocks);
|
||||
m_game_progress_soft->setRange(0, point_spread.total_count);
|
||||
m_game_progress_soft->setValue(point_spread.hard_unlocks + point_spread.soft_unlocks);
|
||||
if (!m_game_progress_soft->isVisible())
|
||||
m_game_progress_soft->setVisible(true);
|
||||
m_game_progress->setRange(0, game_summary.num_core_achievements);
|
||||
if (!m_game_progress->isVisible())
|
||||
m_game_progress->setVisible(true);
|
||||
m_game_progress->setValue(game_summary.num_unlocked_achievements);
|
||||
m_rich_presence->setText(QString::fromUtf8(instance.GetRichPresence().data()));
|
||||
if (!m_rich_presence->isVisible())
|
||||
m_rich_presence->setVisible(Config::Get(Config::RA_RICH_PRESENCE_ENABLED));
|
||||
m_locked_warning->setVisible(false);
|
||||
m_rich_presence->setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_name->setText(user_name);
|
||||
m_points->setText(tr("%1 points").arg(instance.GetPlayerScore()));
|
||||
|
||||
m_game_progress_hard->setVisible(false);
|
||||
m_game_progress_soft->setVisible(false);
|
||||
m_game_progress->setVisible(false);
|
||||
m_rich_presence->setVisible(false);
|
||||
m_locked_warning->setVisible(instance.IsDisabled());
|
||||
}
|
||||
}
|
||||
|
||||
QString
|
||||
AchievementHeaderWidget::GetPointsString(const QString& user_name,
|
||||
const AchievementManager::PointSpread& point_spread) const
|
||||
{
|
||||
if (point_spread.soft_points > 0)
|
||||
{
|
||||
return tr("%1 has unlocked %2/%3 achievements (%4 hardcore) worth %5/%6 points (%7 hardcore)")
|
||||
.arg(user_name)
|
||||
.arg(point_spread.hard_unlocks + point_spread.soft_unlocks)
|
||||
.arg(point_spread.total_count)
|
||||
.arg(point_spread.hard_unlocks)
|
||||
.arg(point_spread.hard_points + point_spread.soft_points)
|
||||
.arg(point_spread.total_points)
|
||||
.arg(point_spread.hard_points);
|
||||
}
|
||||
else
|
||||
{
|
||||
return tr("%1 has unlocked %2/%3 achievements worth %4/%5 points")
|
||||
.arg(user_name)
|
||||
.arg(point_spread.hard_unlocks)
|
||||
.arg(point_spread.total_count)
|
||||
.arg(point_spread.hard_points)
|
||||
.arg(point_spread.total_points);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,17 +20,12 @@ public:
|
|||
void UpdateData();
|
||||
|
||||
private:
|
||||
QString GetPointsString(const QString& user_name,
|
||||
const AchievementManager::PointSpread& point_spread) const;
|
||||
|
||||
QLabel* m_user_icon;
|
||||
QLabel* m_game_icon;
|
||||
QLabel* m_name;
|
||||
QLabel* m_points;
|
||||
QProgressBar* m_game_progress_hard;
|
||||
QProgressBar* m_game_progress_soft;
|
||||
QProgressBar* m_game_progress;
|
||||
QLabel* m_rich_presence;
|
||||
QLabel* m_locked_warning;
|
||||
QGroupBox* m_header_box;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,11 +24,6 @@ AchievementLeaderboardWidget::AchievementLeaderboardWidget(QWidget* parent) : QW
|
|||
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;
|
||||
|
@ -38,77 +33,126 @@ AchievementLeaderboardWidget::AchievementLeaderboardWidget(QWidget* parent) : QW
|
|||
setLayout(layout);
|
||||
}
|
||||
|
||||
void AchievementLeaderboardWidget::UpdateData()
|
||||
void AchievementLeaderboardWidget::UpdateData(bool clean_all)
|
||||
{
|
||||
ClearLayoutRecursively(m_common_layout);
|
||||
|
||||
if (!AchievementManager::GetInstance().IsGameLoaded())
|
||||
return;
|
||||
const auto& leaderboards = AchievementManager::GetInstance().GetLeaderboardsInfo();
|
||||
int row = 0;
|
||||
for (const auto& board_row : leaderboards)
|
||||
if (clean_all)
|
||||
{
|
||||
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)
|
||||
ClearLayoutRecursively(m_common_layout);
|
||||
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
if (!instance.IsGameLoaded())
|
||||
return;
|
||||
auto* client = instance.GetClient();
|
||||
auto* leaderboard_list =
|
||||
rc_client_create_leaderboard_list(client, RC_CLIENT_LEADERBOARD_LIST_GROUPING_NONE);
|
||||
|
||||
u32 row = 0;
|
||||
for (u32 bucket = 0; bucket < leaderboard_list->num_buckets; bucket++)
|
||||
{
|
||||
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())
|
||||
const auto& leaderboard_bucket = leaderboard_list->buckets[bucket];
|
||||
for (u32 board = 0; board < leaderboard_bucket.num_leaderboards; board++)
|
||||
{
|
||||
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()));
|
||||
const auto* leaderboard = leaderboard_bucket.leaderboards[board];
|
||||
m_leaderboard_order[leaderboard->id] = row;
|
||||
QLabel* a_title = new QLabel(QString::fromUtf8(leaderboard->title));
|
||||
QLabel* a_description = new QLabel(QString::fromUtf8(leaderboard->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);
|
||||
for (size_t ix = 0; ix < 4; ix++)
|
||||
{
|
||||
QVBoxLayout* a_col = new QVBoxLayout();
|
||||
for (size_t jx = 0; jx < 3; jx++)
|
||||
a_col->addWidget(new QLabel(QStringLiteral("---")));
|
||||
if (row > 0)
|
||||
{
|
||||
QFrame* a_divider = new QFrame();
|
||||
a_divider->setFrameShape(QFrame::HLine);
|
||||
m_common_layout->addWidget(a_divider, row - 1, static_cast<int>(ix) + 1);
|
||||
}
|
||||
m_common_layout->addLayout(a_col, row, static_cast<int>(ix) + 1);
|
||||
}
|
||||
row += 2;
|
||||
}
|
||||
}
|
||||
rc_client_destroy_leaderboard_list(leaderboard_list);
|
||||
}
|
||||
for (auto row : m_leaderboard_order)
|
||||
{
|
||||
UpdateRow(row.second);
|
||||
}
|
||||
}
|
||||
|
||||
void AchievementLeaderboardWidget::UpdateData(
|
||||
const std::set<AchievementManager::AchievementId>& update_ids)
|
||||
{
|
||||
for (auto row : m_leaderboard_order)
|
||||
{
|
||||
if (update_ids.contains(row.first))
|
||||
{
|
||||
UpdateRow(row.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AchievementLeaderboardWidget::UpdateRow(AchievementManager::AchievementId leaderboard_id)
|
||||
{
|
||||
const auto leaderboard_itr = m_leaderboard_order.find(leaderboard_id);
|
||||
if (leaderboard_itr == m_leaderboard_order.end())
|
||||
return;
|
||||
const int row = leaderboard_itr->second;
|
||||
|
||||
const AchievementManager::LeaderboardStatus* board;
|
||||
{
|
||||
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
|
||||
board = AchievementManager::GetInstance().GetLeaderboardInfo(leaderboard_id);
|
||||
}
|
||||
if (!board)
|
||||
return;
|
||||
|
||||
// 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 ix = 1; ix < to_display.size(); ++ix)
|
||||
to_display[ix] = board->player_index - 3 + offset + static_cast<u32>(ix);
|
||||
}
|
||||
for (size_t ix = 0; ix < to_display.size(); ++ix)
|
||||
{
|
||||
const auto it = board->entries.find(to_display[ix]);
|
||||
if (it != board->entries.end())
|
||||
{
|
||||
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);
|
||||
a_col->addWidget(new QLabel(tr("Rank %1").arg(it->second.rank)));
|
||||
a_col->addWidget(new QLabel(QString::fromStdString(it->second.username)));
|
||||
a_col->addWidget(new QLabel(QString::fromUtf8(it->second.score.data())));
|
||||
auto old_item = m_common_layout->itemAtPosition(row, static_cast<int>(ix) + 1);
|
||||
m_common_layout->removeItem(old_item);
|
||||
ClearLayoutRecursively(static_cast<QLayout*>(old_item));
|
||||
m_common_layout->addLayout(a_col, row, static_cast<int>(ix) + 1);
|
||||
}
|
||||
row += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include <QWidget>
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
|
||||
class QGroupBox;
|
||||
class QGridLayout;
|
||||
|
||||
|
@ -14,11 +16,14 @@ class AchievementLeaderboardWidget final : public QWidget
|
|||
Q_OBJECT
|
||||
public:
|
||||
explicit AchievementLeaderboardWidget(QWidget* parent);
|
||||
void UpdateData();
|
||||
void UpdateData(bool clean_all);
|
||||
void UpdateData(const std::set<AchievementManager::AchievementId>& update_ids);
|
||||
void UpdateRow(AchievementManager::AchievementId leaderboard_id);
|
||||
|
||||
private:
|
||||
QGroupBox* m_common_box;
|
||||
QGridLayout* m_common_layout;
|
||||
std::map<AchievementManager::AchievementId, int> m_leaderboard_order;
|
||||
};
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -18,21 +18,15 @@
|
|||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
|
||||
#include "DolphinQt/Achievements/AchievementBox.h"
|
||||
#include "DolphinQt/QtUtils/ClearLayoutRecursively.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
static constexpr bool hardcore_mode_enabled = false;
|
||||
|
||||
AchievementProgressWidget::AchievementProgressWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
m_common_box = new QGroupBox();
|
||||
m_common_layout = new QVBoxLayout();
|
||||
|
||||
{
|
||||
std::lock_guard lg{AchievementManager::GetInstance().GetLock()};
|
||||
UpdateData();
|
||||
}
|
||||
|
||||
m_common_box->setLayout(m_common_layout);
|
||||
|
||||
auto* layout = new QVBoxLayout;
|
||||
|
@ -42,124 +36,50 @@ AchievementProgressWidget::AchievementProgressWidget(QWidget* parent) : QWidget(
|
|||
setLayout(layout);
|
||||
}
|
||||
|
||||
QGroupBox*
|
||||
AchievementProgressWidget::CreateAchievementBox(const rc_api_achievement_definition_t* achievement)
|
||||
void AchievementProgressWidget::UpdateData(bool clean_all)
|
||||
{
|
||||
const auto& instance = AchievementManager::GetInstance();
|
||||
if (!instance.IsGameLoaded())
|
||||
return new QGroupBox();
|
||||
if (clean_all)
|
||||
{
|
||||
m_achievement_boxes.clear();
|
||||
ClearLayoutRecursively(m_common_layout);
|
||||
|
||||
QLabel* a_badge = new QLabel();
|
||||
const auto unlock_status = instance.GetUnlockStatus(achievement->id);
|
||||
const AchievementManager::BadgeStatus* badge = &unlock_status.locked_badge;
|
||||
std::string_view color = AchievementManager::GRAY;
|
||||
if (unlock_status.remote_unlock_status == AchievementManager::UnlockStatus::UnlockType::HARDCORE)
|
||||
{
|
||||
badge = &unlock_status.unlocked_badge;
|
||||
color = AchievementManager::GOLD;
|
||||
}
|
||||
else if (hardcore_mode_enabled && unlock_status.session_unlock_count > 1)
|
||||
{
|
||||
badge = &unlock_status.unlocked_badge;
|
||||
color = AchievementManager::GOLD;
|
||||
}
|
||||
else if (unlock_status.remote_unlock_status ==
|
||||
AchievementManager::UnlockStatus::UnlockType::SOFTCORE)
|
||||
{
|
||||
badge = &unlock_status.unlocked_badge;
|
||||
color = AchievementManager::BLUE;
|
||||
}
|
||||
else if (unlock_status.session_unlock_count > 1)
|
||||
{
|
||||
badge = &unlock_status.unlocked_badge;
|
||||
color = AchievementManager::BLUE;
|
||||
}
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED) && badge->name != "")
|
||||
{
|
||||
QImage i_badge{};
|
||||
if (i_badge.loadFromData(&badge->badge.front(), (int)badge->badge.size()))
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
if (!instance.IsGameLoaded())
|
||||
return;
|
||||
auto* client = instance.GetClient();
|
||||
auto* achievement_list = rc_client_create_achievement_list(
|
||||
client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL,
|
||||
RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_LOCK_STATE);
|
||||
for (u32 ix = 0; ix < achievement_list->num_buckets; ix++)
|
||||
{
|
||||
a_badge->setPixmap(QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation));
|
||||
a_badge->adjustSize();
|
||||
a_badge->setStyleSheet(
|
||||
QStringLiteral("border: 4px solid %1").arg(QString::fromStdString(std::string(color))));
|
||||
for (u32 jx = 0; jx < achievement_list->buckets[ix].num_achievements; jx++)
|
||||
{
|
||||
auto* achievement = achievement_list->buckets[ix].achievements[jx];
|
||||
m_achievement_boxes[achievement->id] = std::make_shared<AchievementBox>(this, achievement);
|
||||
m_common_layout->addWidget(m_achievement_boxes[achievement->id].get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QLabel* a_title = new QLabel(QString::fromUtf8(achievement->title, strlen(achievement->title)));
|
||||
QLabel* a_description =
|
||||
new QLabel(QString::fromUtf8(achievement->description, strlen(achievement->description)));
|
||||
QLabel* a_points = new QLabel(tr("%1 points").arg(achievement->points));
|
||||
QLabel* a_status = new QLabel(GetStatusString(achievement->id));
|
||||
QProgressBar* a_progress_bar = new QProgressBar();
|
||||
QSizePolicy sp_retain = a_progress_bar->sizePolicy();
|
||||
sp_retain.setRetainSizeWhenHidden(true);
|
||||
a_progress_bar->setSizePolicy(sp_retain);
|
||||
unsigned int value = 0;
|
||||
unsigned int target = 0;
|
||||
if (AchievementManager::GetInstance().GetAchievementProgress(achievement->id, &value, &target) ==
|
||||
AchievementManager::ResponseType::SUCCESS &&
|
||||
target > 0)
|
||||
{
|
||||
a_progress_bar->setRange(0, target);
|
||||
a_progress_bar->setValue(value);
|
||||
rc_client_destroy_achievement_list(achievement_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_progress_bar->setVisible(false);
|
||||
}
|
||||
|
||||
QVBoxLayout* a_col_right = new QVBoxLayout();
|
||||
a_col_right->addWidget(a_title);
|
||||
a_col_right->addWidget(a_description);
|
||||
a_col_right->addWidget(a_points);
|
||||
a_col_right->addWidget(a_status);
|
||||
a_col_right->addWidget(a_progress_bar);
|
||||
QHBoxLayout* a_total = new QHBoxLayout();
|
||||
a_total->addWidget(a_badge);
|
||||
a_total->addLayout(a_col_right);
|
||||
QGroupBox* a_group_box = new QGroupBox();
|
||||
a_group_box->setLayout(a_total);
|
||||
return a_group_box;
|
||||
}
|
||||
|
||||
void AchievementProgressWidget::UpdateData()
|
||||
{
|
||||
ClearLayoutRecursively(m_common_layout);
|
||||
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
if (!instance.IsGameLoaded())
|
||||
return;
|
||||
|
||||
const auto* game_data = instance.GetGameData();
|
||||
for (u32 ix = 0; ix < game_data->num_achievements; ix++)
|
||||
{
|
||||
m_common_layout->addWidget(CreateAchievementBox(game_data->achievements + ix));
|
||||
}
|
||||
}
|
||||
|
||||
QString AchievementProgressWidget::GetStatusString(u32 achievement_id) const
|
||||
{
|
||||
const auto unlock_status = AchievementManager::GetInstance().GetUnlockStatus(achievement_id);
|
||||
if (unlock_status.session_unlock_count > 0)
|
||||
{
|
||||
if (Config::Get(Config::RA_ENCORE_ENABLED))
|
||||
for (auto box : m_achievement_boxes)
|
||||
{
|
||||
return tr("Unlocked %1 times this session").arg(unlock_status.session_unlock_count);
|
||||
box.second->UpdateData();
|
||||
}
|
||||
return tr("Unlocked this session");
|
||||
}
|
||||
switch (unlock_status.remote_unlock_status)
|
||||
}
|
||||
|
||||
void AchievementProgressWidget::UpdateData(
|
||||
const std::set<AchievementManager::AchievementId>& update_ids)
|
||||
{
|
||||
for (auto& [id, box] : m_achievement_boxes)
|
||||
{
|
||||
case AchievementManager::UnlockStatus::UnlockType::LOCKED:
|
||||
return tr("Locked");
|
||||
case AchievementManager::UnlockStatus::UnlockType::SOFTCORE:
|
||||
return tr("Unlocked (Casual)");
|
||||
case AchievementManager::UnlockStatus::UnlockType::HARDCORE:
|
||||
return tr("Unlocked");
|
||||
if (update_ids.contains(id))
|
||||
{
|
||||
box->UpdateData();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#include <QWidget>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/AchievementManager.h"
|
||||
|
||||
class AchievementBox;
|
||||
class QCheckBox;
|
||||
class QGroupBox;
|
||||
class QLineEdit;
|
||||
|
@ -21,14 +23,13 @@ class AchievementProgressWidget final : public QWidget
|
|||
Q_OBJECT
|
||||
public:
|
||||
explicit AchievementProgressWidget(QWidget* parent);
|
||||
void UpdateData();
|
||||
void UpdateData(bool clean_all);
|
||||
void UpdateData(const std::set<AchievementManager::AchievementId>& update_ids);
|
||||
|
||||
private:
|
||||
QGroupBox* CreateAchievementBox(const rc_api_achievement_definition_t* achievement);
|
||||
QString GetStatusString(u32 achievement_id) const;
|
||||
|
||||
QGroupBox* m_common_box;
|
||||
QVBoxLayout* m_common_layout;
|
||||
std::map<AchievementManager::AchievementId, std::shared_ptr<AchievementBox>> m_achievement_boxes;
|
||||
};
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -61,24 +61,6 @@ void AchievementSettingsWidget::CreateLayout()
|
|||
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.<br>"));
|
||||
m_common_leaderboards_enabled_input = new ToolTipCheckBox(tr("Enable Leaderboards"));
|
||||
m_common_leaderboards_enabled_input->SetDescription(
|
||||
tr("Enable competing in RetroAchievements leaderboards.<br><br>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.<br><br>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.<br><br>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.<br><br>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_hardcore_enabled_input = new ToolTipCheckBox(tr("Enable Hardcore Mode"));
|
||||
m_common_hardcore_enabled_input->SetDescription(
|
||||
tr("Enable Hardcore Mode on RetroAchievements.<br><br>Hardcore Mode is intended to provide "
|
||||
|
@ -93,6 +75,25 @@ void AchievementSettingsWidget::CreateLayout()
|
|||
"playing.</dolphin_emphasis><br>Close your current game before enabling.<br>Be aware that "
|
||||
"turning Hardcore Mode off while a game is running requires the game to be closed before "
|
||||
"re-enabling."));
|
||||
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.<br><br>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.<br><br>Setting takes effect on next game load."));
|
||||
m_common_encore_enabled_input = new ToolTipCheckBox(tr("Enable Encore Achievements"));
|
||||
m_common_encore_enabled_input->SetDescription(
|
||||
tr("Enable unlocking achievements in Encore Mode.<br><br>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."
|
||||
"<br><br>Setting takes effect on next game load."));
|
||||
m_common_spectator_enabled_input = new ToolTipCheckBox(tr("Enable Spectator Mode"));
|
||||
m_common_spectator_enabled_input->SetDescription(
|
||||
tr("Enable unlocking achievements in Spectator Mode.<br><br>While in Spectator Mode, "
|
||||
"achievements and leaderboards will be processed and displayed on screen, but will not be "
|
||||
"submitted to the server.<br><br>If this is on at game launch, it will not be turned off "
|
||||
"until game close, because a RetroAchievements session will not be created.<br><br>If "
|
||||
"this is off at game launch, it can be toggled freely while the game is running."));
|
||||
m_common_progress_enabled_input = new ToolTipCheckBox(tr("Enable Progress Notifications"));
|
||||
m_common_progress_enabled_input->SetDescription(
|
||||
tr("Enable progress notifications on achievements.<br><br>Displays a brief popup message "
|
||||
|
@ -103,11 +104,6 @@ void AchievementSettingsWidget::CreateLayout()
|
|||
tr("Enable achievement badges.<br><br>Displays icons for the player, game, and achievements. "
|
||||
"Simple visual option, but will require a small amount of extra memory and time to "
|
||||
"download the images."));
|
||||
m_common_encore_enabled_input = new ToolTipCheckBox(tr("Enable Encore Achievements"));
|
||||
m_common_encore_enabled_input->SetDescription(tr(
|
||||
"Enable unlocking achievements in Encore Mode.<br><br>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);
|
||||
|
@ -117,14 +113,14 @@ void AchievementSettingsWidget::CreateLayout()
|
|||
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(new QLabel(tr("Function Settings")));
|
||||
m_common_layout->addWidget(m_common_hardcore_enabled_input);
|
||||
m_common_layout->addWidget(m_common_progress_enabled_input);
|
||||
m_common_layout->addWidget(m_common_badges_enabled_input);
|
||||
m_common_layout->addWidget(m_common_unofficial_enabled_input);
|
||||
m_common_layout->addWidget(m_common_encore_enabled_input);
|
||||
m_common_layout->addWidget(m_common_spectator_enabled_input);
|
||||
m_common_layout->addWidget(new QLabel(tr("Display Settings")));
|
||||
m_common_layout->addWidget(m_common_progress_enabled_input);
|
||||
m_common_layout->addWidget(m_common_badges_enabled_input);
|
||||
|
||||
m_common_layout->setAlignment(Qt::AlignTop);
|
||||
setLayout(m_common_layout);
|
||||
|
@ -136,22 +132,18 @@ void AchievementSettingsWidget::ConnectWidgets()
|
|||
&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_hardcore_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleHardcore);
|
||||
connect(m_common_progress_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleProgress);
|
||||
connect(m_common_badges_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleBadges);
|
||||
connect(m_common_unofficial_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleUnofficial);
|
||||
connect(m_common_encore_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleEncore);
|
||||
connect(m_common_spectator_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleSpectator);
|
||||
connect(m_common_progress_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleProgress);
|
||||
connect(m_common_badges_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleBadges);
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::OnControllerInterfaceConfigure()
|
||||
|
@ -165,7 +157,6 @@ void AchievementSettingsWidget::OnControllerInterfaceConfigure()
|
|||
void AchievementSettingsWidget::LoadSettings()
|
||||
{
|
||||
bool enabled = Config::Get(Config::RA_ENABLED);
|
||||
bool achievements_enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED);
|
||||
bool hardcore_enabled = Config::Get(Config::RA_HARDCORE_ENABLED);
|
||||
bool logged_out = Config::Get(Config::RA_API_TOKEN).empty();
|
||||
std::string username = Config::Get(Config::RA_USERNAME);
|
||||
|
@ -180,41 +171,36 @@ void AchievementSettingsWidget::LoadSettings()
|
|||
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_login_button)
|
||||
->setEnabled(enabled && !Core::IsRunning(Core::System::GetInstance()));
|
||||
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_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_hardcore_enabled_input)
|
||||
->setChecked(Config::Get(Config::RA_HARDCORE_ENABLED));
|
||||
auto& system = Core::System::GetInstance();
|
||||
SignalBlocking(m_common_hardcore_enabled_input)
|
||||
->setEnabled(enabled && (hardcore_enabled ||
|
||||
(Core::GetState() == Core::State::Uninitialized &&
|
||||
!Core::System::GetInstance().GetMovie().IsPlayingInput())));
|
||||
|
||||
SignalBlocking(m_common_progress_enabled_input)
|
||||
->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED));
|
||||
SignalBlocking(m_common_progress_enabled_input)->setEnabled(enabled && achievements_enabled);
|
||||
|
||||
SignalBlocking(m_common_badges_enabled_input)->setChecked(Config::Get(Config::RA_BADGES_ENABLED));
|
||||
SignalBlocking(m_common_badges_enabled_input)->setEnabled(enabled);
|
||||
->setEnabled(enabled &&
|
||||
(hardcore_enabled || (Core::GetState(system) == Core::State::Uninitialized &&
|
||||
!system.GetMovie().IsPlayingInput())));
|
||||
|
||||
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_unofficial_enabled_input)->setEnabled(enabled);
|
||||
|
||||
SignalBlocking(m_common_encore_enabled_input)->setChecked(Config::Get(Config::RA_ENCORE_ENABLED));
|
||||
SignalBlocking(m_common_encore_enabled_input)->setEnabled(enabled && achievements_enabled);
|
||||
SignalBlocking(m_common_encore_enabled_input)->setEnabled(enabled);
|
||||
|
||||
SignalBlocking(m_common_spectator_enabled_input)
|
||||
->setChecked(Config::Get(Config::RA_SPECTATOR_ENABLED));
|
||||
SignalBlocking(m_common_spectator_enabled_input)->setEnabled(enabled);
|
||||
|
||||
SignalBlocking(m_common_progress_enabled_input)
|
||||
->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED));
|
||||
SignalBlocking(m_common_progress_enabled_input)->setEnabled(enabled);
|
||||
|
||||
SignalBlocking(m_common_badges_enabled_input)->setChecked(Config::Get(Config::RA_BADGES_ENABLED));
|
||||
SignalBlocking(m_common_badges_enabled_input)->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::SaveSettings()
|
||||
|
@ -222,20 +208,16 @@ 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_HARDCORE_ENABLED,
|
||||
m_common_hardcore_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_PROGRESS_ENABLED,
|
||||
m_common_unofficial_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_BADGES_ENABLED, m_common_badges_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::SetBaseOrCurrent(Config::RA_SPECTATOR_ENABLED,
|
||||
m_common_spectator_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_PROGRESS_ENABLED,
|
||||
m_common_progress_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_BADGES_ENABLED, m_common_badges_enabled_input->isChecked());
|
||||
Config::Save();
|
||||
}
|
||||
|
||||
|
@ -248,6 +230,8 @@ void AchievementSettingsWidget::ToggleRAIntegration()
|
|||
instance.Init();
|
||||
else
|
||||
instance.Shutdown();
|
||||
if (Config::Get(Config::RA_HARDCORE_ENABLED))
|
||||
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::Login()
|
||||
|
@ -255,7 +239,6 @@ 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();
|
||||
}
|
||||
|
||||
|
@ -265,27 +248,10 @@ void AchievementSettingsWidget::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::ToggleHardcore()
|
||||
{
|
||||
SaveSettings();
|
||||
AchievementManager::GetInstance().SetHardcoreMode();
|
||||
if (Config::Get(Config::RA_HARDCORE_ENABLED))
|
||||
{
|
||||
if (Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f)
|
||||
|
@ -294,7 +260,23 @@ void AchievementSettingsWidget::ToggleHardcore()
|
|||
Settings::Instance().SetCheatsEnabled(false);
|
||||
Settings::Instance().SetDebugModeEnabled(false);
|
||||
}
|
||||
emit Settings::Instance().EmulationStateChanged(Core::GetState());
|
||||
emit Settings::Instance().EmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleUnofficial()
|
||||
{
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleEncore()
|
||||
{
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleSpectator()
|
||||
{
|
||||
SaveSettings();
|
||||
AchievementManager::GetInstance().SetSpectatorMode();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleProgress()
|
||||
|
@ -305,19 +287,8 @@ void AchievementSettingsWidget::ToggleProgress()
|
|||
void AchievementSettingsWidget::ToggleBadges()
|
||||
{
|
||||
SaveSettings();
|
||||
AchievementManager::GetInstance().FetchBadges();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleUnofficial()
|
||||
{
|
||||
SaveSettings();
|
||||
AchievementManager::GetInstance().ActivateDeactivateAchievements();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleEncore()
|
||||
{
|
||||
SaveSettings();
|
||||
AchievementManager::GetInstance().ActivateDeactivateAchievements();
|
||||
AchievementManager::GetInstance().FetchPlayerBadge();
|
||||
AchievementManager::GetInstance().FetchGameBadges();
|
||||
}
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -32,14 +32,12 @@ private:
|
|||
void ToggleRAIntegration();
|
||||
void Login();
|
||||
void Logout();
|
||||
void ToggleAchievements();
|
||||
void ToggleLeaderboards();
|
||||
void ToggleRichPresence();
|
||||
void ToggleHardcore();
|
||||
void ToggleProgress();
|
||||
void ToggleBadges();
|
||||
void ToggleUnofficial();
|
||||
void ToggleEncore();
|
||||
void ToggleSpectator();
|
||||
void ToggleProgress();
|
||||
void ToggleBadges();
|
||||
|
||||
QGroupBox* m_common_box;
|
||||
QVBoxLayout* m_common_layout;
|
||||
|
@ -51,14 +49,12 @@ private:
|
|||
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_hardcore_enabled_input;
|
||||
ToolTipCheckBox* m_common_progress_enabled_input;
|
||||
ToolTipCheckBox* m_common_badges_enabled_input;
|
||||
ToolTipCheckBox* m_common_unofficial_enabled_input;
|
||||
ToolTipCheckBox* m_common_encore_enabled_input;
|
||||
ToolTipCheckBox* m_common_spectator_enabled_input;
|
||||
ToolTipCheckBox* m_common_progress_enabled_input;
|
||||
ToolTipCheckBox* m_common_badges_enabled_input;
|
||||
};
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -28,11 +28,13 @@ AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent)
|
|||
CreateMainLayout();
|
||||
ConnectWidgets();
|
||||
AchievementManager::GetInstance().SetUpdateCallback(
|
||||
[this] { QueueOnObject(this, &AchievementsWindow::UpdateData); });
|
||||
[this](AchievementManager::UpdatedItems updated_items) {
|
||||
QueueOnObject(this, [this, updated_items = std::move(updated_items)] {
|
||||
AchievementsWindow::UpdateData(std::move(updated_items));
|
||||
});
|
||||
});
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
&AchievementsWindow::UpdateData);
|
||||
|
||||
UpdateData();
|
||||
[this] { AchievementsWindow::UpdateData({.all = true}); });
|
||||
}
|
||||
|
||||
void AchievementsWindow::showEvent(QShowEvent* event)
|
||||
|
@ -71,19 +73,38 @@ void AchievementsWindow::ConnectWidgets()
|
|||
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
}
|
||||
|
||||
void AchievementsWindow::UpdateData()
|
||||
void AchievementsWindow::UpdateData(AchievementManager::UpdatedItems updated_items)
|
||||
{
|
||||
m_settings_widget->UpdateData();
|
||||
if (updated_items.all)
|
||||
{
|
||||
m_header_widget->UpdateData();
|
||||
m_progress_widget->UpdateData(true);
|
||||
m_leaderboard_widget->UpdateData(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (updated_items.player_icon || updated_items.game_icon || updated_items.rich_presence ||
|
||||
updated_items.all_achievements || updated_items.achievements.size() > 0)
|
||||
{
|
||||
m_header_widget->UpdateData();
|
||||
}
|
||||
if (updated_items.all_achievements)
|
||||
m_progress_widget->UpdateData(false);
|
||||
else if (updated_items.achievements.size() > 0)
|
||||
m_progress_widget->UpdateData(updated_items.achievements);
|
||||
if (updated_items.all_leaderboards)
|
||||
m_leaderboard_widget->UpdateData(false);
|
||||
else if (updated_items.leaderboards.size() > 0)
|
||||
m_leaderboard_widget->UpdateData(updated_items.leaderboards);
|
||||
}
|
||||
|
||||
{
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
std::lock_guard lg{instance.GetLock()};
|
||||
const bool is_game_loaded = instance.IsGameLoaded();
|
||||
|
||||
m_header_widget->UpdateData();
|
||||
m_header_widget->setVisible(instance.IsLoggedIn());
|
||||
m_settings_widget->UpdateData();
|
||||
m_progress_widget->UpdateData();
|
||||
m_header_widget->setVisible(instance.HasAPIToken());
|
||||
m_tab_widget->setTabVisible(1, is_game_loaded);
|
||||
m_leaderboard_widget->UpdateData();
|
||||
m_tab_widget->setTabVisible(2, is_game_loaded);
|
||||
}
|
||||
update();
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include <QDialog>
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
|
||||
class AchievementHeaderWidget;
|
||||
class AchievementLeaderboardWidget;
|
||||
class AchievementSettingsWidget;
|
||||
|
@ -19,7 +21,7 @@ class AchievementsWindow : public QDialog
|
|||
Q_OBJECT
|
||||
public:
|
||||
explicit AchievementsWindow(QWidget* parent);
|
||||
void UpdateData();
|
||||
void UpdateData(AchievementManager::UpdatedItems updated_items);
|
||||
void ForceSettingsTab();
|
||||
|
||||
private:
|
||||
|
|
|
@ -28,6 +28,8 @@ add_executable(dolphin-mpn
|
|||
CheatSearchWidget.h
|
||||
CheatsManager.cpp
|
||||
CheatsManager.h
|
||||
Achievements/AchievementBox.cpp
|
||||
Achievements/AchievementBox.h
|
||||
Achievements/AchievementHeaderWidget.cpp
|
||||
Achievements/AchievementHeaderWidget.h
|
||||
Achievements/AchievementLeaderboardWidget.cpp
|
||||
|
@ -303,6 +305,7 @@ add_executable(dolphin-mpn
|
|||
QtUtils/ElidedButton.h
|
||||
QtUtils/FileOpenEventFilter.cpp
|
||||
QtUtils/FileOpenEventFilter.h
|
||||
QtUtils/FromStdString.h
|
||||
QtUtils/ImageConverter.cpp
|
||||
QtUtils/ImageConverter.h
|
||||
QtUtils/ModalMessageBox.cpp
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "DolphinQt/CheatSearchFactoryWidget.h"
|
||||
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -124,7 +125,7 @@ void CheatSearchFactoryWidget::CreateWidgets()
|
|||
|
||||
layout->addStretch();
|
||||
|
||||
setLayout(layout);
|
||||
WrapInScrollArea(this, layout);
|
||||
}
|
||||
|
||||
void CheatSearchFactoryWidget::ConnectWidgets()
|
||||
|
@ -157,7 +158,8 @@ void CheatSearchFactoryWidget::OnNewSearchClicked()
|
|||
PowerPC::RequestedAddressSpace address_space;
|
||||
if (m_standard_address_space->isChecked())
|
||||
{
|
||||
const Core::State core_state = Core::GetState();
|
||||
auto& system = Core::System::GetInstance();
|
||||
const Core::State core_state = Core::GetState(system);
|
||||
if (core_state != Core::State::Running && core_state != Core::State::Paused)
|
||||
{
|
||||
ModalMessageBox::warning(
|
||||
|
@ -166,7 +168,6 @@ void CheatSearchFactoryWidget::OnNewSearchClicked()
|
|||
return;
|
||||
}
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& memory = system.GetMemory();
|
||||
memory_ranges.emplace_back(0x80000000, memory.GetRamSizeReal());
|
||||
if (system.IsWii())
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "DolphinQt/CheatSearchWidget.h"
|
||||
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
@ -54,8 +55,10 @@ constexpr int ADDRESS_TABLE_COLUMN_INDEX_ADDRESS = 1;
|
|||
constexpr int ADDRESS_TABLE_COLUMN_INDEX_LAST_VALUE = 2;
|
||||
constexpr int ADDRESS_TABLE_COLUMN_INDEX_CURRENT_VALUE = 3;
|
||||
|
||||
CheatSearchWidget::CheatSearchWidget(std::unique_ptr<Cheats::CheatSearchSessionBase> session)
|
||||
: m_session(std::move(session))
|
||||
CheatSearchWidget::CheatSearchWidget(Core::System& system,
|
||||
std::unique_ptr<Cheats::CheatSearchSessionBase> session,
|
||||
QWidget* parent)
|
||||
: QWidget(parent), m_system(system), m_session(std::move(session))
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
CreateWidgets();
|
||||
|
@ -172,6 +175,7 @@ void CheatSearchWidget::CreateWidgets()
|
|||
}
|
||||
QString aligned = m_session->GetAligned() ? tr("aligned") : tr("unaligned");
|
||||
session_info_label->setText(tr("%1, %2, %3, %4").arg(ranges).arg(space).arg(type).arg(aligned));
|
||||
session_info_label->setWordWrap(true);
|
||||
}
|
||||
|
||||
// i18n: This label is followed by a dropdown where the user can select things like "is equal to"
|
||||
|
@ -254,7 +258,8 @@ void CheatSearchWidget::CreateWidgets()
|
|||
layout->addWidget(m_info_label_1);
|
||||
layout->addWidget(m_info_label_2);
|
||||
layout->addWidget(m_address_table);
|
||||
setLayout(layout);
|
||||
|
||||
WrapInScrollArea(this, layout);
|
||||
}
|
||||
|
||||
void CheatSearchWidget::ConnectWidgets()
|
||||
|
@ -275,13 +280,10 @@ void CheatSearchWidget::ConnectWidgets()
|
|||
|
||||
void CheatSearchWidget::OnNextScanClicked()
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const bool had_old_results = m_session->WasFirstSearchDone();
|
||||
const size_t old_count = m_session->GetResultCount();
|
||||
|
||||
const auto filter_type = m_value_source_dropdown->currentData().value<Cheats::FilterType>();
|
||||
if (filter_type == Cheats::FilterType::CompareAgainstLastValue &&
|
||||
!m_session->WasFirstSearchDone())
|
||||
if (filter_type == Cheats::FilterType::CompareAgainstLastValue && !had_old_results)
|
||||
{
|
||||
m_info_label_1->setText(tr("Cannot compare against last value on first search."));
|
||||
return;
|
||||
|
@ -301,7 +303,8 @@ void CheatSearchWidget::OnNextScanClicked()
|
|||
}
|
||||
}
|
||||
|
||||
const Cheats::SearchErrorCode error_code = m_session->RunSearch(guard);
|
||||
const size_t old_count = m_session->GetResultCount();
|
||||
const Cheats::SearchErrorCode error_code = m_session->RunSearch(Core::CPUThreadGuard{m_system});
|
||||
|
||||
if (error_code == Cheats::SearchErrorCode::Success)
|
||||
{
|
||||
|
@ -416,11 +419,11 @@ void CheatSearchWidget::UpdateTableVisibleCurrentValues(const UpdateSource sourc
|
|||
if (source == UpdateSource::Auto && !m_autoupdate_current_values->isChecked())
|
||||
return;
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
if (m_address_table->rowCount() == 0)
|
||||
return;
|
||||
|
||||
UpdateTableRows(guard, GetVisibleRowsBeginIndex(), GetVisibleRowsEndIndex(), source);
|
||||
UpdateTableRows(Core::CPUThreadGuard{m_system}, GetVisibleRowsBeginIndex(),
|
||||
GetVisibleRowsEndIndex(), source);
|
||||
}
|
||||
|
||||
bool CheatSearchWidget::UpdateTableAllCurrentValues(const UpdateSource source)
|
||||
|
@ -428,7 +431,6 @@ bool CheatSearchWidget::UpdateTableAllCurrentValues(const UpdateSource source)
|
|||
if (source == UpdateSource::Auto && !m_autoupdate_current_values->isChecked())
|
||||
return false;
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const size_t result_count = m_address_table->rowCount();
|
||||
if (result_count == 0)
|
||||
{
|
||||
|
@ -437,7 +439,7 @@ bool CheatSearchWidget::UpdateTableAllCurrentValues(const UpdateSource source)
|
|||
return false;
|
||||
}
|
||||
|
||||
return UpdateTableRows(guard, 0, result_count, source);
|
||||
return UpdateTableRows(Core::CPUThreadGuard{m_system}, 0, result_count, source);
|
||||
}
|
||||
|
||||
void CheatSearchWidget::OnRefreshClicked()
|
||||
|
@ -447,7 +449,6 @@ void CheatSearchWidget::OnRefreshClicked()
|
|||
|
||||
void CheatSearchWidget::OnResetClicked()
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
m_session->ResetResults();
|
||||
m_address_table_current_values.clear();
|
||||
|
||||
|
@ -494,13 +495,14 @@ void CheatSearchWidget::OnAddressTableContextMenu()
|
|||
const u32 address = item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt();
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
menu->addAction(tr("Show in memory"), [this, address] { emit ShowMemory(address); });
|
||||
menu->addAction(tr("Add to watch"), this, [this, address] {
|
||||
const QString name = QStringLiteral("mem_%1").arg(address, 8, 16, QLatin1Char('0'));
|
||||
emit RequestWatch(name, address);
|
||||
});
|
||||
menu->addAction(tr("Generate Action Replay Code"), this, &CheatSearchWidget::GenerateARCode);
|
||||
menu->addAction(tr("Generate Action Replay Code(s)"), this, &CheatSearchWidget::GenerateARCodes);
|
||||
|
||||
menu->exec(QCursor::pos());
|
||||
}
|
||||
|
@ -519,41 +521,70 @@ void CheatSearchWidget::OnDisplayHexCheckboxStateChanged()
|
|||
return;
|
||||
|
||||
// If the game is running CheatsManager::OnFrameEnd will update values automatically.
|
||||
if (Core::GetState() != Core::State::Running)
|
||||
if (Core::GetState(m_system) != Core::State::Running)
|
||||
UpdateTableAllCurrentValues(UpdateSource::User);
|
||||
}
|
||||
|
||||
void CheatSearchWidget::GenerateARCode()
|
||||
void CheatSearchWidget::GenerateARCodes()
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
if (m_address_table->selectedItems().isEmpty())
|
||||
return;
|
||||
|
||||
auto* item = m_address_table->selectedItems()[0];
|
||||
if (!item)
|
||||
return;
|
||||
bool had_success = false;
|
||||
bool had_error = false;
|
||||
std::optional<Cheats::GenerateActionReplayCodeErrorCode> error_code;
|
||||
|
||||
const u32 index = item->data(ADDRESS_TABLE_RESULT_INDEX_ROLE).toUInt();
|
||||
auto result = Cheats::GenerateActionReplayCode(*m_session, index);
|
||||
if (result)
|
||||
for (auto* const item : m_address_table->selectedItems())
|
||||
{
|
||||
emit ActionReplayCodeGenerated(*result);
|
||||
m_info_label_1->setText(tr("Generated AR code."));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (result.Error())
|
||||
const u32 index = item->data(ADDRESS_TABLE_RESULT_INDEX_ROLE).toUInt();
|
||||
auto result = Cheats::GenerateActionReplayCode(*m_session, index);
|
||||
if (result)
|
||||
{
|
||||
case Cheats::GenerateActionReplayCodeErrorCode::NotVirtualMemory:
|
||||
m_info_label_1->setText(tr("Can only generate AR code for values in virtual memory."));
|
||||
break;
|
||||
case Cheats::GenerateActionReplayCodeErrorCode::InvalidAddress:
|
||||
m_info_label_1->setText(tr("Cannot generate AR code for this address."));
|
||||
break;
|
||||
default:
|
||||
m_info_label_1->setText(tr("Internal error while generating AR code."));
|
||||
break;
|
||||
emit ActionReplayCodeGenerated(*result);
|
||||
had_success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto new_error_code = result.Error();
|
||||
if (!had_error)
|
||||
{
|
||||
error_code = new_error_code;
|
||||
}
|
||||
else if (error_code != new_error_code)
|
||||
{
|
||||
// If we have a different error code signify multiple errors with an empty optional<>.
|
||||
error_code.reset();
|
||||
}
|
||||
|
||||
had_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (had_error)
|
||||
{
|
||||
if (error_code.has_value())
|
||||
{
|
||||
switch (*error_code)
|
||||
{
|
||||
case Cheats::GenerateActionReplayCodeErrorCode::NotVirtualMemory:
|
||||
m_info_label_1->setText(tr("Can only generate AR code for values in virtual memory."));
|
||||
break;
|
||||
case Cheats::GenerateActionReplayCodeErrorCode::InvalidAddress:
|
||||
m_info_label_1->setText(tr("Cannot generate AR code for this address."));
|
||||
break;
|
||||
default:
|
||||
m_info_label_1->setText(tr("Internal error while generating AR code."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_info_label_1->setText(tr("Multiple errors while generating AR codes."));
|
||||
}
|
||||
}
|
||||
else if (had_success)
|
||||
{
|
||||
m_info_label_1->setText(tr("Generated AR code(s)."));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,10 @@ namespace ActionReplay
|
|||
{
|
||||
struct ARCode;
|
||||
}
|
||||
namespace Core
|
||||
{
|
||||
class System;
|
||||
}
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
|
@ -36,7 +40,9 @@ class CheatSearchWidget : public QWidget
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CheatSearchWidget(std::unique_ptr<Cheats::CheatSearchSessionBase> session);
|
||||
explicit CheatSearchWidget(Core::System& system,
|
||||
std::unique_ptr<Cheats::CheatSearchSessionBase> session,
|
||||
QWidget* parent = nullptr);
|
||||
~CheatSearchWidget() override;
|
||||
|
||||
enum class UpdateSource
|
||||
|
@ -70,10 +76,12 @@ private:
|
|||
bool UpdateTableRows(const Core::CPUThreadGuard& guard, size_t begin_index, size_t end_index,
|
||||
UpdateSource source);
|
||||
void RecreateGUITable();
|
||||
void GenerateARCode();
|
||||
void GenerateARCodes();
|
||||
int GetVisibleRowsBeginIndex() const;
|
||||
int GetVisibleRowsEndIndex() const;
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
std::unique_ptr<Cheats::CheatSearchSessionBase> m_session;
|
||||
|
||||
// storage for the 'Current Value' column's data
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
CheatsManager::CheatsManager(QWidget* parent) : QDialog(parent)
|
||||
CheatsManager::CheatsManager(Core::System& system, QWidget* parent)
|
||||
: QDialog(parent), m_system(system)
|
||||
{
|
||||
setWindowTitle(tr("Cheats Manager"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
@ -35,7 +36,7 @@ CheatsManager::CheatsManager(QWidget* parent) : QDialog(parent)
|
|||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
|
||||
RefreshCodeTabs(Core::GetState(), true);
|
||||
RefreshCodeTabs(Core::GetState(m_system), true);
|
||||
|
||||
auto& settings = Settings::GetQSettings();
|
||||
restoreGeometry(settings.value(QStringLiteral("cheatsmanager/geometry")).toByteArray());
|
||||
|
@ -169,7 +170,7 @@ void CheatsManager::CreateWidgets()
|
|||
|
||||
void CheatsManager::OnNewSessionCreated(const Cheats::CheatSearchSessionBase& session)
|
||||
{
|
||||
auto* w = new CheatSearchWidget(session.Clone());
|
||||
auto* w = new CheatSearchWidget(m_system, session.Clone());
|
||||
const int tab_index = m_tab_widget->addTab(w, tr("Cheat Search"));
|
||||
w->connect(w, &CheatSearchWidget::ActionReplayCodeGenerated, this,
|
||||
[this](const ActionReplay::ARCode& ar_code) {
|
||||
|
|
|
@ -26,13 +26,14 @@ class PartiallyClosableTabWidget;
|
|||
namespace Core
|
||||
{
|
||||
enum class State;
|
||||
}
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
class CheatsManager : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CheatsManager(QWidget* parent = nullptr);
|
||||
explicit CheatsManager(Core::System& system, QWidget* parent = nullptr);
|
||||
~CheatsManager();
|
||||
|
||||
signals:
|
||||
|
@ -64,6 +65,8 @@ private:
|
|||
std::string m_game_tdb_id;
|
||||
u16 m_revision = 0;
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
QDialogButtonBox* m_button_box;
|
||||
PartiallyClosableTabWidget* m_tab_widget = nullptr;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "DolphinQt/Config/ARCodeWidget.h"
|
||||
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
@ -86,7 +87,7 @@ void ARCodeWidget::CreateWidgets()
|
|||
layout->addWidget(m_code_list);
|
||||
layout->addLayout(button_layout);
|
||||
|
||||
setLayout(layout);
|
||||
WrapInScrollArea(this, layout);
|
||||
}
|
||||
|
||||
void ARCodeWidget::ConnectWidgets()
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
|
@ -22,11 +23,11 @@ CheatWarningWidget::CheatWarningWidget(const std::string& game_id, bool restart_
|
|||
ConnectWidgets();
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EnableCheatsChanged, this,
|
||||
[this] { Update(Core::IsRunning()); });
|
||||
[this] { Update(Core::IsRunning(Core::System::GetInstance())); });
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
[this](Core::State state) { Update(state == Core::State::Running); });
|
||||
|
||||
Update(Core::IsRunning());
|
||||
Update(Core::IsRunning(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void CheatWarningWidget::CreateWidgets()
|
||||
|
|
|
@ -226,6 +226,7 @@ void FilesystemWidget::ShowContextMenu(const QPoint&)
|
|||
auto* item = m_tree_model->itemFromIndex(selection->selectedIndexes()[0]);
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
EntryType type = item->data(ENTRY_TYPE).value<EntryType>();
|
||||
|
||||
|
|
|
@ -66,10 +66,10 @@ GamecubeControllersWidget::GamecubeControllersWidget(QWidget* parent) : QWidget(
|
|||
ConnectWidgets();
|
||||
|
||||
connect(&Settings::Instance(), &Settings::ConfigChanged, this,
|
||||
[this] { LoadSettings(Core::GetState()); });
|
||||
[this] { LoadSettings(Core::GetState(Core::System::GetInstance())); });
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
[this](Core::State state) { LoadSettings(state); });
|
||||
LoadSettings(Core::GetState());
|
||||
LoadSettings(Core::GetState(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void GamecubeControllersWidget::CreateLayout()
|
||||
|
@ -191,16 +191,16 @@ void GamecubeControllersWidget::SaveSettings()
|
|||
{
|
||||
Config::ConfigChangeCallbackGuard config_guard;
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
for (size_t i = 0; i < m_gc_groups.size(); ++i)
|
||||
{
|
||||
const SerialInterface::SIDevices si_device =
|
||||
FromGCMenuIndex(m_gc_controller_boxes[i]->currentIndex());
|
||||
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast<int>(i)), si_device);
|
||||
|
||||
if (Core::IsRunning())
|
||||
if (Core::IsRunning(system))
|
||||
{
|
||||
Core::System::GetInstance().GetSerialInterface().ChangeDevice(si_device,
|
||||
static_cast<s32>(i));
|
||||
system.GetSerialInterface().ChangeDevice(si_device, static_cast<s32>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "DolphinQt/Config/GeckoCodeWidget.h"
|
||||
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
@ -138,7 +139,7 @@ void GeckoCodeWidget::CreateWidgets()
|
|||
|
||||
layout->addLayout(btn_layout);
|
||||
|
||||
setLayout(layout);
|
||||
WrapInScrollArea(this, layout);
|
||||
}
|
||||
|
||||
void GeckoCodeWidget::ConnectWidgets()
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "Core/Config/SYSCONFSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
|
||||
#include "DolphinQt/Config/ConfigControls/ConfigChoice.h"
|
||||
|
@ -42,7 +43,8 @@ AdvancedWidget::AdvancedWidget(GraphicsWindow* parent)
|
|||
});
|
||||
|
||||
OnBackendChanged();
|
||||
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
|
||||
Core::State::Uninitialized);
|
||||
}
|
||||
|
||||
void AdvancedWidget::CreateWidgets()
|
||||
|
@ -84,6 +86,8 @@ void AdvancedWidget::CreateWidgets()
|
|||
|
||||
m_enable_wireframe = new ConfigBool(tr("Enable Wireframe"), Config::GFX_ENABLE_WIREFRAME);
|
||||
m_show_statistics = new ConfigBool(tr("Show Statistics"), Config::GFX_OVERLAY_STATS);
|
||||
m_show_proj_statistics =
|
||||
new ConfigBool(tr("Show Projection Statistics"), Config::GFX_OVERLAY_PROJ_STATS);
|
||||
m_enable_format_overlay =
|
||||
new ConfigBool(tr("Texture Format Overlay"), Config::GFX_TEXFMT_OVERLAY_ENABLE);
|
||||
m_enable_api_validation =
|
||||
|
@ -92,7 +96,8 @@ void AdvancedWidget::CreateWidgets()
|
|||
debugging_layout->addWidget(m_enable_wireframe, 0, 0);
|
||||
debugging_layout->addWidget(m_show_statistics, 0, 1);
|
||||
debugging_layout->addWidget(m_enable_format_overlay, 1, 0);
|
||||
debugging_layout->addWidget(m_enable_api_validation, 1, 1);
|
||||
debugging_layout->addWidget(m_show_proj_statistics, 1, 1);
|
||||
debugging_layout->addWidget(m_enable_api_validation, 2, 0);
|
||||
|
||||
// Utility
|
||||
auto* utility_box = new QGroupBox(tr("Utility"));
|
||||
|
@ -135,21 +140,24 @@ void AdvancedWidget::CreateWidgets()
|
|||
auto* dump_layout = new QGridLayout();
|
||||
dump_box->setLayout(dump_layout);
|
||||
|
||||
m_use_fullres_framedumps = new ConfigBool(tr("Dump at Internal Resolution"),
|
||||
Config::GFX_INTERNAL_RESOLUTION_FRAME_DUMPS);
|
||||
m_frame_dumps_resolution_type =
|
||||
new ConfigChoice({tr("Window Resolution"), tr("Aspect Ratio Corrected Internal Resolution"),
|
||||
tr("Raw Internal Resolution")},
|
||||
Config::GFX_FRAME_DUMPS_RESOLUTION_TYPE);
|
||||
m_dump_use_ffv1 = new ConfigBool(tr("Use Lossless Codec (FFV1)"), Config::GFX_USE_FFV1);
|
||||
m_dump_bitrate = new ConfigInteger(0, 1000000, Config::GFX_BITRATE_KBPS, 1000);
|
||||
m_png_compression_level = new ConfigInteger(0, 9, Config::GFX_PNG_COMPRESSION_LEVEL);
|
||||
|
||||
dump_layout->addWidget(m_use_fullres_framedumps, 0, 0);
|
||||
dump_layout->addWidget(new QLabel(tr("Resolution Type:")), 0, 0);
|
||||
dump_layout->addWidget(m_frame_dumps_resolution_type, 0, 1);
|
||||
#if defined(HAVE_FFMPEG)
|
||||
dump_layout->addWidget(m_dump_use_ffv1, 0, 1);
|
||||
dump_layout->addWidget(new QLabel(tr("Bitrate (kbps):")), 1, 0);
|
||||
dump_layout->addWidget(m_dump_bitrate, 1, 1);
|
||||
dump_layout->addWidget(m_dump_use_ffv1, 1, 0);
|
||||
dump_layout->addWidget(new QLabel(tr("Bitrate (kbps):")), 2, 0);
|
||||
dump_layout->addWidget(m_dump_bitrate, 2, 1);
|
||||
#endif
|
||||
dump_layout->addWidget(new QLabel(tr("PNG Compression Level:")), 2, 0);
|
||||
dump_layout->addWidget(new QLabel(tr("PNG Compression Level:")), 3, 0);
|
||||
m_png_compression_level->SetTitle(tr("PNG Compression Level"));
|
||||
dump_layout->addWidget(m_png_compression_level, 2, 1);
|
||||
dump_layout->addWidget(m_png_compression_level, 3, 1);
|
||||
|
||||
// Misc.
|
||||
auto* misc_box = new QGroupBox(tr("Misc"));
|
||||
|
@ -294,6 +302,9 @@ void AdvancedWidget::AddDescriptions()
|
|||
static const char TR_SHOW_STATS_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Shows various rendering statistics.<br><br><dolphin_emphasis>If unsure, "
|
||||
"leave this unchecked.</dolphin_emphasis>");
|
||||
static const char TR_SHOW_PROJ_STATS_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Shows various projection statistics.<br><br><dolphin_emphasis>If unsure, "
|
||||
"leave this unchecked.</dolphin_emphasis>");
|
||||
static const char TR_TEXTURE_FORMAT_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Modifies textures to show the format they're encoded in.<br><br>May require "
|
||||
"an emulation reset to apply.<br><br><dolphin_emphasis>If unsure, leave this "
|
||||
|
@ -338,11 +349,21 @@ void AdvancedWidget::AddDescriptions()
|
|||
static const char TR_LOAD_GRAPHICS_MODS_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Loads graphics mods from User/Load/GraphicsMods/.<br><br><dolphin_emphasis>If "
|
||||
"unsure, leave this unchecked.</dolphin_emphasis>");
|
||||
static const char TR_INTERNAL_RESOLUTION_FRAME_DUMPING_DESCRIPTION[] = QT_TR_NOOP(
|
||||
"Creates frame dumps and screenshots at the internal resolution of the renderer, rather than "
|
||||
"the size of the window it is displayed within.<br><br>If the aspect ratio is widescreen, "
|
||||
"the output image will be scaled horizontally to preserve the vertical resolution.<br><br>"
|
||||
"<dolphin_emphasis>If unsure, leave this unchecked.</dolphin_emphasis>");
|
||||
static const char TR_FRAME_DUMPS_RESOLUTION_TYPE_DESCRIPTION[] = QT_TR_NOOP(
|
||||
"Selects how frame dumps (videos) and screenshots are going to be captured.<br>If the game "
|
||||
"or window resolution change during a recording, multiple video files might be created.<br>"
|
||||
"Note that color correction and cropping are always ignored by the captures."
|
||||
"<br><br><b>Window Resolution</b>: Uses the output window resolution (without black bars)."
|
||||
"<br>This is a simple dumping option that will capture the image more or less as you see it."
|
||||
"<br><b>Aspect Ratio Corrected Internal Resolution</b>: "
|
||||
"Uses the Internal Resolution (XFB size), and corrects it by the target aspect ratio.<br>"
|
||||
"This option will consistently dump at the specified Internal Resolution "
|
||||
"regardless of how the image is displayed during recording."
|
||||
"<br><b>Raw Internal Resolution</b>: Uses the Internal Resolution (XFB size) "
|
||||
"without correcting it with the target aspect ratio.<br>"
|
||||
"This will provide a clean dump without any aspect ratio correction so users have as raw as "
|
||||
"possible input for external editing software.<br><br><dolphin_emphasis>If unsure, leave "
|
||||
"this at \"Aspect Ratio Corrected Internal Resolution\".</dolphin_emphasis>");
|
||||
#if defined(HAVE_FFMPEG)
|
||||
static const char TR_USE_FFV1_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Encodes frame dumps using the FFV1 codec.<br><br><dolphin_emphasis>If "
|
||||
|
@ -421,6 +442,7 @@ void AdvancedWidget::AddDescriptions()
|
|||
|
||||
m_enable_wireframe->SetDescription(tr(TR_WIREFRAME_DESCRIPTION));
|
||||
m_show_statistics->SetDescription(tr(TR_SHOW_STATS_DESCRIPTION));
|
||||
m_show_proj_statistics->SetDescription(tr(TR_SHOW_PROJ_STATS_DESCRIPTION));
|
||||
m_enable_format_overlay->SetDescription(tr(TR_TEXTURE_FORMAT_DESCRIPTION));
|
||||
m_enable_api_validation->SetDescription(tr(TR_VALIDATION_LAYER_DESCRIPTION));
|
||||
m_perf_samp_window->SetDescription(tr(TR_PERF_SAMP_WINDOW_DESCRIPTION));
|
||||
|
@ -433,7 +455,7 @@ void AdvancedWidget::AddDescriptions()
|
|||
m_dump_xfb_target->SetDescription(tr(TR_DUMP_XFB_DESCRIPTION));
|
||||
m_disable_vram_copies->SetDescription(tr(TR_DISABLE_VRAM_COPIES_DESCRIPTION));
|
||||
m_enable_graphics_mods->SetDescription(tr(TR_LOAD_GRAPHICS_MODS_DESCRIPTION));
|
||||
m_use_fullres_framedumps->SetDescription(tr(TR_INTERNAL_RESOLUTION_FRAME_DUMPING_DESCRIPTION));
|
||||
m_frame_dumps_resolution_type->SetDescription(tr(TR_FRAME_DUMPS_RESOLUTION_TYPE_DESCRIPTION));
|
||||
#ifdef HAVE_FFMPEG
|
||||
m_dump_use_ffv1->SetDescription(tr(TR_USE_FFV1_DESCRIPTION));
|
||||
#endif
|
||||
|
|
|
@ -33,6 +33,7 @@ private:
|
|||
// Debugging
|
||||
ConfigBool* m_enable_wireframe;
|
||||
ConfigBool* m_show_statistics;
|
||||
ConfigBool* m_show_proj_statistics;
|
||||
ConfigBool* m_enable_format_overlay;
|
||||
ConfigBool* m_enable_api_validation;
|
||||
ConfigBool* m_show_fps;
|
||||
|
@ -60,7 +61,7 @@ private:
|
|||
|
||||
// Frame dumping
|
||||
ConfigBool* m_dump_use_ffv1;
|
||||
ConfigBool* m_use_fullres_framedumps;
|
||||
ConfigChoice* m_frame_dumps_resolution_type;
|
||||
ConfigInteger* m_dump_bitrate;
|
||||
ConfigInteger* m_png_compression_level;
|
||||
|
||||
|
|
|
@ -372,7 +372,8 @@ void EnhancementsWidget::LoadSettings()
|
|||
// Resampling
|
||||
const OutputResamplingMode output_resampling_mode =
|
||||
Config::Get(Config::GFX_ENHANCE_OUTPUT_RESAMPLING);
|
||||
m_output_resampling_combo->setCurrentIndex(static_cast<int>(output_resampling_mode));
|
||||
m_output_resampling_combo->setCurrentIndex(
|
||||
m_output_resampling_combo->findData(static_cast<int>(output_resampling_mode)));
|
||||
|
||||
m_output_resampling_combo->setEnabled(g_Config.backend_info.bSupportsPostProcessing);
|
||||
|
||||
|
@ -527,20 +528,20 @@ void EnhancementsWidget::AddDescriptions()
|
|||
|
||||
"<br><br><b>Bicubic</b> - [16 samples]"
|
||||
"<br>Gamma corrected cubic interpolation between pixels."
|
||||
"<br>Good when rescaling between close resolutions. i.e 1080p and 1440p."
|
||||
"<br>Good when rescaling between close resolutions, e.g. 1080p and 1440p."
|
||||
"<br>Comes in various flavors:"
|
||||
"<br><b>B-Spline</b>: Blurry, but avoids all lobing artifacts"
|
||||
"<br><b>Mitchell-Netravali</b>: Good middle ground between blurry and lobing"
|
||||
"<br><b>Catmull-Rom</b>: Sharper, but can cause lobing artifacts"
|
||||
|
||||
"<br><br><b>Sharp Bilinear</b> - [1-4 samples]"
|
||||
"<br>Similarly to \"Nearest Neighbor\", it maintains a sharp look,"
|
||||
"<br>Similar to \"Nearest Neighbor\", it maintains a sharp look,"
|
||||
"<br>but also does some blending to avoid shimmering."
|
||||
"<br>Works best with 2D games at low resolutions."
|
||||
|
||||
"<br><br><b>Area Sampling</b> - [up to 324 samples]"
|
||||
"<br>Weights pixels by the percentage of area they occupy. Gamma corrected."
|
||||
"<br>Best for down scaling by more than 2x."
|
||||
"<br>Weighs pixels by the percentage of area they occupy. Gamma corrected."
|
||||
"<br>Best for downscaling by more than 2x."
|
||||
|
||||
"<br><br><dolphin_emphasis>If unsure, select 'Default'.</dolphin_emphasis>");
|
||||
static const char TR_COLOR_CORRECTION_DESCRIPTION[] =
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
|
||||
#include "DolphinQt/Config/ConfigControls/ConfigChoice.h"
|
||||
|
@ -43,7 +44,8 @@ GeneralWidget::GeneralWidget(GraphicsWindow* parent)
|
|||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
|
||||
OnEmulationStateChanged(state != Core::State::Uninitialized);
|
||||
});
|
||||
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
|
||||
Core::State::Uninitialized);
|
||||
}
|
||||
|
||||
void GeneralWidget::CreateWidgets()
|
||||
|
@ -253,17 +255,23 @@ void GeneralWidget::AddDescriptions()
|
|||
"a separate render window.<br><br><dolphin_emphasis>If unsure, leave "
|
||||
"this unchecked.</dolphin_emphasis>");
|
||||
static const char TR_ASPECT_RATIO_DESCRIPTION[] = QT_TR_NOOP(
|
||||
"Selects which aspect ratio to use when drawing on the render window.<br>"
|
||||
"Each game can have a slightly different native aspect ratio.<br>They can vary by "
|
||||
"scene and settings and rarely ever exactly match 4:3 or 16:9."
|
||||
"<br><br><b>Auto</b>: Uses the native aspect ratio"
|
||||
"<br><br><b>Force 16:9</b>: Mimics an analog TV with a widescreen aspect ratio."
|
||||
"<br><br><b>Force 4:3</b>: Mimics a standard 4:3 analog TV."
|
||||
"<br><br><b>Stretch to Window</b>: Stretches the picture to the window size."
|
||||
"<br><br><b>Custom</b>: Forces the specified aspect ratio."
|
||||
"<br>This is mostly intended to be used with aspect ratio cheats/mods."
|
||||
"<br><br><b>Custom (Stretch)</b>: Similar to `Custom` but not relative to the "
|
||||
"title's native aspect ratio.<br>This is not meant to be used under normal circumstances."
|
||||
"Selects which aspect ratio to use for displaying the game."
|
||||
"<br><br>The aspect ratio of the image sent out by the original consoles varied depending on "
|
||||
"the game and rarely exactly matched 4:3 or 16:9. Some of the image would be cut off by the "
|
||||
"edges of the TV, or the image wouldn't fill the TV entirely. By default, Dolphin shows the "
|
||||
"whole image without distorting its proportions, which means it's normal for the image to "
|
||||
"not entirely fill your display."
|
||||
"<br><br><b>Auto</b>: Mimics a TV with either a 4:3 or 16:9 aspect ratio, depending on which "
|
||||
"type of TV the game seems to be targeting."
|
||||
"<br><br><b>Force 16:9</b>: Mimics a TV with a 16:9 (widescreen) aspect ratio."
|
||||
"<br><br><b>Force 4:3</b>: Mimics a TV with a 4:3 aspect ratio."
|
||||
"<br><br><b>Stretch to Window</b>: Stretches the image to the window size. "
|
||||
"This will usually distort the image's proportions."
|
||||
"<br><br><b>Custom</b>: Mimics a TV with the specified aspect ratio. "
|
||||
"This is mostly intended to be used with aspect ratio cheats/mods."
|
||||
"<br><br><b>Custom (Stretch)</b>: Similar to `Custom`, but stretches the image to the "
|
||||
"specified aspect ratio. This will usually distort the image's proportions, and should not "
|
||||
"be used under normal circumstances."
|
||||
"<br><br><dolphin_emphasis>If unsure, select Auto.</dolphin_emphasis>");
|
||||
static const char TR_VSYNC_DESCRIPTION[] = QT_TR_NOOP(
|
||||
"Waits for vertical blanks in order to prevent tearing.<br><br>Decreases performance "
|
||||
|
@ -355,7 +363,7 @@ void GeneralWidget::OnBackendChanged(const QString& backend_name)
|
|||
const bool supports_adapters = !adapters.empty();
|
||||
|
||||
m_adapter_combo->setCurrentIndex(g_Config.iAdapter);
|
||||
m_adapter_combo->setEnabled(supports_adapters && !Core::IsRunning());
|
||||
m_adapter_combo->setEnabled(supports_adapters && !Core::IsRunning(Core::System::GetInstance()));
|
||||
|
||||
static constexpr char TR_ADAPTER_AVAILABLE_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Selects a hardware adapter to use.<br><br>"
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "Common/FileUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
#include "DolphinQt/Config/GraphicsModWarningWidget.h"
|
||||
#include "DolphinQt/QtUtils/ClearLayoutRecursively.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
@ -28,7 +29,7 @@
|
|||
GraphicsModListWidget::GraphicsModListWidget(const UICommon::GameFile& game)
|
||||
: m_game_id(game.GetGameID()), m_mod_group(m_game_id)
|
||||
{
|
||||
CalculateGameRunning(Core::GetState());
|
||||
CalculateGameRunning(Core::GetState(Core::System::GetInstance()));
|
||||
if (m_loaded_game_is_running && g_Config.graphics_mod_config)
|
||||
{
|
||||
m_mod_group.SetChangeCount(g_Config.graphics_mod_config->GetChangeCount());
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <QPushButton>
|
||||
#include <QStyle>
|
||||
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
|
||||
|
@ -57,6 +57,6 @@ void HardcoreWarningWidget::ConnectWidgets()
|
|||
|
||||
void HardcoreWarningWidget::Update()
|
||||
{
|
||||
setHidden(!Config::Get(Config::RA_HARDCORE_ENABLED));
|
||||
setHidden(!AchievementManager::GetInstance().IsHardcoreModeActive());
|
||||
}
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -587,28 +587,25 @@ void IOWindow::UpdateOptionList()
|
|||
if (m_selected_device == nullptr)
|
||||
return;
|
||||
|
||||
const auto add_rows = [this](auto& container) {
|
||||
int row = 0;
|
||||
for (ciface::Core::Device::Control* control : container)
|
||||
{
|
||||
m_option_list->insertRow(row);
|
||||
|
||||
if (control->IsHidden())
|
||||
m_option_list->hideRow(row);
|
||||
|
||||
m_option_list->setItem(row, 0,
|
||||
new QTableWidgetItem(QString::fromStdString(control->GetName())));
|
||||
++row;
|
||||
}
|
||||
};
|
||||
|
||||
if (m_reference->IsInput())
|
||||
{
|
||||
int row = 0;
|
||||
for (const auto* input : m_selected_device->Inputs())
|
||||
{
|
||||
m_option_list->insertRow(row);
|
||||
m_option_list->setItem(row, 0,
|
||||
new QTableWidgetItem(QString::fromStdString(input->GetName())));
|
||||
++row;
|
||||
}
|
||||
}
|
||||
add_rows(m_selected_device->Inputs());
|
||||
else
|
||||
{
|
||||
int row = 0;
|
||||
for (const auto* output : m_selected_device->Outputs())
|
||||
{
|
||||
m_option_list->insertRow(row);
|
||||
m_option_list->setItem(row, 0,
|
||||
new QTableWidgetItem(QString::fromStdString(output->GetName())));
|
||||
++row;
|
||||
}
|
||||
}
|
||||
add_rows(m_selected_device->Outputs());
|
||||
}
|
||||
|
||||
void IOWindow::UpdateDeviceList()
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "Common/MathUtil.h"
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Camera.h"
|
||||
|
||||
#include "InputCommon/ControlReference/ControlReference.h"
|
||||
#include "InputCommon/ControllerEmu/Control/Control.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Cursor.h"
|
||||
|
@ -823,6 +825,35 @@ void GyroMappingIndicator::Draw()
|
|||
p.drawEllipse(QPointF{}, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
|
||||
}
|
||||
|
||||
void IRPassthroughMappingIndicator::Draw()
|
||||
{
|
||||
QPainter p(this);
|
||||
DrawBoundingBox(p);
|
||||
TransformPainter(p);
|
||||
|
||||
p.scale(1.0, -1.0);
|
||||
|
||||
auto pen = GetInputDotPen(m_ir_group.enabled ? GetAdjustedInputColor() : GetRawInputColor());
|
||||
|
||||
for (std::size_t i = 0; i != WiimoteEmu::CameraLogic::NUM_POINTS; ++i)
|
||||
{
|
||||
const auto size = m_ir_group.GetObjectSize(i);
|
||||
|
||||
const bool is_visible = size > 0;
|
||||
if (!is_visible)
|
||||
continue;
|
||||
|
||||
const auto point =
|
||||
(QPointF{m_ir_group.GetObjectPositionX(i), m_ir_group.GetObjectPositionY(i)} -
|
||||
QPointF{0.5, 0.5}) *
|
||||
2.0;
|
||||
|
||||
pen.setWidth(size * NORMAL_INDICATOR_WIDTH / 2);
|
||||
p.setPen(pen);
|
||||
p.drawPoint(point);
|
||||
}
|
||||
}
|
||||
|
||||
void ReshapableInputIndicator::DrawCalibration(QPainter& p, Common::DVec2 point)
|
||||
{
|
||||
const auto center = m_calibration_widget->GetCenter();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <deque>
|
||||
|
||||
#include "Core/HW/WiimoteEmu/Dynamics.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IRPassthrough.h"
|
||||
#include "InputCommon/ControllerEmu/StickGate.h"
|
||||
|
||||
namespace ControllerEmu
|
||||
|
@ -180,6 +181,19 @@ private:
|
|||
u32 m_stable_steps = 0;
|
||||
};
|
||||
|
||||
class IRPassthroughMappingIndicator : public SquareIndicator
|
||||
{
|
||||
public:
|
||||
explicit IRPassthroughMappingIndicator(ControllerEmu::IRPassthrough& ir_group)
|
||||
: m_ir_group(ir_group)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void Draw() override;
|
||||
|
||||
ControllerEmu::IRPassthrough& m_ir_group;
|
||||
};
|
||||
class CalibrationWidget : public QToolButton
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -95,6 +95,11 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
|
|||
indicator = new AnalogStickIndicator(*static_cast<ControllerEmu::ReshapableInput*>(group));
|
||||
break;
|
||||
|
||||
case ControllerEmu::GroupType::IRPassthrough:
|
||||
indicator =
|
||||
new IRPassthroughMappingIndicator(*static_cast<ControllerEmu::IRPassthrough*>(group));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -167,7 +172,9 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
|
|||
{
|
||||
QPushButton* mouse_button = new QPushButton(tr("Use Mouse Controlled Pointing"));
|
||||
form_layout->insertRow(2, mouse_button);
|
||||
connect(mouse_button, &QCheckBox::clicked, [this, group] {
|
||||
|
||||
using ControllerEmu::Cursor;
|
||||
connect(mouse_button, &QCheckBox::clicked, [this, group = static_cast<Cursor*>(group)] {
|
||||
std::string default_device = g_controller_interface.GetDefaultDeviceString() + ":";
|
||||
const std::string controller_device = GetController()->GetDefaultDevice().ToString() + ":";
|
||||
if (default_device == controller_device)
|
||||
|
@ -178,6 +185,9 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con
|
|||
group->SetControlExpression(1, fmt::format("`{}Cursor Y+`", default_device));
|
||||
group->SetControlExpression(2, fmt::format("`{}Cursor X-`", default_device));
|
||||
group->SetControlExpression(3, fmt::format("`{}Cursor X+`", default_device));
|
||||
|
||||
group->SetRelativeInput(false);
|
||||
|
||||
emit ConfigChanged();
|
||||
GetController()->UpdateReferences(g_controller_interface);
|
||||
});
|
||||
|
@ -327,6 +337,9 @@ MappingWidget::CreateSettingAdvancedMappingButton(ControllerEmu::NumericSettingB
|
|||
if (setting.IsSimpleValue())
|
||||
setting.SetExpressionFromValue();
|
||||
|
||||
// Ensure the UI has the game-controller indicator while editing the expression.
|
||||
ConfigChanged();
|
||||
|
||||
IOWindow io(this, GetController(), &setting.GetInputReference(), IOWindow::Type::Input);
|
||||
SetQWidgetWindowDecorations(&io);
|
||||
io.exec();
|
||||
|
|
|
@ -48,6 +48,8 @@ void WiimoteEmuMotionControlIMU::CreateMainLayout()
|
|||
auto* groups_layout = new QHBoxLayout();
|
||||
groups_layout->addWidget(
|
||||
CreateGroupBox(Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUPoint)));
|
||||
groups_layout->addWidget(
|
||||
CreateGroupBox(Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IRPassthrough)));
|
||||
groups_layout->addWidget(CreateGroupBox(
|
||||
Wiimote::GetWiimoteGroup(GetPort(), WiimoteEmu::WiimoteGroup::IMUAccelerometer)));
|
||||
groups_layout->addWidget(
|
||||
|
|
|
@ -315,10 +315,12 @@ void BalloonTip::UpdateBoundsAndRedraw(const QPoint& target_arrow_tip_position,
|
|||
// Place the arrow tip at the target position whether the arrow tip is drawn or not
|
||||
const int target_balloontip_global_x =
|
||||
target_arrow_tip_position.x() - static_cast<int>(arrow_tip_x);
|
||||
const int rightmost_valid_balloontip_global_x = screen_rect.width() - size_hint.width();
|
||||
const int rightmost_valid_balloontip_global_x =
|
||||
screen_rect.left() + screen_rect.width() - size_hint.width();
|
||||
// If the balloon would extend off the screen, push it left or right until it's not
|
||||
const int actual_balloontip_global_x =
|
||||
std::max(0, std::min(rightmost_valid_balloontip_global_x, target_balloontip_global_x));
|
||||
std::max(screen_rect.left(),
|
||||
std::min(rightmost_valid_balloontip_global_x, target_balloontip_global_x));
|
||||
// The tip pixel should be in the middle of the control, and arrow_tip_exterior_y is at the bottom
|
||||
// of that pixel. When arrow_at_bottom is true the arrow is above arrow_tip_exterior_y and so the
|
||||
// tip pixel is in the right place, but when it's false the arrow is below arrow_tip_exterior_y
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DiscIO/VolumeVerifier.h"
|
||||
#include "DolphinQt/QtUtils/ParallelProgressDialog.h"
|
||||
|
@ -44,12 +45,12 @@ VerifyWidget::VerifyWidget(std::shared_ptr<DiscIO::Volume> volume) : m_volume(st
|
|||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
&VerifyWidget::OnEmulationStateChanged);
|
||||
|
||||
OnEmulationStateChanged();
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void VerifyWidget::OnEmulationStateChanged()
|
||||
void VerifyWidget::OnEmulationStateChanged(Core::State state)
|
||||
{
|
||||
const bool running = Core::GetState() != Core::State::Uninitialized;
|
||||
const bool running = state != Core::State::Uninitialized;
|
||||
|
||||
// Verifying a Wii game while emulation is running doesn't work correctly
|
||||
// due to verification of a Wii game creating an instance of IOS
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
#include <QTextEdit>
|
||||
#include <QWidget>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
enum class State;
|
||||
}
|
||||
namespace DiscIO
|
||||
{
|
||||
class Volume;
|
||||
|
@ -26,10 +30,8 @@ class VerifyWidget final : public QWidget
|
|||
public:
|
||||
explicit VerifyWidget(std::shared_ptr<DiscIO::Volume> volume);
|
||||
|
||||
private slots:
|
||||
void OnEmulationStateChanged();
|
||||
|
||||
private:
|
||||
void OnEmulationStateChanged(Core::State state);
|
||||
void CreateWidgets();
|
||||
std::pair<QCheckBox*, QLineEdit*> AddHashLine(QFormLayout* layout, QString text);
|
||||
void ConnectWidgets();
|
||||
|
|
|
@ -46,10 +46,10 @@ WiimoteControllersWidget::WiimoteControllersWidget(QWidget* parent) : QWidget(pa
|
|||
ConnectWidgets();
|
||||
|
||||
connect(&Settings::Instance(), &Settings::ConfigChanged, this,
|
||||
[this] { LoadSettings(Core::GetState()); });
|
||||
[this] { LoadSettings(Core::GetState(Core::System::GetInstance())); });
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
[this](Core::State state) { LoadSettings(state); });
|
||||
LoadSettings(Core::GetState());
|
||||
LoadSettings(Core::GetState(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void WiimoteControllersWidget::UpdateBluetoothAvailableStatus()
|
||||
|
@ -173,16 +173,16 @@ void WiimoteControllersWidget::ConnectWidgets()
|
|||
{
|
||||
connect(m_wiimote_passthrough, &QRadioButton::toggled, this, [this] {
|
||||
SaveSettings();
|
||||
LoadSettings(Core::GetState());
|
||||
LoadSettings(Core::GetState(Core::System::GetInstance()));
|
||||
});
|
||||
connect(m_wiimote_ciface, &QCheckBox::toggled, this, [this] {
|
||||
SaveSettings();
|
||||
LoadSettings(Core::GetState());
|
||||
LoadSettings(Core::GetState(Core::System::GetInstance()));
|
||||
WiimoteReal::HandleWiimotesInControllerInterfaceSettingChange();
|
||||
});
|
||||
connect(m_wiimote_continuous_scanning, &QCheckBox::toggled, this, [this] {
|
||||
SaveSettings();
|
||||
LoadSettings(Core::GetState());
|
||||
LoadSettings(Core::GetState(Core::System::GetInstance()));
|
||||
});
|
||||
|
||||
connect(m_wiimote_real_balance_board, &QCheckBox::toggled, this,
|
||||
|
@ -200,7 +200,7 @@ void WiimoteControllersWidget::ConnectWidgets()
|
|||
{
|
||||
connect(m_wiimote_boxes[i], &QComboBox::currentIndexChanged, this, [this] {
|
||||
SaveSettings();
|
||||
LoadSettings(Core::GetState());
|
||||
LoadSettings(Core::GetState(Core::System::GetInstance()));
|
||||
});
|
||||
connect(m_wiimote_buttons[i], &QPushButton::clicked, this,
|
||||
[this, i] { OnWiimoteConfigure(i); });
|
||||
|
|
|
@ -729,9 +729,7 @@ void AssemblerWidget::NewEditor(const QString& path)
|
|||
if (!path.isEmpty() && !new_editor->LoadFromPath())
|
||||
{
|
||||
ModalMessageBox::warning(this, tr("Failed to open file"),
|
||||
tr("Failed to read the contents of file\n\n"
|
||||
"\"%1\"")
|
||||
.arg(path));
|
||||
tr("Failed to read the contents of file:\n%1").arg(path));
|
||||
delete new_editor;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Core/System.h"
|
||||
#include "DolphinQt/Debugger/BranchWatchTableModel.h"
|
||||
#include "DolphinQt/Debugger/CodeWidget.h"
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/QtUtils/DolphinFileDialog.h"
|
||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
||||
|
@ -194,30 +195,33 @@ void BranchWatchProxyModel::SetInspected(const QModelIndex& index)
|
|||
}
|
||||
|
||||
BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& branch_watch,
|
||||
CodeWidget* code_widget, QWidget* parent)
|
||||
PPCSymbolDB& ppc_symbol_db, CodeWidget* code_widget,
|
||||
QWidget* parent)
|
||||
: QDialog(parent), m_system(system), m_branch_watch(branch_watch), m_code_widget(code_widget)
|
||||
{
|
||||
setWindowTitle(tr("Branch Watch Tool"));
|
||||
setWindowFlags((windowFlags() | Qt::WindowMinMaxButtonsHint) & ~Qt::WindowContextHelpButtonHint);
|
||||
SetQWidgetWindowDecorations(this);
|
||||
setLayout([this]() {
|
||||
auto* layout = new QVBoxLayout;
|
||||
setLayout([this, &ppc_symbol_db]() {
|
||||
auto* main_layout = new QVBoxLayout;
|
||||
|
||||
// Controls Toolbar (widgets are added later)
|
||||
layout->addWidget(m_control_toolbar = new QToolBar);
|
||||
main_layout->addWidget(m_control_toolbar = new QToolBar);
|
||||
|
||||
// Branch Watch Table
|
||||
layout->addWidget(m_table_view = [this]() {
|
||||
main_layout->addWidget(m_table_view = [this, &ppc_symbol_db]() {
|
||||
const auto& ui_settings = Settings::Instance();
|
||||
|
||||
m_table_proxy = new BranchWatchProxyModel(m_branch_watch);
|
||||
m_table_proxy->setSourceModel(m_table_model =
|
||||
new BranchWatchTableModel(m_system, m_branch_watch));
|
||||
m_table_proxy->setSourceModel(
|
||||
m_table_model = new BranchWatchTableModel(m_system, m_branch_watch, ppc_symbol_db));
|
||||
m_table_proxy->setSortRole(UserRole::SortRole);
|
||||
|
||||
m_table_model->setFont(ui_settings.GetDebugFont());
|
||||
connect(&ui_settings, &Settings::DebugFontChanged, m_table_model,
|
||||
&BranchWatchTableModel::setFont);
|
||||
connect(Host::GetInstance(), &Host::PPCSymbolsChanged, m_table_model,
|
||||
&BranchWatchTableModel::UpdateSymbols);
|
||||
|
||||
auto* const table_view = new QTableView;
|
||||
table_view->setModel(m_table_proxy);
|
||||
|
@ -271,7 +275,7 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br
|
|||
}();
|
||||
|
||||
// Menu Bar
|
||||
layout->setMenuBar([this]() {
|
||||
main_layout->setMenuBar([this]() {
|
||||
QMenuBar* const menu_bar = new QMenuBar;
|
||||
menu_bar->setNativeMenuBar(false);
|
||||
|
||||
|
@ -308,7 +312,7 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br
|
|||
}());
|
||||
|
||||
// Status Bar
|
||||
layout->addWidget(m_status_bar = []() {
|
||||
main_layout->addWidget(m_status_bar = []() {
|
||||
auto* const status_bar = new QStatusBar;
|
||||
status_bar->setSizeGripEnabled(false);
|
||||
return status_bar;
|
||||
|
@ -394,7 +398,8 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br
|
|||
m_control_toolbar->addWidget([this]() {
|
||||
auto* const layout = new QGridLayout;
|
||||
|
||||
const auto routine = [this, layout](const QString& text, int row, int column, int width,
|
||||
const auto routine = [this, layout](const QString& placeholder_text, int row, int column,
|
||||
int width,
|
||||
void (BranchWatchProxyModel::*slot)(const QString&)) {
|
||||
QLineEdit* const line_edit = new QLineEdit;
|
||||
layout->addWidget(line_edit, row, column, 1, width);
|
||||
|
@ -402,7 +407,7 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br
|
|||
(m_table_proxy->*slot)(text);
|
||||
UpdateStatus();
|
||||
});
|
||||
line_edit->setPlaceholderText(text);
|
||||
line_edit->setPlaceholderText(placeholder_text);
|
||||
return line_edit;
|
||||
};
|
||||
|
||||
|
@ -487,7 +492,7 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br
|
|||
connect(m_table_proxy, &BranchWatchProxyModel::layoutChanged, this,
|
||||
&BranchWatchDialog::UpdateStatus);
|
||||
|
||||
return layout;
|
||||
return main_layout;
|
||||
}());
|
||||
|
||||
// FIXME: On Linux, Qt6 has recently been resetting column widths to their defaults in many
|
||||
|
@ -504,15 +509,9 @@ BranchWatchDialog::BranchWatchDialog(Core::System& system, Core::BranchWatch& br
|
|||
restoreGeometry(settings.value(QStringLiteral("branchwatchdialog/geometry")).toByteArray());
|
||||
}
|
||||
|
||||
void BranchWatchDialog::done(int r)
|
||||
BranchWatchDialog::~BranchWatchDialog()
|
||||
{
|
||||
if (m_timer->isActive())
|
||||
m_timer->stop();
|
||||
auto& settings = Settings::GetQSettings();
|
||||
settings.setValue(QStringLiteral("branchwatchdialog/geometry"), saveGeometry());
|
||||
settings.setValue(QStringLiteral("branchwatchdialog/tableheader/state"),
|
||||
m_table_view->horizontalHeader()->saveState());
|
||||
QDialog::done(r);
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
static constexpr int BRANCH_WATCH_TOOL_TIMER_DELAY_MS = 100;
|
||||
|
@ -523,18 +522,18 @@ static bool TimerCondition(const Core::BranchWatch& branch_watch, Core::State st
|
|||
return branch_watch.GetRecordingActive() && state > Core::State::Paused;
|
||||
}
|
||||
|
||||
int BranchWatchDialog::exec()
|
||||
void BranchWatchDialog::hideEvent(QHideEvent* event)
|
||||
{
|
||||
if (TimerCondition(m_branch_watch, Core::GetState()))
|
||||
m_timer->start(BRANCH_WATCH_TOOL_TIMER_DELAY_MS);
|
||||
return QDialog::exec();
|
||||
if (m_timer->isActive())
|
||||
m_timer->stop();
|
||||
QDialog::hideEvent(event);
|
||||
}
|
||||
|
||||
void BranchWatchDialog::open()
|
||||
void BranchWatchDialog::showEvent(QShowEvent* event)
|
||||
{
|
||||
if (TimerCondition(m_branch_watch, Core::GetState()))
|
||||
if (TimerCondition(m_branch_watch, Core::GetState(m_system)))
|
||||
m_timer->start(BRANCH_WATCH_TOOL_TIMER_DELAY_MS);
|
||||
QDialog::open();
|
||||
QDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void BranchWatchDialog::OnStartPause(bool checked)
|
||||
|
@ -545,7 +544,7 @@ void BranchWatchDialog::OnStartPause(bool checked)
|
|||
m_btn_start_pause->setText(tr("Pause Branch Watch"));
|
||||
// Restart the timer if the situation calls for it, but always turn off single-shot.
|
||||
m_timer->setSingleShot(false);
|
||||
if (Core::GetState() > Core::State::Paused)
|
||||
if (Core::GetState(m_system) > Core::State::Paused)
|
||||
m_timer->start(BRANCH_WATCH_TOOL_TIMER_DELAY_MS);
|
||||
}
|
||||
else
|
||||
|
@ -553,7 +552,7 @@ void BranchWatchDialog::OnStartPause(bool checked)
|
|||
m_branch_watch.Pause();
|
||||
m_btn_start_pause->setText(tr("Start Branch Watch"));
|
||||
// Schedule one last update in the future in case Branch Watch is in the middle of a hit.
|
||||
if (Core::GetState() > Core::State::Paused)
|
||||
if (Core::GetState(m_system) > Core::State::Paused)
|
||||
m_timer->setInterval(BRANCH_WATCH_TOOL_TIMER_PAUSE_ONESHOT_MS);
|
||||
m_timer->setSingleShot(true);
|
||||
}
|
||||
|
@ -646,7 +645,7 @@ void BranchWatchDialog::OnCodePathNotTaken()
|
|||
|
||||
void BranchWatchDialog::OnBranchWasOverwritten()
|
||||
{
|
||||
if (Core::GetState() == Core::State::Uninitialized)
|
||||
if (Core::GetState(m_system) == Core::State::Uninitialized)
|
||||
{
|
||||
ModalMessageBox::warning(this, tr("Error"), tr("Core is uninitialized."));
|
||||
return;
|
||||
|
@ -661,7 +660,7 @@ void BranchWatchDialog::OnBranchWasOverwritten()
|
|||
|
||||
void BranchWatchDialog::OnBranchNotOverwritten()
|
||||
{
|
||||
if (Core::GetState() == Core::State::Uninitialized)
|
||||
if (Core::GetState(m_system) == Core::State::Uninitialized)
|
||||
{
|
||||
ModalMessageBox::warning(this, tr("Error"), tr("Core is uninitialized."));
|
||||
return;
|
||||
|
@ -758,6 +757,8 @@ void BranchWatchDialog::OnToggleAutoSave(bool checked)
|
|||
return;
|
||||
|
||||
const QString filepath = DolphinFileDialog::getSaveFileName(
|
||||
// i18n: If the user selects a file, Branch Watch will save to that file.
|
||||
// If the user presses Cancel, Branch Watch will save to a file in the user folder.
|
||||
this, tr("Select Branch Watch snapshot auto-save file (for user folder location, cancel)"),
|
||||
QString::fromStdString(File::GetUserPath(D_DUMPDEBUG_BRANCHWATCH_IDX)),
|
||||
tr("Text file (*.txt);;All Files (*)"));
|
||||
|
@ -805,13 +806,15 @@ void BranchWatchDialog::OnTableContextMenu(const QPoint& pos)
|
|||
QModelIndexList index_list = m_table_view->selectionModel()->selectedRows(index.column());
|
||||
|
||||
QMenu* const menu = new QMenu;
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
menu->addAction(tr("&Delete"), [this, index_list]() { OnTableDelete(std::move(index_list)); });
|
||||
switch (index.column())
|
||||
{
|
||||
case Column::Origin:
|
||||
{
|
||||
QAction* const action = menu->addAction(tr("Insert &NOP"));
|
||||
if (Core::GetState() != Core::State::Uninitialized)
|
||||
if (Core::GetState(m_system) != Core::State::Uninitialized)
|
||||
connect(action, &QAction::triggered,
|
||||
[this, index_list]() { OnTableSetNOP(std::move(index_list)); });
|
||||
else
|
||||
|
@ -825,9 +828,9 @@ void BranchWatchDialog::OnTableContextMenu(const QPoint& pos)
|
|||
{
|
||||
QAction* const action = menu->addAction(tr("Insert &BLR"));
|
||||
const bool enable_action =
|
||||
Core::GetState() != Core::State::Uninitialized &&
|
||||
std::all_of(index_list.begin(), index_list.end(), [this](const QModelIndex& index) {
|
||||
const QModelIndex sibling = index.siblingAtColumn(Column::Instruction);
|
||||
Core::GetState(m_system) != Core::State::Uninitialized &&
|
||||
std::all_of(index_list.begin(), index_list.end(), [this](const QModelIndex& idx) {
|
||||
const QModelIndex sibling = idx.siblingAtColumn(Column::Instruction);
|
||||
return BranchSavesLR(m_table_proxy->data(sibling, UserRole::ClickRole).value<u32>());
|
||||
});
|
||||
if (enable_action)
|
||||
|
@ -845,9 +848,9 @@ void BranchWatchDialog::OnTableContextMenu(const QPoint& pos)
|
|||
{
|
||||
QAction* const action = menu->addAction(tr("Insert &BLR at start"));
|
||||
const bool enable_action =
|
||||
Core::GetState() != Core::State::Uninitialized &&
|
||||
std::all_of(index_list.begin(), index_list.end(), [this](const QModelIndex& index) {
|
||||
return m_table_proxy->data(index, UserRole::ClickRole).isValid();
|
||||
Core::GetState(m_system) != Core::State::Uninitialized &&
|
||||
std::all_of(index_list.begin(), index_list.end(), [this](const QModelIndex& idx) {
|
||||
return m_table_proxy->data(idx, UserRole::ClickRole).isValid();
|
||||
});
|
||||
if (enable_action)
|
||||
connect(action, &QAction::triggered, [this, index_list = std::move(index_list)]() {
|
||||
|
@ -927,6 +930,14 @@ void BranchWatchDialog::OnTableCopyAddress(QModelIndexList index_list)
|
|||
QApplication::clipboard()->setText(text);
|
||||
}
|
||||
|
||||
void BranchWatchDialog::SaveSettings()
|
||||
{
|
||||
auto& settings = Settings::GetQSettings();
|
||||
settings.setValue(QStringLiteral("branchwatchdialog/geometry"), saveGeometry());
|
||||
settings.setValue(QStringLiteral("branchwatchdialog/tableheader/state"),
|
||||
m_table_view->horizontalHeader()->saveState());
|
||||
}
|
||||
|
||||
void BranchWatchDialog::Update()
|
||||
{
|
||||
if (m_branch_watch.GetRecordingPhase() == Core::BranchWatch::Phase::Blacklist)
|
||||
|
@ -934,11 +945,6 @@ void BranchWatchDialog::Update()
|
|||
m_table_model->UpdateHits();
|
||||
}
|
||||
|
||||
void BranchWatchDialog::UpdateSymbols()
|
||||
{
|
||||
m_table_model->UpdateSymbols();
|
||||
}
|
||||
|
||||
void BranchWatchDialog::UpdateStatus()
|
||||
{
|
||||
switch (m_branch_watch.GetRecordingPhase())
|
||||
|
|
|
@ -17,6 +17,8 @@ class BranchWatch;
|
|||
class CPUThreadGuard;
|
||||
class System;
|
||||
} // namespace Core
|
||||
class PPCSymbolDB;
|
||||
|
||||
class BranchWatchProxyModel;
|
||||
class BranchWatchTableModel;
|
||||
class CodeWidget;
|
||||
|
@ -48,10 +50,13 @@ class BranchWatchDialog : public QDialog
|
|||
|
||||
public:
|
||||
explicit BranchWatchDialog(Core::System& system, Core::BranchWatch& branch_watch,
|
||||
CodeWidget* code_widget, QWidget* parent = nullptr);
|
||||
void done(int r) override;
|
||||
int exec() override;
|
||||
void open() override;
|
||||
PPCSymbolDB& ppc_symbol_db, CodeWidget* code_widget,
|
||||
QWidget* parent = nullptr);
|
||||
~BranchWatchDialog() override;
|
||||
|
||||
protected:
|
||||
void hideEvent(QHideEvent* event) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
private:
|
||||
void OnStartPause(bool checked);
|
||||
|
@ -82,11 +87,11 @@ private:
|
|||
void OnTableSetNOP(QModelIndexList index_list);
|
||||
void OnTableCopyAddress(QModelIndexList index_list);
|
||||
|
||||
void SaveSettings();
|
||||
|
||||
public:
|
||||
// TODO: Step doesn't cause EmulationStateChanged to be emitted, so it has to call this manually.
|
||||
void Update();
|
||||
// TODO: There seems to be a lack of a ubiquitous signal for when symbols change.
|
||||
void UpdateSymbols();
|
||||
|
||||
private:
|
||||
void UpdateStatus();
|
||||
|
|
|
@ -285,8 +285,8 @@ void BranchWatchTableModel::PrefetchSymbols()
|
|||
for (const Core::BranchWatch::Selection::value_type& value : selection)
|
||||
{
|
||||
const Core::BranchWatch::Collection::value_type* const kv = value.collection_ptr;
|
||||
m_symbol_list.emplace_back(g_symbolDB.GetSymbolFromAddr(kv->first.origin_addr),
|
||||
g_symbolDB.GetSymbolFromAddr(kv->first.destin_addr));
|
||||
m_symbol_list.emplace_back(m_ppc_symbol_db.GetSymbolFromAddr(kv->first.origin_addr),
|
||||
m_ppc_symbol_db.GetSymbolFromAddr(kv->first.destin_addr));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ class BranchWatch;
|
|||
class CPUThreadGuard;
|
||||
class System;
|
||||
} // namespace Core
|
||||
class PPCSymbolDB;
|
||||
|
||||
namespace BranchWatchTableModelColumn
|
||||
{
|
||||
|
@ -69,8 +70,9 @@ public:
|
|||
using SymbolList = QList<SymbolListValueType>;
|
||||
|
||||
explicit BranchWatchTableModel(Core::System& system, Core::BranchWatch& branch_watch,
|
||||
QObject* parent = nullptr)
|
||||
: QAbstractTableModel(parent), m_system(system), m_branch_watch(branch_watch)
|
||||
PPCSymbolDB& ppc_symbol_db, QObject* parent = nullptr)
|
||||
: QAbstractTableModel(parent), m_system(system), m_branch_watch(branch_watch),
|
||||
m_ppc_symbol_db(ppc_symbol_db)
|
||||
{
|
||||
}
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
|
@ -113,6 +115,7 @@ private:
|
|||
|
||||
Core::System& m_system;
|
||||
Core::BranchWatch& m_branch_watch;
|
||||
PPCSymbolDB& m_ppc_symbol_db;
|
||||
|
||||
SymbolList m_symbol_list;
|
||||
mutable QFont m_font;
|
||||
|
|
|
@ -331,7 +331,12 @@ void BreakpointDialog::ShowConditionHelp()
|
|||
"\n"
|
||||
"Registers that can be referenced:\n"
|
||||
"GPRs : r0..r31\n"
|
||||
"FPRs : f0..f31\n LR, CTR, PC\n"
|
||||
"FPRs : f0..f31\n"
|
||||
"SPRs : xer, lr, ctr, dsisr, dar, dec, sdr1, srr0, srr1, tbl, tbu, pvr, sprg0..sprg3, ear, "
|
||||
"ibat0u..ibat7u, ibat0l..ibat7l, dbat0u..dbat7u, dbat0l..dbat07, gqr0..gqr7, hid0, hid1, "
|
||||
"hid2, hid4, iabr, dabr, wpar, dmau, dmal, ecid_u, ecid_m, ecid_l, upmc1..upmc4, usia, sia, "
|
||||
"l2cr, ictc, mmcr0, mmcr1, pmc1..pmc4, thrm1..thrm3\n"
|
||||
"Other : pc, msr\n"
|
||||
"\n"
|
||||
"Functions:\n"
|
||||
"Set a register: r1 = 8\n"
|
||||
|
|
|
@ -150,7 +150,7 @@ void BreakpointWidget::UpdateButtonsEnabled()
|
|||
if (!isVisible())
|
||||
return;
|
||||
|
||||
const bool is_initialised = Core::GetState() != Core::State::Uninitialized;
|
||||
const bool is_initialised = Core::GetState(m_system) != Core::State::Uninitialized;
|
||||
m_new->setEnabled(is_initialised);
|
||||
m_load->setEnabled(is_initialised);
|
||||
m_save->setEnabled(is_initialised);
|
||||
|
@ -178,6 +178,7 @@ void BreakpointWidget::Update()
|
|||
auto& power_pc = m_system.GetPowerPC();
|
||||
auto& breakpoints = power_pc.GetBreakPoints();
|
||||
auto& memchecks = power_pc.GetMemChecks();
|
||||
auto& ppc_symbol_db = power_pc.GetSymbolDB();
|
||||
|
||||
// Breakpoints
|
||||
for (const auto& bp : breakpoints.GetBreakPoints())
|
||||
|
@ -192,11 +193,8 @@ void BreakpointWidget::Update()
|
|||
m_table->setItem(i, 0, active);
|
||||
m_table->setItem(i, 1, create_item(QStringLiteral("BP")));
|
||||
|
||||
if (g_symbolDB.GetSymbolFromAddr(bp.address))
|
||||
{
|
||||
m_table->setItem(i, 2,
|
||||
create_item(QString::fromStdString(g_symbolDB.GetDescription(bp.address))));
|
||||
}
|
||||
if (const Common::Symbol* const symbol = ppc_symbol_db.GetSymbolFromAddr(bp.address))
|
||||
m_table->setItem(i, 2, create_item(QString::fromStdString(symbol->name)));
|
||||
|
||||
m_table->setItem(i, 3,
|
||||
create_item(QStringLiteral("%1").arg(bp.address, 8, 16, QLatin1Char('0'))));
|
||||
|
@ -233,11 +231,8 @@ void BreakpointWidget::Update()
|
|||
m_table->setItem(i, 0, active);
|
||||
m_table->setItem(i, 1, create_item(QStringLiteral("MBP")));
|
||||
|
||||
if (g_symbolDB.GetSymbolFromAddr(mbp.start_address))
|
||||
{
|
||||
m_table->setItem(
|
||||
i, 2, create_item(QString::fromStdString(g_symbolDB.GetDescription(mbp.start_address))));
|
||||
}
|
||||
if (const Common::Symbol* const symbol = ppc_symbol_db.GetSymbolFromAddr(mbp.start_address))
|
||||
m_table->setItem(i, 2, create_item(QString::fromStdString(symbol->name)));
|
||||
|
||||
if (mbp.is_ranged)
|
||||
{
|
||||
|
@ -314,6 +309,7 @@ void BreakpointWidget::OnClear()
|
|||
void BreakpointWidget::OnNewBreakpoint()
|
||||
{
|
||||
BreakpointDialog* dialog = new BreakpointDialog(this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
SetQWidgetWindowDecorations(dialog);
|
||||
dialog->exec();
|
||||
}
|
||||
|
@ -324,6 +320,7 @@ void BreakpointWidget::OnEditBreakpoint(u32 address, bool is_instruction_bp)
|
|||
{
|
||||
auto* dialog =
|
||||
new BreakpointDialog(this, m_system.GetPowerPC().GetBreakPoints().GetBreakpoint(address));
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
SetQWidgetWindowDecorations(dialog);
|
||||
dialog->exec();
|
||||
}
|
||||
|
@ -331,6 +328,7 @@ void BreakpointWidget::OnEditBreakpoint(u32 address, bool is_instruction_bp)
|
|||
{
|
||||
auto* dialog =
|
||||
new BreakpointDialog(this, m_system.GetPowerPC().GetMemChecks().GetMemCheck(address));
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
SetQWidgetWindowDecorations(dialog);
|
||||
dialog->exec();
|
||||
}
|
||||
|
@ -392,6 +390,7 @@ void BreakpointWidget::OnContextMenu()
|
|||
const auto is_memory_breakpoint = selected_item->data(IS_MEMCHECK_ROLE).toBool();
|
||||
|
||||
auto* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
if (!is_memory_breakpoint)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "DolphinQt/Debugger/AssembleInstructionDialog.h"
|
||||
#include "DolphinQt/Debugger/PatchInstructionDialog.h"
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/QtUtils/FromStdString.h"
|
||||
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
||||
#include "DolphinQt/Resources.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
@ -138,7 +139,8 @@ constexpr int CODE_VIEW_COLUMN_DESCRIPTION = 4;
|
|||
constexpr int CODE_VIEW_COLUMN_BRANCH_ARROWS = 5;
|
||||
constexpr int CODE_VIEW_COLUMNCOUNT = 6;
|
||||
|
||||
CodeViewWidget::CodeViewWidget() : m_system(Core::System::GetInstance())
|
||||
CodeViewWidget::CodeViewWidget()
|
||||
: m_system(Core::System::GetInstance()), m_ppc_symbol_db(m_system.GetPPCSymbolDB())
|
||||
{
|
||||
setColumnCount(CODE_VIEW_COLUMNCOUNT);
|
||||
setShowGrid(false);
|
||||
|
@ -171,9 +173,8 @@ CodeViewWidget::CodeViewWidget() : m_system(Core::System::GetInstance())
|
|||
|
||||
connect(this, &CodeViewWidget::customContextMenuRequested, this, &CodeViewWidget::OnContextMenu);
|
||||
connect(this, &CodeViewWidget::itemSelectionChanged, this, &CodeViewWidget::OnSelectionChanged);
|
||||
connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &QWidget::setFont);
|
||||
connect(&Settings::Instance(), &Settings::DebugFontChanged, this,
|
||||
&CodeViewWidget::FontBasedSizing);
|
||||
&CodeViewWidget::OnDebugFontChanged);
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] {
|
||||
m_address = m_system.GetPPCState().pc;
|
||||
|
@ -183,6 +184,8 @@ CodeViewWidget::CodeViewWidget() : m_system(Core::System::GetInstance())
|
|||
m_address = m_system.GetPPCState().pc;
|
||||
Update();
|
||||
});
|
||||
connect(Host::GetInstance(), &Host::PPCSymbolsChanged, this,
|
||||
qOverload<>(&CodeViewWidget::Update));
|
||||
|
||||
connect(&Settings::Instance(), &Settings::ThemeChanged, this,
|
||||
qOverload<>(&CodeViewWidget::Update));
|
||||
|
@ -207,7 +210,7 @@ void CodeViewWidget::FontBasedSizing()
|
|||
// just text width is too small with some fonts, so increase by a bit
|
||||
constexpr int extra_text_width = 8;
|
||||
|
||||
const QFontMetrics fm(Settings::Instance().GetDebugFont());
|
||||
const QFontMetrics fm(font());
|
||||
|
||||
const int rowh = fm.height() + 1;
|
||||
verticalHeader()->setMaximumSectionSize(rowh);
|
||||
|
@ -265,7 +268,7 @@ void CodeViewWidget::Update()
|
|||
if (m_updating)
|
||||
return;
|
||||
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
if (Core::GetState(m_system) == Core::State::Paused)
|
||||
{
|
||||
Core::CPUThreadGuard guard(m_system);
|
||||
Update(&guard);
|
||||
|
@ -324,7 +327,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
|
|||
|
||||
std::string ins = (split == std::string::npos ? disas : disas.substr(0, split));
|
||||
std::string param = (split == std::string::npos ? "" : disas.substr(split + 1));
|
||||
std::string desc = debug_interface.GetDescription(addr);
|
||||
const std::string_view desc = debug_interface.GetDescription(addr);
|
||||
|
||||
// Adds whitespace and a minimum size to ins and param. Helps to prevent frequent resizing while
|
||||
// scrolling.
|
||||
|
@ -332,7 +335,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
|
|||
QStringLiteral("%1").arg(QString::fromStdString(ins), -7, QLatin1Char(' '));
|
||||
const QString param_formatted =
|
||||
QStringLiteral("%1").arg(QString::fromStdString(param), -19, QLatin1Char(' '));
|
||||
const QString desc_formatted = QStringLiteral("%1 ").arg(QString::fromStdString(desc));
|
||||
const QString desc_formatted = QStringLiteral("%1 ").arg(QtUtils::FromStdString(desc));
|
||||
|
||||
auto* ins_item = new QTableWidgetItem(ins_formatted);
|
||||
auto* param_item = new QTableWidgetItem(param_formatted);
|
||||
|
@ -372,7 +375,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
|
|||
branch.is_link = IsBranchInstructionWithLink(ins);
|
||||
|
||||
description_item->setText(
|
||||
tr("--> %1").arg(QString::fromStdString(debug_interface.GetDescription(branch_addr))));
|
||||
tr("--> %1").arg(QtUtils::FromStdString(debug_interface.GetDescription(branch_addr))));
|
||||
param_item->setForeground(dark_theme ? QColor(255, 135, 255) : Qt::magenta);
|
||||
}
|
||||
|
||||
|
@ -382,7 +385,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
|
|||
if (debug_interface.IsBreakpoint(addr))
|
||||
{
|
||||
auto icon = Resources::GetThemeIcon("debugger_breakpoint").pixmap(QSize(rowh - 2, rowh - 2));
|
||||
if (!m_system.GetPowerPC().GetBreakPoints().IsBreakPointEnable(addr))
|
||||
if (!power_pc.GetBreakPoints().IsBreakPointEnable(addr))
|
||||
{
|
||||
QPixmap disabled_icon(icon.size());
|
||||
disabled_icon.fill(Qt::transparent);
|
||||
|
@ -410,7 +413,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard)
|
|||
|
||||
CalculateBranchIndentation();
|
||||
|
||||
g_symbolDB.FillInCallers();
|
||||
m_ppc_symbol_db.FillInCallers();
|
||||
|
||||
repaint();
|
||||
m_updating = false;
|
||||
|
@ -555,13 +558,14 @@ void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
|
|||
void CodeViewWidget::OnContextMenu()
|
||||
{
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
const bool running = Core::GetState() != Core::State::Uninitialized;
|
||||
const bool paused = Core::GetState() == Core::State::Paused;
|
||||
const bool running = Core::GetState(m_system) != Core::State::Uninitialized;
|
||||
const bool paused = Core::GetState(m_system) == Core::State::Paused;
|
||||
|
||||
const u32 addr = GetContextAddress();
|
||||
|
||||
bool has_symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
const bool has_symbol = m_ppc_symbol_db.GetSymbolFromAddr(addr);
|
||||
|
||||
auto* follow_branch_action =
|
||||
menu->addAction(tr("Follow &branch"), this, &CodeViewWidget::OnFollowBranch);
|
||||
|
@ -744,6 +748,12 @@ void CodeViewWidget::AutoStep(CodeTrace::AutoStop option)
|
|||
} while (msgbox.clickedButton() == (QAbstractButton*)run_button);
|
||||
}
|
||||
|
||||
void CodeViewWidget::OnDebugFontChanged(const QFont& font)
|
||||
{
|
||||
setFont(font);
|
||||
FontBasedSizing();
|
||||
}
|
||||
|
||||
void CodeViewWidget::OnCopyAddress()
|
||||
{
|
||||
const u32 addr = GetContextAddress();
|
||||
|
@ -753,7 +763,7 @@ void CodeViewWidget::OnCopyAddress()
|
|||
|
||||
void CodeViewWidget::OnCopyTargetAddress()
|
||||
{
|
||||
if (Core::GetState() != Core::State::Paused)
|
||||
if (Core::GetState(m_system) != Core::State::Paused)
|
||||
return;
|
||||
|
||||
const u32 addr = GetContextAddress();
|
||||
|
@ -783,7 +793,7 @@ void CodeViewWidget::OnShowInMemory()
|
|||
|
||||
void CodeViewWidget::OnShowTargetInMemory()
|
||||
{
|
||||
if (Core::GetState() != Core::State::Paused)
|
||||
if (Core::GetState(m_system) != Core::State::Paused)
|
||||
return;
|
||||
|
||||
const u32 addr = GetContextAddress();
|
||||
|
@ -819,7 +829,7 @@ void CodeViewWidget::OnCopyFunction()
|
|||
{
|
||||
const u32 address = GetContextAddress();
|
||||
|
||||
const Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address);
|
||||
const Common::Symbol* const symbol = m_ppc_symbol_db.GetSymbolFromAddr(address);
|
||||
if (!symbol)
|
||||
return;
|
||||
|
||||
|
@ -877,9 +887,8 @@ void CodeViewWidget::OnAddFunction()
|
|||
|
||||
Core::CPUThreadGuard guard(m_system);
|
||||
|
||||
g_symbolDB.AddFunction(guard, addr);
|
||||
emit SymbolsChanged();
|
||||
Update(&guard);
|
||||
m_ppc_symbol_db.AddFunction(guard, addr);
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void CodeViewWidget::OnInsertBLR()
|
||||
|
@ -915,7 +924,7 @@ void CodeViewWidget::OnRenameSymbol()
|
|||
{
|
||||
const u32 addr = GetContextAddress();
|
||||
|
||||
Common::Symbol* const symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
Common::Symbol* const symbol = m_ppc_symbol_db.GetSymbolFromAddr(addr);
|
||||
|
||||
if (!symbol)
|
||||
return;
|
||||
|
@ -928,8 +937,7 @@ void CodeViewWidget::OnRenameSymbol()
|
|||
if (good && !name.isEmpty())
|
||||
{
|
||||
symbol->Rename(name.toStdString());
|
||||
emit SymbolsChanged();
|
||||
Update();
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -950,7 +958,7 @@ void CodeViewWidget::OnSetSymbolSize()
|
|||
{
|
||||
const u32 addr = GetContextAddress();
|
||||
|
||||
Common::Symbol* const symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
Common::Symbol* const symbol = m_ppc_symbol_db.GetSymbolFromAddr(addr);
|
||||
|
||||
if (!symbol)
|
||||
return;
|
||||
|
@ -967,15 +975,14 @@ void CodeViewWidget::OnSetSymbolSize()
|
|||
Core::CPUThreadGuard guard(m_system);
|
||||
|
||||
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, size);
|
||||
emit SymbolsChanged();
|
||||
Update(&guard);
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void CodeViewWidget::OnSetSymbolEndAddress()
|
||||
{
|
||||
const u32 addr = GetContextAddress();
|
||||
|
||||
Common::Symbol* const symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
Common::Symbol* const symbol = m_ppc_symbol_db.GetSymbolFromAddr(addr);
|
||||
|
||||
if (!symbol)
|
||||
return;
|
||||
|
@ -995,8 +1002,7 @@ void CodeViewWidget::OnSetSymbolEndAddress()
|
|||
Core::CPUThreadGuard guard(m_system);
|
||||
|
||||
PPCAnalyst::ReanalyzeFunction(guard, symbol->address, *symbol, address - symbol->address);
|
||||
emit SymbolsChanged();
|
||||
Update(&guard);
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void CodeViewWidget::OnReplaceInstruction()
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Core/Debugger/CodeTrace.h"
|
||||
|
||||
class QFont;
|
||||
class QKeyEvent;
|
||||
class QMouseEvent;
|
||||
class QResizeEvent;
|
||||
|
@ -23,6 +24,7 @@ class System;
|
|||
|
||||
struct CodeViewBranch;
|
||||
class BranchDisplayDelegate;
|
||||
class PPCSymbolDB;
|
||||
|
||||
class CodeViewWidget : public QTableWidget
|
||||
{
|
||||
|
@ -55,7 +57,6 @@ public:
|
|||
signals:
|
||||
void RequestPPCComparison(u32 addr);
|
||||
void ShowMemory(u32 address);
|
||||
void SymbolsChanged();
|
||||
void BreakpointsChanged();
|
||||
void UpdateCodeWidget();
|
||||
|
||||
|
@ -77,6 +78,7 @@ private:
|
|||
void OnContextMenu();
|
||||
|
||||
void AutoStep(CodeTrace::AutoStop option = CodeTrace::AutoStop::Always);
|
||||
void OnDebugFontChanged(const QFont& font);
|
||||
void OnFollowBranch();
|
||||
void OnCopyAddress();
|
||||
void OnCopyTargetAddress();
|
||||
|
@ -102,6 +104,7 @@ private:
|
|||
void CalculateBranchIndentation();
|
||||
|
||||
Core::System& m_system;
|
||||
PPCSymbolDB& m_ppc_symbol_db;
|
||||
|
||||
bool m_updating = false;
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ static const QString BOX_SPLITTER_STYLESHEET = QStringLiteral(
|
|||
|
||||
CodeWidget::CodeWidget(QWidget* parent)
|
||||
: QDockWidget(parent), m_system(Core::System::GetInstance()),
|
||||
m_branch_watch_dialog(
|
||||
new BranchWatchDialog(m_system, m_system.GetPowerPC().GetBranchWatch(), this))
|
||||
m_ppc_symbol_db(m_system.GetPPCSymbolDB())
|
||||
{
|
||||
setWindowTitle(tr("Code"));
|
||||
setObjectName(QStringLiteral("code"));
|
||||
|
@ -61,13 +60,11 @@ CodeWidget::CodeWidget(QWidget* parent)
|
|||
[this](bool visible) { setHidden(!visible); });
|
||||
|
||||
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, [this] {
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
if (Core::GetState(m_system) == Core::State::Paused)
|
||||
SetAddress(m_system.GetPPCState().pc, CodeViewWidget::SetAddressUpdate::WithoutUpdate);
|
||||
Update();
|
||||
});
|
||||
|
||||
connect(Host::GetInstance(), &Host::NotifyMapLoaded, this, &CodeWidget::UpdateSymbols);
|
||||
|
||||
connect(&Settings::Instance(), &Settings::DebugModeToggled, this,
|
||||
[this](bool enabled) { setHidden(!enabled || !Settings::Instance().IsCodeVisible()); });
|
||||
|
||||
|
@ -174,13 +171,11 @@ void CodeWidget::ConnectWidgets()
|
|||
connect(m_search_address, &QLineEdit::returnPressed, this, &CodeWidget::OnSearchAddress);
|
||||
connect(m_search_symbols, &QLineEdit::textChanged, this, &CodeWidget::OnSearchSymbols);
|
||||
connect(m_search_calls, &QLineEdit::textChanged, this, [this]() {
|
||||
const Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(m_code_view->GetAddress());
|
||||
if (symbol)
|
||||
if (const Common::Symbol* symbol = m_ppc_symbol_db.GetSymbolFromAddr(m_code_view->GetAddress()))
|
||||
UpdateFunctionCalls(symbol);
|
||||
});
|
||||
connect(m_search_callers, &QLineEdit::textChanged, this, [this]() {
|
||||
const Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(m_code_view->GetAddress());
|
||||
if (symbol)
|
||||
if (const Common::Symbol* symbol = m_ppc_symbol_db.GetSymbolFromAddr(m_code_view->GetAddress()))
|
||||
UpdateFunctionCallers(symbol);
|
||||
});
|
||||
connect(m_search_callstack, &QLineEdit::textChanged, this, &CodeWidget::UpdateCallstack);
|
||||
|
@ -194,16 +189,7 @@ void CodeWidget::ConnectWidgets()
|
|||
connect(m_function_callers_list, &QListWidget::itemPressed, this,
|
||||
&CodeWidget::OnSelectFunctionCallers);
|
||||
|
||||
connect(m_code_view, &CodeViewWidget::SymbolsChanged, this, [this]() {
|
||||
UpdateCallstack();
|
||||
UpdateSymbols();
|
||||
const Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(m_code_view->GetAddress());
|
||||
if (symbol)
|
||||
{
|
||||
UpdateFunctionCalls(symbol);
|
||||
UpdateFunctionCallers(symbol);
|
||||
}
|
||||
});
|
||||
connect(Host::GetInstance(), &Host::PPCSymbolsChanged, this, &CodeWidget::OnPPCSymbolsChanged);
|
||||
connect(m_code_view, &CodeViewWidget::BreakpointsChanged, this,
|
||||
[this] { emit BreakpointsChanged(); });
|
||||
connect(m_code_view, &CodeViewWidget::UpdateCodeWidget, this, &CodeWidget::Update);
|
||||
|
@ -215,11 +201,27 @@ void CodeWidget::ConnectWidgets()
|
|||
|
||||
void CodeWidget::OnBranchWatchDialog()
|
||||
{
|
||||
m_branch_watch_dialog->open();
|
||||
if (m_branch_watch_dialog == nullptr)
|
||||
{
|
||||
m_branch_watch_dialog = new BranchWatchDialog(m_system, m_system.GetPowerPC().GetBranchWatch(),
|
||||
m_ppc_symbol_db, this, this);
|
||||
}
|
||||
m_branch_watch_dialog->show();
|
||||
m_branch_watch_dialog->raise();
|
||||
m_branch_watch_dialog->activateWindow();
|
||||
}
|
||||
|
||||
void CodeWidget::OnPPCSymbolsChanged()
|
||||
{
|
||||
UpdateSymbols();
|
||||
UpdateCallstack();
|
||||
if (const Common::Symbol* symbol = m_ppc_symbol_db.GetSymbolFromAddr(m_code_view->GetAddress()))
|
||||
{
|
||||
UpdateFunctionCalls(symbol);
|
||||
UpdateFunctionCallers(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeWidget::OnSearchAddress()
|
||||
{
|
||||
bool good = true;
|
||||
|
@ -258,7 +260,7 @@ void CodeWidget::OnSelectSymbol()
|
|||
return;
|
||||
|
||||
const u32 address = items[0]->data(Qt::UserRole).toUInt();
|
||||
const Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address);
|
||||
const Common::Symbol* const symbol = m_ppc_symbol_db.GetSymbolFromAddr(address);
|
||||
|
||||
m_code_view->SetAddress(address, CodeViewWidget::SetAddressUpdate::WithUpdate);
|
||||
UpdateCallstack();
|
||||
|
@ -319,7 +321,7 @@ void CodeWidget::Update()
|
|||
if (!isVisible())
|
||||
return;
|
||||
|
||||
const Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(m_code_view->GetAddress());
|
||||
const Common::Symbol* const symbol = m_ppc_symbol_db.GetSymbolFromAddr(m_code_view->GetAddress());
|
||||
|
||||
UpdateCallstack();
|
||||
|
||||
|
@ -337,17 +339,11 @@ void CodeWidget::UpdateCallstack()
|
|||
{
|
||||
m_callstack_list->clear();
|
||||
|
||||
if (Core::GetState() != Core::State::Paused)
|
||||
if (Core::GetState(m_system) != Core::State::Paused)
|
||||
return;
|
||||
|
||||
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
||||
|
||||
const bool success = [this, &stack] {
|
||||
Core::CPUThreadGuard guard(m_system);
|
||||
return Dolphin_Debugger::GetCallstack(guard, stack);
|
||||
}();
|
||||
|
||||
if (!success)
|
||||
if (!Dolphin_Debugger::GetCallstack(Core::CPUThreadGuard{m_system}, stack))
|
||||
{
|
||||
m_callstack_list->addItem(tr("Invalid callstack"));
|
||||
return;
|
||||
|
@ -375,7 +371,7 @@ void CodeWidget::UpdateSymbols()
|
|||
m_symbols_list->selectedItems()[0]->text();
|
||||
m_symbols_list->clear();
|
||||
|
||||
for (const auto& symbol : g_symbolDB.Symbols())
|
||||
for (const auto& symbol : m_ppc_symbol_db.Symbols())
|
||||
{
|
||||
QString name = QString::fromStdString(symbol.second.name);
|
||||
|
||||
|
@ -394,10 +390,6 @@ void CodeWidget::UpdateSymbols()
|
|||
}
|
||||
|
||||
m_symbols_list->sortItems();
|
||||
|
||||
// TODO: There seems to be a lack of a ubiquitous signal for when symbols change.
|
||||
// This is the best location to catch the signals from MenuBar and CodeViewWidget.
|
||||
m_branch_watch_dialog->UpdateSymbols();
|
||||
}
|
||||
|
||||
void CodeWidget::UpdateFunctionCalls(const Common::Symbol* symbol)
|
||||
|
@ -408,7 +400,7 @@ void CodeWidget::UpdateFunctionCalls(const Common::Symbol* symbol)
|
|||
for (const auto& call : symbol->calls)
|
||||
{
|
||||
const u32 addr = call.function;
|
||||
const Common::Symbol* call_symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
const Common::Symbol* const call_symbol = m_ppc_symbol_db.GetSymbolFromAddr(addr);
|
||||
|
||||
if (call_symbol)
|
||||
{
|
||||
|
@ -433,7 +425,7 @@ void CodeWidget::UpdateFunctionCallers(const Common::Symbol* symbol)
|
|||
for (const auto& caller : symbol->callers)
|
||||
{
|
||||
const u32 addr = caller.call_address;
|
||||
const Common::Symbol* caller_symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
const Common::Symbol* const caller_symbol = m_ppc_symbol_db.GetSymbolFromAddr(addr);
|
||||
|
||||
if (caller_symbol)
|
||||
{
|
||||
|
@ -470,7 +462,8 @@ void CodeWidget::Step()
|
|||
// Will get a UpdateDisasmDialog(), don't update the GUI here.
|
||||
|
||||
// TODO: Step doesn't cause EmulationStateChanged to be emitted, so it has to call this manually.
|
||||
m_branch_watch_dialog->Update();
|
||||
if (m_branch_watch_dialog != nullptr)
|
||||
m_branch_watch_dialog->Update();
|
||||
}
|
||||
|
||||
void CodeWidget::StepOver()
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Core
|
|||
{
|
||||
class System;
|
||||
}
|
||||
class PPCSymbolDB;
|
||||
|
||||
class CodeWidget : public QDockWidget
|
||||
{
|
||||
|
@ -60,6 +61,7 @@ private:
|
|||
void UpdateFunctionCalls(const Common::Symbol* symbol);
|
||||
void UpdateFunctionCallers(const Common::Symbol* symbol);
|
||||
|
||||
void OnPPCSymbolsChanged();
|
||||
void OnSearchAddress();
|
||||
void OnSearchSymbols();
|
||||
void OnSelectSymbol();
|
||||
|
@ -71,8 +73,9 @@ private:
|
|||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
Core::System& m_system;
|
||||
PPCSymbolDB& m_ppc_symbol_db;
|
||||
|
||||
BranchWatchDialog* m_branch_watch_dialog;
|
||||
BranchWatchDialog* m_branch_watch_dialog = nullptr;
|
||||
QLineEdit* m_search_address;
|
||||
QPushButton* m_branch_watch;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "Common/GekkoDisassembler.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/System.h"
|
||||
#include "UICommon/Disassembler.h"
|
||||
|
||||
#include "DolphinQt/Host.h"
|
||||
|
@ -136,7 +137,7 @@ void JITWidget::Update()
|
|||
if (!isVisible())
|
||||
return;
|
||||
|
||||
if (!m_address || (Core::GetState() != Core::State::Paused))
|
||||
if (!m_address || (Core::GetState(Core::System::GetInstance()) != Core::State::Paused))
|
||||
{
|
||||
m_ppc_asm_widget->setHtml(QStringLiteral("<i>%1</i>").arg(tr("(ppc)")));
|
||||
m_host_asm_widget->setHtml(QStringLiteral("<i>%1</i>").arg(tr("(host)")));
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include "DolphinQt/Debugger/MemoryViewWidget.h"
|
||||
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QHBoxLayout>
|
||||
|
@ -14,10 +17,10 @@
|
|||
#include <QTableWidget>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <cmath>
|
||||
#include <fmt/printf.h>
|
||||
|
||||
#include "Common/Align.h"
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/FloatUtils.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Swap.h"
|
||||
|
@ -154,7 +157,7 @@ public:
|
|||
u32 end_address = address + static_cast<u32>(bytes.size()) - 1;
|
||||
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_view->GetAddressSpace());
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(m_view->m_system);
|
||||
|
||||
if (!bytes.empty() && accessors->IsValidAddress(guard, address) &&
|
||||
accessors->IsValidAddress(guard, end_address))
|
||||
|
@ -170,8 +173,8 @@ private:
|
|||
MemoryViewWidget* m_view;
|
||||
};
|
||||
|
||||
MemoryViewWidget::MemoryViewWidget(QWidget* parent)
|
||||
: QWidget(parent), m_system(Core::System::GetInstance())
|
||||
MemoryViewWidget::MemoryViewWidget(Core::System& system, QWidget* parent)
|
||||
: QWidget(parent), m_system(system)
|
||||
{
|
||||
auto* layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
@ -202,18 +205,18 @@ MemoryViewWidget::MemoryViewWidget(QWidget* parent)
|
|||
connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryViewWidget::Update);
|
||||
|
||||
// Also calls create table.
|
||||
UpdateFont();
|
||||
UpdateFont(Settings::Instance().GetDebugFont());
|
||||
}
|
||||
|
||||
void MemoryViewWidget::UpdateFont()
|
||||
void MemoryViewWidget::UpdateFont(const QFont& font)
|
||||
{
|
||||
const QFontMetrics fm(Settings::Instance().GetDebugFont());
|
||||
const QFontMetrics fm(font);
|
||||
m_font_vspace = fm.lineSpacing() + 4;
|
||||
// BoundingRect is too unpredictable, a custom one would be needed for each view type. Different
|
||||
// fonts have wildly different spacing between two characters and horizontalAdvance includes
|
||||
// spacing.
|
||||
m_font_width = fm.horizontalAdvance(QLatin1Char('0'));
|
||||
m_table->setFont(Settings::Instance().GetDebugFont());
|
||||
m_table->setFont(font);
|
||||
|
||||
CreateTable();
|
||||
}
|
||||
|
@ -441,9 +444,9 @@ void MemoryViewWidget::UpdateColumns()
|
|||
if (m_table->item(1, 1) == nullptr)
|
||||
return;
|
||||
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
if (Core::GetState(m_system) == Core::State::Paused)
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(m_system);
|
||||
UpdateColumns(&guard);
|
||||
}
|
||||
else
|
||||
|
@ -520,11 +523,11 @@ QString MemoryViewWidget::ValueToString(const Core::CPUThreadGuard& guard, u32 a
|
|||
case Type::Unsigned32:
|
||||
return QString::number(accessors->ReadU32(guard, address));
|
||||
case Type::Signed8:
|
||||
return QString::number(Common::BitCast<s8>(accessors->ReadU8(guard, address)));
|
||||
return QString::number(std::bit_cast<s8>(accessors->ReadU8(guard, address)));
|
||||
case Type::Signed16:
|
||||
return QString::number(Common::BitCast<s16>(accessors->ReadU16(guard, address)));
|
||||
return QString::number(std::bit_cast<s16>(accessors->ReadU16(guard, address)));
|
||||
case Type::Signed32:
|
||||
return QString::number(Common::BitCast<s32>(accessors->ReadU32(guard, address)));
|
||||
return QString::number(std::bit_cast<s32>(accessors->ReadU32(guard, address)));
|
||||
case Type::Float32:
|
||||
{
|
||||
QString string = QString::number(accessors->ReadF32(guard, address), 'g', 4);
|
||||
|
@ -537,7 +540,7 @@ QString MemoryViewWidget::ValueToString(const Core::CPUThreadGuard& guard, u32 a
|
|||
case Type::Double:
|
||||
{
|
||||
QString string =
|
||||
QString::number(Common::BitCast<double>(accessors->ReadU64(guard, address)), 'g', 4);
|
||||
QString::number(std::bit_cast<double>(accessors->ReadU64(guard, address)), 'g', 4);
|
||||
// Align to first digit.
|
||||
if (!string.startsWith(QLatin1Char('-')))
|
||||
string.prepend(QLatin1Char(' '));
|
||||
|
@ -635,7 +638,7 @@ std::vector<u8> MemoryViewWidget::ConvertTextToBytes(Type type, QStringView inpu
|
|||
|
||||
if (good)
|
||||
{
|
||||
const u32 value = Common::BitCast<u32>(float_value);
|
||||
const u32 value = std::bit_cast<u32>(float_value);
|
||||
auto std_array = Common::BitCastToArray<u8>(Common::swap32(value));
|
||||
return std::vector<u8>(std_array.begin(), std_array.end());
|
||||
}
|
||||
|
@ -647,7 +650,7 @@ std::vector<u8> MemoryViewWidget::ConvertTextToBytes(Type type, QStringView inpu
|
|||
|
||||
if (good)
|
||||
{
|
||||
const u64 value = Common::BitCast<u64>(double_value);
|
||||
const u64 value = std::bit_cast<u64>(double_value);
|
||||
auto std_array = Common::BitCastToArray<u8>(Common::swap64(value));
|
||||
return std::vector<u8>(std_array.begin(), std_array.end());
|
||||
}
|
||||
|
@ -850,12 +853,8 @@ void MemoryViewWidget::OnCopyHex(u32 addr)
|
|||
{
|
||||
const auto length = GetTypeSize(m_type);
|
||||
|
||||
const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space);
|
||||
|
||||
const u64 value = [addr, accessors] {
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
return accessors->ReadU64(guard, addr);
|
||||
}();
|
||||
const u64 value =
|
||||
AddressSpace::GetAccessors(m_address_space)->ReadU64(Core::CPUThreadGuard{m_system}, addr);
|
||||
|
||||
QApplication::clipboard()->setText(
|
||||
QStringLiteral("%1").arg(value, sizeof(u64) * 2, 16, QLatin1Char('0')).left(length * 2));
|
||||
|
@ -873,14 +872,11 @@ void MemoryViewWidget::OnContextMenu(const QPoint& pos)
|
|||
const u32 addr = item_selected->data(USER_ROLE_CELL_ADDRESS).toUInt();
|
||||
const bool item_has_value =
|
||||
item_selected->data(USER_ROLE_VALUE_TYPE).toInt() != static_cast<int>(Type::Null) &&
|
||||
[this, addr] {
|
||||
const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space);
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
return accessors->IsValidAddress(guard, addr);
|
||||
}();
|
||||
AddressSpace::GetAccessors(m_address_space)
|
||||
->IsValidAddress(Core::CPUThreadGuard{m_system}, addr);
|
||||
|
||||
auto* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
menu->addAction(tr("Copy Address"), this, [this, addr] { OnCopyAddress(addr); });
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class QFont;
|
||||
class QPoint;
|
||||
class QScrollBar;
|
||||
|
||||
|
@ -53,11 +54,11 @@ public:
|
|||
WriteOnly
|
||||
};
|
||||
|
||||
explicit MemoryViewWidget(QWidget* parent = nullptr);
|
||||
explicit MemoryViewWidget(Core::System& system, QWidget* parent = nullptr);
|
||||
|
||||
void CreateTable();
|
||||
void Update();
|
||||
void UpdateFont();
|
||||
void UpdateFont(const QFont& font);
|
||||
void ToggleBreakpoint(u32 addr, bool row);
|
||||
|
||||
std::vector<u8> ConvertTextToBytes(Type type, QStringView input_text) const;
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
|
||||
using Type = MemoryViewWidget::Type;
|
||||
|
||||
MemoryWidget::MemoryWidget(QWidget* parent) : QDockWidget(parent)
|
||||
MemoryWidget::MemoryWidget(Core::System& system, QWidget* parent)
|
||||
: QDockWidget(parent), m_system(system)
|
||||
{
|
||||
setWindowTitle(tr("Memory"));
|
||||
setObjectName(QStringLiteral("memory"));
|
||||
|
@ -199,6 +200,7 @@ void MemoryWidget::CreateWidgets()
|
|||
m_display_combo->addItem(tr("Double"), int(Type::Double));
|
||||
|
||||
m_align_combo = new QComboBox;
|
||||
// i18n: "Fixed" here means that the alignment is always the same
|
||||
m_align_combo->addItem(tr("Fixed Alignment"));
|
||||
m_align_combo->addItem(tr("Type-based Alignment"), 0);
|
||||
m_align_combo->addItem(tr("No Alignment"), 1);
|
||||
|
@ -287,7 +289,7 @@ void MemoryWidget::CreateWidgets()
|
|||
sidebar_scroll->setWidget(sidebar);
|
||||
sidebar_scroll->setWidgetResizable(true);
|
||||
|
||||
m_memory_view = new MemoryViewWidget(this);
|
||||
m_memory_view = new MemoryViewWidget(m_system, this);
|
||||
|
||||
m_splitter->addWidget(m_memory_view);
|
||||
m_splitter->addWidget(sidebar_scroll);
|
||||
|
@ -496,7 +498,7 @@ void MemoryWidget::SetAddress(u32 address)
|
|||
AddressSpace::Accessors* accessors =
|
||||
AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(m_system);
|
||||
good = accessors->IsValidAddress(guard, current_addr);
|
||||
}
|
||||
|
||||
|
@ -627,7 +629,7 @@ QByteArray MemoryWidget::GetInputData() const
|
|||
|
||||
void MemoryWidget::OnSetValue()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
if (!Core::IsRunning(m_system))
|
||||
return;
|
||||
|
||||
auto target_addr = GetTargetAddress();
|
||||
|
@ -653,7 +655,7 @@ void MemoryWidget::OnSetValue()
|
|||
return;
|
||||
}
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(m_system);
|
||||
|
||||
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
|
||||
u32 end_address = target_addr.address + static_cast<u32>(bytes.size()) - 1;
|
||||
|
@ -673,7 +675,7 @@ void MemoryWidget::OnSetValue()
|
|||
|
||||
void MemoryWidget::OnSetValueFromFile()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
if (!Core::IsRunning(m_system))
|
||||
return;
|
||||
|
||||
auto target_addr = GetTargetAddress();
|
||||
|
@ -715,7 +717,7 @@ void MemoryWidget::OnSetValueFromFile()
|
|||
|
||||
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(m_system);
|
||||
|
||||
for (u8 b : file_contents)
|
||||
accessors->WriteU8(guard, target_addr.address++, b);
|
||||
|
@ -833,7 +835,7 @@ void MemoryWidget::FindValue(bool next)
|
|||
AddressSpace::Accessors* accessors =
|
||||
AddressSpace::GetAccessors(m_memory_view->GetAddressSpace());
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(m_system);
|
||||
return accessors->Search(guard, target_addr.address,
|
||||
reinterpret_cast<const u8*>(search_for.data()),
|
||||
static_cast<u32>(search_for.size()), next);
|
||||
|
|
|
@ -22,14 +22,15 @@ class QSplitter;
|
|||
|
||||
namespace Core
|
||||
{
|
||||
class System;
|
||||
class CPUThreadGuard;
|
||||
}
|
||||
} // namespace Core
|
||||
|
||||
class MemoryWidget : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MemoryWidget(QWidget* parent = nullptr);
|
||||
explicit MemoryWidget(Core::System& system, QWidget* parent = nullptr);
|
||||
~MemoryWidget();
|
||||
|
||||
void SetAddress(u32 address);
|
||||
|
@ -78,6 +79,8 @@ private:
|
|||
void closeEvent(QCloseEvent*) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
Core::System& m_system;
|
||||
|
||||
MemoryViewWidget* m_memory_view;
|
||||
QSplitter* m_splitter;
|
||||
QComboBox* m_search_address;
|
||||
|
|
|
@ -239,7 +239,8 @@ void NetworkWidget::Update()
|
|||
if (!isVisible())
|
||||
return;
|
||||
|
||||
if (Core::GetState() != Core::State::Paused)
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (Core::GetState(system) != Core::State::Paused)
|
||||
{
|
||||
m_socket_table->setDisabled(true);
|
||||
m_ssl_table->setDisabled(true);
|
||||
|
@ -250,9 +251,9 @@ void NetworkWidget::Update()
|
|||
m_ssl_table->setDisabled(false);
|
||||
|
||||
// needed because there's a race condition on the IOS instance otherwise
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
auto* ios = guard.GetSystem().GetIOS();
|
||||
auto* ios = system.GetIOS();
|
||||
if (!ios)
|
||||
return;
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ void RegisterWidget::ConnectWidgets()
|
|||
connect(m_table, &QTableWidget::customContextMenuRequested, this,
|
||||
&RegisterWidget::ShowContextMenu);
|
||||
connect(m_table, &QTableWidget::itemChanged, this, &RegisterWidget::OnItemChanged);
|
||||
connect(&Settings::Instance(), &Settings::DebugFontChanged, m_table, &QWidget::setFont);
|
||||
connect(&Settings::Instance(), &Settings::DebugFontChanged, m_table, &RegisterWidget::setFont);
|
||||
}
|
||||
|
||||
void RegisterWidget::OnItemChanged(QTableWidgetItem* item)
|
||||
|
@ -118,6 +118,7 @@ void RegisterWidget::OnItemChanged(QTableWidgetItem* item)
|
|||
void RegisterWidget::ShowContextMenu()
|
||||
{
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
auto* raw_item = m_table->currentItem();
|
||||
|
||||
|
@ -533,7 +534,7 @@ void RegisterWidget::AddRegister(int row, int column, RegisterType type, std::st
|
|||
|
||||
void RegisterWidget::Update()
|
||||
{
|
||||
if (isVisible() && Core::GetState() == Core::State::Paused)
|
||||
if (isVisible() && Core::GetState(m_system) == Core::State::Paused)
|
||||
{
|
||||
m_updating = true;
|
||||
emit UpdateTable();
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "DolphinQt/Debugger/ThreadWidget.h"
|
||||
|
||||
#include <bit>
|
||||
|
||||
#include <QGroupBox>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
|
@ -11,12 +13,12 @@
|
|||
#include <QTableWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/QtUtils/FromStdString.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
ThreadWidget::ThreadWidget(QWidget* parent) : QDockWidget(parent)
|
||||
|
@ -118,6 +120,8 @@ void ThreadWidget::ShowContextMenu(QTableWidget* table)
|
|||
return;
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
const QString watch_name = QStringLiteral("thread_context_%1").arg(addr, 8, 16, QLatin1Char('0'));
|
||||
menu->addAction(tr("Add &breakpoint"), this, [this, addr] { emit RequestBreakpoint(addr); });
|
||||
menu->addAction(tr("Add memory breakpoint"), this,
|
||||
|
@ -252,13 +256,14 @@ void ThreadWidget::Update()
|
|||
if (!isVisible())
|
||||
return;
|
||||
|
||||
const auto emu_state = Core::GetState();
|
||||
auto& system = Core::System::GetInstance();
|
||||
const auto emu_state = Core::GetState(system);
|
||||
if (emu_state == Core::State::Stopping)
|
||||
{
|
||||
m_thread_table->setRowCount(0);
|
||||
UpdateThreadContext({});
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
UpdateThreadCallstack(guard, {});
|
||||
}
|
||||
if (emu_state != Core::State::Paused)
|
||||
|
@ -303,7 +308,7 @@ void ThreadWidget::Update()
|
|||
};
|
||||
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
// YAGCD - Section 4.2.1.4 Dolphin OS Globals
|
||||
m_current_context->setText(format_hex_from(guard, 0x800000D4));
|
||||
|
@ -359,8 +364,7 @@ void ThreadWidget::UpdateThreadContext(const Common::Debug::PartialContext& cont
|
|||
const auto format_f64_as_u64_idx = [](const auto& table, std::size_t index) {
|
||||
if (!table || index >= table->size())
|
||||
return QString{};
|
||||
return QStringLiteral("%1").arg(Common::BitCast<u64>(table->at(index)), 16, 16,
|
||||
QLatin1Char('0'));
|
||||
return QStringLiteral("%1").arg(std::bit_cast<u64>(table->at(index)), 16, 16, QLatin1Char('0'));
|
||||
};
|
||||
|
||||
m_context_table->setRowCount(0);
|
||||
|
@ -460,7 +464,7 @@ void ThreadWidget::UpdateThreadCallstack(const Core::CPUThreadGuard& guard,
|
|||
m_callstack_table->setItem(i, 2, new QTableWidgetItem(format_hex(lr_save)));
|
||||
m_callstack_table->setItem(
|
||||
i, 3,
|
||||
new QTableWidgetItem(QString::fromStdString(
|
||||
new QTableWidgetItem(QtUtils::FromStdString(
|
||||
guard.GetSystem().GetPowerPC().GetDebugInterface().GetDescription(lr_save))));
|
||||
}
|
||||
else
|
||||
|
|
|
@ -143,7 +143,7 @@ void WatchWidget::UpdateButtonsEnabled()
|
|||
if (!isVisible())
|
||||
return;
|
||||
|
||||
const bool is_enabled = Core::IsRunning();
|
||||
const bool is_enabled = Core::IsRunning(m_system);
|
||||
m_new->setEnabled(is_enabled);
|
||||
m_delete->setEnabled(is_enabled);
|
||||
m_clear->setEnabled(is_enabled);
|
||||
|
@ -158,7 +158,7 @@ void WatchWidget::Update()
|
|||
|
||||
m_updating = true;
|
||||
|
||||
if (Core::GetState() != Core::State::Paused)
|
||||
if (Core::GetState(m_system) != Core::State::Paused)
|
||||
{
|
||||
m_table->setDisabled(true);
|
||||
m_updating = false;
|
||||
|
@ -195,10 +195,10 @@ void WatchWidget::Update()
|
|||
|
||||
QBrush brush = QPalette().brush(QPalette::Text);
|
||||
|
||||
if (!Core::IsRunning() || !PowerPC::MMU::HostIsRAMAddress(guard, entry.address))
|
||||
if (!Core::IsRunning(m_system) || !PowerPC::MMU::HostIsRAMAddress(guard, entry.address))
|
||||
brush.setColor(Qt::red);
|
||||
|
||||
if (Core::IsRunning())
|
||||
if (Core::IsRunning(m_system))
|
||||
{
|
||||
if (PowerPC::MMU::HostIsRAMAddress(guard, entry.address))
|
||||
{
|
||||
|
@ -327,6 +327,7 @@ void WatchWidget::OnSave()
|
|||
void WatchWidget::ShowContextMenu()
|
||||
{
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
if (!m_table->selectedItems().empty())
|
||||
{
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
<ClCompile Include="CheatSearchFactoryWidget.cpp" />
|
||||
<ClCompile Include="CheatSearchWidget.cpp" />
|
||||
<ClCompile Include="CheatsManager.cpp" />
|
||||
<ClCompile Include="Achievements\AchievementBox.cpp" />
|
||||
<ClCompile Include="Achievements\AchievementHeaderWidget.cpp" />
|
||||
<ClCompile Include="Achievements\AchievementLeaderboardWidget.cpp" />
|
||||
<ClCompile Include="Achievements\AchievementProgressWidget.cpp" />
|
||||
|
@ -274,6 +275,7 @@
|
|||
<QtMoc Include="CheatSearchFactoryWidget.h" />
|
||||
<QtMoc Include="CheatSearchWidget.h" />
|
||||
<QtMoc Include="CheatsManager.h" />
|
||||
<QtMoc Include="Achievements\AchievementBox.h" />
|
||||
<QtMoc Include="Achievements\AchievementHeaderWidget.h" />
|
||||
<QtMoc Include="Achievements\AchievementLeaderboardWidget.h" />
|
||||
<QtMoc Include="Achievements\AchievementProgressWidget.h" />
|
||||
|
@ -403,6 +405,7 @@
|
|||
<QtMoc Include="QtUtils\DoubleClickEventFilter.h" />
|
||||
<QtMoc Include="QtUtils\ElidedButton.h" />
|
||||
<QtMoc Include="QtUtils\FileOpenEventFilter.h" />
|
||||
<ClInclude Include="QtUtils\FromStdString.h" />
|
||||
<QtMoc Include="QtUtils\ParallelProgressDialog.h" />
|
||||
<QtMoc Include="QtUtils\PartiallyClosableTabWidget.h" />
|
||||
<ClInclude Include="QtUtils\SetWindowDecorations.h" />
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "DolphinQt/FIFO/FIFOAnalyzer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
|
@ -51,13 +52,9 @@ FIFOAnalyzer::FIFOAnalyzer(FifoPlayer& fifo_player) : m_fifo_player(fifo_player)
|
|||
m_search_splitter->restoreState(
|
||||
settings.value(QStringLiteral("fifoanalyzer/searchsplitter")).toByteArray());
|
||||
|
||||
m_detail_list->setFont(Settings::Instance().GetDebugFont());
|
||||
m_entry_detail_browser->setFont(Settings::Instance().GetDebugFont());
|
||||
|
||||
connect(&Settings::Instance(), &Settings::DebugFontChanged, this, [this] {
|
||||
m_detail_list->setFont(Settings::Instance().GetDebugFont());
|
||||
m_entry_detail_browser->setFont(Settings::Instance().GetDebugFont());
|
||||
});
|
||||
OnDebugFontChanged(Settings::Instance().GetDebugFont());
|
||||
connect(&Settings::Instance(), &Settings::DebugFontChanged, this,
|
||||
&FIFOAnalyzer::OnDebugFontChanged);
|
||||
}
|
||||
|
||||
FIFOAnalyzer::~FIFOAnalyzer()
|
||||
|
@ -650,7 +647,7 @@ public:
|
|||
}
|
||||
if (format == ComponentFormat::Float)
|
||||
{
|
||||
const float value = Common::BitCast<float>(Common::swap32(&vertex_data[i]));
|
||||
const float value = std::bit_cast<float>(Common::swap32(&vertex_data[i]));
|
||||
text += QStringLiteral(" (%1)").arg(value);
|
||||
}
|
||||
i += component_size;
|
||||
|
@ -779,3 +776,9 @@ void FIFOAnalyzer::UpdateDescription()
|
|||
object_size - entry_start, callback);
|
||||
m_entry_detail_browser->setText(callback.text);
|
||||
}
|
||||
|
||||
void FIFOAnalyzer::OnDebugFontChanged(const QFont& font)
|
||||
{
|
||||
m_detail_list->setFont(font);
|
||||
m_entry_detail_browser->setFont(font);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
|
||||
class FifoPlayer;
|
||||
class QFont;
|
||||
class QGroupBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
|
@ -43,6 +44,8 @@ private:
|
|||
void UpdateDetails();
|
||||
void UpdateDescription();
|
||||
|
||||
void OnDebugFontChanged(const QFont& font);
|
||||
|
||||
FifoPlayer& m_fifo_player;
|
||||
|
||||
QTreeWidget* m_tree_widget;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "Core/FifoPlayer/FifoDataFile.h"
|
||||
#include "Core/FifoPlayer/FifoPlayer.h"
|
||||
#include "Core/FifoPlayer/FifoRecorder.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h"
|
||||
#include "DolphinQt/FIFO/FIFOAnalyzer.h"
|
||||
|
@ -316,7 +317,7 @@ void FIFOPlayerWindow::UpdateInfo()
|
|||
return;
|
||||
}
|
||||
|
||||
if (Core::IsRunning() && m_fifo_recorder.IsRecording())
|
||||
if (Core::IsRunning(Core::System::GetInstance()) && m_fifo_recorder.IsRecording())
|
||||
{
|
||||
m_info_label->setText(tr("Recording..."));
|
||||
return;
|
||||
|
@ -375,7 +376,7 @@ void FIFOPlayerWindow::UpdateLimits()
|
|||
|
||||
void FIFOPlayerWindow::UpdateControls()
|
||||
{
|
||||
bool running = Core::IsRunning();
|
||||
bool running = Core::IsRunning(Core::System::GetInstance());
|
||||
bool is_recording = m_fifo_recorder.IsRecording();
|
||||
bool is_playing = m_fifo_player.IsPlaying();
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
static void RestartCore(const std::weak_ptr<HW::GBA::Core>& core, std::string_view rom_path = {})
|
||||
{
|
||||
Core::RunOnCPUThread(
|
||||
[core, rom_path = std::string(rom_path)] {
|
||||
Core::System::GetInstance(),
|
||||
[core, rom_path = std::string(rom_path)]() {
|
||||
if (auto core_ptr = core.lock())
|
||||
{
|
||||
auto& info = Config::MAIN_GBA_ROM_PATHS[core_ptr->GetCoreInfo().device_number];
|
||||
|
@ -57,7 +58,8 @@ static void RestartCore(const std::weak_ptr<HW::GBA::Core>& core, std::string_vi
|
|||
static void QueueEReaderCard(const std::weak_ptr<HW::GBA::Core>& core, std::string_view card_path)
|
||||
{
|
||||
Core::RunOnCPUThread(
|
||||
[core, card_path = std::string(card_path)] {
|
||||
Core::System::GetInstance(),
|
||||
[core, card_path = std::string(card_path)]() {
|
||||
if (auto core_ptr = core.lock())
|
||||
core_ptr->EReaderQueueCard(card_path);
|
||||
},
|
||||
|
@ -159,7 +161,8 @@ void GBAWidget::ToggleDisconnect()
|
|||
m_force_disconnect = !m_force_disconnect;
|
||||
|
||||
Core::RunOnCPUThread(
|
||||
[core = m_core, force_disconnect = m_force_disconnect] {
|
||||
Core::System::GetInstance(),
|
||||
[core = m_core, force_disconnect = m_force_disconnect]() {
|
||||
if (auto core_ptr = core.lock())
|
||||
core_ptr->SetForceDisconnect(force_disconnect);
|
||||
},
|
||||
|
@ -221,7 +224,8 @@ void GBAWidget::DoState(bool export_state)
|
|||
return;
|
||||
|
||||
Core::RunOnCPUThread(
|
||||
[export_state, core = m_core, state_path = state_path.toStdString()] {
|
||||
Core::System::GetInstance(),
|
||||
[export_state, core = m_core, state_path = state_path.toStdString()]() {
|
||||
if (auto core_ptr = core.lock())
|
||||
{
|
||||
if (export_state)
|
||||
|
@ -251,7 +255,8 @@ void GBAWidget::ImportExportSave(bool export_save)
|
|||
return;
|
||||
|
||||
Core::RunOnCPUThread(
|
||||
[export_save, core = m_core, save_path = save_path.toStdString()] {
|
||||
Core::System::GetInstance(),
|
||||
[export_save, core = m_core, save_path = save_path.toStdString()]() {
|
||||
if (auto core_ptr = core.lock())
|
||||
{
|
||||
if (export_save)
|
||||
|
|
|
@ -370,8 +370,10 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
{
|
||||
if (!GetSelectedGame())
|
||||
return;
|
||||
auto& system = Core::System::GetInstance();
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
if (HasMultipleSelected())
|
||||
{
|
||||
|
@ -421,8 +423,8 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
QAction* change_disc = menu->addAction(tr("Change &Disc"), this, &GameList::ChangeDisc);
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, change_disc,
|
||||
[change_disc] { change_disc->setEnabled(Core::IsRunning()); });
|
||||
change_disc->setEnabled(Core::IsRunning());
|
||||
[&system, change_disc] { change_disc->setEnabled(Core::IsRunning(system)); });
|
||||
change_disc->setEnabled(Core::IsRunning(system));
|
||||
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
@ -436,7 +438,7 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
// system menu, trigger a refresh.
|
||||
Settings::Instance().NANDRefresh();
|
||||
});
|
||||
perform_disc_update->setEnabled(!Core::IsRunning() || !Core::System::GetInstance().IsWii());
|
||||
perform_disc_update->setEnabled(!Core::IsRunning(system) || !system.IsWii());
|
||||
}
|
||||
|
||||
if (!is_mod_descriptor && platform == DiscIO::Platform::WiiWAD)
|
||||
|
@ -449,10 +451,10 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
|
||||
for (QAction* a : {wad_install_action, wad_uninstall_action})
|
||||
{
|
||||
a->setEnabled(!Core::IsRunning());
|
||||
a->setEnabled(!Core::IsRunning(system));
|
||||
menu->addAction(a);
|
||||
}
|
||||
if (!Core::IsRunning())
|
||||
if (!Core::IsRunning(system))
|
||||
wad_uninstall_action->setEnabled(WiiUtils::IsTitleInstalled(game->GetTitleID()));
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu,
|
||||
|
@ -473,8 +475,8 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
QAction* export_wii_save =
|
||||
menu->addAction(tr("Export Wii Save"), this, &GameList::ExportWiiSave);
|
||||
|
||||
open_wii_save_folder->setEnabled(!Core::IsRunning());
|
||||
export_wii_save->setEnabled(!Core::IsRunning());
|
||||
open_wii_save_folder->setEnabled(!Core::IsRunning(system));
|
||||
export_wii_save->setEnabled(!Core::IsRunning(system));
|
||||
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
@ -531,7 +533,7 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
|
||||
netplay_host->setEnabled(state == Core::State::Uninitialized);
|
||||
});
|
||||
netplay_host->setEnabled(!Core::IsRunning());
|
||||
netplay_host->setEnabled(!Core::IsRunning(system));
|
||||
|
||||
menu->addAction(netplay_host);
|
||||
}
|
||||
|
@ -879,9 +881,8 @@ void GameList::ChangeDisc()
|
|||
if (!game)
|
||||
return;
|
||||
|
||||
Core::RunAsCPUThread([file_path = game->GetFilePath()] {
|
||||
Core::System::GetInstance().GetDVDInterface().ChangeDisc(file_path);
|
||||
});
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetDVDInterface().ChangeDisc(Core::CPUThreadGuard{system}, game->GetFilePath());
|
||||
}
|
||||
|
||||
QAbstractItemView* GameList::GetActiveView() const
|
||||
|
|
|
@ -92,14 +92,14 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
|
|||
{
|
||||
QString name = QString::fromStdString(game.GetName(m_title_database));
|
||||
|
||||
// Add disc numbers > 1 to title if not present.
|
||||
const int disc_nr = game.GetDiscNumber() + 1;
|
||||
if (disc_nr > 1)
|
||||
const int disc_number = game.GetDiscNumber() + 1;
|
||||
if (disc_number > 1 || game.IsTwoDiscGame())
|
||||
{
|
||||
if (!name.contains(QRegularExpression(QStringLiteral("disc ?%1").arg(disc_nr),
|
||||
// Add disc number to title if not present.
|
||||
if (!name.contains(QRegularExpression(QStringLiteral("disc ?%1").arg(disc_number),
|
||||
QRegularExpression::CaseInsensitiveOption)))
|
||||
{
|
||||
name.append(tr(" (Disc %1)").arg(disc_nr));
|
||||
name.append(tr(" (Disc %1)").arg(disc_number));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,8 +103,8 @@ static void RunWithGPUThreadInactive(std::function<void()> f)
|
|||
// (Note that this case cannot be reached in single core mode, because in single core mode,
|
||||
// the CPU and GPU threads are the same thread, and we already checked for the GPU thread.)
|
||||
|
||||
const bool was_running = Core::GetState() == Core::State::Running;
|
||||
auto& system = Core::System::GetInstance();
|
||||
const bool was_running = Core::GetState(system) == Core::State::Running;
|
||||
auto& fifo = system.GetFifo();
|
||||
fifo.PauseAndLock(true, was_running);
|
||||
f();
|
||||
|
@ -112,9 +112,9 @@ static void RunWithGPUThreadInactive(std::function<void()> f)
|
|||
}
|
||||
else
|
||||
{
|
||||
// If we reach here, we can call Core::PauseAndLock (which we do using RunAsCPUThread).
|
||||
|
||||
Core::RunAsCPUThread(std::move(f));
|
||||
// If we reach here, we can call Core::PauseAndLock (which we do using a CPUThreadGuard).
|
||||
const Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,14 +238,9 @@ void Host_UpdateDisasmDialog()
|
|||
QueueOnObject(QApplication::instance(), [] { emit Host::GetInstance()->UpdateDisasmDialog(); });
|
||||
}
|
||||
|
||||
void Host::RequestNotifyMapLoaded()
|
||||
void Host_PPCSymbolsChanged()
|
||||
{
|
||||
QueueOnObject(QApplication::instance(), [this] { emit NotifyMapLoaded(); });
|
||||
}
|
||||
|
||||
void Host_NotifyMapLoaded()
|
||||
{
|
||||
Host::GetInstance()->RequestNotifyMapLoaded();
|
||||
QueueOnObject(QApplication::instance(), [] { emit Host::GetInstance()->PPCSymbolsChanged(); });
|
||||
}
|
||||
|
||||
// We ignore these, and their purpose should be questioned individually.
|
||||
|
|
|
@ -32,14 +32,13 @@ public:
|
|||
void SetRenderFullFocus(bool focus);
|
||||
void SetRenderFullscreen(bool fullscreen);
|
||||
void ResizeSurface(int new_width, int new_height);
|
||||
void RequestNotifyMapLoaded();
|
||||
|
||||
signals:
|
||||
void RequestTitle(const QString& title);
|
||||
void RequestStop();
|
||||
void RequestRenderSize(int w, int h);
|
||||
void UpdateDisasmDialog();
|
||||
void NotifyMapLoaded();
|
||||
void PPCSymbolsChanged();
|
||||
|
||||
private:
|
||||
Host();
|
||||
|
|
|
@ -113,7 +113,7 @@ static void HandleFrameStepHotkeys()
|
|||
|
||||
if ((frame_step_count == 0 || frame_step_count == FRAME_STEP_DELAY) && !frame_step_hold)
|
||||
{
|
||||
Core::DoFrameStep();
|
||||
Core::DoFrameStep(Core::System::GetInstance());
|
||||
frame_step_hold = true;
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ void HotkeyScheduler::Run()
|
|||
if (!HotkeyManagerEmu::IsEnabled())
|
||||
continue;
|
||||
|
||||
if (Core::GetState() != Core::State::Stopping)
|
||||
if (Core::GetState(Core::System::GetInstance()) != Core::State::Stopping)
|
||||
{
|
||||
// Obey window focus (config permitting) before checking hotkeys.
|
||||
Core::UpdateInputGate(Config::Get(Config::MAIN_FOCUSED_HOTKEYS));
|
||||
|
|
|
@ -35,6 +35,7 @@ static QString s_last_figure_path;
|
|||
|
||||
InfinityBaseWindow::InfinityBaseWindow(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
// i18n: Window for managing Disney Infinity figures
|
||||
setWindowTitle(tr("Infinity Manager"));
|
||||
setObjectName(QStringLiteral("infinity_manager"));
|
||||
setMinimumSize(QSize(700, 200));
|
||||
|
@ -46,7 +47,7 @@ InfinityBaseWindow::InfinityBaseWindow(QWidget* parent) : QWidget(parent)
|
|||
|
||||
installEventFilter(this);
|
||||
|
||||
OnEmulationStateChanged(Core::GetState());
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
};
|
||||
|
||||
InfinityBaseWindow::~InfinityBaseWindow() = default;
|
||||
|
@ -164,7 +165,7 @@ void InfinityBaseWindow::LoadFigurePath(u8 slot, const QString& path)
|
|||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Failed to open the Infinity file!"),
|
||||
tr("Failed to open the Infinity file(%1)!\nFile may already be in use on the base.")
|
||||
tr("Failed to open the Infinity file:\n%1\n\nThe file may already be in use on the base.")
|
||||
.arg(path),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
|
@ -172,9 +173,10 @@ void InfinityBaseWindow::LoadFigurePath(u8 slot, const QString& path)
|
|||
std::array<u8, IOS::HLE::USB::INFINITY_NUM_BLOCKS * IOS::HLE::USB::INFINITY_BLOCK_SIZE> file_data;
|
||||
if (!inf_file.ReadBytes(file_data.data(), file_data.size()))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Failed to read the Infinity file!"),
|
||||
tr("Failed to read the Infinity file(%1)!\nFile was too small.").arg(path),
|
||||
QMessageBox::Ok);
|
||||
QMessageBox::warning(
|
||||
this, tr("Failed to read the Infinity file!"),
|
||||
tr("Failed to read the Infinity file(%1):\n%1\n\nThe file was too small.").arg(path),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -274,6 +276,7 @@ CreateFigureDialog::CreateFigureDialog(QWidget* parent, u8 slot) : QDialog(paren
|
|||
}
|
||||
else
|
||||
{
|
||||
// i18n: This is used to create a file name. The string must end in ".bin".
|
||||
QString str = tr("Unknown(%1).bin");
|
||||
predef_name += str.arg(char_number);
|
||||
}
|
||||
|
@ -289,7 +292,7 @@ CreateFigureDialog::CreateFigureDialog(QWidget* parent, u8 slot) : QDialog(paren
|
|||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Failed to create Infinity file"),
|
||||
tr("Blank figure creation failed at:\n%1, try again with a different character")
|
||||
tr("Blank figure creation failed at:\n%1\n\nTry again with a different character.")
|
||||
.arg(m_file_path),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/DolphinAnalytics.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/MainWindow.h"
|
||||
|
@ -54,7 +55,7 @@ static bool QtMsgAlertHandler(const char* caption, const char* text, bool yes_no
|
|||
std::optional<bool> r = RunOnObject(QApplication::instance(), [&] {
|
||||
// If we were called from the CPU/GPU thread, set us as the CPU/GPU thread.
|
||||
// This information is used in order to avoid deadlocks when calling e.g.
|
||||
// Host::SetRenderFocus or Core::RunAsCPUThread. (Host::SetRenderFocus
|
||||
// Host::SetRenderFocus or Core::CPUThreadGuard. (Host::SetRenderFocus
|
||||
// can get called automatically when a dialog steals the focus.)
|
||||
|
||||
Common::ScopeGuard cpu_scope_guard(&Core::UndeclareAsCPUThread);
|
||||
|
@ -187,7 +188,7 @@ int main(int argc, char* argv[])
|
|||
// Whenever the event loop is about to go to sleep, dispatch the jobs
|
||||
// queued in the Core first.
|
||||
QObject::connect(QAbstractEventDispatcher::instance(), &QAbstractEventDispatcher::aboutToBlock,
|
||||
&app, &Core::HostDispatchJobs);
|
||||
&app, [] { Core::HostDispatchJobs(Core::System::GetInstance()); });
|
||||
|
||||
std::optional<std::string> save_state_path;
|
||||
if (options.is_set("save_state"))
|
||||
|
@ -303,7 +304,7 @@ int main(int argc, char* argv[])
|
|||
retval = app.exec();
|
||||
}
|
||||
|
||||
Core::Shutdown();
|
||||
Core::Shutdown(Core::System::GetInstance());
|
||||
UICommon::Shutdown();
|
||||
Host::GetInstance()->deleteLater();
|
||||
|
||||
|
|
|
@ -451,14 +451,14 @@ void MainWindow::CreateComponents()
|
|||
m_jit_widget = new JITWidget(this);
|
||||
m_log_widget = new LogWidget(this);
|
||||
m_log_config_widget = new LogConfigWidget(this);
|
||||
m_memory_widget = new MemoryWidget(this);
|
||||
m_memory_widget = new MemoryWidget(Core::System::GetInstance(), this);
|
||||
m_network_widget = new NetworkWidget(this);
|
||||
m_register_widget = new RegisterWidget(this);
|
||||
m_thread_widget = new ThreadWidget(this);
|
||||
m_watch_widget = new WatchWidget(this);
|
||||
m_breakpoint_widget = new BreakpointWidget(this);
|
||||
m_code_widget = new CodeWidget(this);
|
||||
m_cheats_manager = new CheatsManager(this);
|
||||
m_cheats_manager = new CheatsManager(Core::System::GetInstance(), this);
|
||||
m_assembler_widget = new AssemblerWidget(this);
|
||||
|
||||
const auto request_watch = [this](QString name, u32 addr) {
|
||||
|
@ -501,7 +501,7 @@ void MainWindow::CreateComponents()
|
|||
connect(m_breakpoint_widget, &BreakpointWidget::BreakpointsChanged, m_memory_widget,
|
||||
&MemoryWidget::Update);
|
||||
connect(m_breakpoint_widget, &BreakpointWidget::ShowCode, [this](u32 address) {
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
|
||||
m_code_widget->SetAddress(address, CodeViewWidget::SetAddressUpdate::WithDetailedUpdate);
|
||||
});
|
||||
connect(m_breakpoint_widget, &BreakpointWidget::ShowMemory, m_memory_widget,
|
||||
|
@ -591,12 +591,6 @@ void MainWindow::ConnectMenuBar()
|
|||
connect(m_game_list, &GameList::SelectionChanged, m_menu_bar, &MenuBar::SelectionChanged);
|
||||
connect(this, &MainWindow::ReadOnlyModeChanged, m_menu_bar, &MenuBar::ReadOnlyModeChanged);
|
||||
connect(this, &MainWindow::RecordingStatusChanged, m_menu_bar, &MenuBar::RecordingStatusChanged);
|
||||
|
||||
// Symbols
|
||||
connect(m_menu_bar, &MenuBar::NotifySymbolsUpdated, [this] {
|
||||
m_code_widget->UpdateSymbols();
|
||||
m_code_widget->Update();
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::ConnectHotkeys()
|
||||
|
@ -796,15 +790,17 @@ void MainWindow::ChangeDisc()
|
|||
{
|
||||
std::vector<std::string> paths = StringListToStdVector(PromptFileNames());
|
||||
|
||||
if (!paths.empty())
|
||||
Core::RunAsCPUThread(
|
||||
[&paths] { Core::System::GetInstance().GetDVDInterface().ChangeDisc(paths); });
|
||||
if (paths.empty())
|
||||
return;
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetDVDInterface().ChangeDisc(Core::CPUThreadGuard{system}, paths);
|
||||
}
|
||||
|
||||
void MainWindow::EjectDisc()
|
||||
{
|
||||
Core::RunAsCPUThread(
|
||||
[] { Core::System::GetInstance().GetDVDInterface().EjectDisc(DVD::EjectCause::User); });
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetDVDInterface().EjectDisc(Core::CPUThreadGuard{system}, DVD::EjectCause::User);
|
||||
}
|
||||
|
||||
void MainWindow::OpenUserFolder()
|
||||
|
@ -829,9 +825,9 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
|||
// Otherwise, play the default game.
|
||||
// Otherwise, play the last played game, if there is one.
|
||||
// Otherwise, prompt for a new game.
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
|
||||
{
|
||||
Core::SetState(Core::State::Running);
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Running);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -859,12 +855,12 @@ void MainWindow::Play(const std::optional<std::string>& savestate_path)
|
|||
|
||||
void MainWindow::Pause()
|
||||
{
|
||||
Core::SetState(Core::State::Paused);
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Paused);
|
||||
}
|
||||
|
||||
void MainWindow::TogglePause()
|
||||
{
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
|
||||
{
|
||||
Play();
|
||||
}
|
||||
|
@ -907,9 +903,9 @@ void MainWindow::OnStopComplete()
|
|||
|
||||
bool MainWindow::RequestStop()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
if (!Core::IsRunning(Core::System::GetInstance()))
|
||||
{
|
||||
Core::QueueHostJob([this] { OnStopComplete(); }, true);
|
||||
Core::QueueHostJob([this](Core::System&) { OnStopComplete(); }, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -932,13 +928,13 @@ bool MainWindow::RequestStop()
|
|||
|
||||
Common::ScopeGuard confirm_lock([this] { m_stop_confirm_showing = false; });
|
||||
|
||||
const Core::State state = Core::GetState();
|
||||
const Core::State state = Core::GetState(Core::System::GetInstance());
|
||||
|
||||
// Only pause the game, if NetPlay is not running
|
||||
bool pause = !Settings::Instance().GetNetPlayClient();
|
||||
|
||||
if (pause)
|
||||
Core::SetState(Core::State::Paused);
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Paused);
|
||||
|
||||
if (rendered_widget_was_active)
|
||||
{
|
||||
|
@ -968,7 +964,7 @@ bool MainWindow::RequestStop()
|
|||
m_render_widget->SetWaitingForMessageBox(false);
|
||||
|
||||
if (pause)
|
||||
Core::SetState(state);
|
||||
Core::SetState(Core::System::GetInstance(), state);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -989,8 +985,8 @@ bool MainWindow::RequestStop()
|
|||
|
||||
// Unpause because gracefully shutting down needs the game to actually request a shutdown.
|
||||
// TODO: Do not unpause in debug mode to allow debugging until the complete shutdown.
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
Core::SetState(Core::State::Running);
|
||||
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Running);
|
||||
|
||||
// Tell NetPlay about the power event
|
||||
if (NetPlay::IsNetPlayRunning())
|
||||
|
@ -1009,9 +1005,9 @@ bool MainWindow::RequestStop()
|
|||
|
||||
bool MainWindow::RequestStopNetplay()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
if (!Core::IsRunning(Core::System::GetInstance()))
|
||||
{
|
||||
Core::QueueHostJob([this] { OnStopComplete(); }, true);
|
||||
Core::QueueHostJob([this](Core::System&) { OnStopComplete(); }, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1034,13 +1030,13 @@ bool MainWindow::RequestStopNetplay()
|
|||
|
||||
Common::ScopeGuard confirm_lock([this] { m_stop_confirm_showing = false; });
|
||||
|
||||
const Core::State state = Core::GetState();
|
||||
const Core::State state = Core::GetState(Core::System::GetInstance());
|
||||
|
||||
// Only pause the game, if NetPlay is not running
|
||||
bool pause = !Settings::Instance().GetNetPlayClient();
|
||||
|
||||
if (pause)
|
||||
Core::SetState(Core::State::Paused);
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Paused);
|
||||
|
||||
if (rendered_widget_was_active)
|
||||
{
|
||||
|
@ -1072,7 +1068,7 @@ bool MainWindow::RequestStopNetplay()
|
|||
m_render_widget->SetWaitingForMessageBox(false);
|
||||
|
||||
if (pause)
|
||||
Core::SetState(state);
|
||||
Core::SetState(Core::System::GetInstance(), state);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1093,8 +1089,8 @@ bool MainWindow::RequestStopNetplay()
|
|||
|
||||
// Unpause because gracefully shutting down needs the game to actually request a shutdown.
|
||||
// TODO: Do not unpause in debug mode to allow debugging until the complete shutdown.
|
||||
if (Core::GetState() == Core::State::Paused)
|
||||
Core::SetState(Core::State::Running);
|
||||
if (Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Running);
|
||||
|
||||
// Tell NetPlay about the power event
|
||||
if (NetPlay::IsNetPlayRunning())
|
||||
|
@ -1113,7 +1109,7 @@ bool MainWindow::RequestStopNetplay()
|
|||
|
||||
void MainWindow::ForceStop()
|
||||
{
|
||||
Core::Stop();
|
||||
Core::Stop(Core::System::GetInstance());
|
||||
}
|
||||
|
||||
void MainWindow::Reset()
|
||||
|
@ -1127,7 +1123,7 @@ void MainWindow::Reset()
|
|||
|
||||
void MainWindow::FrameAdvance()
|
||||
{
|
||||
Core::DoFrameStep();
|
||||
Core::DoFrameStep(Core::System::GetInstance());
|
||||
}
|
||||
|
||||
void MainWindow::FullScreen()
|
||||
|
@ -1218,7 +1214,7 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
|||
}
|
||||
|
||||
// If we're running, only start a new game once we've stopped the last.
|
||||
if (Core::GetState() != Core::State::Uninitialized)
|
||||
if (Core::GetState(Core::System::GetInstance()) != Core::State::Uninitialized)
|
||||
{
|
||||
if (!RequestStop())
|
||||
return;
|
||||
|
@ -1232,7 +1228,7 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
|||
ShowRenderWidget();
|
||||
|
||||
// Boot up, show an error if it fails to load the game.
|
||||
if (!BootManager::BootCore(std::move(parameters),
|
||||
if (!BootManager::BootCore(Core::System::GetInstance(), std::move(parameters),
|
||||
::GetWindowSystemInfo(m_render_widget->windowHandle())))
|
||||
{
|
||||
ModalMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok);
|
||||
|
@ -1518,7 +1514,7 @@ void MainWindow::StateLoad()
|
|||
this, tr("Select a File"), dialog_path, tr("All Save States (*.sav *.s##);; All Files (*)"));
|
||||
Config::SetBase(Config::MAIN_CURRENT_STATE_PATH, QFileInfo(path).dir().path().toStdString());
|
||||
if (!path.isEmpty())
|
||||
State::LoadAs(path.toStdString());
|
||||
State::LoadAs(Core::System::GetInstance(), path.toStdString());
|
||||
}
|
||||
|
||||
void MainWindow::StateSave()
|
||||
|
@ -1530,47 +1526,47 @@ void MainWindow::StateSave()
|
|||
this, tr("Select a File"), dialog_path, tr("All Save States (*.sav *.s##);; All Files (*)"));
|
||||
Config::SetBase(Config::MAIN_CURRENT_STATE_PATH, QFileInfo(path).dir().path().toStdString());
|
||||
if (!path.isEmpty())
|
||||
State::SaveAs(path.toStdString());
|
||||
State::SaveAs(Core::System::GetInstance(), path.toStdString());
|
||||
}
|
||||
|
||||
void MainWindow::StateLoadSlot()
|
||||
{
|
||||
State::Load(m_state_slot);
|
||||
State::Load(Core::System::GetInstance(), m_state_slot);
|
||||
}
|
||||
|
||||
void MainWindow::StateSaveSlot()
|
||||
{
|
||||
State::Save(m_state_slot);
|
||||
State::Save(Core::System::GetInstance(), m_state_slot);
|
||||
}
|
||||
|
||||
void MainWindow::StateLoadSlotAt(int slot)
|
||||
{
|
||||
State::Load(slot);
|
||||
State::Load(Core::System::GetInstance(), slot);
|
||||
}
|
||||
|
||||
void MainWindow::StateLoadLastSavedAt(int slot)
|
||||
{
|
||||
State::LoadLastSaved(slot);
|
||||
State::LoadLastSaved(Core::System::GetInstance(), slot);
|
||||
}
|
||||
|
||||
void MainWindow::StateSaveSlotAt(int slot)
|
||||
{
|
||||
State::Save(slot);
|
||||
State::Save(Core::System::GetInstance(), slot);
|
||||
}
|
||||
|
||||
void MainWindow::StateLoadUndo()
|
||||
{
|
||||
State::UndoLoadState();
|
||||
State::UndoLoadState(Core::System::GetInstance());
|
||||
}
|
||||
|
||||
void MainWindow::StateSaveUndo()
|
||||
{
|
||||
State::UndoSaveState();
|
||||
State::UndoSaveState(Core::System::GetInstance());
|
||||
}
|
||||
|
||||
void MainWindow::StateSaveOldest()
|
||||
{
|
||||
State::SaveFirstSaved();
|
||||
State::SaveFirstSaved(Core::System::GetInstance());
|
||||
}
|
||||
|
||||
void MainWindow::SetStateSlot(int slot)
|
||||
|
@ -1643,7 +1639,7 @@ void MainWindow::NetPlayInit()
|
|||
|
||||
bool MainWindow::NetPlayJoin()
|
||||
{
|
||||
if (Core::IsRunning())
|
||||
if (Core::IsRunning(Core::System::GetInstance()))
|
||||
{
|
||||
ModalMessageBox::critical(nullptr, tr("Error"),
|
||||
tr("Can't start a NetPlay Session while a game is still running!"));
|
||||
|
@ -1710,7 +1706,7 @@ bool MainWindow::NetPlayJoin()
|
|||
|
||||
bool MainWindow::NetPlayHost(const UICommon::GameFile& game)
|
||||
{
|
||||
if (Core::IsRunning())
|
||||
if (Core::IsRunning(Core::System::GetInstance()))
|
||||
{
|
||||
ModalMessageBox::critical(nullptr, tr("Error"),
|
||||
tr("Can't start a NetPlay Session while a game is still running!"));
|
||||
|
@ -1771,8 +1767,8 @@ void MainWindow::NetPlayQuit()
|
|||
|
||||
void MainWindow::UpdateScreenSaverInhibition()
|
||||
{
|
||||
const bool inhibit =
|
||||
Config::Get(Config::MAIN_DISABLE_SCREENSAVER) && (Core::GetState() == Core::State::Running);
|
||||
const bool inhibit = Config::Get(Config::MAIN_DISABLE_SCREENSAVER) &&
|
||||
(Core::GetState(Core::System::GetInstance()) == Core::State::Running);
|
||||
|
||||
if (inhibit == m_is_screensaver_inhibited)
|
||||
return;
|
||||
|
@ -1957,7 +1953,7 @@ void MainWindow::OnImportNANDBackup()
|
|||
|
||||
result.wait();
|
||||
|
||||
m_menu_bar->UpdateToolsMenu(Core::IsRunning());
|
||||
m_menu_bar->UpdateToolsMenu(Core::IsRunning(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void MainWindow::OnPlayRecording()
|
||||
|
@ -1987,8 +1983,9 @@ void MainWindow::OnPlayRecording()
|
|||
|
||||
void MainWindow::OnStartRecording()
|
||||
{
|
||||
auto& movie = Core::System::GetInstance().GetMovie();
|
||||
if ((!Core::IsRunningAndStarted() && Core::IsRunning()) || movie.IsRecordingInput() ||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& movie = system.GetMovie();
|
||||
if ((!Core::IsRunningAndStarted() && Core::IsRunning(system)) || movie.IsRecordingInput() ||
|
||||
movie.IsPlayingInput())
|
||||
{
|
||||
return;
|
||||
|
@ -2020,7 +2017,7 @@ void MainWindow::OnStartRecording()
|
|||
{
|
||||
emit RecordingStatusChanged(true);
|
||||
|
||||
if (!Core::IsRunning())
|
||||
if (!Core::IsRunning(system))
|
||||
Play();
|
||||
}
|
||||
}
|
||||
|
@ -2037,12 +2034,13 @@ void MainWindow::OnStopRecording()
|
|||
|
||||
void MainWindow::OnExportRecording()
|
||||
{
|
||||
Core::RunAsCPUThread([this] {
|
||||
QString dtm_file = DolphinFileDialog::getSaveFileName(
|
||||
this, tr("Save Recording File As"), QString(), tr("Dolphin TAS Movies (*.dtm)"));
|
||||
if (!dtm_file.isEmpty())
|
||||
Core::System::GetInstance().GetMovie().SaveRecording(dtm_file.toStdString());
|
||||
});
|
||||
auto& system = Core::System::GetInstance();
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
QString dtm_file = DolphinFileDialog::getSaveFileName(
|
||||
this, tr("Save Recording File As"), QString(), tr("Dolphin TAS Movies (*.dtm)"));
|
||||
if (!dtm_file.isEmpty())
|
||||
system.GetMovie().SaveRecording(dtm_file.toStdString());
|
||||
}
|
||||
|
||||
void MainWindow::OnActivateChat()
|
||||
|
@ -2080,10 +2078,11 @@ void MainWindow::ShowTASInput()
|
|||
}
|
||||
}
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
for (int i = 0; i < num_wii_controllers; i++)
|
||||
{
|
||||
if (Config::Get(Config::GetInfoForWiimoteSource(i)) == WiimoteSource::Emulated &&
|
||||
(!Core::IsRunning() || Core::System::GetInstance().IsWii()))
|
||||
(!Core::IsRunning(system) || system.IsWii()))
|
||||
{
|
||||
SetQWidgetWindowDecorations(m_wii_tas_input_windows[i]);
|
||||
m_wii_tas_input_windows[i]->show();
|
||||
|
@ -2095,13 +2094,12 @@ void MainWindow::ShowTASInput()
|
|||
|
||||
void MainWindow::OnConnectWiiRemote(int id)
|
||||
{
|
||||
Core::RunAsCPUThread([&] {
|
||||
if (const auto bt = WiiUtils::GetBluetoothEmuDevice())
|
||||
{
|
||||
const auto wm = bt->AccessWiimoteByIndex(id);
|
||||
wm->Activate(!wm->IsConnected());
|
||||
}
|
||||
});
|
||||
const Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
if (const auto bt = WiiUtils::GetBluetoothEmuDevice())
|
||||
{
|
||||
const auto wm = bt->AccessWiimoteByIndex(id);
|
||||
wm->Activate(!wm->IsConnected());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
|
@ -2116,6 +2114,7 @@ void MainWindow::ShowAchievementsWindow()
|
|||
m_achievements_window->show();
|
||||
m_achievements_window->raise();
|
||||
m_achievements_window->activateWindow();
|
||||
m_achievements_window->UpdateData(AchievementManager::UpdatedItems{.all = true});
|
||||
}
|
||||
|
||||
void MainWindow::ShowAchievementSettings()
|
||||
|
|
|
@ -15,9 +15,12 @@
|
|||
#include <QMap>
|
||||
#include <QUrl>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Common/Align.h"
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IOFile.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/AchievementManager.h"
|
||||
|
@ -94,9 +97,9 @@ MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent)
|
|||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
[=, this](Core::State state) { OnEmulationStateChanged(state); });
|
||||
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this,
|
||||
[this] { OnEmulationStateChanged(Core::GetState()); });
|
||||
[this] { OnEmulationStateChanged(Core::GetState(Core::System::GetInstance())); });
|
||||
|
||||
OnEmulationStateChanged(Core::GetState());
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
connect(&Settings::Instance(), &Settings::DebugModeToggled, this, &MenuBar::OnDebugModeToggled);
|
||||
|
||||
connect(this, &MenuBar::SelectionChanged, this, &MenuBar::OnSelectionChanged);
|
||||
|
@ -151,6 +154,7 @@ void MenuBar::OnEmulationStateChanged(Core::State state)
|
|||
!Core::System::GetInstance().GetMovie().IsPlayingInput());
|
||||
|
||||
// JIT
|
||||
const bool jit_exists = Core::System::GetInstance().GetJitInterface().GetCore() != nullptr;
|
||||
m_jit_interpreter_core->setEnabled(running);
|
||||
m_jit_block_linking->setEnabled(!running);
|
||||
m_jit_disable_cache->setEnabled(!running);
|
||||
|
@ -159,6 +163,7 @@ void MenuBar::OnEmulationStateChanged(Core::State state)
|
|||
m_jit_clear_cache->setEnabled(running);
|
||||
m_jit_log_coverage->setEnabled(!running);
|
||||
m_jit_search_instruction->setEnabled(running);
|
||||
m_jit_write_cache_log_dump->setEnabled(running && jit_exists);
|
||||
|
||||
// Symbols
|
||||
m_symbols->setEnabled(running);
|
||||
|
@ -199,6 +204,30 @@ void MenuBar::OnDebugModeToggled(bool enabled)
|
|||
}
|
||||
}
|
||||
|
||||
void MenuBar::OnWriteJitBlockLogDump()
|
||||
{
|
||||
const std::string filename = fmt::format("{}{}.txt", File::GetUserPath(D_DUMPDEBUG_JITBLOCKS_IDX),
|
||||
SConfig::GetInstance().GetGameID());
|
||||
File::IOFile f(filename, "w");
|
||||
if (!f)
|
||||
{
|
||||
ModalMessageBox::warning(
|
||||
this, tr("Error"),
|
||||
tr("Failed to open \"%1\" for writing.").arg(QString::fromStdString(filename)));
|
||||
return;
|
||||
}
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetJitInterface().JitBlockLogDump(Core::CPUThreadGuard{system}, f.GetHandle());
|
||||
if (static bool ignore = false; ignore == false)
|
||||
{
|
||||
const int button_pressed = ModalMessageBox::information(
|
||||
this, tr("Success"), tr("Wrote to \"%1\".").arg(QString::fromStdString(filename)),
|
||||
QMessageBox::Ok | QMessageBox::Ignore);
|
||||
if (button_pressed == QMessageBox::Ignore)
|
||||
ignore = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBar::AddFileMenu()
|
||||
{
|
||||
QMenu* file_menu = addMenu(tr("&File"));
|
||||
|
@ -871,6 +900,17 @@ void MenuBar::AddJITMenu()
|
|||
|
||||
m_jit->addSeparator();
|
||||
|
||||
m_jit_profile_blocks = m_jit->addAction(tr("Enable JIT Block Profiling"));
|
||||
m_jit_profile_blocks->setCheckable(true);
|
||||
m_jit_profile_blocks->setChecked(Config::Get(Config::MAIN_DEBUG_JIT_ENABLE_PROFILING));
|
||||
connect(m_jit_profile_blocks, &QAction::toggled, [](bool enabled) {
|
||||
Config::SetBaseOrCurrent(Config::MAIN_DEBUG_JIT_ENABLE_PROFILING, enabled);
|
||||
});
|
||||
m_jit_write_cache_log_dump =
|
||||
m_jit->addAction(tr("Write JIT Block Log Dump"), this, &MenuBar::OnWriteJitBlockLogDump);
|
||||
|
||||
m_jit->addSeparator();
|
||||
|
||||
m_jit_off = m_jit->addAction(tr("JIT Off (JIT Core)"));
|
||||
m_jit_off->setCheckable(true);
|
||||
m_jit_off->setChecked(Config::Get(Config::MAIN_DEBUG_JIT_OFF));
|
||||
|
@ -1204,14 +1244,17 @@ void MenuBar::OnSelectionChanged(std::shared_ptr<const UICommon::GameFile> game_
|
|||
{
|
||||
m_game_selected = !!game_file;
|
||||
|
||||
m_recording_play->setEnabled(m_game_selected && !Core::IsRunning());
|
||||
m_recording_start->setEnabled((m_game_selected || Core::IsRunning()) &&
|
||||
!Core::System::GetInstance().GetMovie().IsPlayingInput());
|
||||
auto& system = Core::System::GetInstance();
|
||||
const bool core_is_running = Core::IsRunning(system);
|
||||
m_recording_play->setEnabled(m_game_selected && !core_is_running);
|
||||
m_recording_start->setEnabled((m_game_selected || core_is_running) &&
|
||||
!system.GetMovie().IsPlayingInput());
|
||||
}
|
||||
|
||||
void MenuBar::OnRecordingStatusChanged(bool recording)
|
||||
{
|
||||
m_recording_start->setEnabled(!recording && (m_game_selected || Core::IsRunning()));
|
||||
auto& system = Core::System::GetInstance();
|
||||
m_recording_start->setEnabled(!recording && (m_game_selected || Core::IsRunning(system)));
|
||||
m_recording_stop->setEnabled(recording);
|
||||
m_recording_export->setEnabled(recording);
|
||||
}
|
||||
|
@ -1240,35 +1283,37 @@ void MenuBar::ClearSymbols()
|
|||
if (result == QMessageBox::Cancel)
|
||||
return;
|
||||
|
||||
g_symbolDB.Clear();
|
||||
emit NotifySymbolsUpdated();
|
||||
Core::System::GetInstance().GetPPCSymbolDB().Clear();
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MenuBar::GenerateSymbolsFromAddress()
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& memory = system.GetMemory();
|
||||
auto& ppc_symbol_db = system.GetPPCSymbolDB();
|
||||
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR,
|
||||
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB);
|
||||
emit NotifySymbolsUpdated();
|
||||
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &ppc_symbol_db);
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MenuBar::GenerateSymbolsFromSignatureDB()
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& memory = system.GetMemory();
|
||||
auto& ppc_symbol_db = system.GetPPCSymbolDB();
|
||||
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR,
|
||||
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB);
|
||||
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &ppc_symbol_db);
|
||||
SignatureDB db(SignatureDB::HandlerType::DSY);
|
||||
if (db.Load(File::GetSysDirectory() + TOTALDB))
|
||||
{
|
||||
db.Apply(guard, &g_symbolDB);
|
||||
db.Apply(guard, &ppc_symbol_db);
|
||||
ModalMessageBox::information(
|
||||
this, tr("Information"),
|
||||
tr("Generated symbol names from '%1'").arg(QString::fromStdString(TOTALDB)));
|
||||
|
@ -1281,7 +1326,7 @@ void MenuBar::GenerateSymbolsFromSignatureDB()
|
|||
tr("'%1' not found, no symbol names generated").arg(QString::fromStdString(TOTALDB)));
|
||||
}
|
||||
|
||||
emit NotifySymbolsUpdated();
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MenuBar::GenerateSymbolsFromRSO()
|
||||
|
@ -1304,13 +1349,14 @@ void MenuBar::GenerateSymbolsFromRSO()
|
|||
return;
|
||||
}
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
auto& system = Core::System::GetInstance();
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
RSOChainView rso_chain;
|
||||
if (rso_chain.Load(guard, static_cast<u32>(address)))
|
||||
{
|
||||
rso_chain.Apply(guard, &g_symbolDB);
|
||||
emit NotifySymbolsUpdated();
|
||||
rso_chain.Apply(guard, &system.GetPPCSymbolDB());
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1361,12 +1407,13 @@ void MenuBar::GenerateSymbolsFromRSOAuto()
|
|||
RSOChainView rso_chain;
|
||||
const u32 address = item.mid(0, item.indexOf(QLatin1Char(' '))).toUInt(nullptr, 16);
|
||||
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
auto& system = Core::System::GetInstance();
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
if (rso_chain.Load(guard, address))
|
||||
{
|
||||
rso_chain.Apply(guard, &g_symbolDB);
|
||||
emit NotifySymbolsUpdated();
|
||||
rso_chain.Apply(guard, &system.GetPPCSymbolDB());
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1481,22 +1528,23 @@ void MenuBar::LoadSymbolMap()
|
|||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& memory = system.GetMemory();
|
||||
auto& ppc_symbol_db = system.GetPPCSymbolDB();
|
||||
|
||||
std::string existing_map_file, writable_map_file;
|
||||
bool map_exists = CBoot::FindMapFile(&existing_map_file, &writable_map_file);
|
||||
|
||||
if (!map_exists)
|
||||
{
|
||||
g_symbolDB.Clear();
|
||||
ppc_symbol_db.Clear();
|
||||
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
PPCAnalyst::FindFunctions(guard, Memory::MEM1_BASE_ADDR + 0x1300000,
|
||||
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &g_symbolDB);
|
||||
Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal(), &ppc_symbol_db);
|
||||
SignatureDB db(SignatureDB::HandlerType::DSY);
|
||||
if (db.Load(File::GetSysDirectory() + TOTALDB))
|
||||
db.Apply(guard, &g_symbolDB);
|
||||
db.Apply(guard, &ppc_symbol_db);
|
||||
}
|
||||
|
||||
ModalMessageBox::warning(this, tr("Warning"),
|
||||
|
@ -1515,7 +1563,7 @@ void MenuBar::LoadSymbolMap()
|
|||
}
|
||||
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MenuBar::SaveSymbolMap()
|
||||
|
@ -1540,7 +1588,7 @@ void MenuBar::LoadOtherSymbolMap()
|
|||
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MenuBar::LoadBadSymbolMap()
|
||||
|
@ -1557,7 +1605,7 @@ void MenuBar::LoadBadSymbolMap()
|
|||
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MenuBar::SaveSymbolMapAs()
|
||||
|
@ -1582,13 +1630,8 @@ void MenuBar::SaveCode()
|
|||
const std::string path =
|
||||
writable_map_file.substr(0, writable_map_file.find_last_of('.')) + "_code.map";
|
||||
|
||||
bool success;
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
success = g_symbolDB.SaveCodeMap(guard, path);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (!system.GetPPCSymbolDB().SaveCodeMap(Core::CPUThreadGuard{system}, path))
|
||||
{
|
||||
ModalMessageBox::warning(
|
||||
this, tr("Error"),
|
||||
|
@ -1598,9 +1641,10 @@ void MenuBar::SaveCode()
|
|||
|
||||
bool MenuBar::TryLoadMapFile(const QString& path, const bool bad)
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& ppc_symbol_db = system.GetPPCSymbolDB();
|
||||
|
||||
if (!g_symbolDB.LoadMap(guard, path.toStdString(), bad))
|
||||
if (!ppc_symbol_db.LoadMap(Core::CPUThreadGuard{system}, path.toStdString(), bad))
|
||||
{
|
||||
ModalMessageBox::warning(this, tr("Error"), tr("Failed to load map file '%1'").arg(path));
|
||||
return false;
|
||||
|
@ -1611,7 +1655,7 @@ bool MenuBar::TryLoadMapFile(const QString& path, const bool bad)
|
|||
|
||||
void MenuBar::TrySaveSymbolMap(const QString& path)
|
||||
{
|
||||
if (g_symbolDB.SaveSymbolMap(path.toStdString()))
|
||||
if (Core::System::GetInstance().GetPPCSymbolDB().SaveSymbolMap(path.toStdString()))
|
||||
return;
|
||||
|
||||
ModalMessageBox::warning(this, tr("Error"),
|
||||
|
@ -1632,7 +1676,7 @@ void MenuBar::CreateSignatureFile()
|
|||
const std::string prefix = text.toStdString();
|
||||
const std::string save_path = file.toStdString();
|
||||
SignatureDB db(save_path);
|
||||
db.Populate(&g_symbolDB, prefix);
|
||||
db.Populate(&Core::System::GetInstance().GetPPCSymbolDB(), prefix);
|
||||
|
||||
if (!db.Save(save_path))
|
||||
{
|
||||
|
@ -1657,7 +1701,7 @@ void MenuBar::AppendSignatureFile()
|
|||
const std::string prefix = text.toStdString();
|
||||
const std::string signature_path = file.toStdString();
|
||||
SignatureDB db(signature_path);
|
||||
db.Populate(&g_symbolDB, prefix);
|
||||
db.Populate(&Core::System::GetInstance().GetPPCSymbolDB(), prefix);
|
||||
db.List();
|
||||
db.Load(signature_path);
|
||||
if (!db.Save(signature_path))
|
||||
|
@ -1678,17 +1722,15 @@ void MenuBar::ApplySignatureFile()
|
|||
if (file.isEmpty())
|
||||
return;
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
|
||||
const std::string load_path = file.toStdString();
|
||||
SignatureDB db(load_path);
|
||||
db.Load(load_path);
|
||||
{
|
||||
Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||
db.Apply(guard, &g_symbolDB);
|
||||
}
|
||||
db.Apply(Core::CPUThreadGuard{system}, &system.GetPPCSymbolDB());
|
||||
db.List();
|
||||
auto& system = Core::System::GetInstance();
|
||||
HLE::PatchFunctions(system);
|
||||
emit NotifySymbolsUpdated();
|
||||
emit Host::GetInstance()->PPCSymbolsChanged();
|
||||
}
|
||||
|
||||
void MenuBar::CombineSignatureFiles()
|
||||
|
@ -1732,7 +1774,8 @@ void MenuBar::PatchHLEFunctions()
|
|||
|
||||
void MenuBar::ClearCache()
|
||||
{
|
||||
Core::RunAsCPUThread([] { Core::System::GetInstance().GetJitInterface().ClearCache(); });
|
||||
auto& system = Core::System::GetInstance();
|
||||
system.GetJitInterface().ClearCache(Core::CPUThreadGuard{system});
|
||||
}
|
||||
|
||||
void MenuBar::LogInstructions()
|
||||
|
@ -1753,20 +1796,19 @@ void MenuBar::SearchInstruction()
|
|||
auto& system = Core::System::GetInstance();
|
||||
auto& memory = system.GetMemory();
|
||||
|
||||
Core::CPUThreadGuard guard(system);
|
||||
const std::string op_std = op.toStdString();
|
||||
const Core::CPUThreadGuard guard(system);
|
||||
|
||||
bool found = false;
|
||||
for (u32 addr = Memory::MEM1_BASE_ADDR; addr < Memory::MEM1_BASE_ADDR + memory.GetRamSizeReal();
|
||||
addr += 4)
|
||||
{
|
||||
const auto ins_name = QString::fromStdString(
|
||||
PPCTables::GetInstructionName(PowerPC::MMU::HostRead_U32(guard, addr), addr));
|
||||
if (op == ins_name)
|
||||
if (op_std == PPCTables::GetInstructionName(PowerPC::MMU::HostRead_U32(guard, addr), addr))
|
||||
{
|
||||
NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op.toStdString(), addr);
|
||||
NOTICE_LOG_FMT(POWERPC, "Found {} at {:08x}", op_std, addr);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
NOTICE_LOG_FMT(POWERPC, "Opcode {} not found", op.toStdString());
|
||||
NOTICE_LOG_FMT(POWERPC, "Opcode {} not found", op_std);
|
||||
}
|
||||
|
|
|
@ -125,9 +125,6 @@ signals:
|
|||
void RecordingStatusChanged(bool recording);
|
||||
void ReadOnlyModeChanged(bool read_only);
|
||||
|
||||
// Synbols
|
||||
void NotifySymbolsUpdated();
|
||||
|
||||
private:
|
||||
void OnEmulationStateChanged(Core::State state);
|
||||
|
||||
|
@ -188,6 +185,7 @@ private:
|
|||
void OnRecordingStatusChanged(bool recording);
|
||||
void OnReadOnlyModeChanged(bool read_only);
|
||||
void OnDebugModeToggled(bool enabled);
|
||||
void OnWriteJitBlockLogDump();
|
||||
|
||||
QString GetSignatureSelector() const;
|
||||
|
||||
|
@ -271,6 +269,8 @@ private:
|
|||
QAction* m_jit_clear_cache;
|
||||
QAction* m_jit_log_coverage;
|
||||
QAction* m_jit_search_instruction;
|
||||
QAction* m_jit_profile_blocks;
|
||||
QAction* m_jit_write_cache_log_dump;
|
||||
QAction* m_jit_off;
|
||||
QAction* m_jit_loadstore_off;
|
||||
QAction* m_jit_loadstore_lbzx_off;
|
||||
|
|
|
@ -235,19 +235,19 @@ void NetPlayBrowser::accept()
|
|||
|
||||
if (m_sessions[index].has_password)
|
||||
{
|
||||
auto* dialog = new QInputDialog(this);
|
||||
QInputDialog dialog(this);
|
||||
|
||||
dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
dialog->setWindowTitle(tr("Enter password"));
|
||||
dialog->setLabelText(tr("This session requires a password:"));
|
||||
dialog->setWindowModality(Qt::WindowModal);
|
||||
dialog->setTextEchoMode(QLineEdit::Password);
|
||||
dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
dialog.setWindowTitle(tr("Enter password"));
|
||||
dialog.setLabelText(tr("This session requires a password:"));
|
||||
dialog.setWindowModality(Qt::WindowModal);
|
||||
dialog.setTextEchoMode(QLineEdit::Password);
|
||||
|
||||
SetQWidgetWindowDecorations(dialog);
|
||||
if (dialog->exec() != QDialog::Accepted)
|
||||
SetQWidgetWindowDecorations(&dialog);
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
const std::string password = dialog->textValue().toStdString();
|
||||
const std::string password = dialog.textValue().toStdString();
|
||||
|
||||
auto decrypted_id = session.DecryptID(password);
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "Core/IOS/FS/FileSystem.h"
|
||||
#include "Core/NetPlayServer.h"
|
||||
#include "Core/SyncIdentifier.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/NetPlay/ChunkedProgressDialog.h"
|
||||
#include "DolphinQt/NetPlay/GameDigestDialog.h"
|
||||
|
@ -584,7 +585,7 @@ void NetPlayDialog::UpdateDiscordPresence()
|
|||
m_current_game_name);
|
||||
};
|
||||
|
||||
if (Core::IsRunning())
|
||||
if (Core::IsRunning(Core::System::GetInstance()))
|
||||
return use_default();
|
||||
|
||||
if (IsHosting())
|
||||
|
@ -808,7 +809,7 @@ void NetPlayDialog::DisplayMessage(const QString& msg, const std::string& color,
|
|||
|
||||
QColor c(color.empty() ? QStringLiteral("white") : QString::fromStdString(color));
|
||||
|
||||
if (g_ActiveConfig.bShowNetPlayMessages && Core::IsRunning())
|
||||
if (g_ActiveConfig.bShowNetPlayMessages && Core::IsRunning(Core::System::GetInstance()))
|
||||
g_netplay_chat_ui->AppendChat(msg.toStdString(),
|
||||
{static_cast<float>(c.redF()), static_cast<float>(c.greenF()),
|
||||
static_cast<float>(c.blueF())});
|
||||
|
@ -908,7 +909,7 @@ void NetPlayDialog::OnMsgStopGame()
|
|||
|
||||
void NetPlayDialog::OnMsgPowerButton()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
if (!Core::IsRunning(Core::System::GetInstance()))
|
||||
return;
|
||||
QueueOnObject(this, [] { UICommon::TriggerSTMPowerEvent(); });
|
||||
}
|
||||
|
@ -972,9 +973,13 @@ void NetPlayDialog::OnHostInputAuthorityChanged(bool enabled)
|
|||
|
||||
void NetPlayDialog::OnDesync(u32 frame, const std::string& player)
|
||||
{
|
||||
DisplayMessage(tr("Possible desync detected: %1 might have desynced at frame %2")
|
||||
DisplayMessage(tr("Possible desync detected: %1 might have desynced at frame %2. Game restart advised.")
|
||||
.arg(QString::fromStdString(player), QString::number(frame)),
|
||||
"red", OSD::Duration::VERY_LONG);
|
||||
|
||||
OSD::AddTypedMessage(OSD::MessageType::NetPlayDesync,
|
||||
"Possible desync detected. Game restart advised.",
|
||||
OSD::Duration::VERY_LONG, OSD::Color::RED);
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnConnectionLost()
|
||||
|
@ -1283,3 +1288,13 @@ void NetPlayDialog::SetHostWiiSyncData(std::vector<u64> titles, std::string redi
|
|||
if (client)
|
||||
client->SetWiiSyncData(nullptr, std::move(titles), std::move(redirect_folder));
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnActiveGeckoCodes(std::string codeStr)
|
||||
{
|
||||
DisplayMessage(QString::fromStdString(codeStr), "cornflowerblue");
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnActiveARCodes(std::string codeStr)
|
||||
{
|
||||
DisplayMessage(QString::fromStdString(codeStr), "cornflowerblue");
|
||||
}
|
|
@ -118,6 +118,9 @@ private:
|
|||
|
||||
void SendMessage(const std::string& message);
|
||||
|
||||
void OnActiveGeckoCodes(std::string codeStr);
|
||||
void OnActiveARCodes(std::string codeStr);
|
||||
|
||||
// Chat
|
||||
QGroupBox* m_chat_box;
|
||||
QTextEdit* m_chat_edit;
|
||||
|
|
23
Source/Core/DolphinQt/QtUtils/FromStdString.h
Normal file
23
Source/Core/DolphinQt/QtUtils/FromStdString.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2024 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <string_view>
|
||||
|
||||
namespace QtUtils
|
||||
{
|
||||
inline QString FromStdString(std::string_view s)
|
||||
{
|
||||
return QString::fromUtf8(s.data(), s.size());
|
||||
}
|
||||
inline QString FromStdString(std::u8string_view s)
|
||||
{
|
||||
return QString::fromUtf8(s.data(), s.size());
|
||||
}
|
||||
inline QString FromStdString(std::u16string_view s)
|
||||
{
|
||||
return QString::fromUtf16(s.data(), s.size());
|
||||
}
|
||||
} // namespace QtUtils
|
|
@ -22,6 +22,7 @@
|
|||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/State.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <dwmapi.h>
|
||||
#endif
|
||||
|
||||
RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
||||
|
@ -68,7 +70,7 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
|||
// (which results in them not getting called)
|
||||
connect(this, &RenderWidget::StateChanged, Host::GetInstance(), &Host::SetRenderFullscreen,
|
||||
Qt::DirectConnection);
|
||||
connect(this, &RenderWidget::HandleChanged, Host::GetInstance(), &Host::SetRenderHandle,
|
||||
connect(this, &RenderWidget::HandleChanged, this, &RenderWidget::OnHandleChanged,
|
||||
Qt::DirectConnection);
|
||||
connect(this, &RenderWidget::SizeChanged, Host::GetInstance(), &Host::ResizeSurface,
|
||||
Qt::DirectConnection);
|
||||
|
@ -129,7 +131,21 @@ void RenderWidget::dropEvent(QDropEvent* event)
|
|||
return;
|
||||
}
|
||||
|
||||
State::LoadAs(path.toStdString());
|
||||
State::LoadAs(Core::System::GetInstance(), path.toStdString());
|
||||
}
|
||||
|
||||
void RenderWidget::OnHandleChanged(void* handle)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Remove rounded corners from the render window on Windows 11
|
||||
const DWM_WINDOW_CORNER_PREFERENCE corner_preference = DWMWCP_DONOTROUND;
|
||||
DwmSetWindowAttribute(reinterpret_cast<HWND>(handle), DWMWA_WINDOW_CORNER_PREFERENCE,
|
||||
&corner_preference, sizeof(corner_preference));
|
||||
#endif
|
||||
}
|
||||
Host::GetInstance()->SetRenderHandle(handle);
|
||||
}
|
||||
|
||||
void RenderWidget::OnHideCursorChanged()
|
||||
|
@ -405,8 +421,11 @@ bool RenderWidget::event(QEvent* event)
|
|||
// Note that this event in Windows is not always aligned to the window that is highlighted,
|
||||
// it's the window that has keyboard and mouse focus
|
||||
case QEvent::WindowActivate:
|
||||
if (m_should_unpause_on_focus && Core::GetState() == Core::State::Paused)
|
||||
Core::SetState(Core::State::Running);
|
||||
if (m_should_unpause_on_focus &&
|
||||
Core::GetState(Core::System::GetInstance()) == Core::State::Paused)
|
||||
{
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Running);
|
||||
}
|
||||
|
||||
m_should_unpause_on_focus = false;
|
||||
|
||||
|
@ -429,7 +448,8 @@ bool RenderWidget::event(QEvent* event)
|
|||
|
||||
UpdateCursor();
|
||||
|
||||
if (Config::Get(Config::MAIN_PAUSE_ON_FOCUS_LOST) && Core::GetState() == Core::State::Running)
|
||||
if (Config::Get(Config::MAIN_PAUSE_ON_FOCUS_LOST) &&
|
||||
Core::GetState(Core::System::GetInstance()) == Core::State::Running)
|
||||
{
|
||||
// If we are declared as the CPU or GPU thread, it means that the real CPU or GPU thread
|
||||
// is waiting for us to finish showing a panic alert (with that panic alert likely being
|
||||
|
@ -437,7 +457,7 @@ bool RenderWidget::event(QEvent* event)
|
|||
if (!Core::IsCPUThread() && !Core::IsGPUThread())
|
||||
{
|
||||
m_should_unpause_on_focus = true;
|
||||
Core::SetState(Core::State::Paused);
|
||||
Core::SetState(Core::System::GetInstance(), Core::State::Paused);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ signals:
|
|||
|
||||
private:
|
||||
void HandleCursorTimer();
|
||||
void OnHandleChanged(void* handle);
|
||||
void OnHideCursorChanged();
|
||||
void OnNeverHideCursorChanged();
|
||||
void OnLockCursorChanged();
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "Common/FileUtil.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
|
@ -565,7 +565,7 @@ void Settings::SetCheatsEnabled(bool enabled)
|
|||
void Settings::SetDebugModeEnabled(bool enabled)
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (Config::Get(Config::RA_HARDCORE_ENABLED))
|
||||
if (AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
enabled = false;
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
if (IsDebugModeEnabled() != enabled)
|
||||
|
|
|
@ -217,7 +217,7 @@ signals:
|
|||
void JITVisibilityChanged(bool visible);
|
||||
void AssemblerVisibilityChanged(bool visible);
|
||||
void DebugModeToggled(bool enabled);
|
||||
void DebugFontChanged(QFont font);
|
||||
void DebugFontChanged(const QFont& font);
|
||||
void AutoUpdateTrackChanged(const QString& mode);
|
||||
void FallbackRegionChanged(const DiscIO::Region& region);
|
||||
void AnalyticsToggled(bool enabled);
|
||||
|
|
|
@ -240,7 +240,7 @@ void AdvancedPane::ConnectLayout()
|
|||
|
||||
void AdvancedPane::Update()
|
||||
{
|
||||
const bool running = Core::GetState() != Core::State::Uninitialized;
|
||||
const bool running = Core::GetState(Core::System::GetInstance()) != Core::State::Uninitialized;
|
||||
const bool enable_cpu_clock_override_widgets = Config::Get(Config::MAIN_OVERCLOCK_ENABLE);
|
||||
const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
|
||||
const bool enable_custom_rtc_widgets = Config::Get(Config::MAIN_CUSTOM_RTC_ENABLE) && !running;
|
||||
|
|
|
@ -40,7 +40,8 @@ AudioPane::AudioPane()
|
|||
OnEmulationStateChanged(state != Core::State::Uninitialized);
|
||||
});
|
||||
|
||||
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
|
||||
Core::State::Uninitialized);
|
||||
}
|
||||
|
||||
void AudioPane::CreateWidgets()
|
||||
|
|
|
@ -48,6 +48,32 @@ void BroadbandAdapterSettingsDialog::InitControls()
|
|||
window_title = tr("Broadband Adapter MAC Address");
|
||||
break;
|
||||
|
||||
case Type::TapServer:
|
||||
case Type::ModemTapServer:
|
||||
{
|
||||
const bool is_modem = (m_bba_type == Type::ModemTapServer);
|
||||
current_address =
|
||||
QString::fromStdString(Config::Get(is_modem ? Config::MAIN_MODEM_TAPSERVER_DESTINATION :
|
||||
Config::MAIN_BBA_TAPSERVER_DESTINATION));
|
||||
#ifdef _WIN32
|
||||
address_label = new QLabel(tr("Destination (address:port):"));
|
||||
address_placeholder = QStringLiteral("");
|
||||
description = new QLabel(
|
||||
tr("Enter the IP address and port of the tapserver instance you want to connect to."));
|
||||
#else
|
||||
address_label = new QLabel(tr("Destination (UNIX socket path or address:port):"));
|
||||
address_placeholder =
|
||||
is_modem ? QStringLiteral(u"/tmp/dolphin-modem-tap") : QStringLiteral(u"/tmp/dolphin-tap");
|
||||
description =
|
||||
new QLabel(tr("The default value \"%1\" will work with a local tapserver and newserv."
|
||||
" You can also enter a network location (address:port) to connect to a "
|
||||
"remote tapserver.")
|
||||
.arg(address_placeholder));
|
||||
#endif
|
||||
window_title = tr("BBA destination address");
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::BuiltIn:
|
||||
address_label = new QLabel(tr("Enter the DNS server to use:"));
|
||||
address_placeholder = QStringLiteral("8.8.8.8");
|
||||
|
@ -114,6 +140,12 @@ void BroadbandAdapterSettingsDialog::SaveAddress()
|
|||
Config::SetBaseOrCurrent(Config::MAIN_BBA_MAC, bba_new_address);
|
||||
break;
|
||||
}
|
||||
case Type::TapServer:
|
||||
Config::SetBaseOrCurrent(Config::MAIN_BBA_TAPSERVER_DESTINATION, bba_new_address);
|
||||
break;
|
||||
case Type::ModemTapServer:
|
||||
Config::SetBaseOrCurrent(Config::MAIN_MODEM_TAPSERVER_DESTINATION, bba_new_address);
|
||||
break;
|
||||
case Type::BuiltIn:
|
||||
Config::SetBaseOrCurrent(Config::MAIN_BBA_BUILTIN_DNS, bba_new_address);
|
||||
break;
|
||||
|
|
|
@ -15,7 +15,9 @@ public:
|
|||
{
|
||||
Ethernet,
|
||||
XLinkKai,
|
||||
BuiltIn
|
||||
TapServer,
|
||||
BuiltIn,
|
||||
ModemTapServer
|
||||
};
|
||||
|
||||
explicit BroadbandAdapterSettingsDialog(QWidget* target, Type bba_type);
|
||||
|
|
|
@ -149,10 +149,9 @@ void GameCubePane::CreateWidgets()
|
|||
EXIDeviceType::Dummy,
|
||||
EXIDeviceType::Ethernet,
|
||||
EXIDeviceType::EthernetXLink,
|
||||
#ifdef __APPLE__
|
||||
EXIDeviceType::EthernetTapServer,
|
||||
#endif
|
||||
EXIDeviceType::EthernetBuiltIn,
|
||||
EXIDeviceType::ModemTapServer,
|
||||
})
|
||||
{
|
||||
m_slot_combos[ExpansionInterface::Slot::SP1]->addItem(tr(fmt::format("{:n}", device).c_str()),
|
||||
|
@ -355,7 +354,9 @@ void GameCubePane::UpdateButton(ExpansionInterface::Slot slot)
|
|||
case ExpansionInterface::Slot::SP1:
|
||||
has_config = (device == ExpansionInterface::EXIDeviceType::Ethernet ||
|
||||
device == ExpansionInterface::EXIDeviceType::EthernetXLink ||
|
||||
device == ExpansionInterface::EXIDeviceType::EthernetBuiltIn);
|
||||
device == ExpansionInterface::EXIDeviceType::EthernetTapServer ||
|
||||
device == ExpansionInterface::EXIDeviceType::EthernetBuiltIn ||
|
||||
device == ExpansionInterface::EXIDeviceType::ModemTapServer);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -400,6 +401,21 @@ void GameCubePane::OnConfigPressed(ExpansionInterface::Slot slot)
|
|||
dialog.exec();
|
||||
return;
|
||||
}
|
||||
case ExpansionInterface::EXIDeviceType::EthernetTapServer:
|
||||
{
|
||||
BroadbandAdapterSettingsDialog dialog(this, BroadbandAdapterSettingsDialog::Type::TapServer);
|
||||
SetQWidgetWindowDecorations(&dialog);
|
||||
dialog.exec();
|
||||
return;
|
||||
}
|
||||
case ExpansionInterface::EXIDeviceType::ModemTapServer:
|
||||
{
|
||||
BroadbandAdapterSettingsDialog dialog(this,
|
||||
BroadbandAdapterSettingsDialog::Type::ModemTapServer);
|
||||
SetQWidgetWindowDecorations(&dialog);
|
||||
dialog.exec();
|
||||
return;
|
||||
}
|
||||
case ExpansionInterface::EXIDeviceType::EthernetBuiltIn:
|
||||
{
|
||||
BroadbandAdapterSettingsDialog dialog(this, BroadbandAdapterSettingsDialog::Type::BuiltIn);
|
||||
|
@ -498,7 +514,8 @@ bool GameCubePane::SetMemcard(ExpansionInterface::Slot slot, const QString& file
|
|||
const std::string old_eu_path = Config::GetMemcardPath(slot, DiscIO::Region::PAL);
|
||||
Config::SetBase(Config::GetInfoForMemcardPath(slot), raw_path);
|
||||
|
||||
if (Core::IsRunning())
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (Core::IsRunning(system))
|
||||
{
|
||||
// If emulation is running and the new card is different from the old one, notify the system to
|
||||
// eject the old and insert the new card.
|
||||
|
@ -507,8 +524,8 @@ bool GameCubePane::SetMemcard(ExpansionInterface::Slot slot, const QString& file
|
|||
{
|
||||
// ChangeDevice unplugs the device for 1 second, which means that games should notice that
|
||||
// the path has changed and thus the memory card contents have changed
|
||||
Core::System::GetInstance().GetExpansionInterface().ChangeDevice(
|
||||
slot, ExpansionInterface::EXIDeviceType::MemoryCard);
|
||||
system.GetExpansionInterface().ChangeDevice(slot,
|
||||
ExpansionInterface::EXIDeviceType::MemoryCard);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,7 +621,8 @@ bool GameCubePane::SetGCIFolder(ExpansionInterface::Slot slot, const QString& pa
|
|||
|
||||
Config::SetBase(Config::GetInfoForGCIPath(slot), raw_path);
|
||||
|
||||
if (Core::IsRunning())
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (Core::IsRunning(system))
|
||||
{
|
||||
// If emulation is running and the new card is different from the old one, notify the system to
|
||||
// eject the old and insert the new card.
|
||||
|
@ -613,7 +631,7 @@ bool GameCubePane::SetGCIFolder(ExpansionInterface::Slot slot, const QString& pa
|
|||
{
|
||||
// ChangeDevice unplugs the device for 1 second, which means that games should notice that
|
||||
// the path has changed and thus the memory card contents have changed
|
||||
Core::System::GetInstance().GetExpansionInterface().ChangeDevice(
|
||||
system.GetExpansionInterface().ChangeDevice(
|
||||
slot, ExpansionInterface::EXIDeviceType::MemoryCardFolder);
|
||||
}
|
||||
}
|
||||
|
@ -644,14 +662,14 @@ void GameCubePane::SetAGPRom(ExpansionInterface::Slot slot, const QString& filen
|
|||
|
||||
Config::SetBase(Config::GetInfoForAGPCartPath(slot), path_abs.toStdString());
|
||||
|
||||
if (Core::IsRunning() && path_abs != path_old)
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (Core::IsRunning(system) && path_abs != path_old)
|
||||
{
|
||||
// ChangeDevice unplugs the device for 1 second. For an actual AGP, you can remove the
|
||||
// cartridge without unplugging it, and it's not clear if the AGP software actually notices
|
||||
// that it's been unplugged or the cartridge has changed, but this was done for memcards so
|
||||
// we might as well do it for the AGP too.
|
||||
Core::System::GetInstance().GetExpansionInterface().ChangeDevice(
|
||||
slot, ExpansionInterface::EXIDeviceType::AGP);
|
||||
system.GetExpansionInterface().ChangeDevice(slot, ExpansionInterface::EXIDeviceType::AGP);
|
||||
}
|
||||
|
||||
LoadSettings();
|
||||
|
@ -765,6 +783,7 @@ void GameCubePane::SaveSettings()
|
|||
Config::SetBaseOrCurrent(Config::MAIN_SKIP_IPL, m_skip_main_menu->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::MAIN_GC_LANGUAGE, m_language_combo->currentData().toInt());
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
// Device Settings
|
||||
for (ExpansionInterface::Slot slot : ExpansionInterface::SLOTS)
|
||||
{
|
||||
|
@ -773,9 +792,9 @@ void GameCubePane::SaveSettings()
|
|||
const ExpansionInterface::EXIDeviceType current_exi_device =
|
||||
Config::Get(Config::GetInfoForEXIDevice(slot));
|
||||
|
||||
if (Core::IsRunning() && current_exi_device != dev)
|
||||
if (Core::IsRunning(system) && current_exi_device != dev)
|
||||
{
|
||||
Core::System::GetInstance().GetExpansionInterface().ChangeDevice(slot, dev);
|
||||
system.GetExpansionInterface().ChangeDevice(slot, dev);
|
||||
}
|
||||
|
||||
Config::SetBaseOrCurrent(Config::GetInfoForEXIDevice(slot), dev);
|
||||
|
|
|
@ -15,13 +15,14 @@
|
|||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Config/UISettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/DolphinAnalytics.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
|
||||
|
@ -58,7 +59,7 @@ GeneralPane::GeneralPane(QWidget* parent) : QWidget(parent)
|
|||
&GeneralPane::OnEmulationStateChanged);
|
||||
connect(&Settings::Instance(), &Settings::ConfigChanged, this, &GeneralPane::LoadConfig);
|
||||
|
||||
OnEmulationStateChanged(Core::GetState());
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void GeneralPane::CreateLayout()
|
||||
|
@ -83,7 +84,7 @@ void GeneralPane::OnEmulationStateChanged(Core::State state)
|
|||
|
||||
m_checkbox_dualcore->setEnabled(!running);
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
bool hardcore = Config::Get(Config::RA_HARDCORE_ENABLED);
|
||||
bool hardcore = AchievementManager::GetInstance().IsHardcoreModeActive();
|
||||
m_checkbox_cheats->setEnabled(!running && !hardcore);
|
||||
#else // USE_RETRO_ACHIEVEMENTS
|
||||
m_checkbox_cheats->setEnabled(!running);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Config/UISettings.h"
|
||||
|
||||
|
@ -256,7 +256,7 @@ void InterfacePane::LoadConfig()
|
|||
->setChecked(Settings::Instance().IsDebugModeEnabled());
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
bool hardcore = Config::Get(Config::RA_HARDCORE_ENABLED);
|
||||
bool hardcore = AchievementManager::GetInstance().IsHardcoreModeActive();
|
||||
SignalBlocking(m_checkbox_show_debugging_ui)->setEnabled(!hardcore);
|
||||
if (hardcore)
|
||||
{
|
||||
|
|
|
@ -91,6 +91,7 @@ void USBDeviceAddToWhitelistDialog::InitControls()
|
|||
&QPushButton::clicked);
|
||||
connect(m_refresh_devices_timer, &QTimer::timeout, this,
|
||||
&USBDeviceAddToWhitelistDialog::RefreshDeviceList);
|
||||
RefreshDeviceList();
|
||||
m_refresh_devices_timer->start(1000);
|
||||
|
||||
main_layout->addWidget(usb_inserted_devices_list);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "Core/Config/SYSCONFSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/QtUtils/DolphinFileDialog.h"
|
||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||
|
@ -92,7 +93,8 @@ WiiPane::WiiPane(QWidget* parent) : QWidget(parent)
|
|||
LoadConfig();
|
||||
ConnectLayout();
|
||||
ValidateSelectionState();
|
||||
OnEmulationStateChanged(Core::GetState() != Core::State::Uninitialized);
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) !=
|
||||
Core::State::Uninitialized);
|
||||
}
|
||||
|
||||
void WiiPane::CreateLayout()
|
||||
|
|
|
@ -53,10 +53,12 @@ SkylanderModifyDialog::SkylanderModifyDialog(QWidget* parent, u8 slot)
|
|||
{
|
||||
// Should never be able to happen. Still good to have
|
||||
name =
|
||||
// i18n: "Var" is short for "variant"
|
||||
tr("Unknown (Id:%1 Var:%2)").arg(m_figure_data.figure_id).arg(m_figure_data.variant_id);
|
||||
}
|
||||
}
|
||||
|
||||
// i18n: %1 is a name
|
||||
auto* label_name = new QLabel(tr("Modifying Skylander: %1").arg(name));
|
||||
|
||||
hbox_name->addWidget(label_name);
|
||||
|
@ -136,11 +138,13 @@ void SkylanderModifyDialog::PopulateSkylanderOptions(QVBoxLayout* layout)
|
|||
reinterpret_cast<char16_t*>(m_figure_data.skylander_data.nickname.data())));
|
||||
|
||||
auto* hbox_playtime = new QHBoxLayout();
|
||||
// i18n: The total amount of time the Skylander has been used for
|
||||
auto* label_playtime = new QLabel(tr("Playtime:"));
|
||||
auto* edit_playtime =
|
||||
new QLineEdit(QStringLiteral("%1").arg(m_figure_data.skylander_data.playtime));
|
||||
|
||||
auto* hbox_last_reset = new QHBoxLayout();
|
||||
// i18n: A timestamp for when the Skylander was most recently reset
|
||||
auto* label_last_reset = new QLabel(tr("Last reset:"));
|
||||
auto* edit_last_reset =
|
||||
new QDateTimeEdit(QDateTime(QDate(m_figure_data.skylander_data.last_reset.year,
|
||||
|
@ -150,6 +154,7 @@ void SkylanderModifyDialog::PopulateSkylanderOptions(QVBoxLayout* layout)
|
|||
m_figure_data.skylander_data.last_reset.minute)));
|
||||
|
||||
auto* hbox_last_placed = new QHBoxLayout();
|
||||
// i18n: A timestamp for when the Skylander was most recently used
|
||||
auto* label_last_placed = new QLabel(tr("Last placed:"));
|
||||
auto* edit_last_placed =
|
||||
new QDateTimeEdit(QDateTime(QDate(m_figure_data.skylander_data.last_placed.year,
|
||||
|
@ -167,10 +172,10 @@ void SkylanderModifyDialog::PopulateSkylanderOptions(QVBoxLayout* layout)
|
|||
edit_last_placed->setDisplayFormat(QStringLiteral("dd/MM/yyyy hh:mm"));
|
||||
|
||||
edit_toy_code->setToolTip(tr("The toy code for this figure. Only available for real figures."));
|
||||
edit_money->setToolTip(tr("The amount of money this skylander should have. Between 0 and 65000"));
|
||||
edit_hero->setToolTip(tr("The hero level of this skylander. Only seen in Skylanders: Spyro's "
|
||||
edit_money->setToolTip(tr("The amount of money this Skylander has. Between 0 and 65000"));
|
||||
edit_hero->setToolTip(tr("The hero level of this Skylander. Only seen in Skylanders: Spyro's "
|
||||
"Adventures. Between 0 and 100"));
|
||||
edit_nick->setToolTip(tr("The nickname for this skylander. Limited to 15 characters"));
|
||||
edit_nick->setToolTip(tr("The nickname for this Skylander. Limited to 15 characters"));
|
||||
edit_playtime->setToolTip(
|
||||
tr("The total time this figure has been used inside a game in seconds"));
|
||||
edit_last_reset->setToolTip(tr("The last time the figure has been reset. If the figure has never "
|
||||
|
@ -309,6 +314,8 @@ bool SkylanderModifyDialog::PopulateTrophyOptions(QVBoxLayout* layout)
|
|||
edit_villains[i] = new QCheckBox();
|
||||
edit_villains[i]->setChecked(static_cast<bool>(m_figure_data.trophy_data.unlocked_villains &
|
||||
(0b1 << shift_distances[i])));
|
||||
// i18n: "Captured" is a participle here. This string is used when listing villains, not when a
|
||||
// villain was just captured
|
||||
auto* const label = new QLabel(tr("Captured villain %1:").arg(i + 1));
|
||||
auto* const hbox = new QHBoxLayout();
|
||||
hbox->addWidget(label);
|
||||
|
|
|
@ -56,7 +56,7 @@ SkylanderPortalWindow::SkylanderPortalWindow(QWidget* parent) : QWidget(parent)
|
|||
|
||||
installEventFilter(this);
|
||||
|
||||
OnEmulationStateChanged(Core::GetState());
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
|
||||
connect(m_skylander_list, &QListWidget::itemSelectionChanged, this,
|
||||
&SkylanderPortalWindow::UpdateCurrentIDs);
|
||||
|
@ -75,21 +75,8 @@ SkylanderPortalWindow::SkylanderPortalWindow(QWidget* parent) : QWidget(parent)
|
|||
{
|
||||
skylanders_folder = QDir(QString::fromStdString(Config::Get(Config::MAIN_SKYLANDERS_PATH)));
|
||||
}
|
||||
// prompt folder creation if path invalid
|
||||
if (!skylanders_folder.exists())
|
||||
{
|
||||
QMessageBox::StandardButton create_folder_response;
|
||||
create_folder_response =
|
||||
QMessageBox::question(this, tr("Create Skylander Folder"),
|
||||
tr("Skylanders folder not found for this user. Create new folder?"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (create_folder_response == QMessageBox::Yes)
|
||||
{
|
||||
skylanders_folder = QDir(user_path);
|
||||
Config::SetBase(Config::MAIN_SKYLANDERS_PATH, user_path.toStdString());
|
||||
skylanders_folder.mkdir(skylanders_folder.path());
|
||||
}
|
||||
}
|
||||
skylanders_folder.mkdir(skylanders_folder.path());
|
||||
|
||||
m_collection_path = QDir::toNativeSeparators(skylanders_folder.path()) + QDir::separator();
|
||||
m_last_skylander_path = m_collection_path;
|
||||
|
@ -546,6 +533,7 @@ void SkylanderPortalWindow::LoadSelected()
|
|||
}
|
||||
else
|
||||
{
|
||||
// i18n: This is used to create a file name. The string must end in ".sky".
|
||||
const QString str = tr("Unknown(%1 %2).sky");
|
||||
predef_name += str.arg(m_sky_id, m_sky_var);
|
||||
}
|
||||
|
@ -629,6 +617,7 @@ void SkylanderPortalWindow::CreateSkylanderAdvanced()
|
|||
}
|
||||
else
|
||||
{
|
||||
// i18n: This is used to create a file name. The string must end in ".sky".
|
||||
QString str = tr("Unknown(%1 %2).sky");
|
||||
predef_name += str.arg(m_sky_id, m_sky_var);
|
||||
}
|
||||
|
@ -673,7 +662,7 @@ void SkylanderPortalWindow::ClearSlot(u8 slot)
|
|||
if (!system.GetSkylanderPortal().RemoveSkylander(slot_infos->portal_slot))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Failed to clear Skylander!"),
|
||||
tr("Failed to clear the Skylander from slot(%1)!").arg(slot),
|
||||
tr("Failed to clear the Skylander from slot %1!").arg(slot),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
@ -795,7 +784,7 @@ void SkylanderPortalWindow::CreateSkyfile(const QString& path, bool load_after)
|
|||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Failed to create Skylander file!"),
|
||||
tr("Failed to create Skylander file:\n%1\n(Skylander may already be on the portal)")
|
||||
tr("Failed to create Skylander file:\n%1\n\nThe Skylander may already be on the portal.")
|
||||
.arg(path),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
|
@ -813,11 +802,11 @@ void SkylanderPortalWindow::LoadSkyfilePath(u8 slot, const QString& path)
|
|||
File::IOFile sky_file(path.toStdString(), "r+b");
|
||||
if (!sky_file)
|
||||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Failed to open the Skylander file!"),
|
||||
tr("Failed to open the Skylander file(%1)!\nFile may already be in use on the portal.")
|
||||
.arg(path),
|
||||
QMessageBox::Ok);
|
||||
QMessageBox::warning(this, tr("Failed to open the Skylander file!"),
|
||||
tr("Failed to open the Skylander file:\n%1\n\nThe file may already be in "
|
||||
"use on the portal.")
|
||||
.arg(path),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
std::array<u8, 0x40 * 0x10> file_data;
|
||||
|
@ -825,7 +814,7 @@ void SkylanderPortalWindow::LoadSkyfilePath(u8 slot, const QString& path)
|
|||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Failed to read the Skylander file!"),
|
||||
tr("Failed to read the Skylander file(%1)!\nFile was too small.").arg(path),
|
||||
tr("Failed to read the Skylander file:\n%1\n\nThe file was too small.").arg(path),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
@ -839,7 +828,7 @@ void SkylanderPortalWindow::LoadSkyfilePath(u8 slot, const QString& path)
|
|||
if (portal_slot == 0xFF)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Failed to load the Skylander file!"),
|
||||
tr("Failed to load the Skylander file(%1)!\n").arg(path), QMessageBox::Ok);
|
||||
tr("Failed to load the Skylander file:\n%1").arg(path), QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
m_sky_slots[slot] = {portal_slot, id_var.first, id_var.second};
|
||||
|
@ -862,6 +851,7 @@ void SkylanderPortalWindow::UpdateSlotNames()
|
|||
}
|
||||
else
|
||||
{
|
||||
// i18n: "Var" is short for "variant"
|
||||
display_string = tr("Unknown (Id:%1 Var:%2)").arg(sd->m_sky_id).arg(sd->m_sky_var);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "Core/HW/WiimoteEmu/MotionPlus.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/QtUtils/AspectRatioWidget.h"
|
||||
#include "DolphinQt/QtUtils/QueueOnObject.h"
|
||||
|
@ -347,7 +348,7 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(
|
|||
|
||||
setLayout(layout);
|
||||
|
||||
if (Core::IsRunning())
|
||||
if (Core::IsRunning(Core::System::GetInstance()))
|
||||
{
|
||||
m_active_extension = GetWiimote()->GetActiveExtensionNumber();
|
||||
m_is_motion_plus_attached = GetWiimote()->IsMotionPlusAttached();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/NetPlayProto.h"
|
||||
#include "Core/System.h"
|
||||
#include "DolphinQt/Host.h"
|
||||
#include "DolphinQt/Resources.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
@ -36,7 +37,7 @@ ToolBar::ToolBar(QWidget* parent) : QToolBar(parent)
|
|||
[this](Core::State state) { OnEmulationStateChanged(state); });
|
||||
|
||||
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this,
|
||||
[this] { OnEmulationStateChanged(Core::GetState()); });
|
||||
[this] { OnEmulationStateChanged(Core::GetState(Core::System::GetInstance())); });
|
||||
|
||||
connect(&Settings::Instance(), &Settings::DebugModeToggled, this, &ToolBar::OnDebugModeToggled);
|
||||
|
||||
|
@ -51,7 +52,7 @@ ToolBar::ToolBar(QWidget* parent) : QToolBar(parent)
|
|||
connect(&Settings::Instance(), &Settings::GameListRefreshStarted, this,
|
||||
[this] { m_refresh_action->setEnabled(true); });
|
||||
|
||||
OnEmulationStateChanged(Core::GetState());
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
OnDebugModeToggled(Settings::Instance().IsDebugModeEnabled());
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,7 @@ void ToolBar::OnEmulationStateChanged(Core::State state)
|
|||
bool playing = running && state != Core::State::Paused;
|
||||
UpdatePausePlayButtonState(playing);
|
||||
|
||||
bool paused = Core::GetState() == Core::State::Paused;
|
||||
const bool paused = Core::GetState(Core::System::GetInstance()) == Core::State::Paused;
|
||||
m_step_action->setEnabled(paused);
|
||||
m_step_over_action->setEnabled(paused);
|
||||
m_step_out_action->setEnabled(paused);
|
||||
|
@ -87,7 +88,7 @@ void ToolBar::OnDebugModeToggled(bool enabled)
|
|||
m_show_pc_action->setVisible(enabled);
|
||||
m_set_pc_action->setVisible(enabled);
|
||||
|
||||
bool paused = Core::GetState() == Core::State::Paused;
|
||||
const bool paused = Core::GetState(Core::System::GetInstance()) == Core::State::Paused;
|
||||
m_step_action->setEnabled(paused);
|
||||
m_step_over_action->setEnabled(paused);
|
||||
m_step_out_action->setEnabled(paused);
|
||||
|
@ -183,7 +184,7 @@ void ToolBar::UpdateIcons()
|
|||
m_open_action->setIcon(Resources::GetThemeIcon("open"));
|
||||
m_refresh_action->setIcon(Resources::GetThemeIcon("refresh"));
|
||||
|
||||
const Core::State state = Core::GetState();
|
||||
const Core::State state = Core::GetState(Core::System::GetInstance());
|
||||
const bool playing = state != Core::State::Uninitialized && state != Core::State::Paused;
|
||||
if (!playing)
|
||||
m_pause_play_action->setIcon(Resources::GetThemeIcon("play"));
|
||||
|
|
|
@ -57,6 +57,7 @@ void Updater::OnUpdateAvailable(const NewVersionInformation& info)
|
|||
|
||||
std::optional<int> choice = RunOnObject(m_parent, [&] {
|
||||
QDialog* dialog = new QDialog(m_parent);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
dialog->setWindowTitle(tr("Update available"));
|
||||
dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue