src/platform/qt/MemoryModel.cpp (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "MemoryModel.h"
7
8#include "GameController.h"
9
10#include <QFontMetrics>
11#include <QPainter>
12#include <QScrollBar>
13#include <QSlider>
14#include <QWheelEvent>
15
16extern "C" {
17#include "gba/memory.h"
18}
19
20using namespace QGBA;
21
22MemoryModel::MemoryModel(QWidget* parent)
23 : QAbstractScrollArea(parent)
24 , m_top(0)
25{
26 m_font.setFamily("Source Code Pro");
27 m_font.setStyleHint(QFont::Monospace);
28 m_font.setPointSize(12);
29 QFontMetrics metrics(m_font);
30 m_cellHeight = metrics.height();
31 m_letterWidth = metrics.averageCharWidth();
32
33 for (int i = 0; i < 256; ++i) {
34 QStaticText str(QString("%0").arg(i, 2, 16, QChar('0')).toUpper());
35 str.prepare(QTransform(), m_font);
36 m_staticNumbers.append(str);
37 }
38
39 for (int i = 0; i < 128; ++i) {
40 QChar c(0xFFFD);
41 if (c.isPrint()) {
42 c = i;
43 }
44 QStaticText str = QStaticText(QString(c));
45 str.prepare(QTransform(), m_font);
46 m_staticAscii.append(str);
47 }
48
49 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
50 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
51 m_margins = QMargins(metrics.width("FFFFFF ") + 3, m_cellHeight + 1, metrics.width(" AAAAAAAAAAAAAAAA") + 3, 0);
52
53 verticalScrollBar()->setRange(0, 0x01000001 - viewport()->size().height() / m_cellHeight);
54 connect(verticalScrollBar(), &QSlider::sliderMoved, [this](int position) {
55 m_top = position;
56 update();
57 });
58 update();
59}
60
61void MemoryModel::setController(GameController* controller) {
62 m_cpu = controller->thread()->cpu;
63}
64
65void MemoryModel::resizeEvent(QResizeEvent*) {
66 verticalScrollBar()->setRange(0, 0x01000001 - viewport()->size().height() / m_cellHeight);
67 boundsCheck();
68}
69
70void MemoryModel::paintEvent(QPaintEvent* event) {
71 QPainter painter(viewport());
72 painter.setFont(m_font);
73 QChar c0('0');
74 QSizeF cellSize = QSizeF((viewport()->size().width() - (m_margins.left() + m_margins.right())) / 16.f, m_cellHeight);
75 QSizeF letterSize = QSizeF(m_letterWidth, m_cellHeight);
76 painter.drawText(QRect(QPoint(0, 0), QSize(m_margins.left(), m_margins.top())), Qt::AlignHCenter, tr("All"));
77 painter.drawText(QRect(QPoint(viewport()->size().width() - m_margins.right(), 0), QSize(m_margins.right(), m_margins.top())), Qt::AlignHCenter, tr("ASCII"));
78 for (int x = 0; x < 16; ++x) {
79 painter.drawText(QRectF(QPointF(cellSize.width() * x + m_margins.left(), 0), cellSize), Qt::AlignHCenter, QString::number(x, 16).toUpper());
80 }
81 int height = (viewport()->size().height() - m_cellHeight) / m_cellHeight;
82 for (int y = 0; y < height; ++y) {
83 int yp = m_cellHeight * y + m_margins.top();
84 QString data = QString("%0").arg(y + m_top, 6, 16, c0).toUpper();
85 painter.drawText(QRectF(QPointF(0, yp), QSizeF(m_margins.left(), m_cellHeight)), Qt::AlignHCenter, data);
86 for (int x = 0; x < 16; ++x) {
87 uint8_t b = m_cpu->memory.load8(m_cpu, (y + m_top) * 16 + x, nullptr);
88 painter.drawStaticText(QPointF(cellSize.width() * (x + 0.5) - m_letterWidth + m_margins.left(), yp), m_staticNumbers[b]);
89 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]);
90 }
91 }
92 painter.drawLine(m_margins.left() - 2, 0, m_margins.left() - 2, viewport()->size().height());
93 painter.drawLine(viewport()->size().width() - m_margins.right(), 0, viewport()->size().width() - m_margins.right(), viewport()->size().height());
94 painter.drawLine(0, m_margins.top(), viewport()->size().width(), m_margins.top());
95}
96
97void MemoryModel::wheelEvent(QWheelEvent* event) {
98 m_top -= event->angleDelta().y() / 8;
99 boundsCheck();
100 event->accept();
101 update();
102 QAbstractScrollArea::wheelEvent(event);
103}
104
105void MemoryModel::boundsCheck() {
106 if (m_top < 0) {
107 m_top = 0;
108 } else if (m_top > 0x01000001 - viewport()->size().height() / m_cellHeight) {
109 m_top = 0x01000001 - viewport()->size().height() / m_cellHeight;
110 }
111}