Qt: Rudimentary memory viewer
Jeffrey Pfau jeffrey@endrift.com
Tue, 28 Apr 2015 22:38:11 -0700
9 files changed,
230 insertions(+),
0 deletions(-)
M
src/gba/supervisor/thread.c
→
src/gba/supervisor/thread.c
@@ -133,6 +133,7 @@ ARMSetComponents(&cpu, &gba.d, numComponents, components);
ARMInit(&cpu); gba.sync = &threadContext->sync; threadContext->gba = &gba; + threadContext->cpu = &cpu; gba.logLevel = threadContext->logLevel; gba.logHandler = threadContext->logHandler; gba.stream = threadContext->stream;
M
src/platform/qt/CMakeLists.txt
→
src/platform/qt/CMakeLists.txt
@@ -56,6 +56,8 @@ InputController.cpp
KeyEditor.cpp LoadSaveState.cpp LogView.cpp + MemoryModel.cpp + MemoryView.cpp MultiplayerController.cpp OverrideView.cpp PaletteView.cpp@@ -74,6 +76,7 @@ CheatsView.ui
GIFView.ui LoadSaveState.ui LogView.ui + MemoryView.ui OverrideView.ui PaletteView.ui SensorView.ui
A
src/platform/qt/MemoryModel.cpp
@@ -0,0 +1,89 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "MemoryModel.h" + +#include "GameController.h" + +#include <QFontMetrics> +#include <QPainter> +#include <QScrollBar> +#include <QSlider> + +extern "C" { +#include "gba/memory.h" +} + +using namespace QGBA; + +MemoryModel::MemoryModel(QWidget* parent) + : QAbstractScrollArea(parent) + , m_top(0) +{ + m_font.setFamily("Source Code Pro"); + m_font.setStyleHint(QFont::Monospace); + m_font.setPointSize(12); + QFontMetrics metrics(m_font); + m_cellHeight = metrics.height(); + m_letterWidth = metrics.averageCharWidth(); + + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_margins = QMargins(metrics.width("FFFFFF ") + 3, m_cellHeight + 1, metrics.width(" AAAAAAAAAAAAAAAA") + 3, 0); + + verticalScrollBar()->setRange(0, 0x01000000 - viewport()->size().height() / m_cellHeight); + connect(verticalScrollBar(), &QSlider::sliderMoved, [this](int position) { + m_top = position; + }); + update(); +} + +void MemoryModel::setController(GameController* controller) { + m_cpu = controller->thread()->cpu; +} + +void MemoryModel::resizeEvent(QResizeEvent*) { + verticalScrollBar()->setRange(0, 0x01000000 - viewport()->size().height() / m_cellHeight); +} + +void MemoryModel::paintEvent(QPaintEvent* event) { + QPainter painter(viewport()); + painter.setFont(m_font); + QChar c0('0'); + QSizeF cellSize = QSizeF((viewport()->size().width() - (m_margins.left() + m_margins.right())) / 16.f, m_cellHeight); + QSizeF letterSize = QSizeF(m_letterWidth, m_cellHeight); + painter.drawText(QRect(QPoint(0, 0), QSize(m_margins.left(), m_margins.top())), Qt::AlignHCenter, tr("All")); + painter.drawText(QRect(QPoint(viewport()->size().width() - m_margins.right(), 0), QSize(m_margins.right(), m_margins.top())), Qt::AlignHCenter, tr("ASCII")); + for (int x = 0; x < 16; ++x) { + painter.drawText(QRectF(QPointF(cellSize.width() * x + m_margins.left(), 0), cellSize), Qt::AlignHCenter, QString::number(x, 16).toUpper()); + } + int height = (viewport()->size().height() - m_cellHeight + 1) / m_cellHeight; + for (int y = 0; y < height; ++y) { + int yp = m_cellHeight * y + m_margins.top(); + QString data = QString("%0").arg(y + m_top, 6, 16, c0).toUpper(); + painter.drawText(QRectF(QPointF(0, yp), QSizeF(m_margins.left(), m_cellHeight)), Qt::AlignHCenter, data); + for (int x = 0; x < 16; ++x) { + uint8_t b = m_cpu->memory.load8(m_cpu, (y + m_top) * 16 + x, nullptr); + QChar c(b); + if (!c.isPrint() || c.unicode() >= 0x80) { + c = 0xFFFD; + } + data = QString("%0").arg(b, 2, 16, c0).toUpper(); + painter.drawText(QRectF(QPointF(cellSize.width() * x + m_margins.left(), yp), cellSize), Qt::AlignHCenter, data); + painter.drawText(QRectF(QPointF(viewport()->size().width() - (16 - x) * m_margins.right() / 16.f, yp), letterSize), Qt::AlignHCenter, c); + } + } + painter.drawLine(m_margins.left() - 2, 0, m_margins.left() - 2, viewport()->size().height()); + painter.drawLine(viewport()->size().width() - m_margins.right(), 0, viewport()->size().width() - m_margins.right(), viewport()->size().height()); + painter.drawLine(0, m_margins.top(), viewport()->size().width(), m_margins.top()); +} + +QString MemoryModel::headerData(int section, Qt::Orientation orientation) const { + if (orientation == Qt::Vertical) { + return QString("%0").arg(section >> 4, 8, 16, QChar('0')).toUpper(); + } else { + return QString("%0").arg(section, 2, 16, QChar('0')).toUpper(); + } +}
A
src/platform/qt/MemoryModel.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_MEMORY_MODEL +#define QGBA_MEMORY_MODEL + +#include <QAbstractScrollArea> +#include <QFont> +#include <QSize> + +struct ARMCore; + +namespace QGBA { + +class GameController; + +class MemoryModel : public QAbstractScrollArea { +Q_OBJECT + +public: + MemoryModel(QWidget* parent = nullptr); + + void setController(GameController* controller); + +protected: + void resizeEvent(QResizeEvent*) override; + void paintEvent(QPaintEvent*) override; + +private: + QString headerData(int section, Qt::Orientation orientation) const; + + ARMCore* m_cpu; + QFont m_font; + int m_cellHeight; + int m_letterWidth; + int m_top; + QMargins m_margins; +}; + +} + +#endif
A
src/platform/qt/MemoryView.cpp
@@ -0,0 +1,18 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MemoryView.h" + +using namespace QGBA; + +MemoryView::MemoryView(GameController* controller, QWidget* parent) + : QWidget(parent) + , m_controller(controller) +{ + m_ui.setupUi(this); + + m_ui.hexfield->setController(controller); +}
A
src/platform/qt/MemoryView.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_MEMORY_VIEW +#define QGBA_MEMORY_VIEW + +#include "MemoryModel.h" + +#include "ui_MemoryView.h" + +namespace QGBA { + +class GameController; + +class MemoryView : public QWidget { +Q_OBJECT + +public: + MemoryView(GameController* controller, QWidget* parent = nullptr); + +private: + Ui::MemoryView m_ui; + + GameController* m_controller; +}; + +} + +#endif
A
src/platform/qt/MemoryView.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MemoryView</class> + <widget class="QWidget" name="MemoryView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>527</width> + <height>544</height> + </rect> + </property> + <property name="windowTitle"> + <string>Memory</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGBA::MemoryModel" name="hexfield" native="true"/> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QGBA::MemoryModel</class> + <extends>QWidget</extends> + <header>MemoryModel.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui>
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -26,6 +26,7 @@ #include "GIFView.h"
#include "LoadSaveState.h" #include "LogView.h" #include "MultiplayerController.h" +#include "MemoryView.h" #include "OverrideView.h" #include "PaletteView.h" #include "SensorView.h"@@ -326,6 +327,11 @@
void Window::openPaletteWindow() { PaletteView* paletteWindow = new PaletteView(m_controller); openView(paletteWindow); +} + +void Window::openMemoryWindow() { + MemoryView* memoryWindow = new MemoryView(m_controller); + openView(memoryWindow); } #ifdef BUILD_SDL@@ -963,6 +969,11 @@ QAction* paletteView = new QAction(tr("View &palette..."), toolsMenu);
connect(paletteView, SIGNAL(triggered()), this, SLOT(openPaletteWindow())); m_gameActions.append(paletteView); addControlledAction(toolsMenu, paletteView, "paletteWindow"); + + QAction* memoryView = new QAction(tr("View memory..."), toolsMenu); + connect(memoryView, SIGNAL(triggered()), this, SLOT(openMemoryWindow())); + m_gameActions.append(memoryView); + addControlledAction(toolsMenu, memoryView, "memoryView"); ConfigOption* skipBios = m_config->addOption("skipBios"); skipBios->connect([this](const QVariant& value) {
M
src/platform/qt/Window.h
→
src/platform/qt/Window.h
@@ -77,6 +77,7 @@ void openSensorWindow();
void openCheatsWindow(); void openPaletteWindow(); + void openMemoryWindow(); #ifdef BUILD_SDL void openGamepadWindow();