diff --git a/src/frontend/qt_sdl/MemViewDialog.cpp b/src/frontend/qt_sdl/MemViewDialog.cpp index 39a0545b..ee9f2f12 100644 --- a/src/frontend/qt_sdl/MemViewDialog.cpp +++ b/src/frontend/qt_sdl/MemViewDialog.cpp @@ -32,15 +32,41 @@ using namespace melonDS; MemViewDialog* MemViewDialog::currentDlg = nullptr; CustomTextItem::CustomTextItem(const QString &text, QGraphicsItem *parent) : QGraphicsTextItem(text, parent) { - this->setTextInteractionFlags(Qt::TextInteractionFlag::TextSelectableByMouse); + this->setTextInteractionFlags(Qt::TextInteractionFlag::TextEditorInteraction); this->setFlag(QGraphicsItem::ItemIsSelectable, false); this->SetSize(QRectF(2, 6, 20, 15)); + this->isEditing = false; } QRectF CustomTextItem::boundingRect() const { return this->size; } +bool CustomTextItem::isKeyValid(int key) { + // hex chars + if ((key >= Qt::Key_0 && key <= Qt::Key_9) || (key >= Qt::Key_A && key <= Qt::Key_F)) { + return true; + } + + // navigation arrows + if (key >= Qt::Key_Left && key <= Qt::Key_Down) { + return true; + } + + // other important keys + switch (key) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Delete: + case Qt::Key_Backspace: + return true; + default: + break; + } + + return false; +} + void CustomTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { this->QGraphicsTextItem::mousePressEvent(event); } @@ -48,6 +74,43 @@ void CustomTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { // empty on purpose to disable the move behaviour void CustomTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {} +void CustomTextItem::keyPressEvent(QKeyEvent *event) { + QString text = this->toPlainText(); + int key = event->key(); + + // make sure that: + // - 1. the item is focused (probably always true though but wanna be safe) + // - 2. the key is valid, so either an hex digit or other keys like enter or delete + // - 3. the current text length don't exceed 2 + if (!this->hasFocus() || !this->isKeyValid(key) || text.length() > 2) { + this->isEditing = false; + event->ignore(); + return; + } + + // turn enter keys to a validator, not clearing isEditing since focusOutEvent will do it + if (key == Qt::Key_Enter || key == Qt::Key_Return) { + this->clearFocus(); + event->accept(); + return; + } + + // if the validation checks pass and it's not the enter key, process it + this->QGraphicsTextItem::keyPressEvent(event); + this->isEditing = true; +} + +void CustomTextItem::focusOutEvent(QFocusEvent *event) { + // apply the value when the focus is cleared, if necessary + if (this->isEditing) { + QString text = this->toPlainText(); + emit applyEditToRAM(text.toUInt(0, 16), this); + this->isEditing = false; + } + + this->QGraphicsTextItem::focusOutEvent(event); +} + void CustomGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *event) { this->QGraphicsScene::wheelEvent(event); @@ -77,16 +140,11 @@ void CustomGraphicsScene::onFocusItemChanged(QGraphicsItem *newFocus, QGraphicsI MemViewDialog* dialog = (MemViewDialog*)this->parent(); if (dialog != nullptr && newFocus != nullptr) { - int index = dialog->GetItemIndex(newFocus); - uint32_t addr = dialog->GetAddressFromItem((CustomTextItem*)newFocus); + uint32_t addr = dialog->GetFocusAddress(newFocus); - if (addr >= dialog->arm9AddrEnd + 0x100) { - addr = dialog->arm9AddrEnd; - } - - if (index >= 0) { + if (addr != -1) { QString text; - text.setNum(addr + index, 16); + text.setNum(addr, 16); dialog->GetAddrLabel()->setText(text.toUpper().rightJustified(8, '0').prepend("0x")); if (dialog->GetFocusCheckbox()->isChecked()) { @@ -223,6 +281,7 @@ MemViewDialog::MemViewDialog(QWidget* parent) : QDialog(parent) for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { CustomTextItem* textItem = new CustomTextItem("00"); + connect(textItem, &CustomTextItem::applyEditToRAM, this, &MemViewDialog::onApplyEditToRAM); textItem->setParent(this->gfxScene); textItem->setFont(font); qreal x = j * textItem->font().pointSize() * 2; // column number * font size * text length @@ -316,6 +375,42 @@ int MemViewDialog::GetAddressFromItem(CustomTextItem* item) { return -1; } +void* MemViewDialog::GetRAM(uint32_t address) { + melonDS::NDS* nds = this->GetNDS(); + + //! TODO: use Armv5::ReadMem instead + if (nds != nullptr) { + if (address < 0x027E0000) { + if (nds->MainRAM) { + return &nds->MainRAM[address & nds->MainRAMMask]; + } + } else { + if (nds->ARM9.DTCM) { + return &nds->ARM9.DTCM[address & 0xFFFF]; + } + } + } + + return nullptr; +} + +uint32_t MemViewDialog::GetFocusAddress(QGraphicsItem *focus) { + if (focus != nullptr) { + uint32_t addr = this->GetAddressFromItem((CustomTextItem*)focus); + int index = this->GetItemIndex(focus); + + if (addr >= this->arm9AddrEnd + 0x100) { + addr = this->arm9AddrEnd; + } + + if (index >= 0) { + return addr + index; + } + } + + return -1; +} + void MemViewDialog::done(int r) { QDialog::done(r); @@ -327,21 +422,16 @@ void MemViewDialog::done(int r) void MemViewDialog::updateText(int addrIndex, int index) { CustomTextItem* item = (CustomTextItem*)this->GetItem(addrIndex, index); QString text; - melonDS::NDS* nds = this->GetNDS(); - if (item != nullptr && nds != nullptr) { - uint32_t address = ALIGN16(this->scrollBar->value()) + addrIndex * 16; - uint8_t byte; + if (this->scrollBar == nullptr) { + return; + } - if (address < 0x027E0000) { - if (nds->MainRAM) { - byte = nds->MainRAM[(address + index) & nds->MainRAMMask]; - } - } else { - if (nds->ARM9.DTCM) { - byte = nds->ARM9.DTCM[(address + index) & 0xFFFF]; - } - } + uint32_t address = ALIGN16(this->scrollBar->value()) + addrIndex * 16; + uint8_t* pRAM = (uint8_t*)this->GetRAM(address + index); + + if (item != nullptr && pRAM != nullptr) { + uint8_t byte = *pRAM; // only update the text when the item isn't focused so we can edit it if (!item->hasFocus()) { @@ -436,19 +526,7 @@ void MemViewDialog::onValueBtnSetPressed() { text = this->setValNumber->text(); this->StripStringHex(&text); - melonDS::NDS* nds = this->GetNDS(); - void* pRAM = nullptr; - if (nds != nullptr) { - if (address < 0x027E0000) { - if (nds->MainRAM) { - pRAM = (void*)&nds->MainRAM[address & nds->MainRAMMask]; - } - } else { - if (nds->ARM9.DTCM) { - pRAM = (void*)&nds->ARM9.DTCM[address & 0xFFFF]; - } - } - } + void* pRAM = this->GetRAM(address); if (pRAM != nullptr) { switch (this->setValBits->currentIndex()) { @@ -467,6 +545,20 @@ void MemViewDialog::onValueBtnSetPressed() { } } +void MemViewDialog::onApplyEditToRAM(uint8_t value, QGraphicsItem *focus) { + uint32_t addr = this->GetFocusAddress(focus); + if (addr == -1) { + return; + } + + uint8_t* pRAM = (uint8_t*)this->GetRAM(addr); + if (pRAM == nullptr) { + return; + } + + *pRAM = value; +} + // --- MemViewThread --- MemViewThread::~MemViewThread() { diff --git a/src/frontend/qt_sdl/MemViewDialog.h b/src/frontend/qt_sdl/MemViewDialog.h index 5dc5d55b..683e1116 100644 --- a/src/frontend/qt_sdl/MemViewDialog.h +++ b/src/frontend/qt_sdl/MemViewDialog.h @@ -50,17 +50,24 @@ public: explicit CustomTextItem(const QString &text, QGraphicsItem *parent = nullptr); ~CustomTextItem() {} QRectF boundingRect() const override; + bool isKeyValid(int key); void SetSize(QRectF newSize) { this->size = newSize; } +signals: + void applyEditToRAM(uint8_t value, QGraphicsItem *focus); + private: QRectF size; + bool isEditing; protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; }; class CustomGraphicsScene : public QGraphicsScene { @@ -95,6 +102,8 @@ public: ~MemViewDialog(); melonDS::NDS* GetNDS(); int GetAddressFromItem(CustomTextItem* item); + void* GetRAM(uint32_t address); + uint32_t GetFocusAddress(QGraphicsItem *focus); static MemViewDialog* currentDlg; static MemViewDialog* openDlg(QWidget* parent) @@ -114,7 +123,6 @@ public: currentDlg = nullptr; } - QGraphicsItem* GetItem(int addrIndex, int index) { if (addrIndex < 16 && index < 16) { return this->ramTextItems[addrIndex][index]; @@ -178,6 +186,7 @@ private slots: void updateDecoded(int index); void onAddressTextChanged(const QString &text); void onValueBtnSetPressed(); + void onApplyEditToRAM(uint8_t value, QGraphicsItem *focus); public: uint32_t arm9AddrStart;