mirror of https://github.com/mgba-emu/mgba.git
Qt: Rudimentary memory viewer
This commit is contained in:
parent
8b19ad7809
commit
328a41dec7
|
@ -133,6 +133,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
|
||||||
ARMInit(&cpu);
|
ARMInit(&cpu);
|
||||||
gba.sync = &threadContext->sync;
|
gba.sync = &threadContext->sync;
|
||||||
threadContext->gba = &gba;
|
threadContext->gba = &gba;
|
||||||
|
threadContext->cpu = &cpu;
|
||||||
gba.logLevel = threadContext->logLevel;
|
gba.logLevel = threadContext->logLevel;
|
||||||
gba.logHandler = threadContext->logHandler;
|
gba.logHandler = threadContext->logHandler;
|
||||||
gba.stream = threadContext->stream;
|
gba.stream = threadContext->stream;
|
||||||
|
|
|
@ -56,6 +56,8 @@ set(SOURCE_FILES
|
||||||
KeyEditor.cpp
|
KeyEditor.cpp
|
||||||
LoadSaveState.cpp
|
LoadSaveState.cpp
|
||||||
LogView.cpp
|
LogView.cpp
|
||||||
|
MemoryModel.cpp
|
||||||
|
MemoryView.cpp
|
||||||
MultiplayerController.cpp
|
MultiplayerController.cpp
|
||||||
OverrideView.cpp
|
OverrideView.cpp
|
||||||
PaletteView.cpp
|
PaletteView.cpp
|
||||||
|
@ -74,6 +76,7 @@ qt5_wrap_ui(UI_FILES
|
||||||
GIFView.ui
|
GIFView.ui
|
||||||
LoadSaveState.ui
|
LoadSaveState.ui
|
||||||
LogView.ui
|
LogView.ui
|
||||||
|
MemoryView.ui
|
||||||
OverrideView.ui
|
OverrideView.ui
|
||||||
PaletteView.ui
|
PaletteView.ui
|
||||||
SensorView.ui
|
SensorView.ui
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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>
|
|
@ -26,6 +26,7 @@
|
||||||
#include "LoadSaveState.h"
|
#include "LoadSaveState.h"
|
||||||
#include "LogView.h"
|
#include "LogView.h"
|
||||||
#include "MultiplayerController.h"
|
#include "MultiplayerController.h"
|
||||||
|
#include "MemoryView.h"
|
||||||
#include "OverrideView.h"
|
#include "OverrideView.h"
|
||||||
#include "PaletteView.h"
|
#include "PaletteView.h"
|
||||||
#include "SensorView.h"
|
#include "SensorView.h"
|
||||||
|
@ -328,6 +329,11 @@ void Window::openPaletteWindow() {
|
||||||
openView(paletteWindow);
|
openView(paletteWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::openMemoryWindow() {
|
||||||
|
MemoryView* memoryWindow = new MemoryView(m_controller);
|
||||||
|
openView(memoryWindow);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BUILD_SDL
|
#ifdef BUILD_SDL
|
||||||
void Window::openGamepadWindow() {
|
void Window::openGamepadWindow() {
|
||||||
const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON);
|
const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON);
|
||||||
|
@ -964,6 +970,11 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
m_gameActions.append(paletteView);
|
m_gameActions.append(paletteView);
|
||||||
addControlledAction(toolsMenu, paletteView, "paletteWindow");
|
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");
|
ConfigOption* skipBios = m_config->addOption("skipBios");
|
||||||
skipBios->connect([this](const QVariant& value) {
|
skipBios->connect([this](const QVariant& value) {
|
||||||
m_controller->setSkipBIOS(value.toBool());
|
m_controller->setSkipBIOS(value.toBool());
|
||||||
|
|
|
@ -77,6 +77,7 @@ public slots:
|
||||||
void openCheatsWindow();
|
void openCheatsWindow();
|
||||||
|
|
||||||
void openPaletteWindow();
|
void openPaletteWindow();
|
||||||
|
void openMemoryWindow();
|
||||||
|
|
||||||
#ifdef BUILD_SDL
|
#ifdef BUILD_SDL
|
||||||
void openGamepadWindow();
|
void openGamepadWindow();
|
||||||
|
|
Loading…
Reference in New Issue