mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
Some checks are pending
🐧 Linux Builds / AppImage (push) Waiting to run
🐧 Linux Builds / Flatpak (push) Waiting to run
🍎 MacOS Builds / Defaults (push) Waiting to run
🖥️ Windows Builds / Lint VS Project Files (push) Waiting to run
🖥️ Windows Builds / SSE4 (push) Blocked by required conditions
🖥️ Windows Builds / AVX2 (push) Blocked by required conditions
🖥️ Windows Builds / CMake (push) Waiting to run
214 lines
7.0 KiB
C++
214 lines
7.0 KiB
C++
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "MainWindow.h"
|
|
#include "QtHost.h"
|
|
#include "QtUtils.h"
|
|
#include "Settings/GamePatchSettingsWidget.h"
|
|
#include "SettingWidgetBinder.h"
|
|
#include "Settings/SettingsWindow.h"
|
|
|
|
#include "pcsx2/GameList.h"
|
|
#include "pcsx2/Patch.h"
|
|
|
|
#include "common/Assertions.h"
|
|
|
|
#include <algorithm>
|
|
|
|
GamePatchDetailsWidget::GamePatchDetailsWidget(const Patch::PatchInfo& info, bool tristate, Qt::CheckState checkState, SettingsWindow* dialog, QWidget* parent)
|
|
: QWidget(parent)
|
|
, m_dialog(dialog)
|
|
, m_name(info.name)
|
|
{
|
|
m_ui.setupUi(this);
|
|
|
|
const QString name = QString::fromStdString(info.name);
|
|
const QString author = !info.author.empty() ? QString::fromStdString(info.author) : tr("Unknown");
|
|
const QString place = QString::fromUtf8(PlaceToString(info.place));
|
|
const QString description = !info.description.empty() ? QString::fromStdString(info.description) : tr("No description provided.");
|
|
m_ui.name->setText(name);
|
|
m_ui.description->setText(
|
|
tr("<strong>Author:</strong> %1<br><strong>Applied:</strong> %2<br>%3")
|
|
.arg(author)
|
|
.arg(place)
|
|
.arg(description));
|
|
|
|
pxAssert(dialog->getSettingsInterface());
|
|
m_ui.enabled->setTristate(tristate);
|
|
m_ui.enabled->setCheckState(checkState);
|
|
connect(m_ui.enabled, &QCheckBox::checkStateChanged, this, &GamePatchDetailsWidget::onEnabledStateChanged);
|
|
}
|
|
|
|
GamePatchDetailsWidget::~GamePatchDetailsWidget() = default;
|
|
|
|
void GamePatchDetailsWidget::onEnabledStateChanged(int state)
|
|
{
|
|
SettingsInterface* si = m_dialog->getSettingsInterface();
|
|
if (state == Qt::Checked)
|
|
{
|
|
si->AddToStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY, m_name.c_str());
|
|
si->RemoveFromStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_DISABLE_CONFIG_KEY, m_name.c_str());
|
|
}
|
|
else
|
|
{
|
|
si->RemoveFromStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY, m_name.c_str());
|
|
if (m_ui.enabled->isTristate())
|
|
{
|
|
if (state == Qt::Unchecked)
|
|
{
|
|
si->AddToStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_DISABLE_CONFIG_KEY, m_name.c_str());
|
|
}
|
|
else
|
|
{
|
|
si->RemoveFromStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_DISABLE_CONFIG_KEY, m_name.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
si->Save();
|
|
g_emu_thread->reloadGameSettings();
|
|
}
|
|
|
|
GamePatchSettingsWidget::GamePatchSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent)
|
|
: SettingsWidget(settings_dialog, parent)
|
|
{
|
|
setupTab(m_ui);
|
|
|
|
m_ui.scrollArea->setFrameShape(QFrame::WinPanel);
|
|
m_ui.scrollArea->setFrameShadow(QFrame::Sunken);
|
|
|
|
setUnlabeledPatchesWarningVisibility(false);
|
|
setGlobalWsPatchNoteVisibility(false);
|
|
setGlobalNiPatchNoteVisibility(false);
|
|
|
|
SettingsInterface* sif = dialog()->getSettingsInterface();
|
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.allCRCsCheckbox, "EmuCore", "ShowPatchesForAllCRCs", false);
|
|
|
|
connect(m_ui.reload, &QPushButton::clicked, this, &GamePatchSettingsWidget::onReloadClicked);
|
|
connect(m_ui.allCRCsCheckbox, &QCheckBox::checkStateChanged, this, &GamePatchSettingsWidget::reloadList);
|
|
connect(dialog(), &SettingsWindow::discSerialChanged, this, &GamePatchSettingsWidget::reloadList);
|
|
|
|
dialog()->registerWidgetHelp(m_ui.allCRCsCheckbox, tr("Show Patches For All CRCs"), tr("Checked"),
|
|
tr("Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded."));
|
|
|
|
reloadList();
|
|
}
|
|
|
|
GamePatchSettingsWidget::~GamePatchSettingsWidget() = default;
|
|
|
|
void GamePatchSettingsWidget::onReloadClicked()
|
|
{
|
|
reloadList();
|
|
|
|
// reload it on the emu thread too, so it picks up any changes
|
|
g_emu_thread->reloadPatches();
|
|
}
|
|
|
|
void GamePatchSettingsWidget::disableAllPatches()
|
|
{
|
|
SettingsInterface* si = dialog()->getSettingsInterface();
|
|
si->ClearSection(Patch::PATCHES_CONFIG_SECTION);
|
|
si->Save();
|
|
}
|
|
|
|
void GamePatchSettingsWidget::reloadList()
|
|
{
|
|
const SettingsInterface* si = dialog()->getSettingsInterface();
|
|
// Patches shouldn't have any unlabelled patch groups, because they're new.
|
|
u32 number_of_unlabeled_patches = 0;
|
|
bool showAllCRCS = m_ui.allCRCsCheckbox->isChecked();
|
|
std::vector<Patch::PatchInfo> patches = Patch::GetPatchInfo(dialog()->getSerial(), dialog()->getDiscCRC(), false, showAllCRCS, &number_of_unlabeled_patches);
|
|
std::vector<std::string> enabled_list =
|
|
si->GetStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY);
|
|
std::vector<std::string> disabled_list =
|
|
si->GetStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_DISABLE_CONFIG_KEY);
|
|
|
|
const bool ws_patches_enabled_globally = dialog()->getEffectiveBoolValue("EmuCore", "EnableWideScreenPatches", false);
|
|
const bool ni_patches_enabled_globally = dialog()->getEffectiveBoolValue("EmuCore", "EnableNoInterlacingPatches", false);
|
|
|
|
setUnlabeledPatchesWarningVisibility(number_of_unlabeled_patches > 0);
|
|
setGlobalWsPatchNoteVisibility(ws_patches_enabled_globally);
|
|
setGlobalNiPatchNoteVisibility(ni_patches_enabled_globally);
|
|
delete m_ui.scrollArea->takeWidget();
|
|
m_ui.allCRCsCheckbox->setEnabled(!dialog()->getSerial().empty());
|
|
|
|
QWidget* container = new QWidget(m_ui.scrollArea);
|
|
QVBoxLayout* layout = new QVBoxLayout(container);
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
if (!patches.empty())
|
|
{
|
|
bool first = true;
|
|
|
|
for (const Patch::PatchInfo& pi : patches)
|
|
{
|
|
if (!first)
|
|
{
|
|
QFrame* frame = new QFrame(container);
|
|
frame->setFrameShape(QFrame::HLine);
|
|
frame->setFrameShadow(QFrame::Sunken);
|
|
layout->addWidget(frame);
|
|
}
|
|
else
|
|
{
|
|
first = false;
|
|
}
|
|
|
|
const bool is_on_enable_list = std::find(enabled_list.begin(), enabled_list.end(), pi.name) != enabled_list.end();
|
|
const bool is_on_disable_list = std::find(disabled_list.begin(), disabled_list.end(), pi.name) != disabled_list.end();
|
|
const bool globally_toggleable_option = Patch::IsGloballyToggleablePatch(pi);
|
|
|
|
Qt::CheckState check_state;
|
|
if (!globally_toggleable_option)
|
|
{
|
|
// Normal patches
|
|
check_state = is_on_enable_list && !is_on_disable_list ? Qt::CheckState::Checked : Qt::CheckState::Unchecked;
|
|
}
|
|
else
|
|
{
|
|
// WS/NI patches
|
|
if (is_on_disable_list)
|
|
{
|
|
check_state = Qt::CheckState::Unchecked;
|
|
}
|
|
else if (is_on_enable_list)
|
|
{
|
|
check_state = Qt::CheckState::Checked;
|
|
}
|
|
else
|
|
{
|
|
check_state = Qt::CheckState::PartiallyChecked;
|
|
}
|
|
}
|
|
|
|
GamePatchDetailsWidget* it =
|
|
new GamePatchDetailsWidget(pi, globally_toggleable_option, check_state, dialog(), container);
|
|
layout->addWidget(it);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
QLabel* label = new QLabel(tr("There are no patches available for this game."), container);
|
|
layout->addWidget(label);
|
|
}
|
|
|
|
layout->addStretch(1);
|
|
|
|
m_ui.scrollArea->setWidget(container);
|
|
}
|
|
|
|
void GamePatchSettingsWidget::setUnlabeledPatchesWarningVisibility(bool visible)
|
|
{
|
|
m_ui.unlabeledPatchWarning->setVisible(visible);
|
|
}
|
|
|
|
void GamePatchSettingsWidget::setGlobalWsPatchNoteVisibility(bool visible)
|
|
{
|
|
m_ui.globalWsPatchState->setVisible(visible);
|
|
}
|
|
|
|
void GamePatchSettingsWidget::setGlobalNiPatchNoteVisibility(bool visible)
|
|
{
|
|
m_ui.globalNiPatchState->setVisible(visible);
|
|
}
|