all repos — mgba @ a3ee07a6cc20512e3db26d84a23adfa5b8d0f52b

mGBA Game Boy Advance Emulator

Qt: TBL support in Memory Viewer
Jeffrey Pfau jeffrey@endrift.com
Tue, 01 Nov 2016 19:27:44 -0700
commit

a3ee07a6cc20512e3db26d84a23adfa5b8d0f52b

parent

605d5ddcfd1ba1cbf81c98fb4333099a0bbc58d5

M src/platform/qt/MemoryModel.cppsrc/platform/qt/MemoryModel.cpp

@@ -8,6 +8,7 @@

#include "GBAApp.h" #include "GameController.h" #include "LogController.h" +#include "VFileDevice.h" #include <QAction> #include <QApplication>

@@ -31,6 +32,7 @@ , m_top(0)

, 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 @@ m_bufferedNybbles = 0;

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 @@ break;

} } +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 @@ QSizeF letterSize = QSizeF(m_letterWidth, m_cellHeight);

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 @@ break;

} 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 @@ }

emit selectionChanged(m_selection.first, m_selection.second); viewport()->update(); } + +void MemoryModel::TextCodecFree::operator()(TextCodec* codec) { + TextCodecDeinit(codec); + delete(codec); +}
M src/platform/qt/MemoryModel.hsrc/platform/qt/MemoryModel.h

@@ -11,6 +11,11 @@ #include <QFont>

#include <QSize> #include <QStaticText> #include <QVector> +#include <memory> + +extern "C" { +#include "util/text-codec.h" +} struct mCore;

@@ -34,11 +39,15 @@ int alignment() const { return m_align; }

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 @@ void drawEditingText(QPainter& painter, const QPointF& origin);

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;
M src/platform/qt/MemoryView.cppsrc/platform/qt/MemoryView.cpp

@@ -109,6 +109,8 @@ connect(m_ui.copy, SIGNAL(clicked()), m_ui.hexfield, SLOT(copy()));

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 @@ return;

} 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) {
M src/platform/qt/MemoryView.uisrc/platform/qt/MemoryView.ui

@@ -225,6 +225,13 @@ <bool>true</bool>

</property> </widget> </item> + <item> + <widget class="QPushButton" name="loadTBL"> + <property name="text"> + <string>Load TBL</string> + </property> + </widget> + </item> </layout> </item> </layout>