mirror of https://github.com/mgba-emu/mgba.git
Qt: TBL support in Memory Viewer
This commit is contained in:
parent
605d5ddcfd
commit
a3ee07a6cc
|
@ -8,6 +8,7 @@
|
|||
#include "GBAApp.h"
|
||||
#include "GameController.h"
|
||||
#include "LogController.h"
|
||||
#include "VFileDevice.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
|
@ -31,6 +32,7 @@ MemoryModel::MemoryModel(QWidget* parent)
|
|||
, m_align(1)
|
||||
, m_selection(0, 0)
|
||||
, m_selectionAnchor(0)
|
||||
, m_codec(nullptr)
|
||||
{
|
||||
m_font.setFamily("Source Code Pro");
|
||||
m_font.setStyleHint(QFont::Monospace);
|
||||
|
@ -127,6 +129,24 @@ void MemoryModel::setAlignment(int width) {
|
|||
viewport()->update();
|
||||
}
|
||||
|
||||
void MemoryModel::loadTBL(const QString& path) {
|
||||
VFile* vf = VFileDevice::open(path, O_RDONLY);
|
||||
if (!vf) {
|
||||
return;
|
||||
}
|
||||
m_codec = std::unique_ptr<TextCodec, TextCodecFree>(new TextCodec);
|
||||
TextCodecLoadTBL(m_codec.get(), vf, true);
|
||||
vf->close(vf);
|
||||
}
|
||||
|
||||
void MemoryModel::loadTBL() {
|
||||
QString filename = GBAApp::app()->getOpenFileName(this, tr("Load TBL"));
|
||||
if (filename.isNull()) {
|
||||
return;
|
||||
}
|
||||
loadTBL(filename);
|
||||
}
|
||||
|
||||
void MemoryModel::jumpToAddress(const QString& hex) {
|
||||
bool ok = false;
|
||||
uint32_t i = hex.toInt(&ok, 16);
|
||||
|
@ -266,6 +286,39 @@ void MemoryModel::deserialize(const QByteArray& bytes) {
|
|||
}
|
||||
}
|
||||
|
||||
QString MemoryModel::decodeText(const QByteArray& bytes) {
|
||||
QString text;
|
||||
if (m_codec) {
|
||||
TextCodecIterator iter;
|
||||
TextCodecStartDecode(m_codec.get(), &iter);
|
||||
uint8_t lineBuffer[128];
|
||||
for (quint8 byte : bytes) {
|
||||
size_t size = TextCodecAdvance(&iter, byte, lineBuffer, sizeof(lineBuffer));
|
||||
if (size > sizeof(lineBuffer)) {
|
||||
size = sizeof(lineBuffer);
|
||||
}
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
text.append(lineBuffer[i]);
|
||||
}
|
||||
}
|
||||
size_t size = TextCodecFinish(&iter, lineBuffer, sizeof(lineBuffer));
|
||||
if (size > sizeof(lineBuffer)) {
|
||||
size = sizeof(lineBuffer);
|
||||
}
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
text.append(lineBuffer[i]);
|
||||
}
|
||||
} else {
|
||||
for (QChar c : bytes) {
|
||||
if (!c.isPrint() || c >= 127) {
|
||||
continue;
|
||||
}
|
||||
text.append(c);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
void MemoryModel::resizeEvent(QResizeEvent*) {
|
||||
m_cellSize = QSizeF((viewport()->size().width() - (m_margins.left() + m_margins.right())) / 16.0, m_cellHeight);
|
||||
verticalScrollBar()->setRange(0, (m_size >> 4) + 1 - viewport()->size().height() / m_cellHeight);
|
||||
|
@ -284,7 +337,7 @@ void MemoryModel::paintEvent(QPaintEvent* event) {
|
|||
painter.drawStaticText(QPointF((m_margins.left() - m_regionName.size().width() - 1) / 2.0, 0), m_regionName);
|
||||
painter.drawText(
|
||||
QRect(QPoint(viewport()->size().width() - m_margins.right(), 0), QSize(m_margins.right(), m_margins.top())),
|
||||
Qt::AlignHCenter, tr("ASCII"));
|
||||
Qt::AlignHCenter, m_codec ? tr("TBL") : tr("ASCII"));
|
||||
for (int x = 0; x < 16; ++x) {
|
||||
painter.drawText(QRectF(QPointF(m_cellSize.width() * x + m_margins.left(), 0), m_cellSize), Qt::AlignHCenter,
|
||||
QString::number(x, 16).toUpper());
|
||||
|
@ -392,10 +445,20 @@ void MemoryModel::paintEvent(QPaintEvent* event) {
|
|||
}
|
||||
painter.setPen(palette.color(QPalette::WindowText));
|
||||
for (int x = 0; x < 16; ++x) {
|
||||
uint8_t b =m_core->rawRead8(m_core, (y + m_top) * 16 + x + m_base, m_currentBank);
|
||||
uint8_t b = m_core->rawRead8(m_core, (y + m_top) * 16 + x + m_base, m_currentBank);
|
||||
QString text = decodeText(QByteArray(1, b));
|
||||
if (text.isEmpty()) {
|
||||
b = '.';
|
||||
} else {
|
||||
QChar c = text.at(0);
|
||||
if (!c.isPrint() || c >= 127) {
|
||||
b = '.';
|
||||
} else {
|
||||
b = c.toLatin1();
|
||||
}
|
||||
}
|
||||
painter.drawStaticText(
|
||||
QPointF(viewport()->size().width() - (16 - x) * m_margins.right() / 17.0 - m_letterWidth * 0.5, yp),
|
||||
b < 0x80 ? m_staticAscii[b] : m_staticAscii[0]);
|
||||
QPointF(viewport()->size().width() - (16 - x) * m_margins.right() / 17.0 - m_letterWidth * 0.5, yp), m_staticAscii[b]);
|
||||
}
|
||||
}
|
||||
painter.drawLine(m_margins.left(), 0, m_margins.left(), viewport()->size().height());
|
||||
|
@ -635,3 +698,8 @@ void MemoryModel::adjustCursor(int adjust, bool shift) {
|
|||
emit selectionChanged(m_selection.first, m_selection.second);
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void MemoryModel::TextCodecFree::operator()(TextCodec* codec) {
|
||||
TextCodecDeinit(codec);
|
||||
delete(codec);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
#include <QSize>
|
||||
#include <QStaticText>
|
||||
#include <QVector>
|
||||
#include <memory>
|
||||
|
||||
extern "C" {
|
||||
#include "util/text-codec.h"
|
||||
}
|
||||
|
||||
struct mCore;
|
||||
|
||||
|
@ -34,11 +39,15 @@ public:
|
|||
|
||||
QByteArray serialize();
|
||||
void deserialize(const QByteArray&);
|
||||
QString decodeText(const QByteArray&);
|
||||
|
||||
public slots:
|
||||
void jumpToAddress(const QString& hex);
|
||||
void jumpToAddress(uint32_t);
|
||||
|
||||
void loadTBL(const QString& path);
|
||||
void loadTBL();
|
||||
|
||||
void copy();
|
||||
void paste();
|
||||
void save();
|
||||
|
@ -64,7 +73,13 @@ private:
|
|||
|
||||
void adjustCursor(int adjust, bool shift);
|
||||
|
||||
class TextCodecFree {
|
||||
public:
|
||||
void operator()(TextCodec*);
|
||||
};
|
||||
|
||||
mCore* m_core;
|
||||
std::unique_ptr<TextCodec, TextCodecFree> m_codec;
|
||||
QFont m_font;
|
||||
int m_cellHeight;
|
||||
int m_letterWidth;
|
||||
|
|
|
@ -109,6 +109,8 @@ MemoryView::MemoryView(GameController* controller, QWidget* parent)
|
|||
connect(m_ui.save, SIGNAL(clicked()), m_ui.hexfield, SLOT(save()));
|
||||
connect(m_ui.paste, SIGNAL(clicked()), m_ui.hexfield, SLOT(paste()));
|
||||
connect(m_ui.load, SIGNAL(clicked()), m_ui.hexfield, SLOT(load()));
|
||||
|
||||
connect(m_ui.loadTBL, SIGNAL(clicked()), m_ui.hexfield, SLOT(loadTBL()));
|
||||
}
|
||||
|
||||
void MemoryView::setIndex(int index) {
|
||||
|
@ -172,13 +174,7 @@ void MemoryView::updateStatus() {
|
|||
}
|
||||
mCore* core = m_controller->thread()->core;
|
||||
QByteArray selection(m_ui.hexfield->serialize());
|
||||
QString text;
|
||||
for (QChar c : selection) {
|
||||
if (!c.isPrint() || c >= 127) {
|
||||
continue;
|
||||
}
|
||||
text.append(c);
|
||||
}
|
||||
QString text(m_ui.hexfield->decodeText(selection));
|
||||
m_ui.stringVal->setText(text);
|
||||
|
||||
if (m_selection.first & (align - 1) || m_selection.second - m_selection.first != align) {
|
||||
|
|
|
@ -225,6 +225,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loadTBL">
|
||||
<property name="text">
|
||||
<string>Load TBL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
Loading…
Reference in New Issue