From 7025cc33821a09b773c8f5867ef57ca5588f65f9 Mon Sep 17 00:00:00 2001 From: PugsyMAME Date: Fri, 6 Aug 2021 12:11:22 +0100 Subject: [PATCH] Improved Cheat Memory Scanner functionality Work done : ** Made the columns sortable (someone asked for this GH I think) ** Moved the Add to Watch button to under the search parameters, and renamed it. ** Made the selection work on a block level so we can block "add results" and block "Remove Watch" on multiple entries ** Made the description show the raw code - so either 3xxxxxxx, 8xxxxxxx, 9xxxxxxx depending on the Data Size and the memory being under 0x200000. This can be edited still. ** Changed the Watch value field to take a hex number in the form 0xX as well as a decimal number. ** Moved the freeze box to the right column, I originally did this prior to finding out about ContiguousSelection and I think it makes more sense next to the value you want to freeze ** Removed the message about 5000 results limitation (it made searching painful) and added a text box showing it permanently along with the number of results (which you can observe going down as you continue the search) ** Hidden the "Save Watch" & "Load Watch" buttons, they have no functionality (yet) and making them invisible in the mean time makes it less confusing. --- src/duckstation-qt/cheatmanagerdialog.cpp | 117 +++++++++++++------ src/duckstation-qt/cheatmanagerdialog.h | 6 +- src/duckstation-qt/cheatmanagerdialog.ui | 132 ++++++++++++++++++---- 3 files changed, 200 insertions(+), 55 deletions(-) diff --git a/src/duckstation-qt/cheatmanagerdialog.cpp b/src/duckstation-qt/cheatmanagerdialog.cpp index a6eac41b9..6b9a7d39f 100644 --- a/src/duckstation-qt/cheatmanagerdialog.cpp +++ b/src/duckstation-qt/cheatmanagerdialog.cpp @@ -45,6 +45,28 @@ static QString formatHexAndDecValue(u32 value, u8 size, bool is_signed) return QStringLiteral("0x%1 (%2)").arg(static_cast(value), size, 16, QChar('0')).arg(static_cast(value)); } + +static QString formatCheatCode(u32 address, u32 value, const MemoryAccessSize size) +{ + + if (size == MemoryAccessSize::Byte && address <= 0x00200000) + return QStringLiteral("CHEAT CODE: %1 %2") + .arg(static_cast(address) + 0x30000000, 8, 16, QChar('0')).toUpper() + .arg(static_cast(value), 4, 16, QChar('0')).toUpper(); + else if (size == MemoryAccessSize::HalfWord && address <= 0x001FFFFE) + return QStringLiteral("CHEAT CODE: %1 %2") + .arg(static_cast(address) + 0x80000000, 8, 16, QChar('0')).toUpper() + .arg(static_cast(value), 4, 16, QChar('0')).toUpper(); + else if (size == MemoryAccessSize::Word && address <= 0x001FFFFC) + return QStringLiteral("CHEAT CODE: %1 %2") + .arg(static_cast(address) + 0x90000000, 8, 16, QChar('0')).toUpper() + .arg(static_cast(value), 8, 16, QChar('0')).toUpper(); + else + return QStringLiteral("OUTSIDE RAM RANGE. POKE %1 with %2") + .arg(static_cast(address), 8, 16, QChar('0')).toUpper() + .arg(static_cast(value), 8, 16, QChar('0')).toUpper(); +} + static QString formatValue(u32 value, bool is_signed) { if (is_signed) @@ -173,8 +195,8 @@ void CheatManagerDialog::resizeEvent(QResizeEvent* event) void CheatManagerDialog::resizeColumns() { - QtUtils::ResizeColumnsForTableView(m_ui.scanTable, {-1, 100, 100}); - QtUtils::ResizeColumnsForTableView(m_ui.watchTable, {50, -1, 100, 150, 100}); + QtUtils::ResizeColumnsForTableView(m_ui.scanTable, {-1, 130, 130}); + QtUtils::ResizeColumnsForTableView(m_ui.watchTable, {-1, 100, 100, 100, 40}); QtUtils::ResizeColumnsForTreeView(m_ui.cheatList, {-1, 100, 150, 100}); } @@ -195,7 +217,7 @@ void CheatManagerDialog::setUpdateTimerEnabled(bool enabled) m_update_timer->stop(); } -int CheatManagerDialog::getSelectedResultIndex() const +int CheatManagerDialog::getSelectedResultIndexFirst() const { QList sel = m_ui.scanTable->selectedRanges(); if (sel.isEmpty()) @@ -204,7 +226,16 @@ int CheatManagerDialog::getSelectedResultIndex() const return sel.front().topRow(); } -int CheatManagerDialog::getSelectedWatchIndex() const +int CheatManagerDialog::getSelectedResultIndexLast() const +{ + QList sel = m_ui.scanTable->selectedRanges(); + if (sel.isEmpty()) + return -1; + + return sel.front().bottomRow(); +} + +int CheatManagerDialog::getSelectedWatchIndexFirst() const { QList sel = m_ui.watchTable->selectedRanges(); if (sel.isEmpty()) @@ -213,6 +244,15 @@ int CheatManagerDialog::getSelectedWatchIndex() const return sel.front().topRow(); } +int CheatManagerDialog::getSelectedWatchIndexLast() const +{ + QList sel = m_ui.watchTable->selectedRanges(); + if (sel.isEmpty()) + return -1; + + return sel.front().bottomRow(); +} + QTreeWidgetItem* CheatManagerDialog::getItemForCheatIndex(u32 index) const { QTreeWidgetItemIterator iter(m_ui.cheatList); @@ -683,16 +723,20 @@ void CheatManagerDialog::resetClicked() void CheatManagerDialog::addToWatchClicked() { - const int index = getSelectedResultIndex(); - if (index < 0) + const int indexFirst = getSelectedResultIndexFirst(); + const int indexLast = getSelectedResultIndexLast(); + if (indexFirst < 0) return; + for (int index = indexFirst; index <= indexLast; index++) + { const MemoryScan::Result& res = m_scanner.GetResults()[static_cast(index)]; - m_watch.AddEntry(StringUtil::StdStringFromFormat("0x%08x", res.address), res.address, m_scanner.GetSize(), - m_scanner.GetValueSigned(), false); + m_watch.AddEntry(StringUtil::StdStringFromFormat("0x%08x", res.address), res.address, m_scanner.GetSize(), m_scanner.GetValueSigned(), false); updateWatch(); } +} + void CheatManagerDialog::addManualWatchAddressClicked() { std::optional address = QtUtils::PromptForAddress(this, windowTitle(), tr("Enter manual address:"), false); @@ -721,13 +765,17 @@ void CheatManagerDialog::addManualWatchAddressClicked() void CheatManagerDialog::removeWatchClicked() { - const int index = getSelectedWatchIndex(); - if (index < 0) + const int indexFirst = getSelectedWatchIndexFirst(); + const int indexLast = getSelectedWatchIndexLast(); + if (indexFirst < 0) return; + for (int index = indexLast; index >= indexFirst; index--) + { m_watch.RemoveEntry(static_cast(index)); updateWatch(); } +} void CheatManagerDialog::scanCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) { @@ -775,19 +823,19 @@ void CheatManagerDialog::watchItemChanged(QTableWidgetItem* item) switch (item->column()) { - case 0: + case 4: { m_watch.SetEntryFreeze(index, (item->checkState() == Qt::Checked)); } break; - case 1: + case 0: { m_watch.SetEntryDescription(index, item->text().toStdString()); } break; - case 4: + case 3: { const MemoryWatchList::Entry& entry = m_watch.GetEntry(index); bool value_ok = false; @@ -799,7 +847,11 @@ void CheatManagerDialog::watchItemChanged(QTableWidgetItem* item) } else { - uint value = item->text().toUInt(&value_ok); + uint value; + if (item->text()[1] == 'x' || item->text()[1] == 'X') + value = item->text().toUInt(&value_ok, 16); + else + value = item->text().toUInt(&value_ok); if (value_ok) m_watch.SetEntryValue(index, static_cast(value)); } @@ -836,10 +888,6 @@ void CheatManagerDialog::updateResults() { if (row == MAX_DISPLAYED_SCAN_RESULTS) { - QMessageBox::information(this, tr("Memory Scan"), - tr("Memory scan found %1 addresses, but only the first %2 are displayed.") - .arg(m_scanner.GetResultCount()) - .arg(MAX_DISPLAYED_SCAN_RESULTS)); break; } @@ -874,7 +922,11 @@ void CheatManagerDialog::updateResults() m_ui.scanTable->setItem(row, 2, previous_item); row++; } + m_ui.scanResultsCount->setText(QString::number(m_scanner.GetResultCount())); + } + else + m_ui.scanResultsCount->setText("0"); m_ui.scanResetSearch->setEnabled(!results.empty()); m_ui.scanSearchAgain->setEnabled(!results.empty()); @@ -923,22 +975,17 @@ void CheatManagerDialog::updateWatch() { m_ui.watchTable->insertRow(row); - QTableWidgetItem* freeze_item = new QTableWidgetItem(); - freeze_item->setFlags(freeze_item->flags() | (Qt::ItemIsEditable | Qt::ItemIsUserCheckable)); - freeze_item->setCheckState(res.freeze ? Qt::Checked : Qt::Unchecked); - m_ui.watchTable->setItem(row, 0, freeze_item); - - QTableWidgetItem* description_item = new QTableWidgetItem(QString::fromStdString(res.description)); - m_ui.watchTable->setItem(row, 1, description_item); + QTableWidgetItem* description_item = new QTableWidgetItem(formatCheatCode(res.address, res.value, res.size)); + m_ui.watchTable->setItem(row, 0, description_item); QTableWidgetItem* address_item = new QTableWidgetItem(formatHexValue(res.address, 8)); address_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable)); - m_ui.watchTable->setItem(row, 2, address_item); + m_ui.watchTable->setItem(row, 1, address_item); QTableWidgetItem* size_item = new QTableWidgetItem(tr(s_size_strings[static_cast(res.size) + (res.is_signed ? 3 : 0)])); size_item->setFlags(address_item->flags() & ~(Qt::ItemIsEditable)); - m_ui.watchTable->setItem(row, 3, size_item); + m_ui.watchTable->setItem(row, 2, size_item); QTableWidgetItem* value_item; if (res.size == MemoryAccessSize::Byte) @@ -948,7 +995,13 @@ void CheatManagerDialog::updateWatch() else value_item = new QTableWidgetItem(formatHexAndDecValue(res.value, 8, res.is_signed)); - m_ui.watchTable->setItem(row, 4, value_item); + m_ui.watchTable->setItem(row, 3, value_item); + + QTableWidgetItem* freeze_item = new QTableWidgetItem(); + freeze_item->setFlags(freeze_item->flags() | (Qt::ItemIsEditable | Qt::ItemIsUserCheckable)); + freeze_item->setCheckState(res.freeze ? Qt::Checked : Qt::Unchecked); + m_ui.watchTable->setItem(row, 4, freeze_item); + row++; } } @@ -966,13 +1019,13 @@ void CheatManagerDialog::updateWatchValues() if (res.changed) { if (m_ui.scanValueBase->currentIndex() == 0) - m_ui.watchTable->item(row, 4)->setText(formatValue(res.value, res.is_signed)); + m_ui.watchTable->item(row, 3)->setText(formatValue(res.value, res.is_signed)); else if (m_scanner.GetSize() == MemoryAccessSize::Byte) - m_ui.watchTable->item(row, 4)->setText(formatHexValue(res.value, 2)); + m_ui.watchTable->item(row, 3)->setText(formatHexValue(res.value, 2)); else if (m_scanner.GetSize() == MemoryAccessSize::HalfWord) - m_ui.watchTable->item(row, 4)->setText(formatHexValue(res.value, 4)); + m_ui.watchTable->item(row, 3)->setText(formatHexValue(res.value, 4)); else - m_ui.watchTable->item(row, 4)->setText(formatHexValue(res.value, 8)); + m_ui.watchTable->item(row, 3)->setText(formatHexValue(res.value, 8)); } row++; } diff --git a/src/duckstation-qt/cheatmanagerdialog.h b/src/duckstation-qt/cheatmanagerdialog.h index da6e55408..524b86cf6 100644 --- a/src/duckstation-qt/cheatmanagerdialog.h +++ b/src/duckstation-qt/cheatmanagerdialog.h @@ -73,8 +73,10 @@ private: QTreeWidgetItem* createItemForCheatGroup(const QString& group_name) const; QStringList getCheatGroupNames() const; int getSelectedCheatIndex() const; - int getSelectedResultIndex() const; - int getSelectedWatchIndex() const; + int getSelectedResultIndexFirst() const; + int getSelectedResultIndexLast() const; + int getSelectedWatchIndexFirst() const; + int getSelectedWatchIndexLast() const; Ui::CheatManagerDialog m_ui; diff --git a/src/duckstation-qt/cheatmanagerdialog.ui b/src/duckstation-qt/cheatmanagerdialog.ui index 4523da306..233b48faa 100644 --- a/src/duckstation-qt/cheatmanagerdialog.ui +++ b/src/duckstation-qt/cheatmanagerdialog.ui @@ -6,8 +6,8 @@ 0 0 - 864 - 599 + 1046 + 778 @@ -163,7 +163,7 @@ true - QAbstractItemView::SingleSelection + QAbstractItemView::ContiguousSelection QAbstractItemView::SelectRows @@ -171,6 +171,9 @@ false + + true + false @@ -450,6 +453,94 @@ + + + + false + + + Add Selected Results To Watch List + + + + + + + + + false + + + + 300 + 30 + + + + Qt::ImhNone + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + true + + + Qt::NoTextInteraction + + + Number of Results (Display limited to first 5000) : + + + + + + + false + + + + 60 + 30 + + + + Qt::ImhNone + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + true + + + false + + + Qt::NoTextInteraction + + + + + + 0 + + + + + @@ -475,7 +566,7 @@ true - QAbstractItemView::SingleSelection + QAbstractItemView::ContiguousSelection QAbstractItemView::SelectRows @@ -483,6 +574,9 @@ false + + true + false @@ -491,12 +585,7 @@ - Freeze - - - - - Description + Simple Cheat Code or Description @@ -514,20 +603,15 @@ Value + + + Freeze + + - - - - false - - - Add To Watch - - - @@ -541,7 +625,7 @@ false - Remove Watch + Remove Selected Entries from Watch List @@ -550,6 +634,9 @@ false + + false + Load Watch @@ -560,6 +647,9 @@ false + + false + Save Watch