Skip to content

Commit

Permalink
DolphinQt: Patches window added
Browse files Browse the repository at this point in the history
  • Loading branch information
sepalani committed Feb 28, 2021
1 parent 776c48d commit 89fae9f
Show file tree
Hide file tree
Showing 14 changed files with 307 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ add_executable(dolphin-emu
Debugger/CodeWidget.h
Debugger/JITWidget.cpp
Debugger/JITWidget.h
Debugger/MemoryPatchWidget.cpp
Debugger/MemoryPatchWidget.h
Debugger/MemoryViewWidget.cpp
Debugger/MemoryViewWidget.h
Debugger/MemoryWidget.cpp
Expand Down
6 changes: 6 additions & 0 deletions Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,8 @@ void CodeViewWidget::ReplaceAddress(u32 address, ReplaceWith replace)
{
PowerPC::debug_interface.UnsetPatch(address);
PowerPC::debug_interface.SetPatch(address, replace == ReplaceWith::BLR ? 0x4e800020 : 0x60000000);

emit MemoryPatchesChanged();
Update();
}

Expand Down Expand Up @@ -725,6 +727,8 @@ void CodeViewWidget::OnReplaceInstruction()
{
PowerPC::debug_interface.UnsetPatch(addr);
PowerPC::debug_interface.SetPatch(addr, dialog.GetCode());

emit MemoryPatchesChanged();
Update();
}
}
Expand All @@ -734,6 +738,8 @@ void CodeViewWidget::OnRestoreInstruction()
const u32 addr = GetContextAddress();

PowerPC::debug_interface.UnsetPatch(addr);

emit MemoryPatchesChanged();
Update();
}

Expand Down
1 change: 1 addition & 0 deletions Source/Core/DolphinQt/Debugger/CodeViewWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class CodeViewWidget : public QTableWidget
void ShowMemory(u32 address);
void SymbolsChanged();
void BreakpointsChanged();
void MemoryPatchesChanged();
void UpdateCodeWidget();

private:
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/Debugger/CodeWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ void CodeWidget::ConnectWidgets()
connect(m_code_view, &CodeViewWidget::SymbolsChanged, this, &CodeWidget::UpdateSymbols);
connect(m_code_view, &CodeViewWidget::BreakpointsChanged, this,
[this] { emit BreakpointsChanged(); });
connect(m_code_view, &CodeViewWidget::MemoryPatchesChanged, this,
[this] { emit MemoryPatchesChanged(); });
connect(m_code_view, &CodeViewWidget::UpdateCodeWidget, this, &CodeWidget::Update);

connect(m_code_view, &CodeViewWidget::RequestPPCComparison, this,
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DolphinQt/Debugger/CodeWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class CodeWidget : public QDockWidget
void UpdateSymbols();
signals:
void BreakpointsChanged();
void MemoryPatchesChanged();
void RequestPPCComparison(u32 addr);
void ShowMemory(u32 address);

Expand Down
207 changes: 207 additions & 0 deletions Source/Core/DolphinQt/Debugger/MemoryPatchWidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// Copyright 2021 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Debugger/MemoryPatchWidget.h"

#include <iomanip>
#include <sstream>

#include <QHeaderView>
#include <QTableWidget>
#include <QToolBar>
#include <QVBoxLayout>

#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/PowerPC/PowerPC.h"

#include "DolphinQt/Resources.h"
#include "DolphinQt/Settings.h"

MemoryPatchWidget::MemoryPatchWidget(QWidget* parent) : QDockWidget(parent)
{
setWindowTitle(tr("Patches"));
setObjectName(QStringLiteral("patches"));

setAllowedAreas(Qt::AllDockWidgetAreas);

auto& settings = Settings::GetQSettings();

restoreGeometry(settings.value(QStringLiteral("memorypatchwidget/geometry")).toByteArray());
setFloating(settings.value(QStringLiteral("memorypatchwidget/floating")).toBool());

CreateWidgets();

connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) {
if (!Settings::Instance().IsDebugModeEnabled())
return;

UpdateButtonsEnabled();

if (state == Core::State::Uninitialized)
{
PowerPC::debug_interface.ClearPatches();
Update();
}
});

connect(&Settings::Instance(), &Settings::MemoryPatchesVisibilityChanged, this,
[this](bool visible) { setHidden(!visible); });

connect(&Settings::Instance(), &Settings::DebugModeToggled, this, [this](bool enabled) {
setHidden(!enabled || !Settings::Instance().IsMemoryPatchesVisible());
});

connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryPatchWidget::UpdateIcons);
UpdateIcons();

setHidden(!Settings::Instance().IsMemoryPatchesVisible() ||
!Settings::Instance().IsDebugModeEnabled());

Update();
}

MemoryPatchWidget::~MemoryPatchWidget()
{
auto& settings = Settings::GetQSettings();

settings.setValue(QStringLiteral("memorypatchwidget/geometry"), saveGeometry());
settings.setValue(QStringLiteral("memorypatchwidget/floating"), isFloating());
}

void MemoryPatchWidget::CreateWidgets()
{
m_toolbar = new QToolBar;
m_toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);

