diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.cpp b/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.cpp index 5cee329a2d..194197e00e 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.cpp +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.cpp @@ -42,6 +42,7 @@ BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, Breakpo m_ui.rdoExecute->setChecked(true); m_ui.chkEnable->setChecked(bp->enabled); m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(bp->addr, 16)); + m_ui.txtDescription->setText(QString::fromStdString(bp->description)); if (bp->hasCond) m_ui.txtCondition->setText(QString::fromStdString(bp->cond.expressionString)); @@ -53,6 +54,8 @@ BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, Breakpo m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(mc->start, 16)); m_ui.txtSize->setText(QtUtils::FilledQStringFromValue(mc->end - mc->start, 16)); + m_ui.txtDescription->setText(QString::fromStdString(mc->description)); + m_ui.chkRead->setChecked(mc->memCond & MEMCHECK_READ); m_ui.chkWrite->setChecked(mc->memCond & MEMCHECK_WRITE); m_ui.chkChange->setChecked(mc->memCond & MEMCHECK_WRITE_ONCHANGE); @@ -102,6 +105,7 @@ void BreakpointDialog::accept() } bp->addr = address; + bp->description = m_ui.txtDescription->text().toStdString(); bp->enabled = m_ui.chkEnable->isChecked(); @@ -138,6 +142,7 @@ void BreakpointDialog::accept() mc->start = startAddress; mc->end = startAddress + size; + mc->description = m_ui.txtDescription->text().toStdString(); if (!m_ui.txtCondition->text().isEmpty()) { diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.ui b/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.ui index a15212baf0..ec751dd211 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.ui +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointDialog.ui @@ -10,7 +10,7 @@ 0 0 375 - 250 + 300 @@ -22,19 +22,19 @@ 375 - 250 + 300 375 - 250 + 300 375 - 250 + 300 @@ -44,7 +44,7 @@ 20 - 210 + 260 341 32 @@ -102,14 +102,17 @@ 110 10 - 251 - 41 + 250 + 79 + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + @@ -139,6 +142,29 @@ + + + + Description + + + + + + + + 0 + 19 + + + + + 16777215 + 19 + + + + @@ -148,7 +174,7 @@ 110 - 50 + 100 251 91 @@ -224,13 +250,13 @@ 110 - 140 + 190 251 61 - + diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp index 7f8deb09cf..4860f4d9f6 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.cpp @@ -77,6 +77,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const return tr("Execute"); case BreakpointColumns::OFFSET: return QtUtils::FilledQStringFromValue(bp->addr, 16); + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(bp->description); case BreakpointColumns::SIZE_LABEL: return QString::fromStdString(m_cpu.GetSymbolGuardian().FunctionStartingAtAddress(bp->addr).name); case BreakpointColumns::OPCODE: @@ -105,6 +107,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const } case BreakpointColumns::OFFSET: return QtUtils::FilledQStringFromValue(mc->start, 16); + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(mc->description); case BreakpointColumns::SIZE_LABEL: return QString::number(mc->end - mc->start, 16); case BreakpointColumns::OPCODE: @@ -116,6 +120,29 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const } } } + else if (role == Qt::EditRole) + { + if (const auto* bp = std::get_if(&bp_mc)) + { + switch (index.column()) + { + case BreakpointColumns::CONDITION: + return bp->hasCond ? QString::fromStdString(bp->cond.expressionString) : ""; + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(bp->description); + } + } + else if (const auto* mc = std::get_if(&bp_mc)) + { + switch (index.column()) + { + case BreakpointColumns::CONDITION: + return mc->hasCond ? QString::fromStdString(mc->cond.expressionString) : ""; + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(mc->description); + } + } + } else if (role == BreakpointModel::DataRole) { if (const auto* bp = std::get_if(&bp_mc)) @@ -128,6 +155,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const return MEMCHECK_INVALID; case BreakpointColumns::OFFSET: return bp->addr; + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(bp->description); case BreakpointColumns::SIZE_LABEL: return QString::fromStdString(m_cpu.GetSymbolGuardian().FunctionStartingAtAddress(bp->addr).name); case BreakpointColumns::OPCODE: @@ -149,6 +178,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const return mc->memCond; case BreakpointColumns::OFFSET: return mc->start; + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(mc->description); case BreakpointColumns::SIZE_LABEL: return mc->end - mc->start; case BreakpointColumns::OPCODE: @@ -172,6 +203,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const return MEMCHECK_INVALID; case BreakpointColumns::OFFSET: return QtUtils::FilledQStringFromValue(bp->addr, 16); + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(bp->description); case BreakpointColumns::SIZE_LABEL: return QString::fromStdString(m_cpu.GetSymbolGuardian().FunctionStartingAtAddress(bp->addr).name); case BreakpointColumns::OPCODE: @@ -191,6 +224,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const return mc->memCond; case BreakpointColumns::OFFSET: return QtUtils::FilledQStringFromValue(mc->start, 16); + case BreakpointColumns::DESCRIPTION: + return QString::fromStdString(mc->description); case BreakpointColumns::SIZE_LABEL: return mc->end - mc->start; case BreakpointColumns::OPCODE: @@ -233,6 +268,8 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, i case BreakpointColumns::OFFSET: //: Warning: limited space available. Abbreviate if needed. return tr("OFFSET"); + case BreakpointColumns::DESCRIPTION: + return "DESCRIPTION"; case BreakpointColumns::SIZE_LABEL: //: Warning: limited space available. Abbreviate if needed. return tr("SIZE / LABEL"); @@ -260,6 +297,8 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, i return "TYPE"; case BreakpointColumns::OFFSET: return "OFFSET"; + case BreakpointColumns::DESCRIPTION: + return "DESCRIPTION"; case BreakpointColumns::SIZE_LABEL: return "SIZE / LABEL"; case BreakpointColumns::OPCODE: @@ -282,6 +321,7 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const switch (index.column()) { case BreakpointColumns::CONDITION: + case BreakpointColumns::DESCRIPTION: return Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEditable; case BreakpointColumns::TYPE: case BreakpointColumns::OPCODE: @@ -393,6 +433,27 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i } } emit dataChanged(index, index); + return true; + } + else if (role == Qt::EditRole && index.column() == BreakpointColumns::DESCRIPTION) + { + // Update BreakPoint description + if (auto* bp = std::get_if(&bp_mc)) + { + const QString descValue = value.toString(); + Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp, descValue] { + CBreakPoints::ChangeBreakPointDescription(cpu, bp->addr, descValue.toStdString()); + }); + } + // Update MemCheck description + else if (auto* mc = std::get_if(&bp_mc)) + { + const QString descValue = value.toString(); + Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc, descValue] { + CBreakPoints::ChangeMemCheckDescription(cpu, mc->start, mc->end, descValue.toStdString()); + }); + } + emit dataChanged(index, index); return true; } @@ -548,6 +609,12 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields) return; } + // Description + if (!fields[BreakpointColumns::DESCRIPTION].isEmpty()) + { + bp.description = fields[BreakpointColumns::DESCRIPTION].toStdString(); + } + insertBreakpointRows(0, 1, {bp}); } else @@ -608,6 +675,12 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields) } mc.result = static_cast(result); + // Description + if (!fields[BreakpointColumns::DESCRIPTION].isEmpty()) + { + mc.description = fields[BreakpointColumns::DESCRIPTION].toStdString(); + } + insertBreakpointRows(0, 1, {mc}); } } diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h index fd603bb858..161625eb6e 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointModel.h @@ -21,6 +21,7 @@ public: ENABLED = 0, TYPE, OFFSET, + DESCRIPTION, SIZE_LABEL, OPCODE, CONDITION, @@ -38,6 +39,7 @@ public: QHeaderView::ResizeMode::ResizeToContents, QHeaderView::ResizeMode::ResizeToContents, QHeaderView::ResizeMode::ResizeToContents, + QHeaderView::ResizeMode::ResizeToContents, QHeaderView::ResizeMode::Stretch, QHeaderView::ResizeMode::Stretch, QHeaderView::ResizeMode::ResizeToContents, diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointView.cpp b/pcsx2-qt/Debugger/Breakpoints/BreakpointView.cpp index 603f399d27..ffded4e579 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointView.cpp +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointView.cpp @@ -21,6 +21,11 @@ BreakpointView::BreakpointView(const DebuggerViewParameters& parameters) connect(m_ui.breakpointList, &QTableView::doubleClicked, this, &BreakpointView::onDoubleClicked); m_ui.breakpointList->setModel(m_model); + this->resizeColumns(); +} + +void BreakpointView::resizeColumns() +{ for (std::size_t i = 0; auto mode : BreakpointModel::HeaderResizeModes) { m_ui.breakpointList->horizontalHeader()->setSectionResizeMode(i, mode); @@ -124,6 +129,7 @@ void BreakpointView::contextDelete() void BreakpointView::contextNew() { BreakpointDialog* bpDialog = new BreakpointDialog(this, &cpu(), *m_model); + connect(bpDialog, &QDialog::accepted, this, &BreakpointView::resizeColumns); bpDialog->setAttribute(Qt::WA_DeleteOnClose); bpDialog->show(); } @@ -140,6 +146,7 @@ void BreakpointView::contextEdit() auto bpObject = m_model->at(selectedRow); BreakpointDialog* bpDialog = new BreakpointDialog(this, &cpu(), *m_model, bpObject, selectedRow); + connect(bpDialog, &QDialog::accepted, this, &BreakpointView::resizeColumns); bpDialog->setAttribute(Qt::WA_DeleteOnClose); bpDialog->show(); } diff --git a/pcsx2-qt/Debugger/Breakpoints/BreakpointView.h b/pcsx2-qt/Debugger/Breakpoints/BreakpointView.h index 333fd36315..52dd529f50 100644 --- a/pcsx2-qt/Debugger/Breakpoints/BreakpointView.h +++ b/pcsx2-qt/Debugger/Breakpoints/BreakpointView.h @@ -32,6 +32,8 @@ public: void contextEdit(); void contextPasteCSV(); + void resizeColumns(); + void saveBreakpointsToDebuggerSettings(); private: diff --git a/pcsx2-qt/Debugger/DebuggerSettingsManager.cpp b/pcsx2-qt/Debugger/DebuggerSettingsManager.cpp index 81a23c8858..bec1acf0ee 100644 --- a/pcsx2-qt/Debugger/DebuggerSettingsManager.cpp +++ b/pcsx2-qt/Debugger/DebuggerSettingsManager.cpp @@ -12,7 +12,7 @@ #include "VMManager.h" std::mutex DebuggerSettingsManager::writeLock; -const QString DebuggerSettingsManager::settingsFileVersion = "0.00"; +const QString DebuggerSettingsManager::settingsFileVersion = "0.01"; QJsonObject DebuggerSettingsManager::loadGameSettingsJSON() { @@ -61,6 +61,18 @@ void DebuggerSettingsManager::loadGameSettings(BreakpointModel* bpModel) Console.WriteLnFmt("Debugger Settings Manager: Failed to read Breakpoints array from settings file: '{}'", path); return; } + + // Breakpoint descriptions were added at debugger settings file version 0.01. If loading + // saved breakpoints from a previous version (only 0.00 existed prior), the breakpoints will be + // missing a description. This code will add in an empty description so that the previous + // version, 0.00, is compatible with 0.01. + const QJsonValue savedVersionValue = loadGameSettingsJSON().value("Version"); + const QString savedVersion = savedVersionValue.toString(); + bool isMissingDescription = false; + if (!savedVersionValue.isUndefined()) + { + isMissingDescription = savedVersion.toStdString() == "0.00"; + } const QJsonArray breakpointsArray = breakpointsValue.toArray(); for (u32 row = 0; row < breakpointsArray.size(); row++) @@ -71,7 +83,13 @@ void DebuggerSettingsManager::loadGameSettings(BreakpointModel* bpModel) Console.WriteLn("Debugger Settings Manager: Failed to load invalid Breakpoint object."); continue; } - const QJsonObject rowObject = rowValue.toObject(); + QJsonObject rowObject = rowValue.toObject(); + + // Add empty description for saved breakpoints from debugger settings versions prior to 0.01 + if (isMissingDescription) + { + rowObject.insert(QString("DESCRIPTION"), QJsonValue("")); + } QStringList fields; u32 col = 0; diff --git a/pcsx2/DebugTools/Breakpoints.cpp b/pcsx2/DebugTools/Breakpoints.cpp index 8bc670e294..da87b27d84 100644 --- a/pcsx2/DebugTools/Breakpoints.cpp +++ b/pcsx2/DebugTools/Breakpoints.cpp @@ -285,6 +285,16 @@ BreakPointCond* CBreakPoints::GetBreakPointCondition(BreakPointCpu cpu, u32 addr return NULL; } +void CBreakPoints::ChangeBreakPointDescription(BreakPointCpu cpu, u32 addr, std::string description) +{ + const size_t bp = FindBreakpoint(cpu, addr, true, false); + if (bp != INVALID_BREAKPOINT) + { + breakPoints_[bp].description = description; + Update(); + } +} + void CBreakPoints::AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result) { // This will ruin any pending memchecks. @@ -356,6 +366,16 @@ void CBreakPoints::ChangeMemCheckAddCond(BreakPointCpu cpu, u32 start, u32 end, } } +void CBreakPoints::ChangeMemCheckDescription(BreakPointCpu cpu, u32 start, u32 end, std::string description) +{ + const size_t mc = FindMemCheck(cpu, start, end); + if (mc != INVALID_MEMCHECK) + { + memChecks_[mc].description = description; + Update(cpu); + } +} + void CBreakPoints::ClearAllMemChecks() { // This will ruin any pending memchecks. diff --git a/pcsx2/DebugTools/Breakpoints.h b/pcsx2/DebugTools/Breakpoints.h index fd100b4cc7..3d63f39fcc 100644 --- a/pcsx2/DebugTools/Breakpoints.h +++ b/pcsx2/DebugTools/Breakpoints.h @@ -37,6 +37,8 @@ struct BreakPoint BreakPointCond cond; BreakPointCpu cpu; + std::string description; + bool operator==(const BreakPoint& other) const { return addr == other.addr; @@ -78,6 +80,8 @@ struct MemCheck MemCheckResult result; BreakPointCpu cpu; + std::string description; + u32 numHits; u32 lastPC; @@ -119,12 +123,14 @@ public: static void ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond& cond); static void ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr); static BreakPointCond* GetBreakPointCondition(BreakPointCpu cpu, u32 addr); + static void ChangeBreakPointDescription(BreakPointCpu cpu, u32 addr, std::string description); static void AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result); static void RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end); static void ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result); static void ChangeMemCheckRemoveCond(BreakPointCpu cpu, u32 start, u32 end); static void ChangeMemCheckAddCond(BreakPointCpu cpu, u32 start, u32 end, const BreakPointCond& cond); + static void ChangeMemCheckDescription(BreakPointCpu cpu, u32 start, u32 end, std::string description); static void ClearAllMemChecks(); static void SetSkipFirst(BreakPointCpu cpu, u32 pc);