Qt: Memory viewer now supports load/paste

This commit is contained in:
Jeffrey Pfau 2016-11-01 17:45:37 -07:00
parent 57894955a2
commit 27545462e4
3 changed files with 89 additions and 10 deletions

View File

@ -5,6 +5,7 @@ Features:
- GB: Tile viewer - GB: Tile viewer
- Sprite viewer - Sprite viewer
- Debugging console - Debugging console
- Improved memory viewer
Bugfixes: Bugfixes:
- LR35902: Fix core never exiting with certain event patterns - LR35902: Fix core never exiting with certain event patterns
- GB Timer: Improve DIV reset behavior - GB Timer: Improve DIV reset behavior

View File

@ -56,6 +56,16 @@ MemoryModel::MemoryModel(QWidget* parent)
connect(save, SIGNAL(triggered()), this, SLOT(save())); connect(save, SIGNAL(triggered()), this, SLOT(save()));
addAction(save); addAction(save);
QAction* paste = new QAction(tr("Paste"), this);
paste->setShortcut(QKeySequence::Paste);
connect(paste, SIGNAL(triggered()), this, SLOT(paste()));
addAction(paste);
QAction* load = new QAction(tr("Load"), this);
load->setShortcut(QKeySequence::Open);
connect(load, SIGNAL(triggered()), this, SLOT(load()));
addAction(load);
static QString arg("%0"); static QString arg("%0");
for (int i = 0; i < 256; ++i) { for (int i = 0; i < 256; ++i) {
QStaticText str(arg.arg(i, 2, 16, QChar('0')).toUpper()); QStaticText str(arg.arg(i, 2, 16, QChar('0')).toUpper());
@ -144,9 +154,7 @@ void MemoryModel::copy() {
if (!clipboard) { if (!clipboard) {
return; return;
} }
QByteArray bytestring; QByteArray bytestring(serialize());
QDataStream stream(&bytestring, QIODevice::WriteOnly);
serialize(&stream);
QString string; QString string;
string.reserve(bytestring.size() * 2); string.reserve(bytestring.size() * 2);
static QString arg("%0"); static QString arg("%0");
@ -157,6 +165,20 @@ void MemoryModel::copy() {
clipboard->setText(string); clipboard->setText(string);
} }
void MemoryModel::paste() {
QClipboard* clipboard = QApplication::clipboard();
if (!clipboard) {
return;
}
QString string = clipboard->text();
if (string.isEmpty()) {
return;
}
QByteArray bytestring(QByteArray::fromHex(string.toLocal8Bit()));
deserialize(bytestring);
viewport()->update();
}
void MemoryModel::save() { void MemoryModel::save() {
QString filename = GBAApp::app()->getSaveFileName(this, tr("Save selected memory")); QString filename = GBAApp::app()->getSaveFileName(this, tr("Save selected memory"));
if (filename.isNull()) { if (filename.isNull()) {
@ -167,25 +189,78 @@ void MemoryModel::save() {
LOG(QT, WARN) << tr("Failed to open output file: %1").arg(filename); LOG(QT, WARN) << tr("Failed to open output file: %1").arg(filename);
return; return;
} }
QDataStream stream(&outfile); QByteArray out(serialize());
serialize(&stream); outfile.write(out);
} }
void MemoryModel::serialize(QDataStream* stream) { void MemoryModel::load() {
QString filename = GBAApp::app()->getOpenFileName(this, tr("Load memory"));
if (filename.isNull()) {
return;
}
QFile infile(filename);
if (!infile.open(QIODevice::ReadOnly)) {
LOG(QT, WARN) << tr("Failed to open input file: %1").arg(filename);
return;
}
QByteArray bytestring(infile.readAll());
deserialize(bytestring);
viewport()->update();
}
QByteArray MemoryModel::serialize() {
QByteArray bytes;
bytes.reserve(m_selection.second - m_selection.first);
switch (m_align) { switch (m_align) {
case 1: case 1:
for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) {
*stream << m_core->rawRead8(m_core, i, m_currentBank); char datum = m_core->rawRead8(m_core, i, m_currentBank);
bytes.append(datum);
} }
break; break;
case 2: case 2:
for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) {
*stream << m_core->rawRead16(m_core, i, m_currentBank); quint16 datum = m_core->rawRead16(m_core, i, m_currentBank);
char leDatum[2];
STORE_16LE(datum, 0, (uint16_t*) leDatum);
bytes.append(leDatum, 2);
} }
break; break;
case 4: case 4:
for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) {
*stream << m_core->rawRead32(m_core, i, m_currentBank); quint32 datum = m_core->rawRead32(m_core, i, m_currentBank);
char leDatum[4];
STORE_32LE(datum, 0, (uint16_t*) leDatum);
bytes.append(leDatum, 4);
}
break;
}
return bytes;
}
void MemoryModel::deserialize(const QByteArray& bytes) {
uint32_t addr = m_selection.first;
switch (m_align) {
case 1:
for (int i = 0; i < bytes.size(); i += m_align, addr += m_align) {
uint8_t datum = bytes[i];
m_core->rawWrite8(m_core, addr, m_currentBank, datum);
}
break;
case 2:
for (int i = 0; i < bytes.size(); i += m_align, addr += m_align) {
char leDatum[2]{ bytes[i], bytes[i + 1] };
uint16_t datum;
LOAD_16LE(datum, 0, leDatum);
m_core->rawWrite16(m_core, addr, m_currentBank, datum);
}
break;
case 4:
for (int i = 0; i < bytes.size(); i += m_align, addr += m_align) {
char leDatum[4]{ bytes[i], bytes[i + 1], bytes[i + 2], bytes[i + 3] };
uint32_t datum;
LOAD_32LE(datum, 0, leDatum);
m_core->rawWrite32(m_core, addr, m_currentBank, datum);
} }
break; break;
} }

View File

@ -37,7 +37,9 @@ public slots:
void jumpToAddress(uint32_t); void jumpToAddress(uint32_t);
void copy(); void copy();
void paste();
void save(); void save();
void load();
signals: signals:
void selectionChanged(uint32_t start, uint32_t end); void selectionChanged(uint32_t start, uint32_t end);
@ -59,7 +61,8 @@ private:
void adjustCursor(int adjust, bool shift); void adjustCursor(int adjust, bool shift);
void serialize(QDataStream* stream); QByteArray serialize();
void deserialize(const QByteArray&);
mCore* m_core; mCore* m_core;
QFont m_font; QFont m_font;