m_table = new QTableWidget;
m_table->setColumnCount(3);
m_table->setSelectionMode(QAbstractItemView::SingleSelection);
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table->setEditTriggers(QAbstractItemView::NoEditTriggers);

const QStringList header{{tr("Active"), tr("Address"), tr("Value")}};
m_table->setHorizontalHeaderLabels(header);
m_table->verticalHeader()->hide();

auto* layout = new QVBoxLayout;

layout->addWidget(m_toolbar);
layout->addWidget(m_table);

m_toggle_on_off = m_toolbar->addAction(tr("On/Off"), this, &MemoryPatchWidget::OnToggleOnOff);
m_delete = m_toolbar->addAction(tr("Delete"), this, &MemoryPatchWidget::OnDelete);
m_clear = m_toolbar->addAction(tr("Clear"), this, &MemoryPatchWidget::OnClear);

QWidget* widget = new QWidget;
widget->setLayout(layout);

setWidget(widget);
}

void MemoryPatchWidget::UpdateIcons()
{
// TODO: Create a "debugger_toggle_on_off" icon
m_toggle_on_off->setIcon(Resources::GetScaledThemeIcon("debugger_breakpoint"));
m_delete->setIcon(Resources::GetScaledThemeIcon("debugger_delete"));
m_clear->setIcon(Resources::GetScaledThemeIcon("debugger_clear"));
}

void MemoryPatchWidget::UpdateButtonsEnabled()
{
if (!isVisible())
return;

const bool is_enabled = Core::IsRunning();
m_toggle_on_off->setEnabled(is_enabled);
m_delete->setEnabled(is_enabled);
m_clear->setEnabled(is_enabled);
}

void MemoryPatchWidget::closeEvent(QCloseEvent*)
{
Settings::Instance().SetMemoryPatchesVisible(false);
}

void MemoryPatchWidget::showEvent(QShowEvent* event)
{
UpdateButtonsEnabled();
}

void MemoryPatchWidget::Update()
{
m_table->clearContents();

int patch_id = 0;
m_table->setRowCount(patch_id);

auto create_item = [](const QString& string = QString()) {
QTableWidgetItem* item = new QTableWidgetItem(string);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
return item;
};

for (const auto& patch : PowerPC::debug_interface.GetPatches())
{
m_table->setRowCount(patch_id + 1);

const QString is_enabled =
(patch.is_enabled == Common::Debug::MemoryPatch::State::Enabled) ? tr("on") : tr("off");
auto* active = create_item(is_enabled);
active->setData(Qt::UserRole, patch_id);
m_table->setItem(patch_id, 0, active);

const QString address = QStringLiteral("%1").arg(patch.address, 8, 16, QLatin1Char('0'));
m_table->setItem(patch_id, 1, create_item(address));

std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (u8 b : patch.value)
{
oss << std::setw(2) << static_cast<u32>(b);
}
m_table->setItem(patch_id, 2, create_item(QString::fromStdString(oss.str())));

patch_id += 1;
}
}

void MemoryPatchWidget::OnDelete()
{
if (m_table->selectedItems().empty())
return;

const auto patch_id = m_table->selectedItems()[0]->data(Qt::UserRole).toUInt();

PowerPC::debug_interface.RemovePatch(patch_id);

emit MemoryPatchesChanged();
Update();
}

void MemoryPatchWidget::OnClear()
{
PowerPC::debug_interface.ClearPatches();

m_table->setRowCount(0);

emit MemoryPatchesChanged();
Update();
}

void MemoryPatchWidget::OnToggleOnOff()
{
if (m_table->selectedItems().empty())
return;

const auto patch_id = m_table->selectedItems()[0]->data(Qt::UserRole).toUInt();
const auto& patch = PowerPC::debug_interface.GetPatch(patch_id);
if (patch.is_enabled == Common::Debug::MemoryPatch::State::Enabled)
PowerPC::debug_interface.DisablePatch(patch_id);
else
PowerPC::debug_interface.EnablePatch(patch_id);

emit MemoryPatchesChanged();
Update();
}
45 changes: 45 additions & 0 deletions Source/Core/DolphinQt/Debugger/MemoryPatchWidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2021 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <QDockWidget>

class QAction;
class QTableWidget;
class QToolBar;
class QCloseEvent;

