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.
This commit is contained in:
PugsyMAME
2021-08-06 12:24:14 +01:00
committed by GitHub
parent b9d238d28b
commit f835db6b4f
3 changed files with 200 additions and 55 deletions

View File

@ -45,6 +45,28 @@ static QString formatHexAndDecValue(u32 value, u8 size, bool is_signed)
return QStringLiteral("0x%1 (%2)").arg(static_cast<u32>(value), size, 16, QChar('0')).arg(static_cast<uint>(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<u32>(address) + 0x30000000, 8, 16, QChar('0')).toUpper()
.arg(static_cast<u16>(value), 4, 16, QChar('0')).toUpper();
else if (size == MemoryAccessSize::HalfWord && address <= 0x001FFFFE)
return QStringLiteral("CHEAT CODE: %1 %2")
.arg(static_cast<u32>(address) + 0x80000000, 8, 16, QChar('0')).toUpper()
.arg(static_cast<u16>(value), 4, 16, QChar('0')).toUpper();
else if (size == MemoryAccessSize::Word && address <= 0x001FFFFC)
return QStringLiteral("CHEAT CODE: %1 %2")
.arg(static_cast<u32>(address) + 0x90000000, 8, 16, QChar('0')).toUpper()
.arg(static_cast<u32>(value), 8, 16, QChar('0')).toUpper();
else
return QStringLiteral("OUTSIDE RAM RANGE. POKE %1 with %2")
.arg(static_cast<u32>(address), 8, 16, QChar('0')).toUpper()
.arg(static_cast<u16>(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<QTableWidgetSelectionRange> 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<QTableWidgetSelectionRange> sel = m_ui.scanTable->selectedRanges();
if (sel.isEmpty())
return -1;
return sel.front().bottomRow();
}
int CheatManagerDialog::getSelectedWatchIndexFirst() const
{
QList<QTableWidgetSelectionRange> 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<QTableWidgetSelectionRange> 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<u32>(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<unsigned> 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<u32>(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<u32>(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<u32>(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++;
}