|
|
@@ -0,0 +1,175 @@ |
|
|
// Copyright 2018 Dolphin Emulator Project |
|
|
// Licensed under GPLv2+ |
|
|
// Refer to the license.txt file included. |
|
|
|
|
|
#include "DolphinQt2/Config/PatchesWidget.h" |
|
|
|
|
|
#include <QGridLayout> |
|
|
#include <QListWidget> |
|
|
#include <QPushButton> |
|
|
|
|
|
#include "Common/FileUtil.h" |
|
|
#include "Common/IniFile.h" |
|
|
#include "Common/StringUtil.h" |
|
|
#include "Core/ConfigManager.h" |
|
|
#include "DolphinQt2/Config/NewPatchDialog.h" |
|
|
|
|
|
PatchesWidget::PatchesWidget(const GameFile& game) |
|
|
: m_game(game), m_game_id(game.GetGameID().toStdString()), m_game_revision(game.GetRevision()) |
|
|
{ |
|
|
IniFile game_ini_local; |
|
|
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"); |
|
|
|
|
|
IniFile game_ini_default = SConfig::GetInstance().LoadDefaultGameIni(m_game_id, m_game_revision); |
|
|
|
|
|
PatchEngine::LoadPatchSection("OnFrame", m_patches, game_ini_default, game_ini_local); |
|
|
|
|
|
CreateWidgets(); |
|
|
ConnectWidgets(); |
|
|
|
|
|
Update(); |
|
|
|
|
|
UpdateActions(); |
|
|
} |
|
|
|
|
|
void PatchesWidget::CreateWidgets() |
|
|
{ |
|
|
m_list = new QListWidget; |
|
|
m_add_button = new QPushButton(tr("&Add...")); |
|
|
m_edit_button = new QPushButton(); |
|
|
m_remove_button = new QPushButton(tr("&Remove")); |
|
|
|
|
|
auto* layout = new QGridLayout; |
|
|
|
|
|
layout->addWidget(m_list, 0, 0, 1, -1); |
|
|
layout->addWidget(m_add_button, 1, 0); |
|
|
layout->addWidget(m_edit_button, 1, 2); |
|
|
layout->addWidget(m_remove_button, 1, 1); |
|
|
|
|
|
setLayout(layout); |
|
|
} |
|
|
|
|
|
void PatchesWidget::ConnectWidgets() |
|
|
{ |
|
|
connect(m_list, &QListWidget::itemSelectionChanged, this, &PatchesWidget::UpdateActions); |
|
|
connect(m_list, &QListWidget::itemChanged, this, &PatchesWidget::OnItemChanged); |
|
|
connect(m_remove_button, &QPushButton::pressed, this, &PatchesWidget::OnRemove); |
|
|
connect(m_add_button, &QPushButton::pressed, this, &PatchesWidget::OnAdd); |
|
|
connect(m_edit_button, &QPushButton::pressed, this, &PatchesWidget::OnEdit); |
|
|
} |
|
|
|
|
|
void PatchesWidget::OnItemChanged(QListWidgetItem* item) |
|
|
{ |
|
|
m_patches[m_list->row(item)].active = (item->checkState() == Qt::Checked); |
|
|
SavePatches(); |
|
|
} |
|
|
|
|
|
void PatchesWidget::OnAdd() |
|
|
{ |
|
|
PatchEngine::Patch patch; |
|
|
patch.user_defined = true; |
|
|
|
|
|
if (NewPatchDialog(patch).exec()) |
|
|
{ |
|
|
m_patches.push_back(patch); |
|
|
SavePatches(); |
|
|
Update(); |
|
|
} |
|
|
} |
|
|
|
|
|
void PatchesWidget::OnEdit() |
|
|
{ |
|
|
if (m_list->selectedItems().isEmpty()) |
|
|
return; |
|
|
|
|
|
auto* item = m_list->selectedItems()[0]; |
|
|
|
|
|
auto patch = m_patches[m_list->row(item)]; |
|
|
|
|
|
if (!patch.user_defined) |
|
|
patch.name += tr(" (Copy)").toStdString(); |
|
|
|
|
|
if (NewPatchDialog(patch).exec()) |
|
|
{ |
|
|
if (patch.user_defined) |
|
|
{ |
|
|
m_patches[m_list->row(item)] = patch; |
|
|
} |
|
|
else |
|
|
{ |
|
|
patch.user_defined = true; |
|
|
m_patches.push_back(patch); |
|
|
} |
|
|
|
|
|
SavePatches(); |
|
|
Update(); |
|
|
} |
|
|
} |
|
|
|
|
|
void PatchesWidget::OnRemove() |
|
|
{ |
|
|
if (m_list->selectedItems().isEmpty()) |
|
|
return; |
|
|
|
|
|
m_patches.erase(m_patches.begin() + m_list->row(m_list->selectedItems()[0])); |
|
|
SavePatches(); |
|
|
Update(); |
|
|
} |
|
|
|
|
|
void PatchesWidget::SavePatches() |
|
|
{ |
|
|
std::vector<std::string> lines; |
|
|
std::vector<std::string> lines_enabled; |
|
|
|
|
|
for (const auto& patch : m_patches) |
|
|
{ |
|
|
if (patch.active) |
|
|
lines_enabled.push_back("$" + patch.name); |
|
|
|
|
|
if (!patch.user_defined) |
|
|
continue; |
|
|
|
|
|
lines.push_back("$" + patch.name); |
|
|
|
|
|
for (const auto& entry : patch.entries) |
|
|
{ |
|
|
lines.push_back(StringFromFormat("0x%08X:%s:0x%08X", entry.address, |
|
|
PatchEngine::PatchTypeStrings[entry.type], entry.value)); |
|
|
} |
|
|
} |
|
|
|
|
|
IniFile game_ini_local; |
|
|
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"); |
|
|
|
|
|
game_ini_local.SetLines("OnFrame_Enabled", lines_enabled); |
|
|
game_ini_local.SetLines("OnFrame", lines); |
|
|
|
|
|
game_ini_local.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"); |
|
|
} |
|
|
|
|
|
void PatchesWidget::Update() |
|
|
{ |
|
|
m_list->clear(); |
|
|
|
|
|
for (const auto& patch : m_patches) |
|
|
{ |
|
|
auto* item = new QListWidgetItem(QString::fromStdString(patch.name)); |
|
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable); |
|
|
item->setCheckState(patch.active ? Qt::Checked : Qt::Unchecked); |
|
|
item->setData(Qt::UserRole, patch.user_defined); |
|
|
|
|
|
m_list->addItem(item); |
|
|
} |
|
|
} |
|
|
|
|
|
void PatchesWidget::UpdateActions() |
|
|
{ |
|
|
bool selected = !m_list->selectedItems().isEmpty(); |
|
|
auto* item = m_list->selectedItems()[0]; |
|
|
|
|
|
bool user_defined = selected ? item->data(Qt::UserRole).toBool() : true; |
|
|
|
|
|
m_edit_button->setEnabled(selected); |
|
|
m_edit_button->setText(user_defined ? tr("&Edit...") : tr("&Clone...")); |
|
|
m_remove_button->setEnabled(selected && user_defined); |
|
|
} |