class MemoryPatchWidget : public QDockWidget
{
Q_OBJECT
public:
explicit MemoryPatchWidget(QWidget* parent = nullptr);
~MemoryPatchWidget();

void Update();

signals:
void MemoryPatchesChanged();

protected:
void closeEvent(QCloseEvent*) override;
void showEvent(QShowEvent* event) override;

private:
void CreateWidgets();

void OnDelete();
void OnClear();
void OnToggleOnOff();

void UpdateIcons();
void UpdateButtonsEnabled();

QToolBar* m_toolbar;
QTableWidget* m_table;
QAction* m_delete;
QAction* m_clear;
QAction* m_toggle_on_off;
};
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/DolphinQt.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
<ClCompile Include="Debugger\CodeViewWidget.cpp" />
<ClCompile Include="Debugger\CodeWidget.cpp" />
<ClCompile Include="Debugger\JITWidget.cpp" />
<ClCompile Include="Debugger\MemoryPatchWidget.cpp" />
<ClCompile Include="Debugger\MemoryViewWidget.cpp" />
<ClCompile Include="Debugger\MemoryWidget.cpp" />
<ClCompile Include="Debugger\NetworkWidget.cpp" />
Expand Down Expand Up @@ -292,6 +293,7 @@
<QtMoc Include="Debugger\CodeViewWidget.h" />
<QtMoc Include="Debugger\CodeWidget.h" />
<QtMoc Include="Debugger\JITWidget.h" />
<QtMoc Include="Debugger\MemoryPatchWidget.h" />
<QtMoc Include="Debugger\MemoryViewWidget.h" />
<QtMoc Include="Debugger\MemoryWidget.h" />
<QtMoc Include="Debugger\NetworkWidget.h" />
Expand Down
10 changes: 10 additions & 0 deletions Source/Core/DolphinQt/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
#include "DolphinQt/Debugger/CodeViewWidget.h"
#include "DolphinQt/Debugger/CodeWidget.h"
#include "DolphinQt/Debugger/JITWidget.h"
#include "DolphinQt/Debugger/MemoryPatchWidget.h"
#include "DolphinQt/Debugger/MemoryWidget.h"
#include "DolphinQt/Debugger/NetworkWidget.h"
#include "DolphinQt/Debugger/RegisterWidget.h"
Expand Down Expand Up @@ -407,6 +408,7 @@ void MainWindow::CreateComponents()
m_thread_widget = new ThreadWidget(this);
m_watch_widget = new WatchWidget(this);
m_breakpoint_widget = new BreakpointWidget(this);
m_memory_patch_widget = new MemoryPatchWidget(this);
m_code_widget = new CodeWidget(this);
m_cheats_manager = new CheatsManager(m_game_list->GetGameListModel(), this);

Expand Down Expand Up @@ -437,6 +439,9 @@ void MainWindow::CreateComponents()
&BreakpointWidget::Update);
connect(m_code_widget, &CodeWidget::RequestPPCComparison, m_jit_widget, &JITWidget::Compare);
connect(m_code_widget, &CodeWidget::ShowMemory, m_memory_widget, &MemoryWidget::SetAddress);
connect(m_code_widget, &CodeWidget::MemoryPatchesChanged, m_memory_patch_widget,
&MemoryPatchWidget::Update);

connect(m_memory_widget, &MemoryWidget::BreakpointsChanged, m_breakpoint_widget,
&BreakpointWidget::Update);
connect(m_memory_widget, &MemoryWidget::ShowCode, m_code_widget, [this](u32 address) {
Expand All @@ -452,6 +457,9 @@ void MainWindow::CreateComponents()
if (Core::GetState() == Core::State::Paused)
m_code_widget->SetAddress(address, CodeViewWidget::SetAddressUpdate::WithDetailedUpdate);
});

connect(m_memory_patch_widget, &MemoryPatchWidget::MemoryPatchesChanged, m_code_widget,
&CodeWidget::Update);
}

void MainWindow::ConnectMenuBar()
Expand Down Expand Up @@ -673,6 +681,7 @@ void MainWindow::ConnectStack()
addDockWidget(Qt::LeftDockWidgetArea, m_thread_widget);
addDockWidget(Qt::LeftDockWidgetArea, m_watch_widget);
addDockWidget(Qt::LeftDockWidgetArea, m_breakpoint_widget);
addDockWidget(Qt::LeftDockWidgetArea, m_memory_patch_widget);
addDockWidget(Qt::LeftDockWidgetArea, m_memory_widget);
addDockWidget(Qt::LeftDockWidgetArea, m_network_widget);
addDockWidget(Qt::LeftDockWidgetArea, m_jit_widget);
Expand All @@ -683,6 +692,7 @@ void MainWindow::ConnectStack()
tabifyDockWidget(m_log_widget, m_thread_widget);
tabifyDockWidget(m_log_widget, m_watch_widget);
tabifyDockWidget(m_log_widget, m_breakpoint_widget);
tabifyDockWidget(m_log_widget, m_memory_patch_widget);
tabifyDockWidget(m_log_widget, m_memory_widget);
tabifyDockWidget(m_log_widget, m_network_widget);
tabifyDockWidget(m_log_widget, m_jit_widget);
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/DolphinQt/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class JITWidget;
class LogConfigWidget;
class LogWidget;
class MappingWindow;
class MemoryPatchWidget;
class MemoryWidget;
class MenuBar;
class NetPlayDialog;
Expand Down Expand Up @@ -231,6 +232,7 @@ class MainWindow final : public QMainWindow
JITWidget* m_jit_widget;
LogWidget* m_log_widget;
LogConfigWidget* m_log_config_widget;
MemoryPatchWidget* m_memory_patch_widget;
MemoryWidget* m_memory_widget;
NetworkWidget* m_network_widget;
RegisterWidget* m_register_widget;
Expand Down
Loading

0 comments on commit 89fae9f

Please sign in to comment.