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 "GBAApp.h"
|
||||||
#include "GameController.h"
|
#include "GameController.h"
|
||||||
#include "LogController.h"
|
#include "LogController.h"
|
||||||
|
#include "VFileDevice.h"
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
@ -31,6 +32,7 @@ MemoryModel::MemoryModel(QWidget* parent)
|
||||||
, m_align(1)
|
, m_align(1)
|
||||||
, m_selection(0, 0)
|
, m_selection(0, 0)
|
||||||
, m_selectionAnchor(0)
|
, m_selectionAnchor(0)
|
||||||
|
, m_codec(nullptr)
|
||||||
{
|
{
|
||||||
m_font.setFamily("Source Code Pro");
|
m_font.setFamily("Source Code Pro");
|
||||||
m_font.setStyleHint(QFont::Monospace);
|
m_font.setStyleHint(QFont::Monospace);
|
||||||
|
@ -127,6 +129,24 @@ void MemoryModel::setAlignment(int width) {
|
||||||
viewport()->update();
|
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) {
|
void MemoryModel::jumpToAddress(const QString& hex) {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
uint32_t i = hex.toInt(&ok, 16);
|
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*) {
|
void MemoryModel::resizeEvent(QResizeEvent*) {
|
||||||
m_cellSize = QSizeF((viewport()->size().width() - (m_margins.left() + m_margins.right())) / 16.0, m_cellHeight);
|
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);
|
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.drawStaticText(QPointF((m_margins.left() - m_regionName.size().width() - 1) / 2.0, 0), m_regionName);
|
||||||
painter.drawText(
|
painter.drawText(
|
||||||
QRect(QPoint(viewport()->size().width() - m_margins.right(), 0), QSize(m_margins.right(), m_margins.top())),
|
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) {
|
for (int x = 0; x < 16; ++x) {
|
||||||
painter.drawText(QRectF(QPointF(m_cellSize.width() * x + m_margins.left(), 0), m_cellSize), Qt::AlignHCenter,
|
painter.drawText(QRectF(QPointF(m_cellSize.width() * x + m_margins.left(), 0), m_cellSize), Qt::AlignHCenter,
|
||||||
QString::number(x, 16).toUpper());
|
QString::number(x, 16).toUpper());
|
||||||
|
@ -392,10 +445,20 @@ void MemoryModel::paintEvent(QPaintEvent* event) {
|
||||||
}
|
}
|
||||||
painter.setPen(palette.color(QPalette::WindowText));
|
painter.setPen(palette.color(QPalette::WindowText));
|
||||||
for (int x = 0; x < 16; ++x) {
|
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(
|
painter.drawStaticText(
|
||||||
QPointF(viewport()->size().width() - (16 - x) * m_margins.right() / 17.0 - m_letterWidth * 0.5, yp),
|
QPointF(viewport()->size().width() - (16 - x) * m_margins.right() / 17.0 - m_letterWidth * 0.5, yp), m_staticAscii[b]);
|
||||||
b < 0x80 ? m_staticAscii[b] : m_staticAscii[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
painter.drawLine(m_margins.left(), 0, m_margins.left(), viewport()->size().height());
|
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);
|
emit selectionChanged(m_selection.first, m_selection.second);
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryModel::TextCodecFree::operator()(TextCodec* codec) {
|
||||||
|
TextCodecDeinit(codec);
|
||||||
|
delete(codec);
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QStaticText>
|
#include <QStaticText>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "util/text-codec.h"
|
||||||
|
}
|
||||||
|
|
||||||
struct mCore;
|
struct mCore;
|
||||||
|
|
||||||
|
@ -34,11 +39,15 @@ public:
|
||||||
|
|
||||||
QByteArray serialize();
|
QByteArray serialize();
|
||||||
void deserialize(const QByteArray&);
|
void deserialize(const QByteArray&);
|
||||||
|
QString decodeText(const QByteArray&);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void jumpToAddress(const QString& hex);
|
void jumpToAddress(const QString& hex);
|
||||||
void jumpToAddress(uint32_t);
|
void jumpToAddress(uint32_t);
|
||||||
|
|
||||||
|
void loadTBL(const QString& path);
|
||||||
|
void loadTBL();
|
||||||
|
|
||||||
void copy();
|
void copy();
|
||||||
void paste();
|
void paste();
|
||||||
void save();
|
void save();
|
||||||
|
@ -64,7 +73,13 @@ private:
|
||||||
|
|
||||||
void adjustCursor(int adjust, bool shift);
|
void adjustCursor(int adjust, bool shift);
|
||||||
|
|
||||||
|
class TextCodecFree {
|
||||||
|
public:
|
||||||
|
void operator()(TextCodec*);
|
||||||
|
};
|
||||||
|
|
||||||
mCore* m_core;
|
mCore* m_core;
|
||||||
|
std::unique_ptr<TextCodec, TextCodecFree> m_codec;
|
||||||
QFont m_font;
|
QFont m_font;
|
||||||
int m_cellHeight;
|
int m_cellHeight;
|
||||||
int m_letterWidth;
|
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.save, SIGNAL(clicked()), m_ui.hexfield, SLOT(save()));
|
||||||
connect(m_ui.paste, SIGNAL(clicked()), m_ui.hexfield, SLOT(paste()));
|
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.load, SIGNAL(clicked()), m_ui.hexfield, SLOT(load()));
|
||||||
|
|
||||||
|
connect(m_ui.loadTBL, SIGNAL(clicked()), m_ui.hexfield, SLOT(loadTBL()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryView::setIndex(int index) {
|
void MemoryView::setIndex(int index) {
|
||||||
|
@ -172,13 +174,7 @@ void MemoryView::updateStatus() {
|
||||||
}
|
}
|
||||||
mCore* core = m_controller->thread()->core;
|
mCore* core = m_controller->thread()->core;
|
||||||
QByteArray selection(m_ui.hexfield->serialize());
|
QByteArray selection(m_ui.hexfield->serialize());
|
||||||
QString text;
|
QString text(m_ui.hexfield->decodeText(selection));
|
||||||
for (QChar c : selection) {
|
|
||||||
if (!c.isPrint() || c >= 127) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
text.append(c);
|
|
||||||
}
|
|
||||||
m_ui.stringVal->setText(text);
|
m_ui.stringVal->setText(text);
|
||||||
|
|
||||||
if (m_selection.first & (align - 1) || m_selection.second - m_selection.first != align) {
|
if (m_selection.first & (align - 1) || m_selection.second - m_selection.first != align) {
|
||||||
|
|
|
@ -225,6 +225,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="loadTBL">
|
||||||
|
<property name="text">
|
||||||
|
<string>Load TBL</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
Loading…
Reference in New Issue