diff options
Diffstat (limited to 'src/frontend/qt_sdl/RAMInfoDialog.cpp')
-rw-r--r-- | src/frontend/qt_sdl/RAMInfoDialog.cpp | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/frontend/qt_sdl/RAMInfoDialog.cpp b/src/frontend/qt_sdl/RAMInfoDialog.cpp new file mode 100644 index 0000000..b13ff02 --- /dev/null +++ b/src/frontend/qt_sdl/RAMInfoDialog.cpp @@ -0,0 +1,302 @@ +/* + Copyright 2016-2021 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include "RAMInfoDialog.h" +#include "ui_RAMInfoDialog.h" + +#include "main.h" + +extern EmuThread* emuThread; + +s32 GetMainRAMValue(const u32& addr, const ramInfo_ByteType& byteType) +{ + switch (byteType) + { + case ramInfo_OneByte: + return *(s8*)(NDS::MainRAM + (addr&NDS::MainRAMMask)); + case ramInfo_TwoBytes: + return *(s16*)(NDS::MainRAM + (addr&NDS::MainRAMMask)); + case ramInfo_FourBytes: + return *(s32*)(NDS::MainRAM + (addr&NDS::MainRAMMask)); + default: + return 0; + } +} + +RAMInfoDialog* RAMInfoDialog::currentDlg = nullptr; + +RAMInfoDialog::RAMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::RAMInfoDialog) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + + qRegisterMetaType<QVector<int>>("QVector<int>"); + qRegisterMetaType<u32>("u32"); + qRegisterMetaType<s32>("s32"); + qRegisterMetaType<s16>("s16"); + qRegisterMetaType<s8>("s8"); + + SearchThread = new RAMSearchThread(this); + connect(SearchThread, &RAMSearchThread::SetProgressbarValue, this, &RAMInfoDialog::SetProgressbarValue); + connect(SearchThread, &RAMSearchThread::finished, this, &RAMInfoDialog::OnSearchFinished); + // First search (Show everything in main ram) + SearchThread->Start(ramInfoSTh_SearchAll); + + TableUpdater = new QTimer(this); + TableUpdater->setInterval(100); + connect(TableUpdater, &QTimer::timeout, this, &RAMInfoDialog::ShowRowsInTable); + TableUpdater->start(); +} + +RAMInfoDialog::~RAMInfoDialog() +{ + delete SearchThread; + if (TableUpdater->isActive()) + TableUpdater->stop(); + delete TableUpdater; + delete ui; +} + +void RAMInfoDialog::OnSearchFinished() +{ + SearchThread->wait(); + ui->btnSearch->setEnabled(true); + ui->ramTable->clearContents(); + ui->ramTable->setRowCount(SearchThread->GetResults()->size()); + ui->ramTable->verticalScrollBar()->setSliderPosition(0); + ui->txtFound->setText(QString("Found: %1").arg(SearchThread->GetResults()->size())); +} + +void RAMInfoDialog::ShowRowsInTable() +{ + const u32& scrollValue = ui->ramTable->verticalScrollBar()->sliderPosition(); + std::vector<ramInfo_RowData>* RowDataVector = SearchThread->GetResults(); + + for (u32 row = scrollValue; row < std::min<u32>(scrollValue+25, RowDataVector->size()); row++) + { + ramInfo_RowData& rowData = RowDataVector->at(row); + rowData.Update(SearchThread->GetSearchByteType()); + + if (ui->ramTable->item(row, ramInfo_Address) == nullptr) + { + // A new row + QTableWidgetItem* addressItem = new QTableWidgetItem(QString("%1").arg(rowData.Address, 8, 16)); + QTableWidgetItem* valueItem = new QTableWidgetItem(QString("%1").arg(rowData.Value)); + QTableWidgetItem* previousItem = new QTableWidgetItem(QString("%1").arg(rowData.Previous)); + + addressItem->setFlags(addressItem->flags() & ~Qt::ItemIsEditable); + valueItem->setFlags(valueItem->flags() | Qt::ItemIsEditable); + previousItem->setFlags(previousItem->flags() & ~Qt::ItemIsEditable); + + ui->ramTable->setItem(row, ramInfo_Address, addressItem); + ui->ramTable->setItem(row, ramInfo_Value, valueItem); + ui->ramTable->setItem(row, ramInfo_Previous, previousItem); + } + else + { + // A row that exists + ui->ramTable->item(row, ramInfo_Address)->setText(QString("%1").arg(rowData.Address, 8, 16)); + ui->ramTable->item(row, ramInfo_Value)->setText(QString("%1").arg(rowData.Value)); + ui->ramTable->item(row, ramInfo_Previous)->setText(QString("%1").arg(rowData.Previous)); + if (rowData.Value != rowData.Previous) + ui->ramTable->item(row, ramInfo_Previous)->setForeground(Qt::red); + } + } +} + +void RAMInfoDialog::ClearTableContents() +{ + ui->ramTable->clearContents(); + ui->ramTable->setRowCount(0); +} + +void RAMInfoDialog::SetProgressbarValue(const u32& value) +{ + ui->progressBar->setValue(value); +} + +void RAMInfoDialog::done(int r) +{ + QDialog::done(r); + closeDlg(); +} + +void RAMInfoDialog::on_btnSearch_clicked() +{ + ui->btnSearch->setEnabled(false); + ui->radiobtn1byte->setEnabled(false); + ui->radiobtn2bytes->setEnabled(false); + ui->radiobtn4bytes->setEnabled(false); + + if (ui->txtSearch->text().isEmpty()) + SearchThread->Start(ramInfoSTh_SearchAll); + else + SearchThread->Start(ui->txtSearch->text().toInt()); + + if (!TableUpdater->isActive()) + TableUpdater->start(); +} + +void RAMInfoDialog::on_btnClear_clicked() +{ + SearchThread->Stop(); + TableUpdater->stop(); + + ui->radiobtn1byte->setEnabled(true); + ui->radiobtn2bytes->setEnabled(true); + ui->radiobtn4bytes->setEnabled(true); + + OnSearchFinished(); +} + +void RAMInfoDialog::on_radiobtn1byte_clicked() +{ + SearchThread->SetSearchByteType(ramInfo_OneByte); +} + +void RAMInfoDialog::on_radiobtn2bytes_clicked() +{ + SearchThread->SetSearchByteType(ramInfo_TwoBytes); +} + +void RAMInfoDialog::on_radiobtn4bytes_clicked() +{ + SearchThread->SetSearchByteType(ramInfo_FourBytes); +} + +void RAMInfoDialog::on_ramTable_itemChanged(QTableWidgetItem *item) +{ + ramInfo_RowData& rowData = SearchThread->GetResults()->at(item->row()); + s32 itemValue = item->text().toInt(); + + if (rowData.Value != itemValue) + rowData.SetValue(itemValue); +} + +/** + * RAMSearchThread + */ + +RAMSearchThread::RAMSearchThread(RAMInfoDialog* dialog) : Dialog(dialog) +{ + RowDataVector = new std::vector<ramInfo_RowData>(); +} + +RAMSearchThread::~RAMSearchThread() +{ + Stop(); + if (RowDataVector) + { + delete RowDataVector; + RowDataVector = nullptr; + } +} + +void RAMSearchThread::Start(const s32& searchValue, const ramInfoSTh_SearchMode& searchMode) +{ + SearchValue = searchValue; + SearchMode = searchMode; + start(); +} + +void RAMSearchThread::Start(const ramInfoSTh_SearchMode& searchMode) +{ + SearchMode = searchMode; + start(); +} + +void RAMSearchThread::Stop() +{ + SearchRunning = false; + RowDataVector->clear(); + quit(); + wait(); +} + +void RAMSearchThread::run() +{ + SearchRunning = true; + u32 progress = 0; + + // Pause game running + emuThread->emuPause(); + + // For following search modes below, RowDataVector must be filled. + if (SearchMode == ramInfoSTh_SearchAll || RowDataVector->size() == 0) + { + // First search mode + for (u32 addr = 0x02000000; SearchRunning && addr < 0x02000000+NDS::MainRAMMaxSize; addr += SearchByteType) + { + const s32& value = GetMainRAMValue(addr, SearchByteType); + + RowDataVector->push_back({ addr, value, value }); + + // A solution to prevent to call too many slot. + u32 newProgress = (int)((addr-0x02000000) / (NDS::MainRAMMaxSize-1.0f) * 100); + if (progress < newProgress) + { + progress = newProgress; + emit SetProgressbarValue(progress); + } + } + } + + if (SearchMode == ramInfoSTh_Default) + { + // Next search mode + std::vector<ramInfo_RowData>* newRowDataVector = new std::vector<ramInfo_RowData>(); + for (u32 row = 0; SearchRunning && row < RowDataVector->size(); row++) + { + const u32& addr = RowDataVector->at(row).Address; + const s32& value = GetMainRAMValue(addr, SearchByteType); + + if (SearchValue == value) + newRowDataVector->push_back({ addr, value, value }); + + // A solution to prevent to call too many slot. + u32 newProgress = (int)(row / (RowDataVector->size()-1.0f) * 100); + if (progress < newProgress) + { + progress = newProgress; + emit SetProgressbarValue(progress); + } + } + delete RowDataVector; + RowDataVector = newRowDataVector; + } + + // Unpause game running + emuThread->emuUnpause(); + + SearchRunning = false; +} + +void RAMSearchThread::SetSearchByteType(const ramInfo_ByteType& bytetype) +{ + SearchByteType = bytetype; +} + +ramInfo_ByteType RAMSearchThread::GetSearchByteType() const +{ + return SearchByteType; +} + +std::vector<ramInfo_RowData>* RAMSearchThread::GetResults() +{ + return RowDataVector; +} |