basic ui, scroll half-works

This commit is contained in:
Yanis002 2025-07-27 01:03:34 +02:00
parent a3467f6dcb
commit 3bf57be5e2
2 changed files with 367 additions and 0 deletions

View File

@ -0,0 +1,218 @@
/*
Copyright 2016-2025 melonDS team
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include "MemViewDialog.h"
#include <QPainter>
#include <QGraphicsTextItem>
#include <QTextCursor>
#include "main.h"
using namespace melonDS;
using Platform::Log;
using Platform::LogLevel;
// --- MemViewDialog ---
MemViewDialog* MemViewDialog::currentDlg = nullptr;
CustomTextItem::CustomTextItem(const QString &text, QGraphicsItem *parent) : QGraphicsTextItem(text, parent) {
this->setTextInteractionFlags(Qt::TextInteractionFlag::TextSelectableByMouse | Qt::TextInteractionFlag::TextSelectableByKeyboard);
this->setFlag(QGraphicsItem::ItemIsFocusable, false);
}
void CustomTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
if (event->button() == Qt::LeftButton) {
// select everything
QTextCursor cursor = this->textCursor();
cursor.select(QTextCursor::Document);
this->setTextCursor(cursor);
}
}
void CustomTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {}
void CustomGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent* event) {
// if (event->button() == Qt::LeftButton) {
// // deselect items if selected
// foreach(QGraphicsItem* item, this->items()) {
// item->setSelected(false);
// }
// }
}
MemViewDialog::MemViewDialog(QWidget* parent) : QDialog(parent)
{
this->setObjectName("MemViewDialog");
this->setFixedSize(550, 410);
this->setEnabled(true);
this->setModal(false);
this->setWindowTitle("Memory Viewer - melonDS");
setAttribute(Qt::WA_DeleteOnClose);
this->emuInstance = ((MainWindow*)parent)->getEmuInstance();
this->nds = this->emuInstance->getNDS();
this->gfxScene = new CustomGraphicsScene(this);
this->gfxView = new QGraphicsView(this);
this->scrollBar = new QScrollBar(this);
this->updateThread = new MemViewThread();
this->gfxView->setScene(this->gfxScene);
this->gfxView->setGeometry(10, 120, 520, 275);
this->gfxScene->clear();
this->gfxScene->setSceneRect(0, 0, 520, 275);
this->scrollBar->setGeometry(530, 120, 16, 275);
this->scrollBar->setMinimum(0);
this->scrollBar->setMaximum((this->arm9AddrEnd - this->arm9Addr) / 16);
QString text;
QColor color;
QFont font("Monospace", 10, -1, false);
// create hex digits texts
for (int i = 0; i < 16; i++) {
text.setNum(i, 16);
QGraphicsTextItem* textItem = new QGraphicsTextItem(text.toUpper().rightJustified(2, '0'));
textItem->setFont(font);
qreal x = i * textItem->font().pointSize() * 2; // column number * font size * text length
qreal y = 0; // always zero
// account for addresses column length
x += textItem->font().pointSize() * 8;
textItem->setPos(x + 10, y);
this->gfxScene->addItem(textItem);
// kinda hacky but we need to sync the line's color on the text
// and since the text color depends on the system's theme... easy way for now...
if (i == 0) {
color = textItem->defaultTextColor();
}
}
// create addresses texts
for (int i = 0; i < 16; i++) {
text.setNum(i * 16 + this->arm9Addr, 16);
QGraphicsTextItem* textItem = new QGraphicsTextItem(text.toUpper().rightJustified(8, '0').prepend("0x"));
textItem->setFont(font);
textItem->setPos(0, i * textItem->font().pointSize() * 1.5f + textItem->font().pointSize() + 15);
this->gfxScene->addItem(textItem);
this->addresses[i] = textItem;
}
// init memory view
int index = 0;
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
CustomTextItem* textItem = new CustomTextItem("00");
textItem->setFont(font);
qreal x = j * textItem->font().pointSize() * 2; // column number * font size * text length
qreal y = 0; // always zero
// account for addresses column length
x += textItem->font().pointSize() * 8;
textItem->setPos(x + 10, i * textItem->font().pointSize() * 1.5f + textItem->font().pointSize() + 15);
textItem->setTextInteractionFlags(Qt::TextInteractionFlag::TextEditorInteraction);
this->gfxScene->addItem(textItem);
this->items[index++] = textItem;
}
}
// add separators
QGraphicsLineItem* line1 = this->gfxScene->addLine(0, 25, this->gfxScene->width(), 25, QPen(color));
QGraphicsLineItem* line2 = this->gfxScene->addLine(87, 0, 87, this->gfxScene->height(), QPen(color));
this->updateThread->Start();
connect(this->updateThread, &MemViewThread::updateTextSignal, this, &MemViewDialog::updateText);
connect(this->updateThread, &MemViewThread::updateAddressSignal, this, &MemViewDialog::updateAddress);
qRegisterMetaType<QVector<int>>("QVector<int>");
qRegisterMetaType<u32>("u32");
qRegisterMetaType<s32>("s32");
qRegisterMetaType<s16>("s16");
qRegisterMetaType<s8>("s8");
}
MemViewDialog::~MemViewDialog()
{
this->gfxScene->deleteLater();
this->gfxView->deleteLater();
this->scrollBar->deleteLater();
this->updateThread->deleteLater();
delete this->gfxScene;
delete this->gfxView;
delete this->scrollBar;
delete this->updateThread;
}
void MemViewDialog::done(int r)
{
QDialog::done(r);
closeDlg();
}
void MemViewDialog::updateText(int index) {
QGraphicsTextItem* item = (QGraphicsTextItem*)this->GetItem(index);
QString text;
if (item != nullptr) {
u8 value = this->GetNDS()->ARM9Read8(this->arm9Addr + (this->scrollBar->value() * 16) + index);
text.setNum(value, 16);
item->setPlainText(text.toUpper().rightJustified(2, '0'));
}
}
void MemViewDialog::updateAddress(int index) {
QGraphicsTextItem* item = (QGraphicsTextItem*)this->GetAddressItem(index);
QString text;
if (item != nullptr) {
uint32_t address = this->arm9Addr + (this->scrollBar->value() + index) * 16;
text.setNum(address, 16);
item->setPlainText(text.toUpper().rightJustified(8, '0').prepend("0x"));
}
}
// --- MemViewThread ---
MemViewThread::~MemViewThread() {
this->quit();
this->wait();
}
void MemViewThread::Start() {
this->start();
Log(LogLevel::Debug, "MEMVIEW THREAD STARTED!!!!!");
}
void MemViewThread::run() {
while (true) {
QThread::msleep(50);
for (int i = 0; i < 256; i++) {
emit updateTextSignal(i);
}
for (int i = 0; i < 16; i++) {
emit updateAddressSignal(i);
}
}
}

View File

@ -0,0 +1,149 @@
/*
Copyright 2016-2025 melonDS team
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#ifndef MEMVIEWDIALOG_H
#define MEMVIEWDIALOG_H
#include <QDialog>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsTextItem>
#include <QGraphicsSceneMouseEvent>
#include <QThread>
#include <QScrollBar>
#include "types.h"
#include "NDS.h"
class NDS;
class EmuInstance;
class MemViewThread;
// --- main window ---
class CustomTextItem : public QGraphicsTextItem {
Q_OBJECT
public:
explicit CustomTextItem(const QString &text, QGraphicsItem *parent = nullptr);
~CustomTextItem() {}
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
};
class CustomGraphicsScene : public QGraphicsScene {
Q_OBJECT
public:
explicit CustomGraphicsScene(QObject *parent = nullptr) : QGraphicsScene(parent) {}
explicit CustomGraphicsScene(const QRectF &sceneRect, QObject *parent = nullptr) : QGraphicsScene(sceneRect, parent) {}
explicit CustomGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent = nullptr) : QGraphicsScene(x, y, width, height, parent) {}
~CustomGraphicsScene() {}
protected:
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
};
class MemViewDialog : public QDialog
{
Q_OBJECT
public:
explicit MemViewDialog(QWidget* parent);
~MemViewDialog();
static MemViewDialog* currentDlg;
static MemViewDialog* openDlg(QWidget* parent)
{
if (currentDlg)
{
currentDlg->activateWindow();
return currentDlg;
}
currentDlg = new MemViewDialog(parent);
currentDlg->show();
return currentDlg;
}
static void closeDlg()
{
currentDlg = nullptr;
}
melonDS::NDS* GetNDS() { return this->nds; }
QGraphicsItem* GetItem(int index) {
if (index < 256) {
return this->items[index];
}
return nullptr;
}
QGraphicsItem* GetAddressItem(int index) {
if (index < 16) {
return this->addresses[index];
}
return nullptr;
}
static const uint32_t arm9Addr = 0x02000000;
static const uint32_t arm9AddrEnd = 0x03000000 - 1;
private slots:
void done(int r);
void updateText(int index);
void updateAddress(int index);
private:
EmuInstance* emuInstance;
melonDS::NDS* nds;
QGraphicsView* gfxView;
CustomGraphicsScene* gfxScene;
MemViewThread* updateThread;
QScrollBar* scrollBar;
QGraphicsItem* items[256];
QGraphicsItem* addresses[16];
friend class MemViewThread;
};
// --- update thread ---
class MemViewThread : public QThread {
Q_OBJECT
public:
explicit MemViewThread() {}
~MemViewThread() override;
void Start();
private:
virtual void run() override;
signals:
void updateTextSignal(int index);
void updateAddressSignal(int index);
};
#endif // MEMVIEWDIALOG_H