summaryrefslogtreecommitdiff
path: root/Source/Core/DolphinQt/Debugger/WatchWidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/DolphinQt/Debugger/WatchWidget.cpp')
-rw-r--r--Source/Core/DolphinQt/Debugger/WatchWidget.cpp176
1 files changed, 144 insertions, 32 deletions
diff --git a/Source/Core/DolphinQt/Debugger/WatchWidget.cpp b/Source/Core/DolphinQt/Debugger/WatchWidget.cpp
index e0573f39d4..2f4ea27598 100644
--- a/Source/Core/DolphinQt/Debugger/WatchWidget.cpp
+++ b/Source/Core/DolphinQt/Debugger/WatchWidget.cpp
@@ -83,7 +83,8 @@ void WatchWidget::CreateWidgets()
m_table->setColumnCount(NUM_COLUMNS);
m_table->verticalHeader()->setHidden(true);
m_table->setContextMenuPolicy(Qt::CustomContextMenu);
- m_table->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_table->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
m_new = m_toolbar->addAction(tr("New"), this, &WatchWidget::OnNewWatch);
m_delete = m_toolbar->addAction(tr("Delete"), this, &WatchWidget::OnDelete);
@@ -158,11 +159,11 @@ void WatchWidget::Update()
// i18n: Data type used in computing
tr("String"),
// i18n: Floating-point (non-integer) number
- tr("Float")});
+ tr("Float"), tr("Locked")});
for (int i = 0; i < size; i++)
{
- auto entry = PowerPC::debug_interface.GetWatch(i);
+ const auto& entry = PowerPC::debug_interface.GetWatch(i);
auto* label = new QTableWidgetItem(QString::fromStdString(entry.name));
auto* address =
@@ -172,8 +173,11 @@ void WatchWidget::Update()
auto* string = new QTableWidgetItem;
auto* floatValue = new QTableWidgetItem;
- std::array<QTableWidgetItem*, NUM_COLUMNS> items = {label, address, hex,
- decimal, string, floatValue};
+ auto* lockValue = new QTableWidgetItem;
+ lockValue->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable);
+
+ std::array<QTableWidgetItem*, NUM_COLUMNS> items = {label, address, hex, decimal,
+ string, floatValue, lockValue};
QBrush brush = QPalette().brush(QPalette::Text);
@@ -189,6 +193,7 @@ void WatchWidget::Update()
decimal->setText(QString::number(PowerPC::HostRead_U32(entry.address)));
string->setText(QString::fromStdString(PowerPC::HostGetString(entry.address, 32)));
floatValue->setText(QString::number(PowerPC::HostRead_F32(entry.address)));
+ lockValue->setCheckState(entry.locked ? Qt::Checked : Qt::Unchecked);
}
}
@@ -235,11 +240,7 @@ void WatchWidget::OnDelete()
if (m_table->selectedItems().empty())
return;
- auto row_variant = m_table->selectedItems()[0]->data(Qt::UserRole);
- if (row_variant.isNull())
- return;
-
- DeleteWatch(row_variant.toInt());
+ DeleteSelectedWatches();
}
void WatchWidget::OnClear()
@@ -280,6 +281,10 @@ void WatchWidget::OnLoad()
if (ini.GetLines("Watches", &watches, false))
{
+ for (const auto& watch : PowerPC::debug_interface.GetWatches())
+ {
+ PowerPC::debug_interface.UnsetPatch(watch.address);
+ }
PowerPC::debug_interface.ClearWatches();
PowerPC::debug_interface.LoadWatchesFromStrings(watches);
}
@@ -302,20 +307,30 @@ void WatchWidget::ShowContextMenu()
if (!m_table->selectedItems().empty())
{
- auto row_variant = m_table->selectedItems()[0]->data(Qt::UserRole);
-
- if (!row_variant.isNull())
+ const std::size_t count = m_table->selectionModel()->selectedRows().count();
+ if (count > 1)
{
- int row = row_variant.toInt();
+ menu->addAction(tr("&Delete Watches"), this, [this] { DeleteSelectedWatches(); });
+ menu->addAction(tr("&Lock Watches"), this, [this] { LockSelectedWatches(); });
+ menu->addAction(tr("&Unlock Watches"), this, [this] { UnlockSelectedWatches(); });
+ }
+ else if (count == 1)
+ {
+ auto row_variant = m_table->selectedItems()[0]->data(Qt::UserRole);
- if (row >= 0)
+ if (!row_variant.isNull())
{
- menu->addAction(tr("Show in Memory"), this, [this, row] { ShowInMemory(row); });
- // i18n: This kind of "watch" is used for watching emulated memory.
- // It's not related to timekeeping devices.
- menu->addAction(tr("&Delete Watch"), this, [this, row] { DeleteWatch(row); });
- menu->addAction(tr("&Add Memory Breakpoint"), this,
- [this, row] { AddWatchBreakpoint(row); });
+ int row = row_variant.toInt();
+
+ if (row >= 0)
+ {
+ menu->addAction(tr("Show in Memory"), this, [this, row] { ShowInMemory(row); });
+ // i18n: This kind of "watch" is used for watching emulated memory.
+ // It's not related to timekeeping devices.
+ menu->addAction(tr("&Delete Watch"), this, [this, row] { DeleteWatchAndUpdate(row); });
+ menu->addAction(tr("&Add Memory Breakpoint"), this,
+ [this, row] { AddWatchBreakpoint(row); });
+ }
}
}
}
@@ -349,29 +364,35 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item)
{
switch (column)
{
- // Label
- case 0:
+ case COLUMN_INDEX_LABEL:
if (item->text().isEmpty())
- DeleteWatch(row);
+ DeleteWatchAndUpdate(row);
else
PowerPC::debug_interface.UpdateWatchName(row, item->text().toStdString());
break;
- // Address
- // Hexadecimal
- // Decimal
- case 1:
- case 2:
- case 3:
+ case COLUMN_INDEX_ADDRESS:
+ case COLUMN_INDEX_HEX:
+ case COLUMN_INDEX_DECIMAL:
{
bool good;
- quint32 value = item->text().toUInt(&good, column < 3 ? 16 : 10);
+ const bool column_uses_hex_formatting =
+ column == COLUMN_INDEX_ADDRESS || column == COLUMN_INDEX_HEX;
+ quint32 value = item->text().toUInt(&good, column_uses_hex_formatting ? 16 : 10);
if (good)
{
- if (column == 1)
+ if (column == COLUMN_INDEX_ADDRESS)
+ {
+ const auto& watch = PowerPC::debug_interface.GetWatch(row);
+ PowerPC::debug_interface.UnsetPatch(watch.address);
PowerPC::debug_interface.UpdateWatchAddress(row, value);
+ if (watch.locked)
+ LockWatchAddress(value);
+ }
else
+ {
PowerPC::HostWrite_U32(value, PowerPC::debug_interface.GetWatch(row).address);
+ }
}
else
{
@@ -379,15 +400,68 @@ void WatchWidget::OnItemChanged(QTableWidgetItem* item)
}
break;
}
+ case COLUMN_INDEX_LOCK:
+ {
+ PowerPC::debug_interface.UpdateWatchLockedState(row, item->checkState() == Qt::Checked);
+ const auto& watch = PowerPC::debug_interface.GetWatch(row);
+ if (watch.locked)
+ LockWatchAddress(watch.address);
+ else
+ PowerPC::debug_interface.UnsetPatch(watch.address);
+ break;
+ }
}
Update();
}
}
+void WatchWidget::LockWatchAddress(u32 address)
+{
+ const std::string memory_data_as_string = PowerPC::HostGetString(address, 4);
+
+ std::vector<u8> bytes;
+ for (const char c : memory_data_as_string)
+ {
+ bytes.push_back(static_cast<u8>(c));
+ }
+
+ PowerPC::debug_interface.SetFramePatch(address, bytes);
+}
+
+void WatchWidget::DeleteSelectedWatches()
+{
+ std::vector<int> row_indices;
+ for (const auto& index : m_table->selectionModel()->selectedRows())
+ {
+ const auto* item = m_table->item(index.row(), index.column());
+ const auto row_variant = item->data(Qt::UserRole);
+ if (row_variant.isNull())
+ continue;
+
+ row_indices.push_back(row_variant.toInt());
+ }
+
+ // Sort greatest to smallest, so we
+ // don't stomp on existing indices
+ std::sort(row_indices.begin(), row_indices.end(), std::greater{});
+ for (const int row : row_indices)
+ {
+ DeleteWatch(row);
+ }
+
+ Update();
+}
+
void WatchWidget::DeleteWatch(int row)
{
+ PowerPC::debug_interface.UnsetPatch(PowerPC::debug_interface.GetWatch(row).address);
PowerPC::debug_interface.RemoveWatch(row);
+}
+
+void WatchWidget::DeleteWatchAndUpdate(int row)
+{
+ DeleteWatch(row);
Update();
}
@@ -406,3 +480,41 @@ void WatchWidget::AddWatch(QString name, u32 addr)
PowerPC::debug_interface.SetWatch(addr, name.toStdString());
Update();
}
+
+void WatchWidget::LockSelectedWatches()
+{
+ for (const auto& index : m_table->selectionModel()->selectedRows())
+ {
+ const auto* item = m_table->item(index.row(), index.column());
+ const auto row_variant = item->data(Qt::UserRole);
+ if (row_variant.isNull())
+ continue;
+ const int row = row_variant.toInt();
+ const auto& watch = PowerPC::debug_interface.GetWatch(row);
+ if (watch.locked)
+ continue;
+ PowerPC::debug_interface.UpdateWatchLockedState(row, true);
+ LockWatchAddress(watch.address);
+ }
+
+ Update();
+}
+
+void WatchWidget::UnlockSelectedWatches()
+{
+ for (const auto& index : m_table->selectionModel()->selectedRows())
+ {
+ const auto* item = m_table->item(index.row(), index.column());
+ const auto row_variant = item->data(Qt::UserRole);
+ if (row_variant.isNull())
+ continue;
+ const int row = row_variant.toInt();
+ const auto& watch = PowerPC::debug_interface.GetWatch(row);
+ if (!watch.locked)
+ continue;
+ PowerPC::debug_interface.UpdateWatchLockedState(row, false);
+ PowerPC::debug_interface.UnsetPatch(watch.address);
+ }
+
+ Update();
+}