diff options
Diffstat (limited to 'Source/Core/DolphinQt/Debugger/WatchWidget.cpp')
| -rw-r--r-- | Source/Core/DolphinQt/Debugger/WatchWidget.cpp | 176 |
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(); +} |
