From b749c0982e58274cfd9774cbf57334ae730db6f4 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 15 Aug 2020 21:20:58 -0400 Subject: [PATCH 01/37] Changed cheat window text entry field sizing to be proportional to average font char width. --- src/drivers/Qt/CheatsConf.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/CheatsConf.cpp b/src/drivers/Qt/CheatsConf.cpp index 2f1de97d..339d18d0 100644 --- a/src/drivers/Qt/CheatsConf.cpp +++ b/src/drivers/Qt/CheatsConf.cpp @@ -50,7 +50,8 @@ GuiCheatsDialog_t::GuiCheatsDialog_t(QWidget *parent) QFontMetrics fm(font); - fontCharWidth = fm.boundingRect('X').width() * devPixRatio; + //fontCharWidth = fm.boundingRect('X').width() * devPixRatio; + fontCharWidth = 2.00 * fm.averageCharWidth() * devPixRatio; setWindowTitle("Cheat Search"); From 11ccdf77b45d159e80cac3b40e79b41693a922c1 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 15 Aug 2020 21:41:06 -0400 Subject: [PATCH 02/37] Added initial framework for hex editor. --- src/CMakeLists.txt | 1 + src/drivers/Qt/ConsoleWindow.cpp | 29 +++++++++++++++ src/drivers/Qt/ConsoleWindow.h | 3 ++ src/drivers/Qt/HexEditor.cpp | 63 ++++++++++++++++++++++++++++++++ src/drivers/Qt/HexEditor.h | 38 +++++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 src/drivers/Qt/HexEditor.cpp create mode 100644 src/drivers/Qt/HexEditor.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6a13bd2b..4ef224bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -431,6 +431,7 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 8376262b..e81e57ed 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -24,6 +24,7 @@ #include "Qt/GuiConf.h" #include "Qt/LuaControl.h" #include "Qt/CheatsConf.h" +#include "Qt/HexEditor.h" #include "Qt/ConsoleUtilities.h" #include "Qt/ConsoleSoundConf.h" #include "Qt/ConsoleVideoConf.h" @@ -484,6 +485,18 @@ void consoleWin_t::createMainMenu(void) toolsMenu->addAction(cheatsAct); + //----------------------------------------------------------------------- + // Debug + debugMenu = menuBar()->addMenu(tr("Debug")); + + // Debug -> Hex Editor + hexEditAct = new QAction(tr("Hex Editor..."), this); + //hexEditAct->setShortcut( QKeySequence(tr("Shift+F7"))); + hexEditAct->setStatusTip(tr("Open Memory Hex Editor")); + connect(hexEditAct, SIGNAL(triggered()), this, SLOT(openHexEditor(void)) ); + + debugMenu->addAction(hexEditAct); + //----------------------------------------------------------------------- // Movie movieMenu = menuBar()->addMenu(tr("Movie")); @@ -1010,6 +1023,22 @@ void consoleWin_t::openCheats(void) //printf("GUI Cheat Window Destroyed\n"); } +void consoleWin_t::openHexEditor(void) +{ + HexEditorDialog_t *hexEditWin; + + //printf("Open GUI Hex Editor Window\n"); + + hexEditWin = new HexEditorDialog_t(this); + + hexEditWin->show(); + hexEditWin->exec(); + + delete hexEditWin; + + //printf("GUI Cheat Window Destroyed\n"); +} + void consoleWin_t::toggleAutoResume(void) { //printf("Auto Resume: %i\n", autoResume->isChecked() ); diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index e2bd6a69..d2515407 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -53,6 +53,7 @@ class consoleWin_t : public QMainWindow QMenu *optMenu; QMenu *emuMenu; QMenu *toolsMenu; + QMenu *debugMenu; QMenu *movieMenu; QMenu *helpMenu; @@ -88,6 +89,7 @@ class consoleWin_t : public QMainWindow QAction *fdsEjectAct; QAction *fdsLoadBiosAct; QAction *cheatsAct; + QAction *hexEditAct; QAction *openMovAct; QAction *stopMovAct; QAction *recMovAct; @@ -155,6 +157,7 @@ class consoleWin_t : public QMainWindow void fdsEjectDisk(void); void fdsLoadBiosFile(void); void openCheats(void); + void openHexEditor(void); void openMovie(void); void stopMovie(void); void recordMovie(void); diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp new file mode 100644 index 00000000..1e39ed47 --- /dev/null +++ b/src/drivers/Qt/HexEditor.cpp @@ -0,0 +1,63 @@ +// HotKeyConf.cpp +// +#include +#include +#include +#include + +#include +#include + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/HexEditor.h" + +//---------------------------------------------------------------------------- +HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout; + + setWindowTitle("Hex Editor"); + + resize( 512, 512 ); + + mainLayout = new QVBoxLayout(); + + txt = new QTextEdit(); + + txt->moveCursor(QTextCursor::Start); + txt->setReadOnly(true); + + mainLayout->addWidget( txt ); + + setLayout( mainLayout ); +} +//---------------------------------------------------------------------------- +HexEditorDialog_t::~HexEditorDialog_t(void) +{ + +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::keyPressEvent(QKeyEvent *event) +{ + printf("Hex Window Key Press: 0x%x \n", event->key() ); + //assignHotkey( event ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::keyReleaseEvent(QKeyEvent *event) +{ + printf("Hex Window Key Release: 0x%x \n", event->key() ); + //assignHotkey( event ); +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h new file mode 100644 index 00000000..8c71d51a --- /dev/null +++ b/src/drivers/Qt/HexEditor.h @@ -0,0 +1,38 @@ +// GamePadConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class HexEditorDialog_t : public QDialog +{ + Q_OBJECT + + public: + HexEditorDialog_t(QWidget *parent = 0); + ~HexEditorDialog_t(void); + + protected: + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + + QTextEdit *txt; + + private: + + public slots: + void closeWindow(void); + private slots: + +}; From 490289a6f7acb2393ba78b8c3063d25a950cddf5 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 16 Aug 2020 10:38:42 -0400 Subject: [PATCH 03/37] Qt Hex editor in work. --- src/drivers/Qt/HexEditor.cpp | 381 ++++++++++++++++++++++++++++++++++- src/drivers/Qt/HexEditor.h | 40 +++- 2 files changed, 415 insertions(+), 6 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 1e39ed47..93c7a36f 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -8,6 +8,19 @@ #include #include +#include "../../types.h" +#include "../../fceu.h" +#include "../../cheat.h" +#include "../../debug.h" +#include "../../driver.h" +#include "../../version.h" +#include "../../movie.h" +#include "../../palette.h" +#include "../../fds.h" +#include "../../cart.h" +#include "../../ines.h" +#include "../common/configSys.h" + #include "Qt/main.h" #include "Qt/dface.h" #include "Qt/input.h" @@ -16,31 +29,114 @@ #include "Qt/fceuWrapper.h" #include "Qt/HexEditor.h" +//---------------------------------------------------------------------------- +static int getRAM( unsigned int i ) +{ + return GetMem(i); +} +static int getPPU( unsigned int i ) +{ + i &= 0x3FFF; + if (i < 0x2000)return VPage[(i) >> 10][(i)]; + //NSF PPU Viewer crash here (UGETAB) (Also disabled by 'MaxSize = 0x2000') + if (GameInfo->type == GIT_NSF) + return 0; + else + { + if (i < 0x3F00) + return vnapage[(i >> 10) & 0x3][i & 0x3FF]; + return READPAL_MOTHEROFALL(i & 0x1F); + } + return 0; +} +static int getOAM( unsigned int i ) +{ + return SPRAM[i & 0xFF]; +} +static int getROM( unsigned int offset) +{ + if (offset < 16) + { + return *((unsigned char *)&head+offset); + } + else if (offset < (16+PRGsize[0]) ) + { + return PRGptr[0][offset-16]; + } + else if (offset < (16+PRGsize[0]+CHRsize[0]) ) + { + return CHRptr[0][offset-16-PRGsize[0]]; + } + return -1; +} +static int conv2xchar( int i ) +{ + int c = 0; + + if ( (i >= 0) && (i < 10) ) + { + c = i + '0'; + } + else if ( i < 16 ) + { + c = (i - 10) + 'A'; + } + return c; +} //---------------------------------------------------------------------------- HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent ) { QVBoxLayout *mainLayout; + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + setWindowTitle("Hex Editor"); resize( 512, 512 ); mainLayout = new QVBoxLayout(); - txt = new QTextEdit(); + txtBuf = new QPlainTextEdit(); - txt->moveCursor(QTextCursor::Start); - txt->setReadOnly(true); + txtBuf->setFont( font ); + txtBuf->moveCursor(QTextCursor::Start); + txtBuf->setReadOnly(true); + txtBuf->setLineWrapMode( QPlainTextEdit::NoWrap ); - mainLayout->addWidget( txt ); + mainLayout->addWidget( txtBuf ); setLayout( mainLayout ); + + mode = MODE_NES_RAM; + numLines = 0; + numCharsPerLine = 90; + mbuf = NULL; + memSize = 0; + mbuf_size = 0; + memAccessFunc = getRAM; + redraw = false; + total_instructions_lp = 0; + + showMemViewResults(true); + + periodicTimer = new QTimer( this ); + + connect( periodicTimer, &QTimer::timeout, this, &HexEditorDialog_t::updatePeriodic ); + + periodicTimer->start( 1000 ); // 10hz } //---------------------------------------------------------------------------- HexEditorDialog_t::~HexEditorDialog_t(void) { + periodicTimer->stop(); + if ( mbuf != NULL ) + { + ::free( mbuf ); mbuf = NULL; + } } //---------------------------------------------------------------------------- void HexEditorDialog_t::closeWindow(void) @@ -61,3 +157,280 @@ void HexEditorDialog_t::keyReleaseEvent(QKeyEvent *event) //assignHotkey( event ); } //---------------------------------------------------------------------------- +int HexEditorDialog_t::calcVisibleRange( int *start_out, int *end_out, int *center_out ) +{ + int start_pos, end_pos; + QPoint bottom_left( 0, txtBuf->viewport()->height() - 1); + + start_pos = txtBuf->cursorForPosition(QPoint(0, 0)).position(); + end_pos = txtBuf->cursorForPosition(bottom_left).position(); + + start_pos = (start_pos / numCharsPerLine) - 1; + end_pos = (end_pos / numCharsPerLine) + 1; + + if ( start_pos < 0 ) + { + start_pos = 0; + } + + printf("Start: %i End: %i\n", start_pos, end_pos ); + + if ( start_out ) + { + *start_out = start_pos; + } + if ( end_out ) + { + *end_out = end_pos; + } + if ( center_out ) + { + *center_out = (start_pos + end_pos) / 2; + } + return 0; +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setMode(int new_mode) +{ + if ( mode != new_mode ) + { + mode = new_mode; + showMemViewResults(true); + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::initMem(void) +{ + + for (int i=0; itype == GIT_NSF ? 0x2000 : 0x4000); + break; + case MODE_NES_OAM: + memAccessFunc = getOAM; + memSize = 0x100; + break; + case MODE_NES_ROM: + + if ( GameInfo != NULL ) + { + memAccessFunc = getROM; + memSize = 16 + CHRsize[0] + PRGsize[0]; + } + else + { // No Game Loaded!!! Get out of Function + memAccessFunc = NULL; + memSize = 0; + if ( mbuf ) + { + free(mbuf); mbuf = NULL; + } + mbuf_size = 0; + redraw = true; + txtBuf->setPlainText("No ROM Loaded"); + return; + } + break; + } + numLines = memSize / 16; + + if ( (mbuf == NULL) || (mbuf_size != memSize) ) + { + printf("Mode: %i MemSize:%i 0x%08x\n", mode, memSize, (unsigned int)memSize ); + reset = 1; + + if ( mbuf ) + { + free(mbuf); mbuf = NULL; + } + mbuf = (struct memByte_t *)malloc( memSize * sizeof(struct memByte_t) ); + + if ( mbuf ) + { + mbuf_size = memSize; + initMem(); + } + else + { + printf("Error: Failed to allocate memview buffer size\n"); + mbuf_size = 0; + return; + } + } + + if ( reset ) + { + txtBuf->clear(); + row_start = 0; + row_end = numLines; + } + else + { + calcVisibleRange( &row_start, &row_end, NULL ); + + if ( row_start < 0 ) + { + row_start = 0; + } + if ( row_end > numLines ) + { + row_end = numLines; + } + } + + for (row=row_start; rowtextCursor().setPosition( row * numCharsPerLine ); + } + + if ( reset ) + { + //next_iter = iter; + //gtk_text_iter_forward_chars( &next_iter, 9 ); + + sprintf( addrStr, "%08X ", lineAddr ); + + txtBuf->insertPlainText( addrStr ); + } + else + { + txtBuf->textCursor().movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 9 ); + } + + for (i=0; i<16; i++) + { + valChg[i] = reset; + + addr = lineAddr+i; + + c = memAccessFunc(addr); + + if ( mbuf[addr].draw ) + { + mbuf[addr].draw = 0; + valChg[i] = 1; + } + + un = ( c & 0x00f0 ) >> 4; + ln = ( c & 0x000f ); + + valStr[i][0] = ' '; + valStr[i][1] = conv2xchar(un); + valStr[i][2] = conv2xchar(ln); + valStr[i][3] = ' '; + valStr[i][4] = 0; + + if ( isprint(c) ) + { + ascii[i] = c; + } + else + { + ascii[i] = '.'; + } + + if ( valChg[i] ) + { + if ( !reset ) + { + for (int j=0; j<4; j++) + { + txtBuf->textCursor().deleteChar(); + } + } + txtBuf->insertPlainText( valStr[i] ); + } + else + { + txtBuf->textCursor().movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 4 ); + } + } + ascii[16] = 0; + + if ( reset ) + { + txtBuf->insertPlainText( ascii ); + } + + if ( reset ) + { + txtBuf->insertPlainText("\n"); + } + + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::updatePeriodic(void) +{ + printf("Update Periodic\n"); + + checkMemActivity(); + + showMemViewResults(false); +} +//---------------------------------------------------------------------------- +int HexEditorDialog_t::checkMemActivity(void) +{ + int c; + + // Don't perform memory activity checks when: + // 1. In ROM View Mode + // 2. The simulation is not cycling (paused) + + if ( ( mode == MODE_NES_ROM ) || + ( total_instructions_lp == total_instructions ) ) + { + return -1; + } + + for (int i=0; i 0 ) + { + mbuf[i].draw = 1; + mbuf[i].actv--; + } + } + } + total_instructions_lp = total_instructions; + + return 0; +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 8c71d51a..79e27659 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,15 @@ #include #include #include -#include +#include + +struct memByte_t +{ + unsigned char data; + unsigned char color; + unsigned char actv; + unsigned char draw; +}; class HexEditorDialog_t : public QDialog { @@ -23,16 +32,43 @@ class HexEditorDialog_t : public QDialog HexEditorDialog_t(QWidget *parent = 0); ~HexEditorDialog_t(void); + enum { + MODE_NES_RAM = 0, + MODE_NES_PPU, + MODE_NES_OAM, + MODE_NES_ROM + }; protected: void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); - QTextEdit *txt; + void initMem(void); + void setMode(int new_mode); + void showMemViewResults (bool reset); + int checkMemActivity(void); + int calcVisibleRange( int *start_out, int *end_out, int *center_out ); + + QFont font; + QPlainTextEdit *txtBuf; + QTimer *periodicTimer; + + int mode; + int numLines; + int numCharsPerLine; + int memSize; + int mbuf_size; + int (*memAccessFunc)( unsigned int offset); + struct memByte_t *mbuf; + + uint64_t total_instructions_lp; + + bool redraw; private: public slots: void closeWindow(void); private slots: + void updatePeriodic(void); }; From 4e7e82dbcddcb282e00423ccf3eb6d0fd7ff5f38 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 16 Aug 2020 21:24:27 -0400 Subject: [PATCH 04/37] Qt Hex Editor in work. --- src/drivers/Qt/HexEditor.cpp | 114 +++++++++++++++++++++++++++-------- src/drivers/Qt/HexEditor.h | 4 ++ 2 files changed, 93 insertions(+), 25 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 93c7a36f..275b53d6 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -103,9 +104,15 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) txtBuf->setFont( font ); txtBuf->moveCursor(QTextCursor::Start); - txtBuf->setReadOnly(true); + //txtBuf->setReadOnly(true); + txtBuf->setOverwriteMode(true); + txtBuf->setCenterOnScroll(false); txtBuf->setLineWrapMode( QPlainTextEdit::NoWrap ); + connect( txtBuf->verticalScrollBar(), SIGNAL(sliderMoved(int)), this, SLOT(vbarMoved(int)) ); + connect( txtBuf->verticalScrollBar(), SIGNAL(sliderPressed(void)), this, SLOT(vbarPressed(void)) ); + //connect( txtBuf->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(vbarMoved(int)) ); + mainLayout->addWidget( txtBuf ); setLayout( mainLayout ); @@ -173,7 +180,7 @@ int HexEditorDialog_t::calcVisibleRange( int *start_out, int *end_out, int *cent start_pos = 0; } - printf("Start: %i End: %i\n", start_pos, end_pos ); + //printf("Start: %i End: %i\n", start_pos, end_pos ); if ( start_out ) { @@ -211,12 +218,37 @@ void HexEditorDialog_t::initMem(void) } } //---------------------------------------------------------------------------- +void HexEditorDialog_t::vbarMoved( int pos ) +{ + printf("VBAR: %i \n", pos ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::vbarPressed( void ) +{ + printf("VBAR: %i \n", txtBuf->verticalScrollBar()->value() ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setCursor( int pos ) +{ + QTextCursor cursor = txtBuf->textCursor(); + cursor.setPosition( pos ); + txtBuf->setTextCursor( cursor ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::advCursor( int num ) +{ + QTextCursor cursor = txtBuf->textCursor(); + cursor.setPosition( cursor.position() + num ); + txtBuf->setTextCursor( cursor ); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::showMemViewResults (bool reset) { int i, row, row_start, row_end; int addr = 0, lineAddr = 0, c, un, ln; char addrStr[128], valStr[16][8], ascii[18]; - char valChg[16], activityColoringOn, colorEnable; + char valChg[16], asciiChg, activityColoringOn, colorEnable; + QTextCursor cursorSave; switch ( mode ) { @@ -290,40 +322,44 @@ void HexEditorDialog_t::showMemViewResults (bool reset) else { calcVisibleRange( &row_start, &row_end, NULL ); - - if ( row_start < 0 ) - { - row_start = 0; - } - if ( row_end > numLines ) - { - row_end = numLines; - } } + if ( row_start < 0 ) + { + row_start = 0; + } + if ( row_end > numLines ) + { + row_end = numLines; + } + cursorSave = txtBuf->textCursor(); + //printf("Cursor Start Position: %i\n", txtBuf->textCursor().position() ); for (row=row_start; rowtextCursor().position() ); + if ( !reset ) { - txtBuf->textCursor().setPosition( row * numCharsPerLine ); + setCursor( row * numCharsPerLine ); } + //printf("Post Cursor Line %i Position: %i\n", row, txtBuf->textCursor().position() ); + if ( reset ) { - //next_iter = iter; - //gtk_text_iter_forward_chars( &next_iter, 9 ); - sprintf( addrStr, "%08X ", lineAddr ); txtBuf->insertPlainText( addrStr ); } else { - txtBuf->textCursor().movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 9 ); + advCursor(9); } + asciiChg = reset; + for (i=0; i<16; i++) { valChg[i] = reset; @@ -336,6 +372,7 @@ void HexEditorDialog_t::showMemViewResults (bool reset) { mbuf[addr].draw = 0; valChg[i] = 1; + asciiChg = 1; } un = ( c & 0x00f0 ) >> 4; @@ -356,20 +393,24 @@ void HexEditorDialog_t::showMemViewResults (bool reset) ascii[i] = '.'; } - if ( valChg[i] ) + if ( reset ) { - if ( !reset ) + txtBuf->insertPlainText( valStr[i] ); + } + else + { + if ( valChg[i] ) { for (int j=0; j<4; j++) { txtBuf->textCursor().deleteChar(); } + txtBuf->insertPlainText( valStr[i] ); + } + else + { + advCursor(4); } - txtBuf->insertPlainText( valStr[i] ); - } - else - { - txtBuf->textCursor().movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 4 ); } } ascii[16] = 0; @@ -378,18 +419,41 @@ void HexEditorDialog_t::showMemViewResults (bool reset) { txtBuf->insertPlainText( ascii ); } + else + { + if ( asciiChg ) + { + for (int j=0; j<16; j++) + { + txtBuf->textCursor().deleteChar(); + } + txtBuf->insertPlainText( ascii ); + } + else + { + advCursor(16); + } + } if ( reset ) { txtBuf->insertPlainText("\n"); } + else + { + advCursor(1); + } } + + // Restore Cursor to Saved Location + txtBuf->setTextCursor( cursorSave ); + txtBuf->ensureCursorVisible(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::updatePeriodic(void) { - printf("Update Periodic\n"); + //printf("Update Periodic\n"); checkMemActivity(); diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 79e27659..8021f098 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -47,6 +47,8 @@ class HexEditorDialog_t : public QDialog void showMemViewResults (bool reset); int checkMemActivity(void); int calcVisibleRange( int *start_out, int *end_out, int *center_out ); + void setCursor( int pos ); + void advCursor( int num ); QFont font; QPlainTextEdit *txtBuf; @@ -70,5 +72,7 @@ class HexEditorDialog_t : public QDialog void closeWindow(void); private slots: void updatePeriodic(void); + void vbarMoved( int pos ); + void vbarPressed( void ); }; From d4d59b0c011c1ce97faebb43cb34cb8eb4bfb86d Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 17 Aug 2020 22:35:27 -0400 Subject: [PATCH 05/37] Trying out different QHexEdit function as QTextEdit was too inefficient. --- src/CMakeLists.txt | 2 + src/drivers/Qt/HexEditor.cpp | 269 ++------ src/drivers/Qt/HexEditor.h | 15 +- src/drivers/Qt/QHexEdit.cpp | 1154 ++++++++++++++++++++++++++++++++++ src/drivers/Qt/QHexEdit.h | 424 +++++++++++++ src/drivers/Qt/chunks.cpp | 323 ++++++++++ src/drivers/Qt/chunks.h | 77 +++ 7 files changed, 2029 insertions(+), 235 deletions(-) create mode 100644 src/drivers/Qt/QHexEdit.cpp create mode 100644 src/drivers/Qt/QHexEdit.h create mode 100644 src/drivers/Qt/chunks.cpp create mode 100644 src/drivers/Qt/chunks.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ef224bb..d8541fef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -432,6 +432,8 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/QHexEdit.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/chunks.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 275b53d6..bf1874cf 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -70,20 +70,20 @@ static int getROM( unsigned int offset) } return -1; } -static int conv2xchar( int i ) -{ - int c = 0; - - if ( (i >= 0) && (i < 10) ) - { - c = i + '0'; - } - else if ( i < 16 ) - { - c = (i - 10) + 'A'; - } - return c; -} +//static int conv2xchar( int i ) +//{ +// int c = 0; +// +// if ( (i >= 0) && (i < 10) ) +// { +// c = i + '0'; +// } +// else if ( i < 16 ) +// { +// c = (i - 10) + 'A'; +// } +// return c; +//} //---------------------------------------------------------------------------- HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent ) @@ -100,20 +100,9 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); - txtBuf = new QPlainTextEdit(); + editor = new QHexEdit(this); - txtBuf->setFont( font ); - txtBuf->moveCursor(QTextCursor::Start); - //txtBuf->setReadOnly(true); - txtBuf->setOverwriteMode(true); - txtBuf->setCenterOnScroll(false); - txtBuf->setLineWrapMode( QPlainTextEdit::NoWrap ); - - connect( txtBuf->verticalScrollBar(), SIGNAL(sliderMoved(int)), this, SLOT(vbarMoved(int)) ); - connect( txtBuf->verticalScrollBar(), SIGNAL(sliderPressed(void)), this, SLOT(vbarPressed(void)) ); - //connect( txtBuf->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(vbarMoved(int)) ); - - mainLayout->addWidget( txtBuf ); + mainLayout->addWidget( editor ); setLayout( mainLayout ); @@ -127,6 +116,28 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) redraw = false; total_instructions_lp = 0; + dataArray = new QByteArray( 0x20000, '0' ); + dataBuffer = new QBuffer( dataArray, this ); + dataBuffer->setBuffer( dataArray ); + + printf("DataArray: Size: %i \n", dataArray->size() ); + editor->setData( *dataBuffer ); + + editor->setAddressArea(true); + editor->setAsciiArea(true); + editor->setHighlighting(true); + editor->setOverwriteMode(true); + editor->setReadOnly(true); + editor->setHexCaps(true); + + editor->setHighlightingColor( QColor("yellow") ); + editor->setAddressAreaColor( QColor("white") ); + editor->setSelectionColor( QColor("blue") ); + //editor->setFont( font ); + + editor->setAddressWidth(6); + editor->setBytesPerLine(16); + showMemViewResults(true); periodicTimer = new QTimer( this ); @@ -164,39 +175,6 @@ void HexEditorDialog_t::keyReleaseEvent(QKeyEvent *event) //assignHotkey( event ); } //---------------------------------------------------------------------------- -int HexEditorDialog_t::calcVisibleRange( int *start_out, int *end_out, int *center_out ) -{ - int start_pos, end_pos; - QPoint bottom_left( 0, txtBuf->viewport()->height() - 1); - - start_pos = txtBuf->cursorForPosition(QPoint(0, 0)).position(); - end_pos = txtBuf->cursorForPosition(bottom_left).position(); - - start_pos = (start_pos / numCharsPerLine) - 1; - end_pos = (end_pos / numCharsPerLine) + 1; - - if ( start_pos < 0 ) - { - start_pos = 0; - } - - //printf("Start: %i End: %i\n", start_pos, end_pos ); - - if ( start_out ) - { - *start_out = start_pos; - } - if ( end_out ) - { - *end_out = end_pos; - } - if ( center_out ) - { - *center_out = (start_pos + end_pos) / 2; - } - return 0; -} -//---------------------------------------------------------------------------- void HexEditorDialog_t::setMode(int new_mode) { if ( mode != new_mode ) @@ -218,38 +196,8 @@ void HexEditorDialog_t::initMem(void) } } //---------------------------------------------------------------------------- -void HexEditorDialog_t::vbarMoved( int pos ) -{ - printf("VBAR: %i \n", pos ); -} -//---------------------------------------------------------------------------- -void HexEditorDialog_t::vbarPressed( void ) -{ - printf("VBAR: %i \n", txtBuf->verticalScrollBar()->value() ); -} -//---------------------------------------------------------------------------- -void HexEditorDialog_t::setCursor( int pos ) -{ - QTextCursor cursor = txtBuf->textCursor(); - cursor.setPosition( pos ); - txtBuf->setTextCursor( cursor ); -} -//---------------------------------------------------------------------------- -void HexEditorDialog_t::advCursor( int num ) -{ - QTextCursor cursor = txtBuf->textCursor(); - cursor.setPosition( cursor.position() + num ); - txtBuf->setTextCursor( cursor ); -} -//---------------------------------------------------------------------------- void HexEditorDialog_t::showMemViewResults (bool reset) { - int i, row, row_start, row_end; - int addr = 0, lineAddr = 0, c, un, ln; - char addrStr[128], valStr[16][8], ascii[18]; - char valChg[16], asciiChg, activityColoringOn, colorEnable; - QTextCursor cursorSave; - switch ( mode ) { default: @@ -282,7 +230,7 @@ void HexEditorDialog_t::showMemViewResults (bool reset) } mbuf_size = 0; redraw = true; - txtBuf->setPlainText("No ROM Loaded"); + //txtBuf->setPlainText("No ROM Loaded"); return; } break; @@ -294,6 +242,8 @@ void HexEditorDialog_t::showMemViewResults (bool reset) printf("Mode: %i MemSize:%i 0x%08x\n", mode, memSize, (unsigned int)memSize ); reset = 1; + dataArray->resize( mbuf_size ); + if ( mbuf ) { free(mbuf); mbuf = NULL; @@ -312,143 +262,6 @@ void HexEditorDialog_t::showMemViewResults (bool reset) return; } } - - if ( reset ) - { - txtBuf->clear(); - row_start = 0; - row_end = numLines; - } - else - { - calcVisibleRange( &row_start, &row_end, NULL ); - } - if ( row_start < 0 ) - { - row_start = 0; - } - if ( row_end > numLines ) - { - row_end = numLines; - } - cursorSave = txtBuf->textCursor(); - //printf("Cursor Start Position: %i\n", txtBuf->textCursor().position() ); - - for (row=row_start; rowtextCursor().position() ); - - if ( !reset ) - { - setCursor( row * numCharsPerLine ); - } - - //printf("Post Cursor Line %i Position: %i\n", row, txtBuf->textCursor().position() ); - - if ( reset ) - { - sprintf( addrStr, "%08X ", lineAddr ); - - txtBuf->insertPlainText( addrStr ); - } - else - { - advCursor(9); - } - - asciiChg = reset; - - for (i=0; i<16; i++) - { - valChg[i] = reset; - - addr = lineAddr+i; - - c = memAccessFunc(addr); - - if ( mbuf[addr].draw ) - { - mbuf[addr].draw = 0; - valChg[i] = 1; - asciiChg = 1; - } - - un = ( c & 0x00f0 ) >> 4; - ln = ( c & 0x000f ); - - valStr[i][0] = ' '; - valStr[i][1] = conv2xchar(un); - valStr[i][2] = conv2xchar(ln); - valStr[i][3] = ' '; - valStr[i][4] = 0; - - if ( isprint(c) ) - { - ascii[i] = c; - } - else - { - ascii[i] = '.'; - } - - if ( reset ) - { - txtBuf->insertPlainText( valStr[i] ); - } - else - { - if ( valChg[i] ) - { - for (int j=0; j<4; j++) - { - txtBuf->textCursor().deleteChar(); - } - txtBuf->insertPlainText( valStr[i] ); - } - else - { - advCursor(4); - } - } - } - ascii[16] = 0; - - if ( reset ) - { - txtBuf->insertPlainText( ascii ); - } - else - { - if ( asciiChg ) - { - for (int j=0; j<16; j++) - { - txtBuf->textCursor().deleteChar(); - } - txtBuf->insertPlainText( ascii ); - } - else - { - advCursor(16); - } - } - - if ( reset ) - { - txtBuf->insertPlainText("\n"); - } - else - { - advCursor(1); - } - - } - - // Restore Cursor to Saved Location - txtBuf->setTextCursor( cursorSave ); - txtBuf->ensureCursorVisible(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::updatePeriodic(void) diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 8021f098..ac7a0b08 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -14,7 +14,10 @@ #include #include #include -#include +#include +#include + +#include "Qt/QHexEdit.h" struct memByte_t { @@ -47,12 +50,12 @@ class HexEditorDialog_t : public QDialog void showMemViewResults (bool reset); int checkMemActivity(void); int calcVisibleRange( int *start_out, int *end_out, int *center_out ); - void setCursor( int pos ); - void advCursor( int num ); - QFont font; - QPlainTextEdit *txtBuf; + QFont font; + QHexEdit *editor; QTimer *periodicTimer; + QByteArray *dataArray; + QBuffer *dataBuffer; int mode; int numLines; @@ -72,7 +75,5 @@ class HexEditorDialog_t : public QDialog void closeWindow(void); private slots: void updatePeriodic(void); - void vbarMoved( int pos ); - void vbarPressed( void ); }; diff --git a/src/drivers/Qt/QHexEdit.cpp b/src/drivers/Qt/QHexEdit.cpp new file mode 100644 index 00000000..81c75a41 --- /dev/null +++ b/src/drivers/Qt/QHexEdit.cpp @@ -0,0 +1,1154 @@ +#include +#include +#include +#include +#include + +#include + +#include "Qt/QHexEdit.h" + + +// ********************************************************************** Constructor, destructor + +QHexEdit::QHexEdit(QWidget *parent) : QAbstractScrollArea(parent) +{ + _addressArea = true; + _addressWidth = 4; + _asciiArea = true; + _overwriteMode = true; + _highlighting = true; + _readOnly = false; + _cursorPosition = 0; + _lastEventSize = 0; + _hexCharsInLine = 47; + _bytesPerLine = 16; + _editAreaIsAscii = false; + _hexCaps = false; + _dynamicBytesPerLine = false; + + _chunks = new Chunks(this); + //_undoStack = new UndoStack(_chunks, this); +#ifdef Q_OS_WIN32 + setFont(QFont("Courier", 10)); +#else + setFont(QFont("Monospace", 10)); +#endif + setAddressAreaColor(this->palette().alternateBase().color()); + setHighlightingColor(QColor(0xff, 0xff, 0x99, 0xff)); + setSelectionColor(this->palette().highlight().color()); + + connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor())); + connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); + connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); + //connect(_undoStack, SIGNAL(indexChanged(int)), this, SLOT(dataChangedPrivate(int))); + + _cursorTimer.setInterval(500); + _cursorTimer.start(); + + setAddressWidth(4); + setAddressArea(true); + setAsciiArea(true); + setOverwriteMode(true); + setHighlighting(true); + setReadOnly(false); + + init(); + +} + +QHexEdit::~QHexEdit() +{ +} + +// ********************************************************************** Properties + +void QHexEdit::setAddressArea(bool addressArea) +{ + _addressArea = addressArea; + adjust(); + setCursorPosition(_cursorPosition); + viewport()->update(); +} + +bool QHexEdit::addressArea() +{ + return _addressArea; +} + +void QHexEdit::setAddressAreaColor(const QColor &color) +{ + _addressAreaColor = color; + viewport()->update(); +} + +QColor QHexEdit::addressAreaColor() +{ + return _addressAreaColor; +} + +void QHexEdit::setAddressOffset(qint64 addressOffset) +{ + _addressOffset = addressOffset; + adjust(); + setCursorPosition(_cursorPosition); + viewport()->update(); +} + +qint64 QHexEdit::addressOffset() +{ + return _addressOffset; +} + +void QHexEdit::setAddressWidth(int addressWidth) +{ + _addressWidth = addressWidth; + adjust(); + setCursorPosition(_cursorPosition); + viewport()->update(); +} + +int QHexEdit::addressWidth() +{ + qint64 size = _chunks->size(); + int n = 1; + if (size > Q_INT64_C(0x100000000)){ n += 8; size /= Q_INT64_C(0x100000000);} + if (size > 0x10000){ n += 4; size /= 0x10000;} + if (size > 0x100){ n += 2; size /= 0x100;} + if (size > 0x10){ n += 1;} + + if (n > _addressWidth) + return n; + else + return _addressWidth; +} + +void QHexEdit::setAsciiArea(bool asciiArea) +{ + if (!asciiArea) + _editAreaIsAscii = false; + _asciiArea = asciiArea; + adjust(); + setCursorPosition(_cursorPosition); + viewport()->update(); +} + +bool QHexEdit::asciiArea() +{ + return _asciiArea; +} + +void QHexEdit::setBytesPerLine(int count) +{ + _bytesPerLine = count; + _hexCharsInLine = count * 3 - 1; + + adjust(); + setCursorPosition(_cursorPosition); + viewport()->update(); +} + +int QHexEdit::bytesPerLine() +{ + return _bytesPerLine; +} + +void QHexEdit::setCursorPosition(qint64 position) +{ + // 1. delete old cursor + _blink = false; + viewport()->update(_cursorRect); + + // 2. Check, if cursor in range? + if (position > (_chunks->size() * 2 - 1)) + position = _chunks->size() * 2 - (_overwriteMode ? 1 : 0); + + if (position < 0) + position = 0; + + // 3. Calc new position of cursor + _bPosCurrent = position / 2; + _pxCursorY = ((position / 2 - _bPosFirst) / _bytesPerLine + 1) * _pxCharHeight; + int x = (position % (2 * _bytesPerLine)); + if (_editAreaIsAscii) + { + _pxCursorX = x / 2 * _pxCharWidth + _pxPosAsciiX; + _cursorPosition = position & 0xFFFFFFFFFFFFFFFE; + } else { + _pxCursorX = (((x / 2) * 3) + (x % 2)) * _pxCharWidth + _pxPosHexX; + _cursorPosition = position; + } + + if (_overwriteMode) + _cursorRect = QRect(_pxCursorX - horizontalScrollBar()->value(), _pxCursorY + _pxCursorWidth, _pxCharWidth, _pxCursorWidth); + else + _cursorRect = QRect(_pxCursorX - horizontalScrollBar()->value(), _pxCursorY - _pxCharHeight + 4, _pxCursorWidth, _pxCharHeight); + + // 4. Immediately draw new cursor + _blink = true; + viewport()->update(_cursorRect); + emit currentAddressChanged(_bPosCurrent); +} + +qint64 QHexEdit::cursorPosition(QPoint pos) +{ + // Calc cursor position depending on a graphical position + qint64 result = -1; + int posX = pos.x() + horizontalScrollBar()->value(); + int posY = pos.y() - 3; + if ((posX >= _pxPosHexX) && (posX < (_pxPosHexX + (1 + _hexCharsInLine) * _pxCharWidth))) + { + _editAreaIsAscii = false; + int x = (posX - _pxPosHexX) / _pxCharWidth; + x = (x / 3) * 2 + x % 3; + int y = (posY / _pxCharHeight) * 2 * _bytesPerLine; + result = _bPosFirst * 2 + x + y; + } + else + if (_asciiArea && (posX >= _pxPosAsciiX) && (posX < (_pxPosAsciiX + (1 + _bytesPerLine) * _pxCharWidth))) + { + _editAreaIsAscii = true; + int x = 2 * (posX - _pxPosAsciiX) / _pxCharWidth; + int y = (posY / _pxCharHeight) * 2 * _bytesPerLine; + result = _bPosFirst * 2 + x + y; + } + return result; +} + +qint64 QHexEdit::cursorPosition() +{ + return _cursorPosition; +} + +void QHexEdit::setData(const QByteArray &ba) +{ + _data = ba; + _bData.setData(_data); + setData(_bData); +} + +QByteArray QHexEdit::data() +{ + return _chunks->data(0, -1); +} + +void QHexEdit::setHighlighting(bool highlighting) +{ + _highlighting = highlighting; + viewport()->update(); +} + +bool QHexEdit::highlighting() +{ + return _highlighting; +} + +void QHexEdit::setHighlightingColor(const QColor &color) +{ + _brushHighlighted = QBrush(color); + _penHighlighted = QPen(viewport()->palette().color(QPalette::WindowText)); + viewport()->update(); +} + +QColor QHexEdit::highlightingColor() +{ + return _brushHighlighted.color(); +} + +void QHexEdit::setOverwriteMode(bool overwriteMode) +{ + _overwriteMode = overwriteMode; + emit overwriteModeChanged(overwriteMode); +} + +bool QHexEdit::overwriteMode() +{ + return _overwriteMode; +} + +void QHexEdit::setSelectionColor(const QColor &color) +{ + _brushSelection = QBrush(color); + _penSelection = QPen(Qt::white); + viewport()->update(); +} + +QColor QHexEdit::selectionColor() +{ + return _brushSelection.color(); +} + +bool QHexEdit::isReadOnly() +{ + return _readOnly; +} + +void QHexEdit::setReadOnly(bool readOnly) +{ + _readOnly = readOnly; +} + +void QHexEdit::setHexCaps(const bool isCaps) +{ + if (_hexCaps != isCaps) + { + _hexCaps = isCaps; + viewport()->update(); + } +} + +bool QHexEdit::hexCaps() +{ + return _hexCaps; +} + +void QHexEdit::setDynamicBytesPerLine(const bool isDynamic) +{ + _dynamicBytesPerLine = isDynamic; + resizeEvent(NULL); +} + +bool QHexEdit::dynamicBytesPerLine() +{ + return _dynamicBytesPerLine; +} + +// ********************************************************************** Access to data of qhexedit +bool QHexEdit::setData(QIODevice &iODevice) +{ + bool ok = _chunks->setIODevice(iODevice); + init(); + dataChangedPrivate(); + return ok; +} + +QByteArray QHexEdit::dataAt(qint64 pos, qint64 count) +{ + return _chunks->data(pos, count); +} + +bool QHexEdit::write(QIODevice &iODevice, qint64 pos, qint64 count) +{ + return _chunks->write(iODevice, pos, count); +} + +// ********************************************************************** Char handling +void QHexEdit::insert(qint64 index, char ch) +{ + //_undoStack->insert(index, ch); + refresh(); +} + +void QHexEdit::remove(qint64 index, qint64 len) +{ + //_undoStack->removeAt(index, len); + refresh(); +} + +void QHexEdit::replace(qint64 index, char ch) +{ + //_undoStack->overwrite(index, ch); + refresh(); +} + +// ********************************************************************** ByteArray handling +void QHexEdit::insert(qint64 pos, const QByteArray &ba) +{ + //_undoStack->insert(pos, ba); + refresh(); +} + +void QHexEdit::replace(qint64 pos, qint64 len, const QByteArray &ba) +{ + //_undoStack->overwrite(pos, len, ba); + refresh(); +} + +// ********************************************************************** Utility functions +void QHexEdit::ensureVisible() +{ + if (_cursorPosition < (_bPosFirst * 2)) + verticalScrollBar()->setValue((int)(_cursorPosition / 2 / _bytesPerLine)); + if (_cursorPosition > ((_bPosFirst + (_rowsShown - 1)*_bytesPerLine) * 2)) + verticalScrollBar()->setValue((int)(_cursorPosition / 2 / _bytesPerLine) - _rowsShown + 1); + if (_pxCursorX < horizontalScrollBar()->value()) + horizontalScrollBar()->setValue(_pxCursorX); + if ((_pxCursorX + _pxCharWidth) > (horizontalScrollBar()->value() + viewport()->width())) + horizontalScrollBar()->setValue(_pxCursorX + _pxCharWidth - viewport()->width()); + viewport()->update(); +} + +qint64 QHexEdit::indexOf(const QByteArray &ba, qint64 from) +{ + qint64 pos = _chunks->indexOf(ba, from); + if (pos > -1) + { + qint64 curPos = pos*2; + setCursorPosition(curPos + ba.length()*2); + resetSelection(curPos); + setSelection(curPos + ba.length()*2); + ensureVisible(); + } + return pos; +} + +bool QHexEdit::isModified() +{ + return _modified; +} + +qint64 QHexEdit::lastIndexOf(const QByteArray &ba, qint64 from) +{ + qint64 pos = _chunks->lastIndexOf(ba, from); + if (pos > -1) + { + qint64 curPos = pos*2; + setCursorPosition(curPos - 1); + resetSelection(curPos); + setSelection(curPos + ba.length()*2); + ensureVisible(); + } + return pos; +} + +void QHexEdit::redo() +{ + //_undoStack->redo(); + setCursorPosition(_chunks->pos()*(_editAreaIsAscii ? 1 : 2)); + refresh(); +} + +QString QHexEdit::selectionToReadableString() +{ + QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); + return toReadable(ba); +} + +QString QHexEdit::selectedData() +{ + QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); + return ba; +} + +void QHexEdit::setFont(const QFont &font) +{ + QFont theFont(font); + theFont.setStyleHint(QFont::Monospace); + QWidget::setFont(theFont); + QFontMetrics metrics = fontMetrics(); +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + _pxCharWidth = metrics.horizontalAdvance(QLatin1Char('2')); +#else + _pxCharWidth = metrics.width(QLatin1Char('2')); +#endif + _pxCharHeight = metrics.height(); + _pxGapAdr = _pxCharWidth / 2; + _pxGapAdrHex = _pxCharWidth; + _pxGapHexAscii = 2 * _pxCharWidth; + _pxCursorWidth = _pxCharHeight / 7; + _pxSelectionSub = _pxCharHeight / 5; + viewport()->update(); +} + +QString QHexEdit::toReadableString() +{ + QByteArray ba = _chunks->data(); + return toReadable(ba); +} + +void QHexEdit::undo() +{ + //_undoStack->undo(); + setCursorPosition(_chunks->pos()*(_editAreaIsAscii ? 1 : 2)); + refresh(); +} + +// ********************************************************************** Handle events +void QHexEdit::keyPressEvent(QKeyEvent *event) +{ + // Cursor movements + if (event->matches(QKeySequence::MoveToNextChar)) + { + qint64 pos = _cursorPosition + 1; + if (_editAreaIsAscii) + pos += 1; + setCursorPosition(pos); + resetSelection(pos); + } + if (event->matches(QKeySequence::MoveToPreviousChar)) + { + qint64 pos = _cursorPosition - 1; + if (_editAreaIsAscii) + pos -= 1; + setCursorPosition(pos); + resetSelection(pos); + } + if (event->matches(QKeySequence::MoveToEndOfLine)) + { + qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)) + (2 * _bytesPerLine) - 1; + setCursorPosition(pos); + resetSelection(_cursorPosition); + } + if (event->matches(QKeySequence::MoveToStartOfLine)) + { + qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)); + setCursorPosition(pos); + resetSelection(_cursorPosition); + } + if (event->matches(QKeySequence::MoveToPreviousLine)) + { + setCursorPosition(_cursorPosition - (2 * _bytesPerLine)); + resetSelection(_cursorPosition); + } + if (event->matches(QKeySequence::MoveToNextLine)) + { + setCursorPosition(_cursorPosition + (2 * _bytesPerLine)); + resetSelection(_cursorPosition); + } + if (event->matches(QKeySequence::MoveToNextPage)) + { + setCursorPosition(_cursorPosition + (((_rowsShown - 1) * 2 * _bytesPerLine))); + resetSelection(_cursorPosition); + } + if (event->matches(QKeySequence::MoveToPreviousPage)) + { + setCursorPosition(_cursorPosition - (((_rowsShown - 1) * 2 * _bytesPerLine))); + resetSelection(_cursorPosition); + } + if (event->matches(QKeySequence::MoveToEndOfDocument)) + { + setCursorPosition(_chunks->size() * 2 ); + resetSelection(_cursorPosition); + } + if (event->matches(QKeySequence::MoveToStartOfDocument)) + { + setCursorPosition(0); + resetSelection(_cursorPosition); + } + + // Select commands + if (event->matches(QKeySequence::SelectAll)) + { + resetSelection(0); + setSelection(2 * _chunks->size() + 1); + } + if (event->matches(QKeySequence::SelectNextChar)) + { + qint64 pos = _cursorPosition + 1; + if (_editAreaIsAscii) + pos += 1; + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectPreviousChar)) + { + qint64 pos = _cursorPosition - 1; + if (_editAreaIsAscii) + pos -= 1; + setSelection(pos); + setCursorPosition(pos); + } + if (event->matches(QKeySequence::SelectEndOfLine)) + { + qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)) + (2 * _bytesPerLine) - 1; + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectStartOfLine)) + { + qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)); + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectPreviousLine)) + { + qint64 pos = _cursorPosition - (2 * _bytesPerLine); + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectNextLine)) + { + qint64 pos = _cursorPosition + (2 * _bytesPerLine); + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectNextPage)) + { + qint64 pos = _cursorPosition + (((viewport()->height() / _pxCharHeight) - 1) * 2 * _bytesPerLine); + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectPreviousPage)) + { + qint64 pos = _cursorPosition - (((viewport()->height() / _pxCharHeight) - 1) * 2 * _bytesPerLine); + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectEndOfDocument)) + { + qint64 pos = _chunks->size() * 2; + setCursorPosition(pos); + setSelection(pos); + } + if (event->matches(QKeySequence::SelectStartOfDocument)) + { + qint64 pos = 0; + setCursorPosition(pos); + setSelection(pos); + } + + // Edit Commands + if (!_readOnly) + { + /* Cut */ + if (event->matches(QKeySequence::Cut)) + { + QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); + for (qint64 idx = 32; idx < ba.size(); idx +=33) + ba.insert(idx, "\n"); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(ba); + if (_overwriteMode) + { + qint64 len = getSelectionEnd() - getSelectionBegin(); + replace(getSelectionBegin(), (int)len, QByteArray((int)len, char(0))); + } + else + { + remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); + } + setCursorPosition(2 * getSelectionBegin()); + resetSelection(2 * getSelectionBegin()); + } else + + /* Paste */ + if (event->matches(QKeySequence::Paste)) + { + QClipboard *clipboard = QApplication::clipboard(); + QByteArray ba = QByteArray().fromHex(clipboard->text().toLatin1()); + if (_overwriteMode) + { + ba = ba.left(std::min(ba.size(), (_chunks->size() - _bPosCurrent))); + replace(_bPosCurrent, ba.size(), ba); + } + else + insert(_bPosCurrent, ba); + setCursorPosition(_cursorPosition + 2 * ba.size()); + resetSelection(getSelectionBegin()); + } else + + /* Delete char */ + if (event->matches(QKeySequence::Delete)) + { + if (getSelectionBegin() != getSelectionEnd()) + { + _bPosCurrent = getSelectionBegin(); + if (_overwriteMode) + { + QByteArray ba = QByteArray(getSelectionEnd() - getSelectionBegin(), char(0)); + replace(_bPosCurrent, ba.size(), ba); + } + else + { + remove(_bPosCurrent, getSelectionEnd() - getSelectionBegin()); + } + } + else + { + if (_overwriteMode) + replace(_bPosCurrent, char(0)); + else + remove(_bPosCurrent, 1); + } + setCursorPosition(2 * _bPosCurrent); + resetSelection(2 * _bPosCurrent); + } else + + /* Backspace */ + if ((event->key() == Qt::Key_Backspace) && (event->modifiers() == Qt::NoModifier)) + { + if (getSelectionBegin() != getSelectionEnd()) + { + _bPosCurrent = getSelectionBegin(); + setCursorPosition(2 * _bPosCurrent); + if (_overwriteMode) + { + QByteArray ba = QByteArray(getSelectionEnd() - getSelectionBegin(), char(0)); + replace(_bPosCurrent, ba.size(), ba); + } + else + { + remove(_bPosCurrent, getSelectionEnd() - getSelectionBegin()); + } + resetSelection(2 * _bPosCurrent); + } + else + { + bool behindLastByte = false; + if ((_cursorPosition / 2) == _chunks->size()) + behindLastByte = true; + + _bPosCurrent -= 1; + if (_overwriteMode) + replace(_bPosCurrent, char(0)); + else + remove(_bPosCurrent, 1); + + if (!behindLastByte) + _bPosCurrent -= 1; + + setCursorPosition(2 * _bPosCurrent); + resetSelection(2 * _bPosCurrent); + } + } else + + /* undo */ + if (event->matches(QKeySequence::Undo)) + { + undo(); + } else + + /* redo */ + if (event->matches(QKeySequence::Redo)) + { + redo(); + } else + + if ((QApplication::keyboardModifiers() == Qt::NoModifier) || + (QApplication::keyboardModifiers() == Qt::KeypadModifier) || + (QApplication::keyboardModifiers() == Qt::ShiftModifier) || + (QApplication::keyboardModifiers() == (Qt::AltModifier | Qt::ControlModifier)) || + (QApplication::keyboardModifiers() == Qt::GroupSwitchModifier)) + { + /* Hex and ascii input */ + int key; + if (_editAreaIsAscii) + key = (uchar)event->text()[0].toLatin1(); + else + key = int(event->text()[0].toLower().toLatin1()); + + if ((((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f')) && _editAreaIsAscii == false) + || (key >= ' ' && _editAreaIsAscii)) + { + if (getSelectionBegin() != getSelectionEnd()) + { + if (_overwriteMode) + { + qint64 len = getSelectionEnd() - getSelectionBegin(); + replace(getSelectionBegin(), (int)len, QByteArray((int)len, char(0))); + } else + { + remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); + _bPosCurrent = getSelectionBegin(); + } + setCursorPosition(2 * _bPosCurrent); + resetSelection(2 * _bPosCurrent); + } + + // If insert mode, then insert a byte + if (_overwriteMode == false) + if ((_cursorPosition % 2) == 0) + insert(_bPosCurrent, char(0)); + + // Change content + if (_chunks->size() > 0) + { + char ch = key; + if (!_editAreaIsAscii){ + QByteArray hexValue = _chunks->data(_bPosCurrent, 1).toHex(); + if ((_cursorPosition % 2) == 0) + hexValue[0] = key; + else + hexValue[1] = key; + ch = QByteArray().fromHex(hexValue)[0]; + } + replace(_bPosCurrent, ch); + if (_editAreaIsAscii) + setCursorPosition(_cursorPosition + 2); + else + setCursorPosition(_cursorPosition + 1); + resetSelection(_cursorPosition); + } + } + } + + + } + + /* Copy */ + if (event->matches(QKeySequence::Copy)) + { + QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); + for (qint64 idx = 32; idx < ba.size(); idx +=33) + ba.insert(idx, "\n"); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(ba); + } + + // Switch between insert/overwrite mode + if ((event->key() == Qt::Key_Insert) && (event->modifiers() == Qt::NoModifier)) + { + setOverwriteMode(!overwriteMode()); + setCursorPosition(_cursorPosition); + } + + // switch from hex to ascii edit + if (event->key() == Qt::Key_Tab && !_editAreaIsAscii){ + _editAreaIsAscii = true; + setCursorPosition(_cursorPosition); + } + + // switch from ascii to hex edit + if (event->key() == Qt::Key_Backtab && _editAreaIsAscii){ + _editAreaIsAscii = false; + setCursorPosition(_cursorPosition); + } + + refresh(); + QAbstractScrollArea::keyPressEvent(event); +} + +void QHexEdit::mouseMoveEvent(QMouseEvent * event) +{ + _blink = false; + viewport()->update(); + qint64 actPos = cursorPosition(event->pos()); + if (actPos >= 0) + { + setCursorPosition(actPos); + setSelection(actPos); + } +} + +void QHexEdit::mousePressEvent(QMouseEvent * event) +{ + _blink = false; + viewport()->update(); + qint64 cPos = cursorPosition(event->pos()); + if (cPos >= 0) + { + if (event->button() != Qt::RightButton) + resetSelection(cPos); + setCursorPosition(cPos); + } +} + +void QHexEdit::paintEvent(QPaintEvent *event) +{ + QPainter painter(viewport()); + int pxOfsX = horizontalScrollBar()->value(); + + if (event->rect() != _cursorRect) + { + int pxPosStartY = _pxCharHeight; + + // draw some patterns if needed + painter.fillRect(event->rect(), viewport()->palette().color(QPalette::Base)); + if (_addressArea) + painter.fillRect(QRect(-pxOfsX, event->rect().top(), _pxPosHexX - _pxGapAdrHex/2, height()), _addressAreaColor); + if (_asciiArea) + { + int linePos = _pxPosAsciiX - (_pxGapHexAscii / 2); + painter.setPen(Qt::gray); + painter.drawLine(linePos - pxOfsX, event->rect().top(), linePos - pxOfsX, height()); + } + + painter.setPen(viewport()->palette().color(QPalette::WindowText)); + + // paint address area + if (_addressArea) + { + QString address; + for (int row=0, pxPosY = _pxCharHeight; row <= (_dataShown.size()/_bytesPerLine); row++, pxPosY +=_pxCharHeight) + { + address = QString("%1").arg(_bPosFirst + row*_bytesPerLine + _addressOffset, _addrDigits, 16, QChar('0')); + painter.drawText(_pxPosAdrX - pxOfsX, pxPosY, hexCaps() ? address.toUpper() : address); + } + } + + // paint hex and ascii area + QPen colStandard = QPen(viewport()->palette().color(QPalette::WindowText)); + + painter.setBackgroundMode(Qt::TransparentMode); + + for (int row = 0, pxPosY = pxPosStartY; row <= _rowsShown; row++, pxPosY +=_pxCharHeight) + { + QByteArray hex; + int pxPosX = _pxPosHexX - pxOfsX; + int pxPosAsciiX2 = _pxPosAsciiX - pxOfsX; + qint64 bPosLine = row * _bytesPerLine; + for (int colIdx = 0; ((bPosLine + colIdx) < _dataShown.size() && (colIdx < _bytesPerLine)); colIdx++) + { + QColor c = viewport()->palette().color(QPalette::Base); + painter.setPen(colStandard); + + qint64 posBa = _bPosFirst + bPosLine + colIdx; + if ((getSelectionBegin() <= posBa) && (getSelectionEnd() > posBa)) + { + c = _brushSelection.color(); + painter.setPen(_penSelection); + } + else + { + if (_highlighting) + if (_markedShown.at((int)(posBa - _bPosFirst))) + { + c = _brushHighlighted.color(); + painter.setPen(_penHighlighted); + } + } + + // render hex value + QRect r; + if (colIdx == 0) + r.setRect(pxPosX, pxPosY - _pxCharHeight + _pxSelectionSub, 2*_pxCharWidth, _pxCharHeight); + else + r.setRect(pxPosX - _pxCharWidth, pxPosY - _pxCharHeight + _pxSelectionSub, 3*_pxCharWidth, _pxCharHeight); + painter.fillRect(r, c); + hex = _hexDataShown.mid((bPosLine + colIdx) * 2, 2); + painter.drawText(pxPosX, pxPosY, hexCaps()?hex.toUpper():hex); + pxPosX += 3*_pxCharWidth; + + // render ascii value + if (_asciiArea) + { + int ch = (uchar)_dataShown.at(bPosLine + colIdx); + if ( ch < ' ' || ch > '~' ) + ch = '.'; + r.setRect(pxPosAsciiX2, pxPosY - _pxCharHeight + _pxSelectionSub, _pxCharWidth, _pxCharHeight); + painter.fillRect(r, c); + painter.drawText(pxPosAsciiX2, pxPosY, QChar(ch)); + pxPosAsciiX2 += _pxCharWidth; + } + } + } + painter.setBackgroundMode(Qt::TransparentMode); + painter.setPen(viewport()->palette().color(QPalette::WindowText)); + } + + // _cursorPosition counts in 2, _bPosFirst counts in 1 + int hexPositionInShowData = _cursorPosition - 2 * _bPosFirst; + + // due to scrolling the cursor can go out of the currently displayed data + if ((hexPositionInShowData >= 0) && (hexPositionInShowData < _hexDataShown.size())) + { + // paint cursor + if (_readOnly) + { + // make the background stick out + QColor color = viewport()->palette().dark().color(); + painter.fillRect(QRect(_pxCursorX - pxOfsX, _pxCursorY - _pxCharHeight + _pxSelectionSub, _pxCharWidth, _pxCharHeight), color); + } + else + { + if (_blink && hasFocus()) + painter.fillRect(_cursorRect, this->palette().color(QPalette::WindowText)); + } + + if (_editAreaIsAscii) + { + // every 2 hex there is 1 ascii + int asciiPositionInShowData = hexPositionInShowData / 2; + int ch = (uchar)_dataShown.at(asciiPositionInShowData); + if (ch < ' ' || ch > '~') + ch = '.'; + painter.drawText(_pxCursorX - pxOfsX, _pxCursorY, QChar(ch)); + } + else + { + painter.drawText(_pxCursorX - pxOfsX, _pxCursorY, hexCaps() ? _hexDataShown.mid(hexPositionInShowData, 1).toUpper() : _hexDataShown.mid(hexPositionInShowData, 1)); + } + } + + // emit event, if size has changed + if (_lastEventSize != _chunks->size()) + { + _lastEventSize = _chunks->size(); + emit currentSizeChanged(_lastEventSize); + } +} + +void QHexEdit::resizeEvent(QResizeEvent *) +{ + if (_dynamicBytesPerLine) + { + int pxFixGaps = 0; + if (_addressArea) + pxFixGaps = addressWidth() * _pxCharWidth + _pxGapAdr; + pxFixGaps += _pxGapAdrHex; + if (_asciiArea) + pxFixGaps += _pxGapHexAscii; + + // +1 because the last hex value do not have space. so it is effective one char more + int charWidth = (viewport()->width() - pxFixGaps ) / _pxCharWidth + 1; + + // 2 hex alfa-digits 1 space 1 ascii per byte = 4; if ascii is disabled then 3 + // to prevent devision by zero use the min value 1 + setBytesPerLine(std::max(charWidth / (_asciiArea ? 4 : 3),1)); + } + adjust(); +} + +bool QHexEdit::focusNextPrevChild(bool next) +{ + if (_addressArea) + { + if ( (next && _editAreaIsAscii) || (!next && !_editAreaIsAscii )) + return QWidget::focusNextPrevChild(next); + else + return false; + } + else + { + return QWidget::focusNextPrevChild(next); + } +} + +// ********************************************************************** Handle selections +void QHexEdit::resetSelection() +{ + _bSelectionBegin = _bSelectionInit; + _bSelectionEnd = _bSelectionInit; +} + +void QHexEdit::resetSelection(qint64 pos) +{ + pos = pos / 2 ; + if (pos < 0) + pos = 0; + if (pos > _chunks->size()) + pos = _chunks->size(); + + _bSelectionInit = pos; + _bSelectionBegin = pos; + _bSelectionEnd = pos; +} + +void QHexEdit::setSelection(qint64 pos) +{ + pos = pos / 2; + if (pos < 0) + pos = 0; + if (pos > _chunks->size()) + pos = _chunks->size(); + + if (pos >= _bSelectionInit) + { + _bSelectionEnd = pos; + _bSelectionBegin = _bSelectionInit; + } + else + { + _bSelectionBegin = pos; + _bSelectionEnd = _bSelectionInit; + } +} + +qint64 QHexEdit::getSelectionBegin() +{ + return _bSelectionBegin; +} + +qint64 QHexEdit::getSelectionEnd() +{ + return _bSelectionEnd; +} + +// ********************************************************************** Private utility functions +void QHexEdit::init() +{ + //_undoStack->clear(); + setAddressOffset(0); + resetSelection(0); + setCursorPosition(0); + verticalScrollBar()->setValue(0); + _modified = false; +} + +void QHexEdit::adjust() +{ + // recalc Graphics + if (_addressArea) + { + _addrDigits = addressWidth(); + _pxPosHexX = _pxGapAdr + _addrDigits*_pxCharWidth + _pxGapAdrHex; + } + else + _pxPosHexX = _pxGapAdrHex; + _pxPosAdrX = _pxGapAdr; + _pxPosAsciiX = _pxPosHexX + _hexCharsInLine * _pxCharWidth + _pxGapHexAscii; + + // set horizontalScrollBar() + int pxWidth = _pxPosAsciiX; + if (_asciiArea) + pxWidth += _bytesPerLine*_pxCharWidth; + horizontalScrollBar()->setRange(0, pxWidth - viewport()->width()); + horizontalScrollBar()->setPageStep(viewport()->width()); + + // set verticalScrollbar() + _rowsShown = ((viewport()->height()-4)/_pxCharHeight); + int lineCount = (int)(_chunks->size() / (qint64)_bytesPerLine) + 1; + verticalScrollBar()->setRange(0, lineCount - _rowsShown); + verticalScrollBar()->setPageStep(_rowsShown); + + int value = verticalScrollBar()->value(); + _bPosFirst = (qint64)value * _bytesPerLine; + _bPosLast = _bPosFirst + (qint64)(_rowsShown * _bytesPerLine) - 1; + if (_bPosLast >= _chunks->size()) + _bPosLast = _chunks->size() - 1; + readBuffers(); + setCursorPosition(_cursorPosition); +} + +void QHexEdit::dataChangedPrivate(int) +{ + _modified = 0; //_undoStack->index() != 0; + adjust(); + emit dataChanged(); +} + +void QHexEdit::refresh() +{ + ensureVisible(); + readBuffers(); +} + +void QHexEdit::readBuffers() +{ + _dataShown = _chunks->data(_bPosFirst, _bPosLast - _bPosFirst + _bytesPerLine + 1, &_markedShown); + _hexDataShown = QByteArray(_dataShown.toHex()); +} + +QString QHexEdit::toReadable(const QByteArray &ba) +{ + QString result; + + for (int i=0; i < ba.size(); i += 16) + { + QString addrStr = QString("%1").arg(_addressOffset + i, addressWidth(), 16, QChar('0')); + QString hexStr; + QString ascStr; + for (int j=0; j<16; j++) + { + if ((i + j) < ba.size()) + { + hexStr.append(" ").append(ba.mid(i+j, 1).toHex()); + char ch = ba[i + j]; + if ((ch < 0x20) || (ch > 0x7e)) + ch = '.'; + ascStr.append(QChar(ch)); + } + } + result += addrStr + " " + QString("%1").arg(hexStr, -48) + " " + QString("%1").arg(ascStr, -17) + "\n"; + } + return result; +} + +void QHexEdit::updateCursor() +{ + if (_blink) + _blink = false; + else + _blink = true; + viewport()->update(_cursorRect); +} diff --git a/src/drivers/Qt/QHexEdit.h b/src/drivers/Qt/QHexEdit.h new file mode 100644 index 00000000..df585cdd --- /dev/null +++ b/src/drivers/Qt/QHexEdit.h @@ -0,0 +1,424 @@ +#ifndef QHEXEDIT_H +#define QHEXEDIT_H + +#include +#include +#include +#include + +#include "Qt/chunks.h" +//#include "commands.h" + +#ifdef QHEXEDIT_EXPORTS +#define QHEXEDIT_API Q_DECL_EXPORT +#elif QHEXEDIT_IMPORTS +#define QHEXEDIT_API Q_DECL_IMPORT +#else +#define QHEXEDIT_API +#endif + +/** \mainpage +QHexEdit is a binary editor widget for Qt. + +\version Version 0.8.9 +\image html qhexedit.png +*/ + + +/** QHexEdit is a hex editor widget written in C++ for the Qt (Qt4, Qt5) framework. +It is a simple editor for binary data, just like QPlainTextEdit is for text +data. There are sip configuration files included, so it is easy to create +bindings for PyQt and you can use this widget also in python 2 and 3. + +QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use +the mouse or the keyboard to navigate inside the widget. If you hit the keys +(0..9, a..f) you will change the data. Changed data is highlighted and can be +accessed via data(). + +Normally QHexEdit works in the overwrite mode. You can set overwrite mode(false) +and insert data. In this case the size of data() increases. It is also possible +to delete bytes (del or backspace), here the size of data decreases. + +You can select data with keyboard hits or mouse movements. The copy-key will +copy the selected data into the clipboard. The cut-key copies also but deletes +it afterwards. In overwrite mode, the paste function overwrites the content of +the (does not change the length) data. In insert mode, clipboard data will be +inserted. The clipboard content is expected in ASCII Hex notation. Unknown +characters will be ignored. + +QHexEdit comes with undo/redo functionality. All changes can be undone, by +pressing the undo-key (usually ctr-z). They can also be redone afterwards. +The undo/redo framework is cleared, when setData() sets up a new +content for the editor. You can search data inside the content with indexOf() +and lastIndexOf(). The replace() function is to change located subdata. This +'replaced' data can also be undone by the undo/redo framework. + +QHexEdit is based on QIODevice, that's why QHexEdit can handle big amounts of +data. The size of edited data can be more then two gigabytes without any +restrictions. +*/ +class QHEXEDIT_API QHexEdit : public QAbstractScrollArea +{ + Q_OBJECT + + /*! Property address area switch the address area on or off. Set addressArea true + (show it), false (hide it). + */ + Q_PROPERTY(bool addressArea READ addressArea WRITE setAddressArea) + + /*! Property address area color sets (setAddressAreaColor()) the background + color of address areas. You can also read the color (addressAreaColor()). + */ + Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor) + + /*! Property addressOffset is added to the Numbers of the Address Area. + A offset in the address area (left side) is sometimes useful, whe you show + only a segment of a complete memory picture. With setAddressOffset() you set + this property - with addressOffset() you get the current value. + */ + Q_PROPERTY(qint64 addressOffset READ addressOffset WRITE setAddressOffset) + + /*! Set and get the minimum width of the address area, width in characters. + */ + Q_PROPERTY(int addressWidth READ addressWidth WRITE setAddressWidth) + + /*! Switch the ascii area on (true, show it) or off (false, hide it). + */ + Q_PROPERTY(bool asciiArea READ asciiArea WRITE setAsciiArea) + + /*! Set and get bytes number per line.*/ + Q_PROPERTY(int bytesPerLine READ bytesPerLine WRITE setBytesPerLine) + + /*! Property cursorPosition sets or gets the position of the editor cursor + in QHexEdit. Every byte in data has two cursor positions: the lower and upper + Nibble. Maximum cursor position is factor two of data.size(). + */ + Q_PROPERTY(qint64 cursorPosition READ cursorPosition WRITE setCursorPosition) + + /*! Property data holds the content of QHexEdit. Call setData() to set the + content of QHexEdit, data() returns the actual content. When calling setData() + with a QByteArray as argument, QHexEdit creates a internal copy of the data + If you want to edit big files please use setData(), based on QIODevice. + */ + Q_PROPERTY(QByteArray data READ data WRITE setData NOTIFY dataChanged) + + /*! That property defines if the hex values looks as a-f if the value is false(default) + or A-F if value is true. + */ + Q_PROPERTY(bool hexCaps READ hexCaps WRITE setHexCaps) + + /*! Property defines the dynamic calculation of bytesPerLine parameter depends of width of widget. + set this property true to avoid horizontal scrollbars and show the maximal possible data. defalut value is false*/ + Q_PROPERTY(bool dynamicBytesPerLine READ dynamicBytesPerLine WRITE setDynamicBytesPerLine) + + /*! Switch the highlighting feature on or of: true (show it), false (hide it). + */ + Q_PROPERTY(bool highlighting READ highlighting WRITE setHighlighting) + + /*! Property highlighting color sets (setHighlightingColor()) the background + color of highlighted text areas. You can also read the color + (highlightingColor()). + */ + Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor) + + /*! Property overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode + in which the editor works. In overwrite mode the user will overwrite existing data. The + size of data will be constant. In insert mode the size will grow, when inserting + new data. + */ + Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode) + + /*! Property selection color sets (setSelectionColor()) the background + color of selected text areas. You can also read the color + (selectionColor()). + */ + Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor) + + /*! Property readOnly sets (setReadOnly()) or gets (isReadOnly) the mode + in which the editor works. In readonly mode the the user can only navigate + through the data and select data; modifying is not possible. This + property's default is false. + */ + Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) + + /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/ + Q_PROPERTY(QFont font READ font WRITE setFont) + +public: + /*! Creates an instance of QHexEdit. + \param parent Parent widget of QHexEdit. + */ + QHexEdit(QWidget *parent=0); + + // Access to data of qhexedit + + /*! Sets the data of QHexEdit. The QIODevice will be opened just before reading + and closed immediately afterwards. This is to allow other programs to rewrite + the file while editing it. + */ + bool setData(QIODevice &iODevice); + + /*! Gives back the data as a QByteArray starting at position \param pos and + delivering \param count bytes. + */ + QByteArray dataAt(qint64 pos, qint64 count=-1); + + /*! Gives back the data into a \param iODevice starting at position \param pos + and delivering \param count bytes. + */ + bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1); + + + // Char handling + + /*! Inserts a char. + \param pos Index position, where to insert + \param ch Char, which is to insert + The char will be inserted and size of data grows. + */ + void insert(qint64 pos, char ch); + + /*! Removes len bytes from the content. + \param pos Index position, where to remove + \param len Amount of bytes to remove + */ + void remove(qint64 pos, qint64 len=1); + + /*! Replaces a char. + \param pos Index position, where to overwrite + \param ch Char, which is to insert + The char will be overwritten and size remains constant. + */ + void replace(qint64 pos, char ch); + + + // ByteArray handling + + /*! Inserts a byte array. + \param pos Index position, where to insert + \param ba QByteArray, which is to insert + The QByteArray will be inserted and size of data grows. + */ + void insert(qint64 pos, const QByteArray &ba); + + /*! Replaces \param len bytes with a byte array \param ba + \param pos Index position, where to overwrite + \param ba QByteArray, which is inserted + \param len count of bytes to overwrite + The data is overwritten and size of data may change. + */ + void replace(qint64 pos, qint64 len, const QByteArray &ba); + + + // Utility functions + /*! Calc cursor position from graphics position + * \param point from where the cursor position should be calculated + * \return Cursor position + */ + qint64 cursorPosition(QPoint point); + + /*! Ensure the cursor to be visbile + */ + void ensureVisible(); + + /*! Find first occurrence of ba in QHexEdit data + * \param ba Data to find + * \param from Point where the search starts + * \return pos if fond, else -1 + */ + qint64 indexOf(const QByteArray &ba, qint64 from); + + /*! Returns if any changes where done on document + * \return true when document is modified else false + */ + bool isModified(); + + /*! Find last occurrence of ba in QHexEdit data + * \param ba Data to find + * \param from Point where the search starts + * \return pos if fond, else -1 + */ + qint64 lastIndexOf(const QByteArray &ba, qint64 from); + + /*! Gives back a formatted image of the selected content of QHexEdit + */ + QString selectionToReadableString(); + + /*! Return the selected content of QHexEdit as QByteArray + */ + QString selectedData(); + + /*! Set Font of QHexEdit + * \param font + */ + void setFont(const QFont &font); + + /*! Gives back a formatted image of the content of QHexEdit + */ + QString toReadableString(); + + +public slots: + /*! Redoes the last operation. If there is no operation to redo, i.e. + there is no redo step in the undo/redo history, nothing happens. + */ + void redo(); + + /*! Undoes the last operation. If there is no operation to undo, i.e. + there is no undo step in the undo/redo history, nothing happens. + */ + void undo(); + +signals: + + /*! Contains the address, where the cursor is located. */ + void currentAddressChanged(qint64 address); + + /*! Contains the size of the data to edit. */ + void currentSizeChanged(qint64 size); + + /*! The signal is emitted every time, the data is changed. */ + void dataChanged(); + + /*! The signal is emitted every time, the overwrite mode is changed. */ + void overwriteModeChanged(bool state); + + +/*! \cond docNever */ +public: + ~QHexEdit(); + + // Properties + bool addressArea(); + void setAddressArea(bool addressArea); + + QColor addressAreaColor(); + void setAddressAreaColor(const QColor &color); + + qint64 addressOffset(); + void setAddressOffset(qint64 addressArea); + + int addressWidth(); + void setAddressWidth(int addressWidth); + + bool asciiArea(); + void setAsciiArea(bool asciiArea); + + int bytesPerLine(); + void setBytesPerLine(int count); + + qint64 cursorPosition(); + void setCursorPosition(qint64 position); + + QByteArray data(); + void setData(const QByteArray &ba); + + void setHexCaps(const bool isCaps); + bool hexCaps(); + + void setDynamicBytesPerLine(const bool isDynamic); + bool dynamicBytesPerLine(); + + bool highlighting(); + void setHighlighting(bool mode); + + QColor highlightingColor(); + void setHighlightingColor(const QColor &color); + + bool overwriteMode(); + void setOverwriteMode(bool overwriteMode); + + bool isReadOnly(); + void setReadOnly(bool readOnly); + + QColor selectionColor(); + void setSelectionColor(const QColor &color); + +protected: + // Handle events + void keyPressEvent(QKeyEvent *event); + void mouseMoveEvent(QMouseEvent * event); + void mousePressEvent(QMouseEvent * event); + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *); + virtual bool focusNextPrevChild(bool next); +private: + // Handle selections + void resetSelection(qint64 pos); // set selectionStart and selectionEnd to pos + void resetSelection(); // set selectionEnd to selectionStart + void setSelection(qint64 pos); // set min (if below init) or max (if greater init) + qint64 getSelectionBegin(); + qint64 getSelectionEnd(); + + // Private utility functions + void init(); + void readBuffers(); + QString toReadable(const QByteArray &ba); + +private slots: + void adjust(); // recalc pixel positions + void dataChangedPrivate(int idx=0); // emit dataChanged() signal + void refresh(); // ensureVisible() and readBuffers() + void updateCursor(); // update blinking cursor + +private: + // Name convention: pixel positions start with _px + int _pxCharWidth, _pxCharHeight; // char dimensions (dependend on font) + int _pxPosHexX; // X-Pos of HeaxArea + int _pxPosAdrX; // X-Pos of Address Area + int _pxPosAsciiX; // X-Pos of Ascii Area + int _pxGapAdr; // gap left from AddressArea + int _pxGapAdrHex; // gap between AddressArea and HexAerea + int _pxGapHexAscii; // gap between HexArea and AsciiArea + int _pxCursorWidth; // cursor width + int _pxSelectionSub; // offset selection rect + int _pxCursorX; // current cursor pos + int _pxCursorY; // current cursor pos + + // Name convention: absolute byte positions in chunks start with _b + qint64 _bSelectionBegin; // first position of Selection + qint64 _bSelectionEnd; // end of Selection + qint64 _bSelectionInit; // memory position of Selection + qint64 _bPosFirst; // position of first byte shown + qint64 _bPosLast; // position of last byte shown + qint64 _bPosCurrent; // current position + + // variables to store the property values + bool _addressArea; // left area of QHexEdit + QColor _addressAreaColor; + int _addressWidth; + bool _asciiArea; + qint64 _addressOffset; + int _bytesPerLine; + int _hexCharsInLine; + bool _highlighting; + bool _overwriteMode; + QBrush _brushSelection; + QPen _penSelection; + QBrush _brushHighlighted; + QPen _penHighlighted; + bool _readOnly; + bool _hexCaps; + bool _dynamicBytesPerLine; + + // other variables + bool _editAreaIsAscii; // flag about the ascii mode edited + int _addrDigits; // real no of addressdigits, may be > addressWidth + bool _blink; // help get cursor blinking + QBuffer _bData; // buffer, when setup with QByteArray + Chunks *_chunks; // IODevice based access to data + QTimer _cursorTimer; // for blinking cursor + qint64 _cursorPosition; // absolute position of cursor, 1 Byte == 2 tics + QRect _cursorRect; // physical dimensions of cursor + QByteArray _data; // QHexEdit's data, when setup with QByteArray + QByteArray _dataShown; // data in the current View + QByteArray _hexDataShown; // data in view, transformed to hex + qint64 _lastEventSize; // size, which was emitted last time + QByteArray _markedShown; // marked data in view + bool _modified; // Is any data in editor modified? + int _rowsShown; // lines of text shown + //UndoStack * _undoStack; // Stack to store edit actions for undo/redo + /*! \endcond docNever */ +}; + +#endif // QHEXEDIT_H diff --git a/src/drivers/Qt/chunks.cpp b/src/drivers/Qt/chunks.cpp new file mode 100644 index 00000000..a4e420bf --- /dev/null +++ b/src/drivers/Qt/chunks.cpp @@ -0,0 +1,323 @@ +#include "chunks.h" +#include + +#define NORMAL 0 +#define HIGHLIGHTED 1 + +#define BUFFER_SIZE 0x10000 +#define CHUNK_SIZE 0x1000 +#define READ_CHUNK_MASK Q_INT64_C(0xfffffffffffff000) + +// ***************************************** Constructors and file settings + +Chunks::Chunks(QObject *parent): QObject(parent) +{ + QBuffer *buf = new QBuffer(this); + setIODevice(*buf); +} + +Chunks::Chunks(QIODevice &ioDevice, QObject *parent): QObject(parent) +{ + setIODevice(ioDevice); +} + +bool Chunks::setIODevice(QIODevice &ioDevice) +{ + _ioDevice = &ioDevice; + bool ok = _ioDevice->open(QIODevice::ReadOnly); + if (ok) // Try to open IODevice + { + _size = _ioDevice->size(); + _ioDevice->close(); + } + else // Fallback is an empty buffer + { + QBuffer *buf = new QBuffer(this); + _ioDevice = buf; + _size = 0; + } + _chunks.clear(); + _pos = 0; + return ok; +} + + +// ***************************************** Getting data out of Chunks + +QByteArray Chunks::data(qint64 pos, qint64 maxSize, QByteArray *highlighted) +{ + qint64 ioDelta = 0; + int chunkIdx = 0; + + Chunk chunk; + QByteArray buffer; + + // Do some checks and some arrangements + if (highlighted) + highlighted->clear(); + + if (pos >= _size) + return buffer; + + if (maxSize < 0) + maxSize = _size; + else + if ((pos + maxSize) > _size) + maxSize = _size - pos; + + _ioDevice->open(QIODevice::ReadOnly); + + while (maxSize > 0) + { + chunk.absPos = LLONG_MAX; + bool chunksLoopOngoing = true; + while ((chunkIdx < _chunks.count()) && chunksLoopOngoing) + { + // In this section, we track changes before our required data and + // we take the editdet data, if availible. ioDelta is a difference + // counter to justify the read pointer to the original data, if + // data in between was deleted or inserted. + + chunk = _chunks[chunkIdx]; + if (chunk.absPos > pos) + chunksLoopOngoing = false; + else + { + chunkIdx += 1; + qint64 count; + qint64 chunkOfs = pos - chunk.absPos; + if (maxSize > ((qint64)chunk.data.size() - chunkOfs)) + { + count = (qint64)chunk.data.size() - chunkOfs; + ioDelta += CHUNK_SIZE - chunk.data.size(); + } + else + count = maxSize; + if (count > 0) + { + buffer += chunk.data.mid(chunkOfs, (int)count); + maxSize -= count; + pos += count; + if (highlighted) + *highlighted += chunk.dataChanged.mid(chunkOfs, (int)count); + } + } + } + + if ((maxSize > 0) && (pos < chunk.absPos)) + { + // In this section, we read data from the original source. This only will + // happen, whe no copied data is available + + qint64 byteCount; + QByteArray readBuffer; + if ((chunk.absPos - pos) > maxSize) + byteCount = maxSize; + else + byteCount = chunk.absPos - pos; + + maxSize -= byteCount; + _ioDevice->seek(pos + ioDelta); + readBuffer = _ioDevice->read(byteCount); + buffer += readBuffer; + if (highlighted) + *highlighted += QByteArray(readBuffer.size(), NORMAL); + pos += readBuffer.size(); + } + } + _ioDevice->close(); + return buffer; +} + +bool Chunks::write(QIODevice &iODevice, qint64 pos, qint64 count) +{ + if (count == -1) + count = _size; + bool ok = iODevice.open(QIODevice::WriteOnly); + if (ok) + { + for (qint64 idx=pos; idx < count; idx += BUFFER_SIZE) + { + QByteArray ba = data(idx, BUFFER_SIZE); + iODevice.write(ba); + } + iODevice.close(); + } + return ok; +} + + +// ***************************************** Set and get highlighting infos + +void Chunks::setDataChanged(qint64 pos, bool dataChanged) +{ + if ((pos < 0) || (pos >= _size)) + return; + int chunkIdx = getChunkIndex(pos); + qint64 posInBa = pos - _chunks[chunkIdx].absPos; + _chunks[chunkIdx].dataChanged[(int)posInBa] = char(dataChanged); +} + +bool Chunks::dataChanged(qint64 pos) +{ + QByteArray highlighted; + data(pos, 1, &highlighted); + return bool(highlighted.at(0)); +} + + +// ***************************************** Search API + +qint64 Chunks::indexOf(const QByteArray &ba, qint64 from) +{ + qint64 result = -1; + QByteArray buffer; + + for (qint64 pos=from; (pos < _size) && (result < 0); pos += BUFFER_SIZE) + { + buffer = data(pos, BUFFER_SIZE + ba.size() - 1); + int findPos = buffer.indexOf(ba); + if (findPos >= 0) + result = pos + (qint64)findPos; + } + return result; +} + +qint64 Chunks::lastIndexOf(const QByteArray &ba, qint64 from) +{ + qint64 result = -1; + QByteArray buffer; + + for (qint64 pos=from; (pos > 0) && (result < 0); pos -= BUFFER_SIZE) + { + qint64 sPos = pos - BUFFER_SIZE - (qint64)ba.size() + 1; + if (sPos < 0) + sPos = 0; + buffer = data(sPos, pos - sPos); + int findPos = buffer.lastIndexOf(ba); + if (findPos >= 0) + result = sPos + (qint64)findPos; + } + return result; +} + + +// ***************************************** Char manipulations + +bool Chunks::insert(qint64 pos, char b) +{ + if ((pos < 0) || (pos > _size)) + return false; + int chunkIdx; + if (pos == _size) + chunkIdx = getChunkIndex(pos-1); + else + chunkIdx = getChunkIndex(pos); + qint64 posInBa = pos - _chunks[chunkIdx].absPos; + _chunks[chunkIdx].data.insert(posInBa, b); + _chunks[chunkIdx].dataChanged.insert(posInBa, char(1)); + for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) + _chunks[idx].absPos += 1; + _size += 1; + _pos = pos; + return true; +} + +bool Chunks::overwrite(qint64 pos, char b) +{ + if ((pos < 0) || (pos >= _size)) + return false; + int chunkIdx = getChunkIndex(pos); + qint64 posInBa = pos - _chunks[chunkIdx].absPos; + _chunks[chunkIdx].data[(int)posInBa] = b; + _chunks[chunkIdx].dataChanged[(int)posInBa] = char(1); + _pos = pos; + return true; +} + +bool Chunks::removeAt(qint64 pos) +{ + if ((pos < 0) || (pos >= _size)) + return false; + int chunkIdx = getChunkIndex(pos); + qint64 posInBa = pos - _chunks[chunkIdx].absPos; + _chunks[chunkIdx].data.remove(posInBa, 1); + _chunks[chunkIdx].dataChanged.remove(posInBa, 1); + for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) + _chunks[idx].absPos -= 1; + _size -= 1; + _pos = pos; + return true; +} + + +// ***************************************** Utility functions + +char Chunks::operator[](qint64 pos) +{ + return data(pos, 1)[0]; +} + +qint64 Chunks::pos() +{ + return _pos; +} + +qint64 Chunks::size() +{ + return _size; +} + +int Chunks::getChunkIndex(qint64 absPos) +{ + // This routine checks, if there is already a copied chunk available. If os, it + // returns a reference to it. If there is no copied chunk available, original + // data will be copied into a new chunk. + + int foundIdx = -1; + int insertIdx = 0; + qint64 ioDelta = 0; + + + for (int idx=0; idx < _chunks.size(); idx++) + { + Chunk chunk = _chunks[idx]; + if ((absPos >= chunk.absPos) && (absPos < (chunk.absPos + chunk.data.size()))) + { + foundIdx = idx; + break; + } + if (absPos < chunk.absPos) + { + insertIdx = idx; + break; + } + ioDelta += chunk.data.size() - CHUNK_SIZE; + insertIdx = idx + 1; + } + + if (foundIdx == -1) + { + Chunk newChunk; + qint64 readAbsPos = absPos - ioDelta; + qint64 readPos = (readAbsPos & READ_CHUNK_MASK); + _ioDevice->open(QIODevice::ReadOnly); + _ioDevice->seek(readPos); + newChunk.data = _ioDevice->read(CHUNK_SIZE); + _ioDevice->close(); + newChunk.absPos = absPos - (readAbsPos - readPos); + newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0)); + _chunks.insert(insertIdx, newChunk); + foundIdx = insertIdx; + } + return foundIdx; +} + + +#ifdef MODUL_TEST +int Chunks::chunkSize() +{ + return _chunks.size(); +} + +#endif diff --git a/src/drivers/Qt/chunks.h b/src/drivers/Qt/chunks.h new file mode 100644 index 00000000..43df76ca --- /dev/null +++ b/src/drivers/Qt/chunks.h @@ -0,0 +1,77 @@ +#ifndef CHUNKS_H +#define CHUNKS_H + +/** \cond docNever */ + +/*! The Chunks class is the storage backend for QHexEdit. + * + * When QHexEdit loads data, Chunks access them using a QIODevice interface. When the app uses + * a QByteArray interface, QBuffer is used to provide again a QIODevice like interface. No data + * will be changed, therefore Chunks opens the QIODevice in QIODevice::ReadOnly mode. After every + * access Chunks closes the QIODevice, that's why external applications can overwrite files while + * QHexEdit shows them. + * + * When the the user starts to edit the data, Chunks creates a local copy of a chunk of data (4 + * kilobytes) and notes all changes there. Parallel to that chunk, there is a second chunk, + * which keep track of which bytes are changed and which not. + * + */ + +#include + +struct Chunk +{ + QByteArray data; + QByteArray dataChanged; + qint64 absPos; +}; + +class Chunks: public QObject +{ +Q_OBJECT +public: + // Constructors and file settings + Chunks(QObject *parent); + Chunks(QIODevice &ioDevice, QObject *parent); + bool setIODevice(QIODevice &ioDevice); + + // Getting data out of Chunks + QByteArray data(qint64 pos=0, qint64 count=-1, QByteArray *highlighted=0); + bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1); + + // Set and get highlighting infos + void setDataChanged(qint64 pos, bool dataChanged); + bool dataChanged(qint64 pos); + + // Search API + qint64 indexOf(const QByteArray &ba, qint64 from); + qint64 lastIndexOf(const QByteArray &ba, qint64 from); + + // Char manipulations + bool insert(qint64 pos, char b); + bool overwrite(qint64 pos, char b); + bool removeAt(qint64 pos); + + // Utility functions + char operator[](qint64 pos); + qint64 pos(); + qint64 size(); + + +private: + int getChunkIndex(qint64 absPos); + + QIODevice * _ioDevice; + qint64 _pos; + qint64 _size; + QList _chunks; + +#ifdef MODUL_TEST +public: + int chunkSize(); +#endif +}; + +/** \endcond docNever */ + +#endif // CHUNKS_H From 466e513778f9fbef510fefb39a8da51d3a39accf Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 18 Aug 2020 22:19:53 -0400 Subject: [PATCH 06/37] QHexEdit did not meet performance goals. Removing to try other options. --- src/CMakeLists.txt | 2 - src/drivers/Qt/HexEditor.cpp | 63 +- src/drivers/Qt/HexEditor.h | 16 +- src/drivers/Qt/QHexEdit.cpp | 1154 ---------------------------------- src/drivers/Qt/QHexEdit.h | 424 ------------- src/drivers/Qt/chunks.cpp | 323 ---------- src/drivers/Qt/chunks.h | 77 --- 7 files changed, 40 insertions(+), 2019 deletions(-) delete mode 100644 src/drivers/Qt/QHexEdit.cpp delete mode 100644 src/drivers/Qt/QHexEdit.h delete mode 100644 src/drivers/Qt/chunks.cpp delete mode 100644 src/drivers/Qt/chunks.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d8541fef..4ef224bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -432,8 +432,6 @@ set(SRC_DRIVERS_SDL ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/LuaControl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/CheatsConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HexEditor.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/QHexEdit.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/chunks.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleUtilities.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index bf1874cf..6ce26075 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -100,7 +100,11 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); - editor = new QHexEdit(this); + editor = new QPlainTextEdit(this); + + editor->setFont(font); + editor->setWordWrapMode(QTextOption::NoWrap); + editor->setOverwriteMode(true); mainLayout->addWidget( editor ); @@ -116,35 +120,13 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) redraw = false; total_instructions_lp = 0; - dataArray = new QByteArray( 0x20000, '0' ); - dataBuffer = new QBuffer( dataArray, this ); - dataBuffer->setBuffer( dataArray ); - - printf("DataArray: Size: %i \n", dataArray->size() ); - editor->setData( *dataBuffer ); - - editor->setAddressArea(true); - editor->setAsciiArea(true); - editor->setHighlighting(true); - editor->setOverwriteMode(true); - editor->setReadOnly(true); - editor->setHexCaps(true); - - editor->setHighlightingColor( QColor("yellow") ); - editor->setAddressAreaColor( QColor("white") ); - editor->setSelectionColor( QColor("blue") ); - //editor->setFont( font ); - - editor->setAddressWidth(6); - editor->setBytesPerLine(16); - showMemViewResults(true); periodicTimer = new QTimer( this ); connect( periodicTimer, &QTimer::timeout, this, &HexEditorDialog_t::updatePeriodic ); - periodicTimer->start( 1000 ); // 10hz + periodicTimer->start( 100 ); // 10hz } //---------------------------------------------------------------------------- HexEditorDialog_t::~HexEditorDialog_t(void) @@ -192,12 +174,16 @@ void HexEditorDialog_t::initMem(void) mbuf[i].data = memAccessFunc(i); mbuf[i].color = 0; mbuf[i].actv = 0; - mbuf[i].draw = 1; + //mbuf[i].draw = 1; } } //---------------------------------------------------------------------------- void HexEditorDialog_t::showMemViewResults (bool reset) { + static unsigned int counter = 0; + std::string txt; + QTextCursor cursor; + switch ( mode ) { default: @@ -242,8 +228,6 @@ void HexEditorDialog_t::showMemViewResults (bool reset) printf("Mode: %i MemSize:%i 0x%08x\n", mode, memSize, (unsigned int)memSize ); reset = 1; - dataArray->resize( mbuf_size ); - if ( mbuf ) { free(mbuf); mbuf = NULL; @@ -262,6 +246,27 @@ void HexEditorDialog_t::showMemViewResults (bool reset) return; } } + + cursor = editor->textCursor(); + + txt.clear(); + + for (int i=0; i<20; i++) + { + char stmp[32]; + sprintf( stmp, "%06X ", i*16 ); + txt.append(stmp); + + for (int j=0; j<16; j++) + { + sprintf( stmp, " %02X ", counter ); counter = (counter + 1) % 256; + txt.append(stmp); + } + txt.append("\n"); + } + editor->setPlainText( QString::fromStdString(txt) ); + + editor->setTextCursor( cursor ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::updatePeriodic(void) @@ -295,13 +300,13 @@ int HexEditorDialog_t::checkMemActivity(void) { mbuf[i].actv = 15; mbuf[i].data = c; - mbuf[i].draw = 1; + //mbuf[i].draw = 1; } else { if ( mbuf[i].actv > 0 ) { - mbuf[i].draw = 1; + //mbuf[i].draw = 1; mbuf[i].actv--; } } diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index ac7a0b08..852e93dc 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -14,17 +14,13 @@ #include #include #include -#include -#include - -#include "Qt/QHexEdit.h" +#include struct memByte_t { unsigned char data; unsigned char color; unsigned char actv; - unsigned char draw; }; class HexEditorDialog_t : public QDialog @@ -51,11 +47,11 @@ class HexEditorDialog_t : public QDialog int checkMemActivity(void); int calcVisibleRange( int *start_out, int *end_out, int *center_out ); - QFont font; - QHexEdit *editor; - QTimer *periodicTimer; - QByteArray *dataArray; - QBuffer *dataBuffer; + QFont font; + QPlainTextEdit *editor; + QTimer *periodicTimer; + //QByteArray *dataArray; + //QBuffer *dataBuffer; int mode; int numLines; diff --git a/src/drivers/Qt/QHexEdit.cpp b/src/drivers/Qt/QHexEdit.cpp deleted file mode 100644 index 81c75a41..00000000 --- a/src/drivers/Qt/QHexEdit.cpp +++ /dev/null @@ -1,1154 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "Qt/QHexEdit.h" - - -// ********************************************************************** Constructor, destructor - -QHexEdit::QHexEdit(QWidget *parent) : QAbstractScrollArea(parent) -{ - _addressArea = true; - _addressWidth = 4; - _asciiArea = true; - _overwriteMode = true; - _highlighting = true; - _readOnly = false; - _cursorPosition = 0; - _lastEventSize = 0; - _hexCharsInLine = 47; - _bytesPerLine = 16; - _editAreaIsAscii = false; - _hexCaps = false; - _dynamicBytesPerLine = false; - - _chunks = new Chunks(this); - //_undoStack = new UndoStack(_chunks, this); -#ifdef Q_OS_WIN32 - setFont(QFont("Courier", 10)); -#else - setFont(QFont("Monospace", 10)); -#endif - setAddressAreaColor(this->palette().alternateBase().color()); - setHighlightingColor(QColor(0xff, 0xff, 0x99, 0xff)); - setSelectionColor(this->palette().highlight().color()); - - connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor())); - connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); - connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjust())); - //connect(_undoStack, SIGNAL(indexChanged(int)), this, SLOT(dataChangedPrivate(int))); - - _cursorTimer.setInterval(500); - _cursorTimer.start(); - - setAddressWidth(4); - setAddressArea(true); - setAsciiArea(true); - setOverwriteMode(true); - setHighlighting(true); - setReadOnly(false); - - init(); - -} - -QHexEdit::~QHexEdit() -{ -} - -// ********************************************************************** Properties - -void QHexEdit::setAddressArea(bool addressArea) -{ - _addressArea = addressArea; - adjust(); - setCursorPosition(_cursorPosition); - viewport()->update(); -} - -bool QHexEdit::addressArea() -{ - return _addressArea; -} - -void QHexEdit::setAddressAreaColor(const QColor &color) -{ - _addressAreaColor = color; - viewport()->update(); -} - -QColor QHexEdit::addressAreaColor() -{ - return _addressAreaColor; -} - -void QHexEdit::setAddressOffset(qint64 addressOffset) -{ - _addressOffset = addressOffset; - adjust(); - setCursorPosition(_cursorPosition); - viewport()->update(); -} - -qint64 QHexEdit::addressOffset() -{ - return _addressOffset; -} - -void QHexEdit::setAddressWidth(int addressWidth) -{ - _addressWidth = addressWidth; - adjust(); - setCursorPosition(_cursorPosition); - viewport()->update(); -} - -int QHexEdit::addressWidth() -{ - qint64 size = _chunks->size(); - int n = 1; - if (size > Q_INT64_C(0x100000000)){ n += 8; size /= Q_INT64_C(0x100000000);} - if (size > 0x10000){ n += 4; size /= 0x10000;} - if (size > 0x100){ n += 2; size /= 0x100;} - if (size > 0x10){ n += 1;} - - if (n > _addressWidth) - return n; - else - return _addressWidth; -} - -void QHexEdit::setAsciiArea(bool asciiArea) -{ - if (!asciiArea) - _editAreaIsAscii = false; - _asciiArea = asciiArea; - adjust(); - setCursorPosition(_cursorPosition); - viewport()->update(); -} - -bool QHexEdit::asciiArea() -{ - return _asciiArea; -} - -void QHexEdit::setBytesPerLine(int count) -{ - _bytesPerLine = count; - _hexCharsInLine = count * 3 - 1; - - adjust(); - setCursorPosition(_cursorPosition); - viewport()->update(); -} - -int QHexEdit::bytesPerLine() -{ - return _bytesPerLine; -} - -void QHexEdit::setCursorPosition(qint64 position) -{ - // 1. delete old cursor - _blink = false; - viewport()->update(_cursorRect); - - // 2. Check, if cursor in range? - if (position > (_chunks->size() * 2 - 1)) - position = _chunks->size() * 2 - (_overwriteMode ? 1 : 0); - - if (position < 0) - position = 0; - - // 3. Calc new position of cursor - _bPosCurrent = position / 2; - _pxCursorY = ((position / 2 - _bPosFirst) / _bytesPerLine + 1) * _pxCharHeight; - int x = (position % (2 * _bytesPerLine)); - if (_editAreaIsAscii) - { - _pxCursorX = x / 2 * _pxCharWidth + _pxPosAsciiX; - _cursorPosition = position & 0xFFFFFFFFFFFFFFFE; - } else { - _pxCursorX = (((x / 2) * 3) + (x % 2)) * _pxCharWidth + _pxPosHexX; - _cursorPosition = position; - } - - if (_overwriteMode) - _cursorRect = QRect(_pxCursorX - horizontalScrollBar()->value(), _pxCursorY + _pxCursorWidth, _pxCharWidth, _pxCursorWidth); - else - _cursorRect = QRect(_pxCursorX - horizontalScrollBar()->value(), _pxCursorY - _pxCharHeight + 4, _pxCursorWidth, _pxCharHeight); - - // 4. Immediately draw new cursor - _blink = true; - viewport()->update(_cursorRect); - emit currentAddressChanged(_bPosCurrent); -} - -qint64 QHexEdit::cursorPosition(QPoint pos) -{ - // Calc cursor position depending on a graphical position - qint64 result = -1; - int posX = pos.x() + horizontalScrollBar()->value(); - int posY = pos.y() - 3; - if ((posX >= _pxPosHexX) && (posX < (_pxPosHexX + (1 + _hexCharsInLine) * _pxCharWidth))) - { - _editAreaIsAscii = false; - int x = (posX - _pxPosHexX) / _pxCharWidth; - x = (x / 3) * 2 + x % 3; - int y = (posY / _pxCharHeight) * 2 * _bytesPerLine; - result = _bPosFirst * 2 + x + y; - } - else - if (_asciiArea && (posX >= _pxPosAsciiX) && (posX < (_pxPosAsciiX + (1 + _bytesPerLine) * _pxCharWidth))) - { - _editAreaIsAscii = true; - int x = 2 * (posX - _pxPosAsciiX) / _pxCharWidth; - int y = (posY / _pxCharHeight) * 2 * _bytesPerLine; - result = _bPosFirst * 2 + x + y; - } - return result; -} - -qint64 QHexEdit::cursorPosition() -{ - return _cursorPosition; -} - -void QHexEdit::setData(const QByteArray &ba) -{ - _data = ba; - _bData.setData(_data); - setData(_bData); -} - -QByteArray QHexEdit::data() -{ - return _chunks->data(0, -1); -} - -void QHexEdit::setHighlighting(bool highlighting) -{ - _highlighting = highlighting; - viewport()->update(); -} - -bool QHexEdit::highlighting() -{ - return _highlighting; -} - -void QHexEdit::setHighlightingColor(const QColor &color) -{ - _brushHighlighted = QBrush(color); - _penHighlighted = QPen(viewport()->palette().color(QPalette::WindowText)); - viewport()->update(); -} - -QColor QHexEdit::highlightingColor() -{ - return _brushHighlighted.color(); -} - -void QHexEdit::setOverwriteMode(bool overwriteMode) -{ - _overwriteMode = overwriteMode; - emit overwriteModeChanged(overwriteMode); -} - -bool QHexEdit::overwriteMode() -{ - return _overwriteMode; -} - -void QHexEdit::setSelectionColor(const QColor &color) -{ - _brushSelection = QBrush(color); - _penSelection = QPen(Qt::white); - viewport()->update(); -} - -QColor QHexEdit::selectionColor() -{ - return _brushSelection.color(); -} - -bool QHexEdit::isReadOnly() -{ - return _readOnly; -} - -void QHexEdit::setReadOnly(bool readOnly) -{ - _readOnly = readOnly; -} - -void QHexEdit::setHexCaps(const bool isCaps) -{ - if (_hexCaps != isCaps) - { - _hexCaps = isCaps; - viewport()->update(); - } -} - -bool QHexEdit::hexCaps() -{ - return _hexCaps; -} - -void QHexEdit::setDynamicBytesPerLine(const bool isDynamic) -{ - _dynamicBytesPerLine = isDynamic; - resizeEvent(NULL); -} - -bool QHexEdit::dynamicBytesPerLine() -{ - return _dynamicBytesPerLine; -} - -// ********************************************************************** Access to data of qhexedit -bool QHexEdit::setData(QIODevice &iODevice) -{ - bool ok = _chunks->setIODevice(iODevice); - init(); - dataChangedPrivate(); - return ok; -} - -QByteArray QHexEdit::dataAt(qint64 pos, qint64 count) -{ - return _chunks->data(pos, count); -} - -bool QHexEdit::write(QIODevice &iODevice, qint64 pos, qint64 count) -{ - return _chunks->write(iODevice, pos, count); -} - -// ********************************************************************** Char handling -void QHexEdit::insert(qint64 index, char ch) -{ - //_undoStack->insert(index, ch); - refresh(); -} - -void QHexEdit::remove(qint64 index, qint64 len) -{ - //_undoStack->removeAt(index, len); - refresh(); -} - -void QHexEdit::replace(qint64 index, char ch) -{ - //_undoStack->overwrite(index, ch); - refresh(); -} - -// ********************************************************************** ByteArray handling -void QHexEdit::insert(qint64 pos, const QByteArray &ba) -{ - //_undoStack->insert(pos, ba); - refresh(); -} - -void QHexEdit::replace(qint64 pos, qint64 len, const QByteArray &ba) -{ - //_undoStack->overwrite(pos, len, ba); - refresh(); -} - -// ********************************************************************** Utility functions -void QHexEdit::ensureVisible() -{ - if (_cursorPosition < (_bPosFirst * 2)) - verticalScrollBar()->setValue((int)(_cursorPosition / 2 / _bytesPerLine)); - if (_cursorPosition > ((_bPosFirst + (_rowsShown - 1)*_bytesPerLine) * 2)) - verticalScrollBar()->setValue((int)(_cursorPosition / 2 / _bytesPerLine) - _rowsShown + 1); - if (_pxCursorX < horizontalScrollBar()->value()) - horizontalScrollBar()->setValue(_pxCursorX); - if ((_pxCursorX + _pxCharWidth) > (horizontalScrollBar()->value() + viewport()->width())) - horizontalScrollBar()->setValue(_pxCursorX + _pxCharWidth - viewport()->width()); - viewport()->update(); -} - -qint64 QHexEdit::indexOf(const QByteArray &ba, qint64 from) -{ - qint64 pos = _chunks->indexOf(ba, from); - if (pos > -1) - { - qint64 curPos = pos*2; - setCursorPosition(curPos + ba.length()*2); - resetSelection(curPos); - setSelection(curPos + ba.length()*2); - ensureVisible(); - } - return pos; -} - -bool QHexEdit::isModified() -{ - return _modified; -} - -qint64 QHexEdit::lastIndexOf(const QByteArray &ba, qint64 from) -{ - qint64 pos = _chunks->lastIndexOf(ba, from); - if (pos > -1) - { - qint64 curPos = pos*2; - setCursorPosition(curPos - 1); - resetSelection(curPos); - setSelection(curPos + ba.length()*2); - ensureVisible(); - } - return pos; -} - -void QHexEdit::redo() -{ - //_undoStack->redo(); - setCursorPosition(_chunks->pos()*(_editAreaIsAscii ? 1 : 2)); - refresh(); -} - -QString QHexEdit::selectionToReadableString() -{ - QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); - return toReadable(ba); -} - -QString QHexEdit::selectedData() -{ - QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); - return ba; -} - -void QHexEdit::setFont(const QFont &font) -{ - QFont theFont(font); - theFont.setStyleHint(QFont::Monospace); - QWidget::setFont(theFont); - QFontMetrics metrics = fontMetrics(); -#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) - _pxCharWidth = metrics.horizontalAdvance(QLatin1Char('2')); -#else - _pxCharWidth = metrics.width(QLatin1Char('2')); -#endif - _pxCharHeight = metrics.height(); - _pxGapAdr = _pxCharWidth / 2; - _pxGapAdrHex = _pxCharWidth; - _pxGapHexAscii = 2 * _pxCharWidth; - _pxCursorWidth = _pxCharHeight / 7; - _pxSelectionSub = _pxCharHeight / 5; - viewport()->update(); -} - -QString QHexEdit::toReadableString() -{ - QByteArray ba = _chunks->data(); - return toReadable(ba); -} - -void QHexEdit::undo() -{ - //_undoStack->undo(); - setCursorPosition(_chunks->pos()*(_editAreaIsAscii ? 1 : 2)); - refresh(); -} - -// ********************************************************************** Handle events -void QHexEdit::keyPressEvent(QKeyEvent *event) -{ - // Cursor movements - if (event->matches(QKeySequence::MoveToNextChar)) - { - qint64 pos = _cursorPosition + 1; - if (_editAreaIsAscii) - pos += 1; - setCursorPosition(pos); - resetSelection(pos); - } - if (event->matches(QKeySequence::MoveToPreviousChar)) - { - qint64 pos = _cursorPosition - 1; - if (_editAreaIsAscii) - pos -= 1; - setCursorPosition(pos); - resetSelection(pos); - } - if (event->matches(QKeySequence::MoveToEndOfLine)) - { - qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)) + (2 * _bytesPerLine) - 1; - setCursorPosition(pos); - resetSelection(_cursorPosition); - } - if (event->matches(QKeySequence::MoveToStartOfLine)) - { - qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)); - setCursorPosition(pos); - resetSelection(_cursorPosition); - } - if (event->matches(QKeySequence::MoveToPreviousLine)) - { - setCursorPosition(_cursorPosition - (2 * _bytesPerLine)); - resetSelection(_cursorPosition); - } - if (event->matches(QKeySequence::MoveToNextLine)) - { - setCursorPosition(_cursorPosition + (2 * _bytesPerLine)); - resetSelection(_cursorPosition); - } - if (event->matches(QKeySequence::MoveToNextPage)) - { - setCursorPosition(_cursorPosition + (((_rowsShown - 1) * 2 * _bytesPerLine))); - resetSelection(_cursorPosition); - } - if (event->matches(QKeySequence::MoveToPreviousPage)) - { - setCursorPosition(_cursorPosition - (((_rowsShown - 1) * 2 * _bytesPerLine))); - resetSelection(_cursorPosition); - } - if (event->matches(QKeySequence::MoveToEndOfDocument)) - { - setCursorPosition(_chunks->size() * 2 ); - resetSelection(_cursorPosition); - } - if (event->matches(QKeySequence::MoveToStartOfDocument)) - { - setCursorPosition(0); - resetSelection(_cursorPosition); - } - - // Select commands - if (event->matches(QKeySequence::SelectAll)) - { - resetSelection(0); - setSelection(2 * _chunks->size() + 1); - } - if (event->matches(QKeySequence::SelectNextChar)) - { - qint64 pos = _cursorPosition + 1; - if (_editAreaIsAscii) - pos += 1; - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectPreviousChar)) - { - qint64 pos = _cursorPosition - 1; - if (_editAreaIsAscii) - pos -= 1; - setSelection(pos); - setCursorPosition(pos); - } - if (event->matches(QKeySequence::SelectEndOfLine)) - { - qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)) + (2 * _bytesPerLine) - 1; - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectStartOfLine)) - { - qint64 pos = _cursorPosition - (_cursorPosition % (2 * _bytesPerLine)); - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectPreviousLine)) - { - qint64 pos = _cursorPosition - (2 * _bytesPerLine); - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectNextLine)) - { - qint64 pos = _cursorPosition + (2 * _bytesPerLine); - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectNextPage)) - { - qint64 pos = _cursorPosition + (((viewport()->height() / _pxCharHeight) - 1) * 2 * _bytesPerLine); - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectPreviousPage)) - { - qint64 pos = _cursorPosition - (((viewport()->height() / _pxCharHeight) - 1) * 2 * _bytesPerLine); - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectEndOfDocument)) - { - qint64 pos = _chunks->size() * 2; - setCursorPosition(pos); - setSelection(pos); - } - if (event->matches(QKeySequence::SelectStartOfDocument)) - { - qint64 pos = 0; - setCursorPosition(pos); - setSelection(pos); - } - - // Edit Commands - if (!_readOnly) - { - /* Cut */ - if (event->matches(QKeySequence::Cut)) - { - QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); - for (qint64 idx = 32; idx < ba.size(); idx +=33) - ba.insert(idx, "\n"); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(ba); - if (_overwriteMode) - { - qint64 len = getSelectionEnd() - getSelectionBegin(); - replace(getSelectionBegin(), (int)len, QByteArray((int)len, char(0))); - } - else - { - remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); - } - setCursorPosition(2 * getSelectionBegin()); - resetSelection(2 * getSelectionBegin()); - } else - - /* Paste */ - if (event->matches(QKeySequence::Paste)) - { - QClipboard *clipboard = QApplication::clipboard(); - QByteArray ba = QByteArray().fromHex(clipboard->text().toLatin1()); - if (_overwriteMode) - { - ba = ba.left(std::min(ba.size(), (_chunks->size() - _bPosCurrent))); - replace(_bPosCurrent, ba.size(), ba); - } - else - insert(_bPosCurrent, ba); - setCursorPosition(_cursorPosition + 2 * ba.size()); - resetSelection(getSelectionBegin()); - } else - - /* Delete char */ - if (event->matches(QKeySequence::Delete)) - { - if (getSelectionBegin() != getSelectionEnd()) - { - _bPosCurrent = getSelectionBegin(); - if (_overwriteMode) - { - QByteArray ba = QByteArray(getSelectionEnd() - getSelectionBegin(), char(0)); - replace(_bPosCurrent, ba.size(), ba); - } - else - { - remove(_bPosCurrent, getSelectionEnd() - getSelectionBegin()); - } - } - else - { - if (_overwriteMode) - replace(_bPosCurrent, char(0)); - else - remove(_bPosCurrent, 1); - } - setCursorPosition(2 * _bPosCurrent); - resetSelection(2 * _bPosCurrent); - } else - - /* Backspace */ - if ((event->key() == Qt::Key_Backspace) && (event->modifiers() == Qt::NoModifier)) - { - if (getSelectionBegin() != getSelectionEnd()) - { - _bPosCurrent = getSelectionBegin(); - setCursorPosition(2 * _bPosCurrent); - if (_overwriteMode) - { - QByteArray ba = QByteArray(getSelectionEnd() - getSelectionBegin(), char(0)); - replace(_bPosCurrent, ba.size(), ba); - } - else - { - remove(_bPosCurrent, getSelectionEnd() - getSelectionBegin()); - } - resetSelection(2 * _bPosCurrent); - } - else - { - bool behindLastByte = false; - if ((_cursorPosition / 2) == _chunks->size()) - behindLastByte = true; - - _bPosCurrent -= 1; - if (_overwriteMode) - replace(_bPosCurrent, char(0)); - else - remove(_bPosCurrent, 1); - - if (!behindLastByte) - _bPosCurrent -= 1; - - setCursorPosition(2 * _bPosCurrent); - resetSelection(2 * _bPosCurrent); - } - } else - - /* undo */ - if (event->matches(QKeySequence::Undo)) - { - undo(); - } else - - /* redo */ - if (event->matches(QKeySequence::Redo)) - { - redo(); - } else - - if ((QApplication::keyboardModifiers() == Qt::NoModifier) || - (QApplication::keyboardModifiers() == Qt::KeypadModifier) || - (QApplication::keyboardModifiers() == Qt::ShiftModifier) || - (QApplication::keyboardModifiers() == (Qt::AltModifier | Qt::ControlModifier)) || - (QApplication::keyboardModifiers() == Qt::GroupSwitchModifier)) - { - /* Hex and ascii input */ - int key; - if (_editAreaIsAscii) - key = (uchar)event->text()[0].toLatin1(); - else - key = int(event->text()[0].toLower().toLatin1()); - - if ((((key >= '0' && key <= '9') || (key >= 'a' && key <= 'f')) && _editAreaIsAscii == false) - || (key >= ' ' && _editAreaIsAscii)) - { - if (getSelectionBegin() != getSelectionEnd()) - { - if (_overwriteMode) - { - qint64 len = getSelectionEnd() - getSelectionBegin(); - replace(getSelectionBegin(), (int)len, QByteArray((int)len, char(0))); - } else - { - remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); - _bPosCurrent = getSelectionBegin(); - } - setCursorPosition(2 * _bPosCurrent); - resetSelection(2 * _bPosCurrent); - } - - // If insert mode, then insert a byte - if (_overwriteMode == false) - if ((_cursorPosition % 2) == 0) - insert(_bPosCurrent, char(0)); - - // Change content - if (_chunks->size() > 0) - { - char ch = key; - if (!_editAreaIsAscii){ - QByteArray hexValue = _chunks->data(_bPosCurrent, 1).toHex(); - if ((_cursorPosition % 2) == 0) - hexValue[0] = key; - else - hexValue[1] = key; - ch = QByteArray().fromHex(hexValue)[0]; - } - replace(_bPosCurrent, ch); - if (_editAreaIsAscii) - setCursorPosition(_cursorPosition + 2); - else - setCursorPosition(_cursorPosition + 1); - resetSelection(_cursorPosition); - } - } - } - - - } - - /* Copy */ - if (event->matches(QKeySequence::Copy)) - { - QByteArray ba = _chunks->data(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()).toHex(); - for (qint64 idx = 32; idx < ba.size(); idx +=33) - ba.insert(idx, "\n"); - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(ba); - } - - // Switch between insert/overwrite mode - if ((event->key() == Qt::Key_Insert) && (event->modifiers() == Qt::NoModifier)) - { - setOverwriteMode(!overwriteMode()); - setCursorPosition(_cursorPosition); - } - - // switch from hex to ascii edit - if (event->key() == Qt::Key_Tab && !_editAreaIsAscii){ - _editAreaIsAscii = true; - setCursorPosition(_cursorPosition); - } - - // switch from ascii to hex edit - if (event->key() == Qt::Key_Backtab && _editAreaIsAscii){ - _editAreaIsAscii = false; - setCursorPosition(_cursorPosition); - } - - refresh(); - QAbstractScrollArea::keyPressEvent(event); -} - -void QHexEdit::mouseMoveEvent(QMouseEvent * event) -{ - _blink = false; - viewport()->update(); - qint64 actPos = cursorPosition(event->pos()); - if (actPos >= 0) - { - setCursorPosition(actPos); - setSelection(actPos); - } -} - -void QHexEdit::mousePressEvent(QMouseEvent * event) -{ - _blink = false; - viewport()->update(); - qint64 cPos = cursorPosition(event->pos()); - if (cPos >= 0) - { - if (event->button() != Qt::RightButton) - resetSelection(cPos); - setCursorPosition(cPos); - } -} - -void QHexEdit::paintEvent(QPaintEvent *event) -{ - QPainter painter(viewport()); - int pxOfsX = horizontalScrollBar()->value(); - - if (event->rect() != _cursorRect) - { - int pxPosStartY = _pxCharHeight; - - // draw some patterns if needed - painter.fillRect(event->rect(), viewport()->palette().color(QPalette::Base)); - if (_addressArea) - painter.fillRect(QRect(-pxOfsX, event->rect().top(), _pxPosHexX - _pxGapAdrHex/2, height()), _addressAreaColor); - if (_asciiArea) - { - int linePos = _pxPosAsciiX - (_pxGapHexAscii / 2); - painter.setPen(Qt::gray); - painter.drawLine(linePos - pxOfsX, event->rect().top(), linePos - pxOfsX, height()); - } - - painter.setPen(viewport()->palette().color(QPalette::WindowText)); - - // paint address area - if (_addressArea) - { - QString address; - for (int row=0, pxPosY = _pxCharHeight; row <= (_dataShown.size()/_bytesPerLine); row++, pxPosY +=_pxCharHeight) - { - address = QString("%1").arg(_bPosFirst + row*_bytesPerLine + _addressOffset, _addrDigits, 16, QChar('0')); - painter.drawText(_pxPosAdrX - pxOfsX, pxPosY, hexCaps() ? address.toUpper() : address); - } - } - - // paint hex and ascii area - QPen colStandard = QPen(viewport()->palette().color(QPalette::WindowText)); - - painter.setBackgroundMode(Qt::TransparentMode); - - for (int row = 0, pxPosY = pxPosStartY; row <= _rowsShown; row++, pxPosY +=_pxCharHeight) - { - QByteArray hex; - int pxPosX = _pxPosHexX - pxOfsX; - int pxPosAsciiX2 = _pxPosAsciiX - pxOfsX; - qint64 bPosLine = row * _bytesPerLine; - for (int colIdx = 0; ((bPosLine + colIdx) < _dataShown.size() && (colIdx < _bytesPerLine)); colIdx++) - { - QColor c = viewport()->palette().color(QPalette::Base); - painter.setPen(colStandard); - - qint64 posBa = _bPosFirst + bPosLine + colIdx; - if ((getSelectionBegin() <= posBa) && (getSelectionEnd() > posBa)) - { - c = _brushSelection.color(); - painter.setPen(_penSelection); - } - else - { - if (_highlighting) - if (_markedShown.at((int)(posBa - _bPosFirst))) - { - c = _brushHighlighted.color(); - painter.setPen(_penHighlighted); - } - } - - // render hex value - QRect r; - if (colIdx == 0) - r.setRect(pxPosX, pxPosY - _pxCharHeight + _pxSelectionSub, 2*_pxCharWidth, _pxCharHeight); - else - r.setRect(pxPosX - _pxCharWidth, pxPosY - _pxCharHeight + _pxSelectionSub, 3*_pxCharWidth, _pxCharHeight); - painter.fillRect(r, c); - hex = _hexDataShown.mid((bPosLine + colIdx) * 2, 2); - painter.drawText(pxPosX, pxPosY, hexCaps()?hex.toUpper():hex); - pxPosX += 3*_pxCharWidth; - - // render ascii value - if (_asciiArea) - { - int ch = (uchar)_dataShown.at(bPosLine + colIdx); - if ( ch < ' ' || ch > '~' ) - ch = '.'; - r.setRect(pxPosAsciiX2, pxPosY - _pxCharHeight + _pxSelectionSub, _pxCharWidth, _pxCharHeight); - painter.fillRect(r, c); - painter.drawText(pxPosAsciiX2, pxPosY, QChar(ch)); - pxPosAsciiX2 += _pxCharWidth; - } - } - } - painter.setBackgroundMode(Qt::TransparentMode); - painter.setPen(viewport()->palette().color(QPalette::WindowText)); - } - - // _cursorPosition counts in 2, _bPosFirst counts in 1 - int hexPositionInShowData = _cursorPosition - 2 * _bPosFirst; - - // due to scrolling the cursor can go out of the currently displayed data - if ((hexPositionInShowData >= 0) && (hexPositionInShowData < _hexDataShown.size())) - { - // paint cursor - if (_readOnly) - { - // make the background stick out - QColor color = viewport()->palette().dark().color(); - painter.fillRect(QRect(_pxCursorX - pxOfsX, _pxCursorY - _pxCharHeight + _pxSelectionSub, _pxCharWidth, _pxCharHeight), color); - } - else - { - if (_blink && hasFocus()) - painter.fillRect(_cursorRect, this->palette().color(QPalette::WindowText)); - } - - if (_editAreaIsAscii) - { - // every 2 hex there is 1 ascii - int asciiPositionInShowData = hexPositionInShowData / 2; - int ch = (uchar)_dataShown.at(asciiPositionInShowData); - if (ch < ' ' || ch > '~') - ch = '.'; - painter.drawText(_pxCursorX - pxOfsX, _pxCursorY, QChar(ch)); - } - else - { - painter.drawText(_pxCursorX - pxOfsX, _pxCursorY, hexCaps() ? _hexDataShown.mid(hexPositionInShowData, 1).toUpper() : _hexDataShown.mid(hexPositionInShowData, 1)); - } - } - - // emit event, if size has changed - if (_lastEventSize != _chunks->size()) - { - _lastEventSize = _chunks->size(); - emit currentSizeChanged(_lastEventSize); - } -} - -void QHexEdit::resizeEvent(QResizeEvent *) -{ - if (_dynamicBytesPerLine) - { - int pxFixGaps = 0; - if (_addressArea) - pxFixGaps = addressWidth() * _pxCharWidth + _pxGapAdr; - pxFixGaps += _pxGapAdrHex; - if (_asciiArea) - pxFixGaps += _pxGapHexAscii; - - // +1 because the last hex value do not have space. so it is effective one char more - int charWidth = (viewport()->width() - pxFixGaps ) / _pxCharWidth + 1; - - // 2 hex alfa-digits 1 space 1 ascii per byte = 4; if ascii is disabled then 3 - // to prevent devision by zero use the min value 1 - setBytesPerLine(std::max(charWidth / (_asciiArea ? 4 : 3),1)); - } - adjust(); -} - -bool QHexEdit::focusNextPrevChild(bool next) -{ - if (_addressArea) - { - if ( (next && _editAreaIsAscii) || (!next && !_editAreaIsAscii )) - return QWidget::focusNextPrevChild(next); - else - return false; - } - else - { - return QWidget::focusNextPrevChild(next); - } -} - -// ********************************************************************** Handle selections -void QHexEdit::resetSelection() -{ - _bSelectionBegin = _bSelectionInit; - _bSelectionEnd = _bSelectionInit; -} - -void QHexEdit::resetSelection(qint64 pos) -{ - pos = pos / 2 ; - if (pos < 0) - pos = 0; - if (pos > _chunks->size()) - pos = _chunks->size(); - - _bSelectionInit = pos; - _bSelectionBegin = pos; - _bSelectionEnd = pos; -} - -void QHexEdit::setSelection(qint64 pos) -{ - pos = pos / 2; - if (pos < 0) - pos = 0; - if (pos > _chunks->size()) - pos = _chunks->size(); - - if (pos >= _bSelectionInit) - { - _bSelectionEnd = pos; - _bSelectionBegin = _bSelectionInit; - } - else - { - _bSelectionBegin = pos; - _bSelectionEnd = _bSelectionInit; - } -} - -qint64 QHexEdit::getSelectionBegin() -{ - return _bSelectionBegin; -} - -qint64 QHexEdit::getSelectionEnd() -{ - return _bSelectionEnd; -} - -// ********************************************************************** Private utility functions -void QHexEdit::init() -{ - //_undoStack->clear(); - setAddressOffset(0); - resetSelection(0); - setCursorPosition(0); - verticalScrollBar()->setValue(0); - _modified = false; -} - -void QHexEdit::adjust() -{ - // recalc Graphics - if (_addressArea) - { - _addrDigits = addressWidth(); - _pxPosHexX = _pxGapAdr + _addrDigits*_pxCharWidth + _pxGapAdrHex; - } - else - _pxPosHexX = _pxGapAdrHex; - _pxPosAdrX = _pxGapAdr; - _pxPosAsciiX = _pxPosHexX + _hexCharsInLine * _pxCharWidth + _pxGapHexAscii; - - // set horizontalScrollBar() - int pxWidth = _pxPosAsciiX; - if (_asciiArea) - pxWidth += _bytesPerLine*_pxCharWidth; - horizontalScrollBar()->setRange(0, pxWidth - viewport()->width()); - horizontalScrollBar()->setPageStep(viewport()->width()); - - // set verticalScrollbar() - _rowsShown = ((viewport()->height()-4)/_pxCharHeight); - int lineCount = (int)(_chunks->size() / (qint64)_bytesPerLine) + 1; - verticalScrollBar()->setRange(0, lineCount - _rowsShown); - verticalScrollBar()->setPageStep(_rowsShown); - - int value = verticalScrollBar()->value(); - _bPosFirst = (qint64)value * _bytesPerLine; - _bPosLast = _bPosFirst + (qint64)(_rowsShown * _bytesPerLine) - 1; - if (_bPosLast >= _chunks->size()) - _bPosLast = _chunks->size() - 1; - readBuffers(); - setCursorPosition(_cursorPosition); -} - -void QHexEdit::dataChangedPrivate(int) -{ - _modified = 0; //_undoStack->index() != 0; - adjust(); - emit dataChanged(); -} - -void QHexEdit::refresh() -{ - ensureVisible(); - readBuffers(); -} - -void QHexEdit::readBuffers() -{ - _dataShown = _chunks->data(_bPosFirst, _bPosLast - _bPosFirst + _bytesPerLine + 1, &_markedShown); - _hexDataShown = QByteArray(_dataShown.toHex()); -} - -QString QHexEdit::toReadable(const QByteArray &ba) -{ - QString result; - - for (int i=0; i < ba.size(); i += 16) - { - QString addrStr = QString("%1").arg(_addressOffset + i, addressWidth(), 16, QChar('0')); - QString hexStr; - QString ascStr; - for (int j=0; j<16; j++) - { - if ((i + j) < ba.size()) - { - hexStr.append(" ").append(ba.mid(i+j, 1).toHex()); - char ch = ba[i + j]; - if ((ch < 0x20) || (ch > 0x7e)) - ch = '.'; - ascStr.append(QChar(ch)); - } - } - result += addrStr + " " + QString("%1").arg(hexStr, -48) + " " + QString("%1").arg(ascStr, -17) + "\n"; - } - return result; -} - -void QHexEdit::updateCursor() -{ - if (_blink) - _blink = false; - else - _blink = true; - viewport()->update(_cursorRect); -} diff --git a/src/drivers/Qt/QHexEdit.h b/src/drivers/Qt/QHexEdit.h deleted file mode 100644 index df585cdd..00000000 --- a/src/drivers/Qt/QHexEdit.h +++ /dev/null @@ -1,424 +0,0 @@ -#ifndef QHEXEDIT_H -#define QHEXEDIT_H - -#include -#include -#include -#include - -#include "Qt/chunks.h" -//#include "commands.h" - -#ifdef QHEXEDIT_EXPORTS -#define QHEXEDIT_API Q_DECL_EXPORT -#elif QHEXEDIT_IMPORTS -#define QHEXEDIT_API Q_DECL_IMPORT -#else -#define QHEXEDIT_API -#endif - -/** \mainpage -QHexEdit is a binary editor widget for Qt. - -\version Version 0.8.9 -\image html qhexedit.png -*/ - - -/** QHexEdit is a hex editor widget written in C++ for the Qt (Qt4, Qt5) framework. -It is a simple editor for binary data, just like QPlainTextEdit is for text -data. There are sip configuration files included, so it is easy to create -bindings for PyQt and you can use this widget also in python 2 and 3. - -QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use -the mouse or the keyboard to navigate inside the widget. If you hit the keys -(0..9, a..f) you will change the data. Changed data is highlighted and can be -accessed via data(). - -Normally QHexEdit works in the overwrite mode. You can set overwrite mode(false) -and insert data. In this case the size of data() increases. It is also possible -to delete bytes (del or backspace), here the size of data decreases. - -You can select data with keyboard hits or mouse movements. The copy-key will -copy the selected data into the clipboard. The cut-key copies also but deletes -it afterwards. In overwrite mode, the paste function overwrites the content of -the (does not change the length) data. In insert mode, clipboard data will be -inserted. The clipboard content is expected in ASCII Hex notation. Unknown -characters will be ignored. - -QHexEdit comes with undo/redo functionality. All changes can be undone, by -pressing the undo-key (usually ctr-z). They can also be redone afterwards. -The undo/redo framework is cleared, when setData() sets up a new -content for the editor. You can search data inside the content with indexOf() -and lastIndexOf(). The replace() function is to change located subdata. This -'replaced' data can also be undone by the undo/redo framework. - -QHexEdit is based on QIODevice, that's why QHexEdit can handle big amounts of -data. The size of edited data can be more then two gigabytes without any -restrictions. -*/ -class QHEXEDIT_API QHexEdit : public QAbstractScrollArea -{ - Q_OBJECT - - /*! Property address area switch the address area on or off. Set addressArea true - (show it), false (hide it). - */ - Q_PROPERTY(bool addressArea READ addressArea WRITE setAddressArea) - - /*! Property address area color sets (setAddressAreaColor()) the background - color of address areas. You can also read the color (addressAreaColor()). - */ - Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor) - - /*! Property addressOffset is added to the Numbers of the Address Area. - A offset in the address area (left side) is sometimes useful, whe you show - only a segment of a complete memory picture. With setAddressOffset() you set - this property - with addressOffset() you get the current value. - */ - Q_PROPERTY(qint64 addressOffset READ addressOffset WRITE setAddressOffset) - - /*! Set and get the minimum width of the address area, width in characters. - */ - Q_PROPERTY(int addressWidth READ addressWidth WRITE setAddressWidth) - - /*! Switch the ascii area on (true, show it) or off (false, hide it). - */ - Q_PROPERTY(bool asciiArea READ asciiArea WRITE setAsciiArea) - - /*! Set and get bytes number per line.*/ - Q_PROPERTY(int bytesPerLine READ bytesPerLine WRITE setBytesPerLine) - - /*! Property cursorPosition sets or gets the position of the editor cursor - in QHexEdit. Every byte in data has two cursor positions: the lower and upper - Nibble. Maximum cursor position is factor two of data.size(). - */ - Q_PROPERTY(qint64 cursorPosition READ cursorPosition WRITE setCursorPosition) - - /*! Property data holds the content of QHexEdit. Call setData() to set the - content of QHexEdit, data() returns the actual content. When calling setData() - with a QByteArray as argument, QHexEdit creates a internal copy of the data - If you want to edit big files please use setData(), based on QIODevice. - */ - Q_PROPERTY(QByteArray data READ data WRITE setData NOTIFY dataChanged) - - /*! That property defines if the hex values looks as a-f if the value is false(default) - or A-F if value is true. - */ - Q_PROPERTY(bool hexCaps READ hexCaps WRITE setHexCaps) - - /*! Property defines the dynamic calculation of bytesPerLine parameter depends of width of widget. - set this property true to avoid horizontal scrollbars and show the maximal possible data. defalut value is false*/ - Q_PROPERTY(bool dynamicBytesPerLine READ dynamicBytesPerLine WRITE setDynamicBytesPerLine) - - /*! Switch the highlighting feature on or of: true (show it), false (hide it). - */ - Q_PROPERTY(bool highlighting READ highlighting WRITE setHighlighting) - - /*! Property highlighting color sets (setHighlightingColor()) the background - color of highlighted text areas. You can also read the color - (highlightingColor()). - */ - Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor) - - /*! Property overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode - in which the editor works. In overwrite mode the user will overwrite existing data. The - size of data will be constant. In insert mode the size will grow, when inserting - new data. - */ - Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode) - - /*! Property selection color sets (setSelectionColor()) the background - color of selected text areas. You can also read the color - (selectionColor()). - */ - Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor) - - /*! Property readOnly sets (setReadOnly()) or gets (isReadOnly) the mode - in which the editor works. In readonly mode the the user can only navigate - through the data and select data; modifying is not possible. This - property's default is false. - */ - Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) - - /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/ - Q_PROPERTY(QFont font READ font WRITE setFont) - -public: - /*! Creates an instance of QHexEdit. - \param parent Parent widget of QHexEdit. - */ - QHexEdit(QWidget *parent=0); - - // Access to data of qhexedit - - /*! Sets the data of QHexEdit. The QIODevice will be opened just before reading - and closed immediately afterwards. This is to allow other programs to rewrite - the file while editing it. - */ - bool setData(QIODevice &iODevice); - - /*! Gives back the data as a QByteArray starting at position \param pos and - delivering \param count bytes. - */ - QByteArray dataAt(qint64 pos, qint64 count=-1); - - /*! Gives back the data into a \param iODevice starting at position \param pos - and delivering \param count bytes. - */ - bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1); - - - // Char handling - - /*! Inserts a char. - \param pos Index position, where to insert - \param ch Char, which is to insert - The char will be inserted and size of data grows. - */ - void insert(qint64 pos, char ch); - - /*! Removes len bytes from the content. - \param pos Index position, where to remove - \param len Amount of bytes to remove - */ - void remove(qint64 pos, qint64 len=1); - - /*! Replaces a char. - \param pos Index position, where to overwrite - \param ch Char, which is to insert - The char will be overwritten and size remains constant. - */ - void replace(qint64 pos, char ch); - - - // ByteArray handling - - /*! Inserts a byte array. - \param pos Index position, where to insert - \param ba QByteArray, which is to insert - The QByteArray will be inserted and size of data grows. - */ - void insert(qint64 pos, const QByteArray &ba); - - /*! Replaces \param len bytes with a byte array \param ba - \param pos Index position, where to overwrite - \param ba QByteArray, which is inserted - \param len count of bytes to overwrite - The data is overwritten and size of data may change. - */ - void replace(qint64 pos, qint64 len, const QByteArray &ba); - - - // Utility functions - /*! Calc cursor position from graphics position - * \param point from where the cursor position should be calculated - * \return Cursor position - */ - qint64 cursorPosition(QPoint point); - - /*! Ensure the cursor to be visbile - */ - void ensureVisible(); - - /*! Find first occurrence of ba in QHexEdit data - * \param ba Data to find - * \param from Point where the search starts - * \return pos if fond, else -1 - */ - qint64 indexOf(const QByteArray &ba, qint64 from); - - /*! Returns if any changes where done on document - * \return true when document is modified else false - */ - bool isModified(); - - /*! Find last occurrence of ba in QHexEdit data - * \param ba Data to find - * \param from Point where the search starts - * \return pos if fond, else -1 - */ - qint64 lastIndexOf(const QByteArray &ba, qint64 from); - - /*! Gives back a formatted image of the selected content of QHexEdit - */ - QString selectionToReadableString(); - - /*! Return the selected content of QHexEdit as QByteArray - */ - QString selectedData(); - - /*! Set Font of QHexEdit - * \param font - */ - void setFont(const QFont &font); - - /*! Gives back a formatted image of the content of QHexEdit - */ - QString toReadableString(); - - -public slots: - /*! Redoes the last operation. If there is no operation to redo, i.e. - there is no redo step in the undo/redo history, nothing happens. - */ - void redo(); - - /*! Undoes the last operation. If there is no operation to undo, i.e. - there is no undo step in the undo/redo history, nothing happens. - */ - void undo(); - -signals: - - /*! Contains the address, where the cursor is located. */ - void currentAddressChanged(qint64 address); - - /*! Contains the size of the data to edit. */ - void currentSizeChanged(qint64 size); - - /*! The signal is emitted every time, the data is changed. */ - void dataChanged(); - - /*! The signal is emitted every time, the overwrite mode is changed. */ - void overwriteModeChanged(bool state); - - -/*! \cond docNever */ -public: - ~QHexEdit(); - - // Properties - bool addressArea(); - void setAddressArea(bool addressArea); - - QColor addressAreaColor(); - void setAddressAreaColor(const QColor &color); - - qint64 addressOffset(); - void setAddressOffset(qint64 addressArea); - - int addressWidth(); - void setAddressWidth(int addressWidth); - - bool asciiArea(); - void setAsciiArea(bool asciiArea); - - int bytesPerLine(); - void setBytesPerLine(int count); - - qint64 cursorPosition(); - void setCursorPosition(qint64 position); - - QByteArray data(); - void setData(const QByteArray &ba); - - void setHexCaps(const bool isCaps); - bool hexCaps(); - - void setDynamicBytesPerLine(const bool isDynamic); - bool dynamicBytesPerLine(); - - bool highlighting(); - void setHighlighting(bool mode); - - QColor highlightingColor(); - void setHighlightingColor(const QColor &color); - - bool overwriteMode(); - void setOverwriteMode(bool overwriteMode); - - bool isReadOnly(); - void setReadOnly(bool readOnly); - - QColor selectionColor(); - void setSelectionColor(const QColor &color); - -protected: - // Handle events - void keyPressEvent(QKeyEvent *event); - void mouseMoveEvent(QMouseEvent * event); - void mousePressEvent(QMouseEvent * event); - void paintEvent(QPaintEvent *event); - void resizeEvent(QResizeEvent *); - virtual bool focusNextPrevChild(bool next); -private: - // Handle selections - void resetSelection(qint64 pos); // set selectionStart and selectionEnd to pos - void resetSelection(); // set selectionEnd to selectionStart - void setSelection(qint64 pos); // set min (if below init) or max (if greater init) - qint64 getSelectionBegin(); - qint64 getSelectionEnd(); - - // Private utility functions - void init(); - void readBuffers(); - QString toReadable(const QByteArray &ba); - -private slots: - void adjust(); // recalc pixel positions - void dataChangedPrivate(int idx=0); // emit dataChanged() signal - void refresh(); // ensureVisible() and readBuffers() - void updateCursor(); // update blinking cursor - -private: - // Name convention: pixel positions start with _px - int _pxCharWidth, _pxCharHeight; // char dimensions (dependend on font) - int _pxPosHexX; // X-Pos of HeaxArea - int _pxPosAdrX; // X-Pos of Address Area - int _pxPosAsciiX; // X-Pos of Ascii Area - int _pxGapAdr; // gap left from AddressArea - int _pxGapAdrHex; // gap between AddressArea and HexAerea - int _pxGapHexAscii; // gap between HexArea and AsciiArea - int _pxCursorWidth; // cursor width - int _pxSelectionSub; // offset selection rect - int _pxCursorX; // current cursor pos - int _pxCursorY; // current cursor pos - - // Name convention: absolute byte positions in chunks start with _b - qint64 _bSelectionBegin; // first position of Selection - qint64 _bSelectionEnd; // end of Selection - qint64 _bSelectionInit; // memory position of Selection - qint64 _bPosFirst; // position of first byte shown - qint64 _bPosLast; // position of last byte shown - qint64 _bPosCurrent; // current position - - // variables to store the property values - bool _addressArea; // left area of QHexEdit - QColor _addressAreaColor; - int _addressWidth; - bool _asciiArea; - qint64 _addressOffset; - int _bytesPerLine; - int _hexCharsInLine; - bool _highlighting; - bool _overwriteMode; - QBrush _brushSelection; - QPen _penSelection; - QBrush _brushHighlighted; - QPen _penHighlighted; - bool _readOnly; - bool _hexCaps; - bool _dynamicBytesPerLine; - - // other variables - bool _editAreaIsAscii; // flag about the ascii mode edited - int _addrDigits; // real no of addressdigits, may be > addressWidth - bool _blink; // help get cursor blinking - QBuffer _bData; // buffer, when setup with QByteArray - Chunks *_chunks; // IODevice based access to data - QTimer _cursorTimer; // for blinking cursor - qint64 _cursorPosition; // absolute position of cursor, 1 Byte == 2 tics - QRect _cursorRect; // physical dimensions of cursor - QByteArray _data; // QHexEdit's data, when setup with QByteArray - QByteArray _dataShown; // data in the current View - QByteArray _hexDataShown; // data in view, transformed to hex - qint64 _lastEventSize; // size, which was emitted last time - QByteArray _markedShown; // marked data in view - bool _modified; // Is any data in editor modified? - int _rowsShown; // lines of text shown - //UndoStack * _undoStack; // Stack to store edit actions for undo/redo - /*! \endcond docNever */ -}; - -#endif // QHEXEDIT_H diff --git a/src/drivers/Qt/chunks.cpp b/src/drivers/Qt/chunks.cpp deleted file mode 100644 index a4e420bf..00000000 --- a/src/drivers/Qt/chunks.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "chunks.h" -#include - -#define NORMAL 0 -#define HIGHLIGHTED 1 - -#define BUFFER_SIZE 0x10000 -#define CHUNK_SIZE 0x1000 -#define READ_CHUNK_MASK Q_INT64_C(0xfffffffffffff000) - -// ***************************************** Constructors and file settings - -Chunks::Chunks(QObject *parent): QObject(parent) -{ - QBuffer *buf = new QBuffer(this); - setIODevice(*buf); -} - -Chunks::Chunks(QIODevice &ioDevice, QObject *parent): QObject(parent) -{ - setIODevice(ioDevice); -} - -bool Chunks::setIODevice(QIODevice &ioDevice) -{ - _ioDevice = &ioDevice; - bool ok = _ioDevice->open(QIODevice::ReadOnly); - if (ok) // Try to open IODevice - { - _size = _ioDevice->size(); - _ioDevice->close(); - } - else // Fallback is an empty buffer - { - QBuffer *buf = new QBuffer(this); - _ioDevice = buf; - _size = 0; - } - _chunks.clear(); - _pos = 0; - return ok; -} - - -// ***************************************** Getting data out of Chunks - -QByteArray Chunks::data(qint64 pos, qint64 maxSize, QByteArray *highlighted) -{ - qint64 ioDelta = 0; - int chunkIdx = 0; - - Chunk chunk; - QByteArray buffer; - - // Do some checks and some arrangements - if (highlighted) - highlighted->clear(); - - if (pos >= _size) - return buffer; - - if (maxSize < 0) - maxSize = _size; - else - if ((pos + maxSize) > _size) - maxSize = _size - pos; - - _ioDevice->open(QIODevice::ReadOnly); - - while (maxSize > 0) - { - chunk.absPos = LLONG_MAX; - bool chunksLoopOngoing = true; - while ((chunkIdx < _chunks.count()) && chunksLoopOngoing) - { - // In this section, we track changes before our required data and - // we take the editdet data, if availible. ioDelta is a difference - // counter to justify the read pointer to the original data, if - // data in between was deleted or inserted. - - chunk = _chunks[chunkIdx]; - if (chunk.absPos > pos) - chunksLoopOngoing = false; - else - { - chunkIdx += 1; - qint64 count; - qint64 chunkOfs = pos - chunk.absPos; - if (maxSize > ((qint64)chunk.data.size() - chunkOfs)) - { - count = (qint64)chunk.data.size() - chunkOfs; - ioDelta += CHUNK_SIZE - chunk.data.size(); - } - else - count = maxSize; - if (count > 0) - { - buffer += chunk.data.mid(chunkOfs, (int)count); - maxSize -= count; - pos += count; - if (highlighted) - *highlighted += chunk.dataChanged.mid(chunkOfs, (int)count); - } - } - } - - if ((maxSize > 0) && (pos < chunk.absPos)) - { - // In this section, we read data from the original source. This only will - // happen, whe no copied data is available - - qint64 byteCount; - QByteArray readBuffer; - if ((chunk.absPos - pos) > maxSize) - byteCount = maxSize; - else - byteCount = chunk.absPos - pos; - - maxSize -= byteCount; - _ioDevice->seek(pos + ioDelta); - readBuffer = _ioDevice->read(byteCount); - buffer += readBuffer; - if (highlighted) - *highlighted += QByteArray(readBuffer.size(), NORMAL); - pos += readBuffer.size(); - } - } - _ioDevice->close(); - return buffer; -} - -bool Chunks::write(QIODevice &iODevice, qint64 pos, qint64 count) -{ - if (count == -1) - count = _size; - bool ok = iODevice.open(QIODevice::WriteOnly); - if (ok) - { - for (qint64 idx=pos; idx < count; idx += BUFFER_SIZE) - { - QByteArray ba = data(idx, BUFFER_SIZE); - iODevice.write(ba); - } - iODevice.close(); - } - return ok; -} - - -// ***************************************** Set and get highlighting infos - -void Chunks::setDataChanged(qint64 pos, bool dataChanged) -{ - if ((pos < 0) || (pos >= _size)) - return; - int chunkIdx = getChunkIndex(pos); - qint64 posInBa = pos - _chunks[chunkIdx].absPos; - _chunks[chunkIdx].dataChanged[(int)posInBa] = char(dataChanged); -} - -bool Chunks::dataChanged(qint64 pos) -{ - QByteArray highlighted; - data(pos, 1, &highlighted); - return bool(highlighted.at(0)); -} - - -// ***************************************** Search API - -qint64 Chunks::indexOf(const QByteArray &ba, qint64 from) -{ - qint64 result = -1; - QByteArray buffer; - - for (qint64 pos=from; (pos < _size) && (result < 0); pos += BUFFER_SIZE) - { - buffer = data(pos, BUFFER_SIZE + ba.size() - 1); - int findPos = buffer.indexOf(ba); - if (findPos >= 0) - result = pos + (qint64)findPos; - } - return result; -} - -qint64 Chunks::lastIndexOf(const QByteArray &ba, qint64 from) -{ - qint64 result = -1; - QByteArray buffer; - - for (qint64 pos=from; (pos > 0) && (result < 0); pos -= BUFFER_SIZE) - { - qint64 sPos = pos - BUFFER_SIZE - (qint64)ba.size() + 1; - if (sPos < 0) - sPos = 0; - buffer = data(sPos, pos - sPos); - int findPos = buffer.lastIndexOf(ba); - if (findPos >= 0) - result = sPos + (qint64)findPos; - } - return result; -} - - -// ***************************************** Char manipulations - -bool Chunks::insert(qint64 pos, char b) -{ - if ((pos < 0) || (pos > _size)) - return false; - int chunkIdx; - if (pos == _size) - chunkIdx = getChunkIndex(pos-1); - else - chunkIdx = getChunkIndex(pos); - qint64 posInBa = pos - _chunks[chunkIdx].absPos; - _chunks[chunkIdx].data.insert(posInBa, b); - _chunks[chunkIdx].dataChanged.insert(posInBa, char(1)); - for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) - _chunks[idx].absPos += 1; - _size += 1; - _pos = pos; - return true; -} - -bool Chunks::overwrite(qint64 pos, char b) -{ - if ((pos < 0) || (pos >= _size)) - return false; - int chunkIdx = getChunkIndex(pos); - qint64 posInBa = pos - _chunks[chunkIdx].absPos; - _chunks[chunkIdx].data[(int)posInBa] = b; - _chunks[chunkIdx].dataChanged[(int)posInBa] = char(1); - _pos = pos; - return true; -} - -bool Chunks::removeAt(qint64 pos) -{ - if ((pos < 0) || (pos >= _size)) - return false; - int chunkIdx = getChunkIndex(pos); - qint64 posInBa = pos - _chunks[chunkIdx].absPos; - _chunks[chunkIdx].data.remove(posInBa, 1); - _chunks[chunkIdx].dataChanged.remove(posInBa, 1); - for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) - _chunks[idx].absPos -= 1; - _size -= 1; - _pos = pos; - return true; -} - - -// ***************************************** Utility functions - -char Chunks::operator[](qint64 pos) -{ - return data(pos, 1)[0]; -} - -qint64 Chunks::pos() -{ - return _pos; -} - -qint64 Chunks::size() -{ - return _size; -} - -int Chunks::getChunkIndex(qint64 absPos) -{ - // This routine checks, if there is already a copied chunk available. If os, it - // returns a reference to it. If there is no copied chunk available, original - // data will be copied into a new chunk. - - int foundIdx = -1; - int insertIdx = 0; - qint64 ioDelta = 0; - - - for (int idx=0; idx < _chunks.size(); idx++) - { - Chunk chunk = _chunks[idx]; - if ((absPos >= chunk.absPos) && (absPos < (chunk.absPos + chunk.data.size()))) - { - foundIdx = idx; - break; - } - if (absPos < chunk.absPos) - { - insertIdx = idx; - break; - } - ioDelta += chunk.data.size() - CHUNK_SIZE; - insertIdx = idx + 1; - } - - if (foundIdx == -1) - { - Chunk newChunk; - qint64 readAbsPos = absPos - ioDelta; - qint64 readPos = (readAbsPos & READ_CHUNK_MASK); - _ioDevice->open(QIODevice::ReadOnly); - _ioDevice->seek(readPos); - newChunk.data = _ioDevice->read(CHUNK_SIZE); - _ioDevice->close(); - newChunk.absPos = absPos - (readAbsPos - readPos); - newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0)); - _chunks.insert(insertIdx, newChunk); - foundIdx = insertIdx; - } - return foundIdx; -} - - -#ifdef MODUL_TEST -int Chunks::chunkSize() -{ - return _chunks.size(); -} - -#endif diff --git a/src/drivers/Qt/chunks.h b/src/drivers/Qt/chunks.h deleted file mode 100644 index 43df76ca..00000000 --- a/src/drivers/Qt/chunks.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef CHUNKS_H -#define CHUNKS_H - -/** \cond docNever */ - -/*! The Chunks class is the storage backend for QHexEdit. - * - * When QHexEdit loads data, Chunks access them using a QIODevice interface. When the app uses - * a QByteArray interface, QBuffer is used to provide again a QIODevice like interface. No data - * will be changed, therefore Chunks opens the QIODevice in QIODevice::ReadOnly mode. After every - * access Chunks closes the QIODevice, that's why external applications can overwrite files while - * QHexEdit shows them. - * - * When the the user starts to edit the data, Chunks creates a local copy of a chunk of data (4 - * kilobytes) and notes all changes there. Parallel to that chunk, there is a second chunk, - * which keep track of which bytes are changed and which not. - * - */ - -#include - -struct Chunk -{ - QByteArray data; - QByteArray dataChanged; - qint64 absPos; -}; - -class Chunks: public QObject -{ -Q_OBJECT -public: - // Constructors and file settings - Chunks(QObject *parent); - Chunks(QIODevice &ioDevice, QObject *parent); - bool setIODevice(QIODevice &ioDevice); - - // Getting data out of Chunks - QByteArray data(qint64 pos=0, qint64 count=-1, QByteArray *highlighted=0); - bool write(QIODevice &iODevice, qint64 pos=0, qint64 count=-1); - - // Set and get highlighting infos - void setDataChanged(qint64 pos, bool dataChanged); - bool dataChanged(qint64 pos); - - // Search API - qint64 indexOf(const QByteArray &ba, qint64 from); - qint64 lastIndexOf(const QByteArray &ba, qint64 from); - - // Char manipulations - bool insert(qint64 pos, char b); - bool overwrite(qint64 pos, char b); - bool removeAt(qint64 pos); - - // Utility functions - char operator[](qint64 pos); - qint64 pos(); - qint64 size(); - - -private: - int getChunkIndex(qint64 absPos); - - QIODevice * _ioDevice; - qint64 _pos; - qint64 _size; - QList _chunks; - -#ifdef MODUL_TEST -public: - int chunkSize(); -#endif -}; - -/** \endcond docNever */ - -#endif // CHUNKS_H From 09ec67259733922e46d432b5c234d03aadabad7c Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 19 Aug 2020 22:27:42 -0400 Subject: [PATCH 07/37] Changed approach to Qt hex editor to use raw painting of text. --- src/drivers/Qt/HexEditor.cpp | 133 +++++++++++++++++++++++++++-------- src/drivers/Qt/HexEditor.h | 18 ++++- 2 files changed, 122 insertions(+), 29 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 6ce26075..feccf7b9 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -100,16 +101,18 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) mainLayout = new QVBoxLayout(); - editor = new QPlainTextEdit(this); + editor = new QWidget(this); - editor->setFont(font); - editor->setWordWrapMode(QTextOption::NoWrap); - editor->setOverwriteMode(true); + calcFontData(); mainLayout->addWidget( editor ); setLayout( mainLayout ); + cursorPosX = 0; + cursorPosY = 0; + cursorBlink = true; + cursorBlinkCount = 0; mode = MODE_NES_RAM; numLines = 0; numCharsPerLine = 90; @@ -180,9 +183,6 @@ void HexEditorDialog_t::initMem(void) //---------------------------------------------------------------------------- void HexEditorDialog_t::showMemViewResults (bool reset) { - static unsigned int counter = 0; - std::string txt; - QTextCursor cursor; switch ( mode ) { @@ -246,27 +246,6 @@ void HexEditorDialog_t::showMemViewResults (bool reset) return; } } - - cursor = editor->textCursor(); - - txt.clear(); - - for (int i=0; i<20; i++) - { - char stmp[32]; - sprintf( stmp, "%06X ", i*16 ); - txt.append(stmp); - - for (int j=0; j<16; j++) - { - sprintf( stmp, " %02X ", counter ); counter = (counter + 1) % 256; - txt.append(stmp); - } - txt.append("\n"); - } - editor->setPlainText( QString::fromStdString(txt) ); - - editor->setTextCursor( cursor ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::updatePeriodic(void) @@ -276,6 +255,8 @@ void HexEditorDialog_t::updatePeriodic(void) checkMemActivity(); showMemViewResults(false); + + editor->update(); } //---------------------------------------------------------------------------- int HexEditorDialog_t::checkMemActivity(void) @@ -316,3 +297,99 @@ int HexEditorDialog_t::checkMemActivity(void) return 0; } //---------------------------------------------------------------------------- +void HexEditorDialog_t::calcFontData(void) +{ + editor->setFont(font); + QFontMetrics metrics(font); +#if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) + pxCharWidth = metrics.horizontalAdvance(QLatin1Char('2')); +#else + pxCharWidth = metrics.width(QLatin1Char('2')); +#endif + pxCharHeight = metrics.height(); + pxLineSpacing = metrics.lineSpacing() * 1.25; + pxLineLead = pxLineSpacing - pxCharHeight; + pxXoffset = pxCharHeight; + pxYoffset = pxLineSpacing * 1.25; + pxHexOffset = pxXoffset + (7*pxCharWidth); + pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (2*pxCharWidth); + //_pxGapAdr = _pxCharWidth / 2; + //_pxGapAdrHex = _pxCharWidth; + //_pxGapHexAscii = 2 * _pxCharWidth; + pxCursorHeight = pxCharHeight; + //_pxSelectionSub = _pxCharHeight / 5; +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::paintEvent(QPaintEvent *event) +{ + int x, y, w, h, row, col, nrow, addr; + char txt[32]; + QPainter painter(this); + + painter.setFont(font); + w = event->rect().width(); + h = event->rect().height(); + + //painter.fillRect( 0, 0, w, h, QColor("white") ); + + nrow = (h / pxLineSpacing) + 1; + + if ( nrow < 1 ) nrow = 1; + + //printf("Draw Area: %ix%i \n", event->rect().width(), event->rect().height() ); + // + + + if ( cursorBlinkCount >= 10 ) + { + cursorBlink = !cursorBlink; + cursorBlinkCount = 0; + } + else + { + cursorBlinkCount++; + } + + if ( cursorBlink ) + { + y = pxYoffset + (pxLineSpacing*cursorPosY) - pxCursorHeight + pxLineLead; + + if ( cursorPosX < 32 ) + { + int a = (cursorPosX / 2); + int r = (cursorPosX % 2); + x = pxHexOffset + (a*3*pxCharWidth) + (r*pxCharWidth); + } + else + { + x = pxHexAscii; + } + + painter.fillRect( x , y, pxCharWidth, pxCursorHeight, QColor("gray") ); + } + + + addr = 0; + y = pxYoffset; + + for ( row=0; row < nrow; row++) + { + x = pxXoffset; + + sprintf( txt, "%06X", addr ); + painter.drawText( x, y, txt ); + + x = pxHexOffset; + + for (col=0; col<16; col++) + { + sprintf( txt, "%02X", mbuf[addr+col].data ); + painter.drawText( x, y, txt ); + x += (3*pxCharWidth); + } + addr += 16; + y += pxLineSpacing; + } + +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 852e93dc..6e9d5b02 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -38,9 +38,11 @@ class HexEditorDialog_t : public QDialog MODE_NES_ROM }; protected: + void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); + void calcFontData(void); void initMem(void); void setMode(int new_mode); void showMemViewResults (bool reset); @@ -48,11 +50,24 @@ class HexEditorDialog_t : public QDialog int calcVisibleRange( int *start_out, int *end_out, int *center_out ); QFont font; - QPlainTextEdit *editor; + QWidget *editor; QTimer *periodicTimer; //QByteArray *dataArray; //QBuffer *dataBuffer; + // + int pxCharWidth; + int pxCharHeight; + int pxCursorHeight; + int pxLineSpacing; + int pxLineLead; + int pxXoffset; + int pxYoffset; + int pxHexOffset; + int pxHexAscii; + int cursorPosX; + int cursorPosY; + int cursorBlinkCount; int mode; int numLines; int numCharsPerLine; @@ -64,6 +79,7 @@ class HexEditorDialog_t : public QDialog uint64_t total_instructions_lp; bool redraw; + bool cursorBlink; private: From 9b90d2d6848f2d9d0ed3288e785f75fdf540e927 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Wed, 19 Aug 2020 23:05:01 -0400 Subject: [PATCH 08/37] Updated Hex editor fore/back ground color schemes to use dark background and light foreground text. --- src/drivers/Qt/HexEditor.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index feccf7b9..62e6911d 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -89,6 +89,7 @@ static int getROM( unsigned int offset) HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent ) { + QPalette pal; QVBoxLayout *mainLayout; font.setFamily("Courier New"); @@ -103,6 +104,14 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) editor = new QWidget(this); + pal = editor->palette(); + pal.setColor(QPalette::Base , Qt::black); + pal.setColor(QPalette::Background, Qt::black); + pal.setColor(QPalette::WindowText, Qt::white); + + //editor->setAutoFillBackground(true); + editor->setPalette(pal); + calcFontData(); mainLayout->addWidget( editor ); @@ -310,7 +319,7 @@ void HexEditorDialog_t::calcFontData(void) pxLineSpacing = metrics.lineSpacing() * 1.25; pxLineLead = pxLineSpacing - pxCharHeight; pxXoffset = pxCharHeight; - pxYoffset = pxLineSpacing * 1.25; + pxYoffset = pxLineSpacing * 2.0; pxHexOffset = pxXoffset + (7*pxCharWidth); pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (2*pxCharWidth); //_pxGapAdr = _pxCharWidth / 2; @@ -339,6 +348,7 @@ void HexEditorDialog_t::paintEvent(QPaintEvent *event) //printf("Draw Area: %ix%i \n", event->rect().width(), event->rect().height() ); // + painter.fillRect( 0, 0, w, h, editor->palette().color(QPalette::Background) ); if ( cursorBlinkCount >= 10 ) { @@ -365,10 +375,13 @@ void HexEditorDialog_t::paintEvent(QPaintEvent *event) x = pxHexAscii; } + //painter.setPen( editor->palette().color(QPalette::WindowText)); painter.fillRect( x , y, pxCharWidth, pxCursorHeight, QColor("gray") ); } + painter.setPen( editor->palette().color(QPalette::WindowText)); + //painter.setPen( QColor("white") ); addr = 0; y = pxYoffset; @@ -391,5 +404,9 @@ void HexEditorDialog_t::paintEvent(QPaintEvent *event) y += pxLineSpacing; } + painter.drawText( pxHexOffset, pxLineSpacing, "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" ); + painter.drawLine( pxHexOffset - (pxCharWidth/2), 0, pxHexOffset - (pxCharWidth/2), h ); + painter.drawLine( 0, pxLineSpacing + (pxLineLead), w, pxLineSpacing + (pxLineLead) ); + } //---------------------------------------------------------------------------- From 12f27d21580f08fa1740f8877bf03f61aa3c0b07 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 20 Aug 2020 20:22:24 -0400 Subject: [PATCH 09/37] Moved hex text editor into its own widget QHexEdit --- src/drivers/Qt/HexEditor.cpp | 211 ++++++++++++++++++++--------------- src/drivers/Qt/HexEditor.h | 83 +++++++++----- 2 files changed, 174 insertions(+), 120 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 62e6911d..69a59980 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -85,49 +85,78 @@ static int getROM( unsigned int offset) // } // return c; //} + +//---------------------------------------------------------------------------- +memBlock_t::memBlock_t( void ) +{ + buf = NULL; + _size = 0; + memAccessFunc = NULL; +} +//---------------------------------------------------------------------------- + +memBlock_t::~memBlock_t(void) +{ + if ( buf != NULL ) + { + ::free( buf ); buf = NULL; + } + _size = 0; +} + +//---------------------------------------------------------------------------- +int memBlock_t::reAlloc( int newSize ) +{ + if ( buf != NULL ) + { + ::free( buf ); buf = NULL; + } + _size = 0; + + buf = (struct memByte_t *)malloc( newSize * sizeof(struct memByte_t) ); + + if ( buf != NULL ) + { + _size = newSize; + init(); + } + return (buf != NULL); +} +//---------------------------------------------------------------------------- +void memBlock_t::setAccessFunc( int (*newMemAccessFunc)( unsigned int offset) ) +{ + memAccessFunc = newMemAccessFunc; +} +//---------------------------------------------------------------------------- +void memBlock_t::init(void) +{ + for (int i=0; i<_size; i++) + { + buf[i].data = memAccessFunc(i); + buf[i].color = 0; + buf[i].actv = 0; + //buf[i].draw = 1; + } +} //---------------------------------------------------------------------------- HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent ) { - QPalette pal; QVBoxLayout *mainLayout; - font.setFamily("Courier New"); - font.setStyle( QFont::StyleNormal ); - font.setStyleHint( QFont::Monospace ); - setWindowTitle("Hex Editor"); resize( 512, 512 ); mainLayout = new QVBoxLayout(); - editor = new QWidget(this); - - pal = editor->palette(); - pal.setColor(QPalette::Base , Qt::black); - pal.setColor(QPalette::Background, Qt::black); - pal.setColor(QPalette::WindowText, Qt::white); - - //editor->setAutoFillBackground(true); - editor->setPalette(pal); - - calcFontData(); + editor = new QHexEdit( &mb, this); mainLayout->addWidget( editor ); setLayout( mainLayout ); - cursorPosX = 0; - cursorPosY = 0; - cursorBlink = true; - cursorBlinkCount = 0; mode = MODE_NES_RAM; - numLines = 0; - numCharsPerLine = 90; - mbuf = NULL; - memSize = 0; - mbuf_size = 0; memAccessFunc = getRAM; redraw = false; total_instructions_lp = 0; @@ -144,11 +173,6 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) HexEditorDialog_t::~HexEditorDialog_t(void) { periodicTimer->stop(); - - if ( mbuf != NULL ) - { - ::free( mbuf ); mbuf = NULL; - } } //---------------------------------------------------------------------------- void HexEditorDialog_t::closeWindow(void) @@ -157,18 +181,6 @@ void HexEditorDialog_t::closeWindow(void) done(0); } //---------------------------------------------------------------------------- -void HexEditorDialog_t::keyPressEvent(QKeyEvent *event) -{ - printf("Hex Window Key Press: 0x%x \n", event->key() ); - //assignHotkey( event ); -} -//---------------------------------------------------------------------------- -void HexEditorDialog_t::keyReleaseEvent(QKeyEvent *event) -{ - printf("Hex Window Key Release: 0x%x \n", event->key() ); - //assignHotkey( event ); -} -//---------------------------------------------------------------------------- void HexEditorDialog_t::setMode(int new_mode) { if ( mode != new_mode ) @@ -178,20 +190,9 @@ void HexEditorDialog_t::setMode(int new_mode) } } //---------------------------------------------------------------------------- -void HexEditorDialog_t::initMem(void) -{ - - for (int i=0; isetPlainText("No ROM Loaded"); return; } break; } - numLines = memSize / 16; - if ( (mbuf == NULL) || (mbuf_size != memSize) ) + if ( memSize != mb.size() ) { - printf("Mode: %i MemSize:%i 0x%08x\n", mode, memSize, (unsigned int)memSize ); - reset = 1; + mb.setAccessFunc( memAccessFunc ); - if ( mbuf ) - { - free(mbuf); mbuf = NULL; - } - mbuf = (struct memByte_t *)malloc( memSize * sizeof(struct memByte_t) ); - - if ( mbuf ) - { - mbuf_size = memSize; - initMem(); - } - else + if ( mb.reAlloc( memSize ) ) { printf("Error: Failed to allocate memview buffer size\n"); - mbuf_size = 0; return; } } @@ -282,22 +262,22 @@ int HexEditorDialog_t::checkMemActivity(void) return -1; } - for (int i=0; i 0 ) + if ( mb.buf[i].actv > 0 ) { - //mbuf[i].draw = 1; - mbuf[i].actv--; + //mb.buf[i].draw = 1; + mb.buf[i].actv--; } } } @@ -306,9 +286,42 @@ int HexEditorDialog_t::checkMemActivity(void) return 0; } //---------------------------------------------------------------------------- -void HexEditorDialog_t::calcFontData(void) +QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) + : QWidget( parent ) { - editor->setFont(font); + QPalette pal; + + mb = blkPtr; + + font.setFamily("Courier New"); + font.setStyle( QFont::StyleNormal ); + font.setStyleHint( QFont::Monospace ); + + pal = this->palette(); + pal.setColor(QPalette::Base , Qt::black); + pal.setColor(QPalette::Background, Qt::black); + pal.setColor(QPalette::WindowText, Qt::white); + + //editor->setAutoFillBackground(true); + this->setPalette(pal); + + calcFontData(); + + cursorPosX = 0; + cursorPosY = 0; + cursorBlink = true; + cursorBlinkCount = 0; + +} +//---------------------------------------------------------------------------- +QHexEdit::~QHexEdit(void) +{ + +} +//---------------------------------------------------------------------------- +void QHexEdit::calcFontData(void) +{ + this->setFont(font); QFontMetrics metrics(font); #if QT_VERSION > QT_VERSION_CHECK(5, 11, 0) pxCharWidth = metrics.horizontalAdvance(QLatin1Char('2')); @@ -329,7 +342,19 @@ void HexEditorDialog_t::calcFontData(void) //_pxSelectionSub = _pxCharHeight / 5; } //---------------------------------------------------------------------------- -void HexEditorDialog_t::paintEvent(QPaintEvent *event) +void QHexEdit::keyPressEvent(QKeyEvent *event) +{ + printf("Hex Window Key Press: 0x%x \n", event->key() ); + //assignHotkey( event ); +} +//---------------------------------------------------------------------------- +void QHexEdit::keyReleaseEvent(QKeyEvent *event) +{ + printf("Hex Window Key Release: 0x%x \n", event->key() ); + //assignHotkey( event ); +} +//---------------------------------------------------------------------------- +void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; char txt[32]; @@ -348,7 +373,7 @@ void HexEditorDialog_t::paintEvent(QPaintEvent *event) //printf("Draw Area: %ix%i \n", event->rect().width(), event->rect().height() ); // - painter.fillRect( 0, 0, w, h, editor->palette().color(QPalette::Background) ); + painter.fillRect( 0, 0, w, h, this->palette().color(QPalette::Background) ); if ( cursorBlinkCount >= 10 ) { @@ -375,11 +400,11 @@ void HexEditorDialog_t::paintEvent(QPaintEvent *event) x = pxHexAscii; } - //painter.setPen( editor->palette().color(QPalette::WindowText)); + //painter.setPen( this->palette().color(QPalette::WindowText)); painter.fillRect( x , y, pxCharWidth, pxCursorHeight, QColor("gray") ); } - painter.setPen( editor->palette().color(QPalette::WindowText)); + painter.setPen( this->palette().color(QPalette::WindowText)); //painter.setPen( QColor("white") ); addr = 0; @@ -396,7 +421,7 @@ void HexEditorDialog_t::paintEvent(QPaintEvent *event) for (col=0; col<16; col++) { - sprintf( txt, "%02X", mbuf[addr+col].data ); + sprintf( txt, "%02X", mb->buf[addr+col].data ); painter.drawText( x, y, txt ); x += (3*pxCharWidth); } diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 6e9d5b02..a2faf616 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -23,6 +23,58 @@ struct memByte_t unsigned char actv; }; +struct memBlock_t +{ + memBlock_t(void); + ~memBlock_t(void); + + void init(void); + int size(void){ return _size; } + int reAlloc( int newSize ); + void setAccessFunc( int (*newMemAccessFunc)( unsigned int offset) ); + + struct memByte_t *buf; + int _size; + int (*memAccessFunc)( unsigned int offset); +}; + +class QHexEdit : public QWidget +{ + Q_OBJECT + + public: + QHexEdit(memBlock_t *blkPtr, QWidget *parent = 0); + ~QHexEdit(void); + + protected: + void paintEvent(QPaintEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + + void calcFontData(void); + + QFont font; + + memBlock_t *mb; + + int pxCharWidth; + int pxCharHeight; + int pxCursorHeight; + int pxLineSpacing; + int pxLineLead; + int pxXoffset; + int pxYoffset; + int pxHexOffset; + int pxHexAscii; + int cursorPosX; + int cursorPosY; + int cursorBlinkCount; + int numLines; + int numCharsPerLine; + + bool cursorBlink; +}; + class HexEditorDialog_t : public QDialog { Q_OBJECT @@ -38,48 +90,25 @@ class HexEditorDialog_t : public QDialog MODE_NES_ROM }; protected: - void paintEvent(QPaintEvent *event); - void keyPressEvent(QKeyEvent *event); - void keyReleaseEvent(QKeyEvent *event); - void calcFontData(void); void initMem(void); void setMode(int new_mode); void showMemViewResults (bool reset); int checkMemActivity(void); int calcVisibleRange( int *start_out, int *end_out, int *center_out ); - QFont font; - QWidget *editor; + QHexEdit *editor; QTimer *periodicTimer; - //QByteArray *dataArray; - //QBuffer *dataBuffer; - // - int pxCharWidth; - int pxCharHeight; - int pxCursorHeight; - int pxLineSpacing; - int pxLineLead; - int pxXoffset; - int pxYoffset; - int pxHexOffset; - int pxHexAscii; - int cursorPosX; - int cursorPosY; - int cursorBlinkCount; int mode; - int numLines; - int numCharsPerLine; - int memSize; - int mbuf_size; + //int memSize; + //int mbuf_size; + memBlock_t mb; int (*memAccessFunc)( unsigned int offset); - struct memByte_t *mbuf; uint64_t total_instructions_lp; bool redraw; - bool cursorBlink; private: From b6b2038c967ed44f5f8331b7f544bc17f20f44f8 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 20 Aug 2020 20:41:38 -0400 Subject: [PATCH 10/37] Added initial framework for hex editor menu. --- src/drivers/Qt/HexEditor.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 69a59980..68e959fe 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -143,15 +144,38 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent ) { QVBoxLayout *mainLayout; + QMenuBar *menuBar; + QMenu *fileMenu; + QAction *saveROM; setWindowTitle("Hex Editor"); resize( 512, 512 ); + menuBar = new QMenuBar(this); + + //----------------------------------------------------------------------- + // Menu + //----------------------------------------------------------------------- + // File + fileMenu = menuBar->addMenu(tr("File")); + + // File -> Open ROM + saveROM = new QAction(tr("Save ROM"), this); + saveROM->setShortcuts(QKeySequence::Open); + saveROM->setStatusTip(tr("Save ROM File")); + //connect(saveROM, SIGNAL(triggered()), this, SLOT(saveROMFile(void)) ); + + fileMenu->addAction(saveROM); + + //----------------------------------------------------------------------- + // Menu End + //----------------------------------------------------------------------- mainLayout = new QVBoxLayout(); editor = new QHexEdit( &mb, this); + mainLayout->setMenuBar( menuBar ); mainLayout->addWidget( editor ); setLayout( mainLayout ); From b23349e870230c238d15b6376ec081c85c6e1214 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 20 Aug 2020 21:21:48 -0400 Subject: [PATCH 11/37] Added vertical slider logic. --- src/drivers/Qt/HexEditor.cpp | 65 +++++++++++++++++++++++++++++++----- src/drivers/Qt/HexEditor.h | 11 ++++-- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 68e959fe..d7ab8b26 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -144,6 +144,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent ) { QVBoxLayout *mainLayout; + QGridLayout *grid; QMenuBar *menuBar; QMenu *fileMenu; QAction *saveROM; @@ -173,13 +174,28 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) //----------------------------------------------------------------------- mainLayout = new QVBoxLayout(); + grid = new QGridLayout(this); editor = new QHexEdit( &mb, this); + vbar = new QScrollBar( Qt::Vertical, this ); + hbar = new QScrollBar( Qt::Horizontal, this ); - mainLayout->setMenuBar( menuBar ); - mainLayout->addWidget( editor ); + grid->setMenuBar( menuBar ); + + grid->addWidget( editor, 0, 0 ); + grid->addWidget( vbar , 0, 1 ); + grid->addWidget( hbar , 1, 0 ); + mainLayout->addLayout( grid ); setLayout( mainLayout ); + hbar->setMinimum(0); + hbar->setMaximum(100); + vbar->setMinimum(0); + vbar->setMaximum( 0x10000 / 16 ); + + //connect( vbar, SIGNAL(sliderMoved(int)), this, SLOT(vbarMoved(int)) ); + connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); + mode = MODE_NES_RAM; memAccessFunc = getRAM; redraw = false; @@ -205,6 +221,18 @@ void HexEditorDialog_t::closeWindow(void) done(0); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::vbarMoved(int value) +{ + printf("VBar Moved: %i\n", value); + editor->setLine( value ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::vbarChanged(int value) +{ + printf("VBar Changed: %i\n", value); + editor->setLine( value ); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::setMode(int new_mode) { if ( mode != new_mode ) @@ -331,6 +359,7 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) calcFontData(); + lineOffset = 0; cursorPosX = 0; cursorPosY = 0; cursorBlink = true; @@ -352,10 +381,10 @@ void QHexEdit::calcFontData(void) #else pxCharWidth = metrics.width(QLatin1Char('2')); #endif - pxCharHeight = metrics.height(); + pxCharHeight = metrics.height(); pxLineSpacing = metrics.lineSpacing() * 1.25; pxLineLead = pxLineSpacing - pxCharHeight; - pxXoffset = pxCharHeight; + pxXoffset = pxCharWidth; pxYoffset = pxLineSpacing * 2.0; pxHexOffset = pxXoffset + (7*pxCharWidth); pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (2*pxCharWidth); @@ -366,6 +395,11 @@ void QHexEdit::calcFontData(void) //_pxSelectionSub = _pxCharHeight / 5; } //---------------------------------------------------------------------------- +void QHexEdit::setLine( int newLineOffset ) +{ + lineOffset = newLineOffset; +} +//---------------------------------------------------------------------------- void QHexEdit::keyPressEvent(QKeyEvent *event) { printf("Hex Window Key Press: 0x%x \n", event->key() ); @@ -381,6 +415,7 @@ void QHexEdit::keyReleaseEvent(QKeyEvent *event) void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; + int maxLines, maxLineOffset; char txt[32]; QPainter painter(this); @@ -390,7 +425,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) //painter.fillRect( 0, 0, w, h, QColor("white") ); - nrow = (h / pxLineSpacing) + 1; + nrow = (h / pxLineSpacing); if ( nrow < 1 ) nrow = 1; @@ -430,8 +465,16 @@ void QHexEdit::paintEvent(QPaintEvent *event) painter.setPen( this->palette().color(QPalette::WindowText)); + maxLines = (mb->size() / 16); + maxLineOffset = maxLines - nrow + 2; + + if ( lineOffset > maxLineOffset ) + { + lineOffset = maxLineOffset; + } + //painter.setPen( QColor("white") ); - addr = 0; + addr = lineOffset * 16; y = pxYoffset; for ( row=0; row < nrow; row++) @@ -445,11 +488,15 @@ void QHexEdit::paintEvent(QPaintEvent *event) for (col=0; col<16; col++) { - sprintf( txt, "%02X", mb->buf[addr+col].data ); - painter.drawText( x, y, txt ); + if ( addr < mb->size() ) + { + sprintf( txt, "%02X", mb->buf[addr].data ); + painter.drawText( x, y, txt ); + } x += (3*pxCharWidth); + addr++; } - addr += 16; + //addr += 16; y += pxLineSpacing; } diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index a2faf616..9d42ae1c 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -46,6 +46,8 @@ class QHexEdit : public QWidget QHexEdit(memBlock_t *blkPtr, QWidget *parent = 0); ~QHexEdit(void); + void setLine( int newLineOffset ); + void setAddr( int newAddrOffset ); protected: void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); @@ -57,6 +59,7 @@ class QHexEdit : public QWidget memBlock_t *mb; + int lineOffset; int pxCharWidth; int pxCharHeight; int pxCursorHeight; @@ -97,8 +100,10 @@ class HexEditorDialog_t : public QDialog int checkMemActivity(void); int calcVisibleRange( int *start_out, int *end_out, int *center_out ); - QHexEdit *editor; - QTimer *periodicTimer; + QScrollBar *vbar; + QScrollBar *hbar; + QHexEdit *editor; + QTimer *periodicTimer; int mode; //int memSize; @@ -116,5 +121,7 @@ class HexEditorDialog_t : public QDialog void closeWindow(void); private slots: void updatePeriodic(void); + void vbarMoved(int value); + void vbarChanged(int value); }; From 65f6b060333d3e13fc02d474d3e42052bba7de25 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 20 Aug 2020 21:47:21 -0400 Subject: [PATCH 12/37] Added ascii output to hex editor. --- src/drivers/Qt/HexEditor.cpp | 42 ++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index d7ab8b26..d7257ac8 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -108,6 +108,15 @@ memBlock_t::~memBlock_t(void) //---------------------------------------------------------------------------- int memBlock_t::reAlloc( int newSize ) { + if ( newSize == 0 ) + { + return 0; + } + if ( _size == newSize ) + { + return 0; + } + if ( buf != NULL ) { ::free( buf ); buf = NULL; @@ -121,7 +130,7 @@ int memBlock_t::reAlloc( int newSize ) _size = newSize; init(); } - return (buf != NULL); + return (buf == NULL); } //---------------------------------------------------------------------------- void memBlock_t::setAccessFunc( int (*newMemAccessFunc)( unsigned int offset) ) @@ -223,13 +232,13 @@ void HexEditorDialog_t::closeWindow(void) //---------------------------------------------------------------------------- void HexEditorDialog_t::vbarMoved(int value) { - printf("VBar Moved: %i\n", value); + //printf("VBar Moved: %i\n", value); editor->setLine( value ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::vbarChanged(int value) { - printf("VBar Changed: %i\n", value); + //printf("VBar Changed: %i\n", value); editor->setLine( value ); } //---------------------------------------------------------------------------- @@ -387,7 +396,7 @@ void QHexEdit::calcFontData(void) pxXoffset = pxCharWidth; pxYoffset = pxLineSpacing * 2.0; pxHexOffset = pxXoffset + (7*pxCharWidth); - pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (2*pxCharWidth); + pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (pxCharWidth); //_pxGapAdr = _pxCharWidth / 2; //_pxGapAdrHex = _pxCharWidth; //_pxGapHexAscii = 2 * _pxCharWidth; @@ -415,8 +424,8 @@ void QHexEdit::keyReleaseEvent(QKeyEvent *event) void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; - int maxLines, maxLineOffset; - char txt[32]; + int c, maxLines, maxLineOffset; + char txt[32], asciiTxt[32]; QPainter painter(this); painter.setFont(font); @@ -490,18 +499,37 @@ void QHexEdit::paintEvent(QPaintEvent *event) { if ( addr < mb->size() ) { - sprintf( txt, "%02X", mb->buf[addr].data ); + c = mb->buf[addr].data; + + if ( ::isprint(c) ) + { + asciiTxt[col] = c; + } + else + { + asciiTxt[col] = '.'; + } + sprintf( txt, "%02X", c ); painter.drawText( x, y, txt ); } + else + { + asciiTxt[col] = 0; + } x += (3*pxCharWidth); addr++; } + asciiTxt[16] = 0; + + painter.drawText( pxHexAscii, y, tr(asciiTxt) ); + //addr += 16; y += pxLineSpacing; } painter.drawText( pxHexOffset, pxLineSpacing, "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" ); painter.drawLine( pxHexOffset - (pxCharWidth/2), 0, pxHexOffset - (pxCharWidth/2), h ); + painter.drawLine( pxHexAscii - (pxCharWidth/2), 0, pxHexAscii - (pxCharWidth/2), h ); painter.drawLine( 0, pxLineSpacing + (pxLineLead), w, pxLineSpacing + (pxLineLead) ); } From 5f57455de75ac0a029e32b639770ffe8adf8fb04 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 20 Aug 2020 22:28:02 -0400 Subject: [PATCH 13/37] Cursor positioning logic in work. --- src/drivers/Qt/HexEditor.cpp | 95 +++++++++++++++++++++++++++++------- src/drivers/Qt/HexEditor.h | 8 ++- 2 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index d7257ac8..660d9686 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -152,7 +152,7 @@ void memBlock_t::init(void) HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent ) { - QVBoxLayout *mainLayout; + //QVBoxLayout *mainLayout; QGridLayout *grid; QMenuBar *menuBar; QMenu *fileMenu; @@ -181,7 +181,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) //----------------------------------------------------------------------- // Menu End //----------------------------------------------------------------------- - mainLayout = new QVBoxLayout(); + //mainLayout = new QVBoxLayout(); grid = new QGridLayout(this); editor = new QHexEdit( &mb, this); @@ -193,9 +193,9 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) grid->addWidget( editor, 0, 0 ); grid->addWidget( vbar , 0, 1 ); grid->addWidget( hbar , 1, 0 ); - mainLayout->addLayout( grid ); + //mainLayout->addLayout( grid ); - setLayout( mainLayout ); + setLayout( grid ); hbar->setMinimum(0); hbar->setMaximum(100); @@ -354,6 +354,8 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) mb = blkPtr; + this->setFocusPolicy(Qt::StrongFocus); + font.setFamily("Courier New"); font.setStyle( QFont::StyleNormal ); font.setStyleHint( QFont::Monospace ); @@ -402,6 +404,7 @@ void QHexEdit::calcFontData(void) //_pxGapHexAscii = 2 * _pxCharWidth; pxCursorHeight = pxCharHeight; //_pxSelectionSub = _pxCharHeight / 5; + viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; } //---------------------------------------------------------------------------- void QHexEdit::setLine( int newLineOffset ) @@ -409,10 +412,54 @@ void QHexEdit::setLine( int newLineOffset ) lineOffset = newLineOffset; } //---------------------------------------------------------------------------- +void QHexEdit::resizeEvent(QResizeEvent *event) +{ + viewWidth = event->size().width(); + viewHeight = event->size().height(); + + //printf("QHexEdit Resize: %ix%i\n", viewWidth, viewHeight ); + + viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; +} +//---------------------------------------------------------------------------- +void QHexEdit::resetCursorBlink(void) +{ + cursorBlink = true; + cursorBlinkCount = 0; +} +//---------------------------------------------------------------------------- void QHexEdit::keyPressEvent(QKeyEvent *event) { printf("Hex Window Key Press: 0x%x \n", event->key() ); - //assignHotkey( event ); + + if (event->matches(QKeySequence::MoveToPreviousLine)) + { + cursorPosY--; + + if ( cursorPosY < 0 ) + { + lineOffset--; + + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + cursorPosY = 0; + } + resetCursorBlink(); + } + if (event->matches(QKeySequence::MoveToNextLine)) + { + cursorPosY++; + + if ( cursorPosY >= viewLines ) + { + lineOffset++; + + cursorPosY = viewLines-1; + } + resetCursorBlink(); + } } //---------------------------------------------------------------------------- void QHexEdit::keyReleaseEvent(QKeyEvent *event) @@ -432,18 +479,40 @@ void QHexEdit::paintEvent(QPaintEvent *event) w = event->rect().width(); h = event->rect().height(); + viewWidth = w; + viewHeight = h; //painter.fillRect( 0, 0, w, h, QColor("white") ); - nrow = (h / pxLineSpacing); + nrow = (h - pxLineSpacing) / pxLineSpacing; if ( nrow < 1 ) nrow = 1; + viewLines = nrow; + + if ( cursorPosY >= viewLines ) + { + cursorPosY = viewLines-1; + } //printf("Draw Area: %ix%i \n", event->rect().width(), event->rect().height() ); // + if ( (mb->size() % 16) ) + { + maxLines = (mb->size() / 16) + 1; + } + else + { + maxLines = (mb->size() / 16); + } + maxLineOffset = maxLines - nrow + 1; + + if ( lineOffset > maxLineOffset ) + { + lineOffset = maxLineOffset; + } painter.fillRect( 0, 0, w, h, this->palette().color(QPalette::Background) ); - if ( cursorBlinkCount >= 10 ) + if ( cursorBlinkCount >= 5 ) { cursorBlink = !cursorBlink; cursorBlinkCount = 0; @@ -474,14 +543,6 @@ void QHexEdit::paintEvent(QPaintEvent *event) painter.setPen( this->palette().color(QPalette::WindowText)); - maxLines = (mb->size() / 16); - maxLineOffset = maxLines - nrow + 2; - - if ( lineOffset > maxLineOffset ) - { - lineOffset = maxLineOffset; - } - //painter.setPen( QColor("white") ); addr = lineOffset * 16; y = pxYoffset; @@ -491,7 +552,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) x = pxXoffset; sprintf( txt, "%06X", addr ); - painter.drawText( x, y, txt ); + painter.drawText( x, y, tr(txt) ); x = pxHexOffset; @@ -510,7 +571,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) asciiTxt[col] = '.'; } sprintf( txt, "%02X", c ); - painter.drawText( x, y, txt ); + painter.drawText( x, y, tr(txt) ); } else { diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 9d42ae1c..99b7d08a 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -15,6 +15,7 @@ #include #include #include +#include struct memByte_t { @@ -52,8 +53,10 @@ class QHexEdit : public QWidget void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); + void resizeEvent(QResizeEvent *event); void calcFontData(void); + void resetCursorBlink(void); QFont font; @@ -72,8 +75,9 @@ class QHexEdit : public QWidget int cursorPosX; int cursorPosY; int cursorBlinkCount; - int numLines; - int numCharsPerLine; + int viewLines; + int viewWidth; + int viewHeight; bool cursorBlink; }; From f6afca360f8c1fc36d3f81502e739af2cc76e6f5 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 20 Aug 2020 22:34:45 -0400 Subject: [PATCH 14/37] Added hex editor X,Y cursor movement via arrow keys. --- src/drivers/Qt/HexEditor.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 660d9686..e54c0bbd 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -432,6 +432,26 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { printf("Hex Window Key Press: 0x%x \n", event->key() ); + if (event->matches(QKeySequence::MoveToNextChar)) + { + cursorPosX++; + + if ( cursorPosX >= 48 ) + { + cursorPosX = 47; + } + resetCursorBlink(); + } + if (event->matches(QKeySequence::MoveToPreviousChar)) + { + cursorPosX--; + + if ( cursorPosX < 0 ) + { + cursorPosX = 0; + } + resetCursorBlink(); + } if (event->matches(QKeySequence::MoveToPreviousLine)) { cursorPosY--; @@ -534,7 +554,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) } else { - x = pxHexAscii; + x = pxHexAscii + (cursorPosX - 32)*pxCharWidth; } //painter.setPen( this->palette().color(QPalette::WindowText)); From 75b076f25649d928c6449de05f9ad77382abb0ea Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Thu, 20 Aug 2020 22:44:14 -0400 Subject: [PATCH 15/37] Added a couple more key bindings to hex editor cursor control. --- src/drivers/Qt/HexEditor.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index e54c0bbd..25f5261e 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -442,7 +442,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) } resetCursorBlink(); } - if (event->matches(QKeySequence::MoveToPreviousChar)) + else if (event->matches(QKeySequence::MoveToPreviousChar)) { cursorPosX--; @@ -452,7 +452,17 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) } resetCursorBlink(); } - if (event->matches(QKeySequence::MoveToPreviousLine)) + else if (event->matches(QKeySequence::MoveToEndOfLine)) + { + cursorPosX = 47; + resetCursorBlink(); + } + else if (event->matches(QKeySequence::MoveToStartOfLine)) + { + cursorPosX = 0; + resetCursorBlink(); + } + else if (event->matches(QKeySequence::MoveToPreviousLine)) { cursorPosY--; @@ -468,7 +478,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) } resetCursorBlink(); } - if (event->matches(QKeySequence::MoveToNextLine)) + else if (event->matches(QKeySequence::MoveToNextLine)) { cursorPosY++; From b614edee7573848087359691ac97e92e5b5c4d36 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 21 Aug 2020 11:50:36 -0400 Subject: [PATCH 16/37] Added memory write logic to hex editor. --- src/drivers/Qt/HexEditor.cpp | 326 +++++++++++++++++++++++++++++++---- src/drivers/Qt/HexEditor.h | 16 +- 2 files changed, 308 insertions(+), 34 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 25f5261e..2c2e14e7 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -32,6 +32,12 @@ #include "Qt/fceuWrapper.h" #include "Qt/HexEditor.h" +//enum { +// MODE_NES_RAM = 0, +// MODE_NES_PPU, +// MODE_NES_OAM, +// MODE_NES_ROM +//}; //---------------------------------------------------------------------------- static int getRAM( unsigned int i ) { @@ -72,26 +78,135 @@ static int getROM( unsigned int offset) } return -1; } -//static int conv2xchar( int i ) -//{ -// int c = 0; -// -// if ( (i >= 0) && (i < 10) ) -// { -// c = i + '0'; -// } -// else if ( i < 16 ) -// { -// c = (i - 10) + 'A'; -// } -// return c; -//} +static void PalettePoke(uint32 addr, uint8 data) +{ + data = data & 0x3F; + addr = addr & 0x1F; + if ((addr & 3) == 0) + { + addr = (addr & 0xC) >> 2; + if (addr == 0) + { + PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = data; + } + else + { + UPALRAM[addr-1] = UPALRAM[0x10|(addr-1)] = data; + } + } + else + { + PALRAM[addr] = data; + } +} +static int writeMem( int mode, unsigned int addr, int value ) +{ + value = value & 0x000000ff; + + switch ( mode ) + { + default: + case HexEditorDialog_t::MODE_NES_RAM: + { + if ( addr < 0x8000 ) + { + writefunc wfunc; + + wfunc = GetWriteHandler (addr); + + if (wfunc) + { + wfunc ((uint32) addr, + (uint8) (value & 0x000000ff)); + } + } + else + { + fprintf( stdout, "Error: Writing into RAM addresses >= 0x8000 is unsafe. Operation Denied.\n"); + } + } + break; + case HexEditorDialog_t::MODE_NES_PPU: + { + addr &= 0x3FFF; + if (addr < 0x2000) + { + VPage[addr >> 10][addr] = value; //todo: detect if this is vrom and turn it red if so + } + if ((addr >= 0x2000) && (addr < 0x3F00)) + { + vnapage[(addr >> 10) & 0x3][addr & 0x3FF] = value; //todo: this causes 0x3000-0x3f00 to mirror 0x2000-0x2f00, is this correct? + } + if ((addr >= 0x3F00) && (addr < 0x3FFF)) + { + PalettePoke(addr, value); + } + } + break; + case HexEditorDialog_t::MODE_NES_OAM: + { + addr &= 0xFF; + SPRAM[addr] = value; + } + break; + case HexEditorDialog_t::MODE_NES_ROM: + { + if (addr < 16) + { + fprintf( stdout, "You can't edit ROM header here, however you can use iNES Header Editor to edit the header if it's an iNES format file."); + } + else if ( (addr >= 16) && (addr < PRGsize[0]+16) ) + { + *(uint8 *)(GetNesPRGPointer(addr-16)) = value; + } + else if ( (addr >= PRGsize[0]+16) && (addr < CHRsize[0]+PRGsize[0]+16) ) + { + *(uint8 *)(GetNesCHRPointer(addr-16-PRGsize[0])) = value; + } + } + break; + } + return 0; +} + +static int convToXchar( int i ) +{ + int c = 0; + + if ( (i >= 0) && (i < 10) ) + { + c = i + '0'; + } + else if ( i < 16 ) + { + c = (i - 10) + 'A'; + } + return c; +} + +static int convFromXchar( int i ) +{ + int c = 0; + + i = ::toupper(i); + + if ( (i >= '0') && (i <= '9') ) + { + c = i - '0'; + } + else if ( (i >= 'A') && (i <= 'F') ) + { + c = (i - 'A') + 10; + } + return c; +} //---------------------------------------------------------------------------- memBlock_t::memBlock_t( void ) { buf = NULL; _size = 0; + _maxLines = 0; memAccessFunc = NULL; } //---------------------------------------------------------------------------- @@ -103,6 +218,7 @@ memBlock_t::~memBlock_t(void) ::free( buf ); buf = NULL; } _size = 0; + _maxLines = 0; } //---------------------------------------------------------------------------- @@ -122,6 +238,7 @@ int memBlock_t::reAlloc( int newSize ) ::free( buf ); buf = NULL; } _size = 0; + _maxLines = 0; buf = (struct memByte_t *)malloc( newSize * sizeof(struct memByte_t) ); @@ -129,6 +246,15 @@ int memBlock_t::reAlloc( int newSize ) { _size = newSize; init(); + + if ( (_size % 16) ) + { + _maxLines = (_size / 16) + 1; + } + else + { + _maxLines = (_size / 16); + } } return (buf == NULL); } @@ -202,6 +328,8 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) vbar->setMinimum(0); vbar->setMaximum( 0x10000 / 16 ); + editor->setScrollBars( hbar, vbar ); + //connect( vbar, SIGNAL(sliderMoved(int)), this, SLOT(vbarMoved(int)) ); connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); @@ -248,6 +376,7 @@ void HexEditorDialog_t::setMode(int new_mode) { mode = new_mode; showMemViewResults(true); + editor->setMode( mode ); } } //---------------------------------------------------------------------------- @@ -370,11 +499,16 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) calcFontData(); + viewMode = HexEditorDialog_t::MODE_NES_RAM; lineOffset = 0; cursorPosX = 0; cursorPosY = 0; cursorBlink = true; cursorBlinkCount = 0; + maxLineOffset = 0; + editAddr = -1; + editValue = 0; + editMask = 0; } //---------------------------------------------------------------------------- @@ -407,11 +541,21 @@ void QHexEdit::calcFontData(void) viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; } //---------------------------------------------------------------------------- +void QHexEdit::setMode( int mode ) +{ + viewMode = mode; +} +//---------------------------------------------------------------------------- void QHexEdit::setLine( int newLineOffset ) { lineOffset = newLineOffset; } //---------------------------------------------------------------------------- +void QHexEdit::setScrollBars( QScrollBar *h, QScrollBar *v ) +{ + hbar = h; vbar = v; +} +//---------------------------------------------------------------------------- void QHexEdit::resizeEvent(QResizeEvent *event) { viewWidth = event->size().width(); @@ -420,12 +564,17 @@ void QHexEdit::resizeEvent(QResizeEvent *event) //printf("QHexEdit Resize: %ix%i\n", viewWidth, viewHeight ); viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; + + maxLineOffset = mb->numLines() - viewLines + 1; } //---------------------------------------------------------------------------- -void QHexEdit::resetCursorBlink(void) +void QHexEdit::resetCursor(void) { cursorBlink = true; cursorBlinkCount = 0; + editAddr = -1; + editValue = 0; + editMask = 0; } //---------------------------------------------------------------------------- void QHexEdit::keyPressEvent(QKeyEvent *event) @@ -440,7 +589,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { cursorPosX = 47; } - resetCursorBlink(); + resetCursor(); } else if (event->matches(QKeySequence::MoveToPreviousChar)) { @@ -450,17 +599,17 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { cursorPosX = 0; } - resetCursorBlink(); + resetCursor(); } else if (event->matches(QKeySequence::MoveToEndOfLine)) { cursorPosX = 47; - resetCursorBlink(); + resetCursor(); } else if (event->matches(QKeySequence::MoveToStartOfLine)) { cursorPosX = 0; - resetCursorBlink(); + resetCursor(); } else if (event->matches(QKeySequence::MoveToPreviousLine)) { @@ -475,8 +624,10 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) lineOffset = 0; } cursorPosY = 0; + + vbar->setValue( lineOffset ); } - resetCursorBlink(); + resetCursor(); } else if (event->matches(QKeySequence::MoveToNextLine)) { @@ -486,9 +637,112 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { lineOffset++; + if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } cursorPosY = viewLines-1; + + vbar->setValue( lineOffset ); } - resetCursorBlink(); + resetCursor(); + + } + else if (event->matches(QKeySequence::MoveToNextPage)) + { + lineOffset += ( (3 * viewLines) / 4); + + if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToPreviousPage)) + { + lineOffset -= ( (3 * viewLines) / 4); + + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToEndOfDocument)) + { + lineOffset = maxLineOffset; + resetCursor(); + } + else if (event->matches(QKeySequence::MoveToStartOfDocument)) + { + lineOffset = 0; + resetCursor(); + } + else if (event->key() == Qt::Key_Tab && (cursorPosX < 32) ) + { // switch from hex to ascii edit + cursorPosX = 32 + (cursorPosX / 2); + } + else if (event->key() == Qt::Key_Backtab && (cursorPosX >= 32) ) + { // switch from ascii to hex edit + cursorPosX = 2 * (cursorPosX - 32); + } + else + { + int key; + if ( cursorPosX >= 32 ) + { // Edit Area is ASCII + key = (uchar)event->text()[0].toLatin1(); + + if ( ::isascii( key ) ) + { + int offs = (cursorPosX-32); + int addr = 16*(lineOffset+cursorPosY) + offs; + writeMem( viewMode, addr, key ); + + editAddr = -1; + editValue = 0; + editMask = 0; + } + } + else + { // Edit Area is Hex + key = int(event->text()[0].toUpper().toLatin1()); + + if ( ::isxdigit( key ) ) + { + int offs, nibbleValue, nibbleIndex; + + offs = (cursorPosX / 2); + nibbleIndex = (cursorPosX % 2); + + editAddr = 16*(lineOffset+cursorPosY) + offs; + + nibbleValue = convFromXchar( key ); + + if ( nibbleIndex ) + { + nibbleValue = editValue | nibbleValue; + + writeMem( viewMode, editAddr, nibbleValue ); + + editAddr = -1; + editValue = 0; + editMask = 0; + } + else + { + editValue = (nibbleValue << 4); + editMask = 0x00f0; + } + cursorPosX++; + + if ( cursorPosX >= 32 ) + { + cursorPosX = 0; + } + } + } + //printf("Key: %c %i \n", key, key); } } //---------------------------------------------------------------------------- @@ -501,7 +755,7 @@ void QHexEdit::keyReleaseEvent(QKeyEvent *event) void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; - int c, maxLines, maxLineOffset; + int c; char txt[32], asciiTxt[32]; QPainter painter(this); @@ -525,15 +779,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) } //printf("Draw Area: %ix%i \n", event->rect().width(), event->rect().height() ); // - if ( (mb->size() % 16) ) - { - maxLines = (mb->size() / 16) + 1; - } - else - { - maxLines = (mb->size() / 16); - } - maxLineOffset = maxLines - nrow + 1; + maxLineOffset = mb->numLines() - nrow + 1; if ( lineOffset > maxLineOffset ) { @@ -600,8 +846,22 @@ void QHexEdit::paintEvent(QPaintEvent *event) { asciiTxt[col] = '.'; } - sprintf( txt, "%02X", c ); - painter.drawText( x, y, tr(txt) ); + if ( addr == editAddr ) + { // Set a cell currently being editting to red text + painter.setPen( QColor("red") ); + txt[0] = convToXchar( (editValue >> 4) & 0x0F ); + txt[1] = convToXchar( c & 0x0F ); + txt[2] = 0; + painter.drawText( x, y, tr(txt) ); + painter.setPen( this->palette().color(QPalette::WindowText)); + } + else + { + txt[0] = convToXchar( (c >> 4) & 0x0F ); + txt[1] = convToXchar( c & 0x0F ); + txt[2] = 0; + painter.drawText( x, y, tr(txt) ); + } } else { diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 99b7d08a..eb9ee0d0 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -31,11 +31,13 @@ struct memBlock_t void init(void); int size(void){ return _size; } + int numLines(void){ return _maxLines; } int reAlloc( int newSize ); void setAccessFunc( int (*newMemAccessFunc)( unsigned int offset) ); struct memByte_t *buf; int _size; + int _maxLines; int (*memAccessFunc)( unsigned int offset); }; @@ -47,8 +49,10 @@ class QHexEdit : public QWidget QHexEdit(memBlock_t *blkPtr, QWidget *parent = 0); ~QHexEdit(void); + void setMode( int mode ); void setLine( int newLineOffset ); void setAddr( int newAddrOffset ); + void setScrollBars( QScrollBar *h, QScrollBar *v ); protected: void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); @@ -56,12 +60,16 @@ class QHexEdit : public QWidget void resizeEvent(QResizeEvent *event); void calcFontData(void); - void resetCursorBlink(void); + void resetCursor(void); QFont font; memBlock_t *mb; + QScrollBar *vbar; + QScrollBar *hbar; + + int viewMode; int lineOffset; int pxCharWidth; int pxCharHeight; @@ -78,6 +86,10 @@ class QHexEdit : public QWidget int viewLines; int viewWidth; int viewHeight; + int maxLineOffset; + int editAddr; + int editValue; + int editMask; bool cursorBlink; }; @@ -96,6 +108,8 @@ class HexEditorDialog_t : public QDialog MODE_NES_OAM, MODE_NES_ROM }; + + int getMode(void){ return mode; } protected: void initMem(void); From b37e1e03f0c9d3b7d2d6682a2b5acebf0c0e52b3 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Fri, 21 Aug 2020 11:55:19 -0400 Subject: [PATCH 17/37] Cppcheck warning fixes for Qt GUI. --- src/drivers/Qt/fceuWrapper.cpp | 3 ++- src/drivers/Qt/input.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index cfbbb98b..a8dcad5f 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -104,7 +104,8 @@ void FCEUD_PrintError(const char *errormsg) */ FILE *FCEUD_UTF8fopen(const char *fn, const char *mode) { - return(fopen(fn,mode)); + FILE *fp = ::fopen(fn,mode); + return(fp); } /** diff --git a/src/drivers/Qt/input.cpp b/src/drivers/Qt/input.cpp index ce2bf93b..1510857b 100644 --- a/src/drivers/Qt/input.cpp +++ b/src/drivers/Qt/input.cpp @@ -1570,6 +1570,7 @@ const char * ButtonName (const ButtConfig * bc) { int joyNum, inputNum; const char *inputType, *inputDirection; + char direction[128] = ""; joyNum = bc->DeviceNum; @@ -1582,7 +1583,6 @@ const char * ButtonName (const ButtConfig * bc) else if (bc->ButtonNum & 0x2000) { int inputValue; - char direction[128] = ""; inputType = "Hat"; inputNum = (bc->ButtonNum >> 8) & 0x1F; From 1eaa3f46f914a7811952d1539710e383d8e2b33d Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 21 Aug 2020 21:05:52 -0400 Subject: [PATCH 18/37] Added logic to position cursor via left mouse clicks on hex editor. --- src/drivers/Qt/HexEditor.cpp | 80 ++++++++++++++++++++++++++++++++++++ src/drivers/Qt/HexEditor.h | 1 + 2 files changed, 81 insertions(+) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 2c2e14e7..762b7dd6 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -752,6 +752,86 @@ void QHexEdit::keyReleaseEvent(QKeyEvent *event) //assignHotkey( event ); } //---------------------------------------------------------------------------- +void QHexEdit::mousePressEvent(QMouseEvent * event) +{ + int cx = 0, cy = 0; + QPoint p = event->pos(); + + //printf("Pos: %ix%i \n", p.x(), p.y() ); + + if ( p.x() < pxHexOffset ) + { + cx = 0; + } + else if ( (p.x() >= pxHexOffset) && (p.x() < pxHexAscii) ) + { + float px = ( (float)p.x() - (float)pxHexOffset) / (float)(pxCharWidth); + float ox = (px/3.0); + float rx = fmodf(px,3.0); + + if ( rx >= 2.50 ) + { + cx = 2*( (int)ox + 1 ); + } + else + { + if ( rx >= 1.0 ) + { + cx = 2*( (int)ox ) + 1; + } + else + { + cx = 2*( (int)ox ); + } + } + } + else + { + cx = 32 + (p.x() - pxHexAscii) / pxCharWidth; + } + if ( cx >= 48 ) + { + cx = 47; + } + + if ( p.y() < pxYoffset ) + { + cy = 0; + } + else + { + float ly = ( (float)pxLineLead / (float)pxLineSpacing ); + float py = ( (float)p.y() - (float)pxLineSpacing) / (float)pxLineSpacing; + float ry = fmod( py, 1.0 ); + + if ( ry < ly ) + { + cy = ((int)py) - 1; + } + else + { + cy = (int)py; + } + } + if ( cy < 0 ) + { + cy = 0; + } + else if ( cy >= viewLines ) + { + cy = viewLines - 1; + } + //printf("c: %ix%i \n", cx, cy ); + + if ( event->button() == Qt::LeftButton ) + { + cursorPosX = cx; + cursorPosY = cy; + resetCursor(); + } + +} +//---------------------------------------------------------------------------- void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index eb9ee0d0..c49d3ced 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -57,6 +57,7 @@ class QHexEdit : public QWidget void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); + void mousePressEvent(QMouseEvent * event); void resizeEvent(QResizeEvent *event); void calcFontData(void); From ecf558c1a3c97c213f634bfb99dbe8e297e83dd9 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 13:57:36 -0400 Subject: [PATCH 19/37] Moved pixel space to cursor position conversion into its own function. --- src/drivers/Qt/HexEditor.cpp | 147 +++++++++++++++++++---------------- src/drivers/Qt/HexEditor.h | 1 + 2 files changed, 79 insertions(+), 69 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 762b7dd6..6ce3ffe7 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -577,6 +577,80 @@ void QHexEdit::resetCursor(void) editMask = 0; } //---------------------------------------------------------------------------- +QPoint QHexEdit::convPixToCursor( QPoint p ) +{ + QPoint c(0,0); + + //printf("Pos: %ix%i \n", p.x(), p.y() ); + + if ( p.x() < pxHexOffset ) + { + c.setX(0); + } + else if ( (p.x() >= pxHexOffset) && (p.x() < pxHexAscii) ) + { + float px = ( (float)p.x() - (float)pxHexOffset) / (float)(pxCharWidth); + float ox = (px/3.0); + float rx = fmodf(px,3.0); + + if ( rx >= 2.50 ) + { + c.setX( 2*( (int)ox + 1 ) ); + } + else + { + if ( rx >= 1.0 ) + { + c.setX( 2*( (int)ox ) + 1 ); + } + else + { + c.setX( 2*( (int)ox ) ); + } + } + } + else + { + c.setX( 32 + (p.x() - pxHexAscii) / pxCharWidth ); + } + if ( c.x() >= 48 ) + { + c.setX( 47 ); + } + + if ( p.y() < pxYoffset ) + { + c.setY( 0 ); + } + else + { + float ly = ( (float)pxLineLead / (float)pxLineSpacing ); + float py = ( (float)p.y() - (float)pxLineSpacing) / (float)pxLineSpacing; + float ry = fmod( py, 1.0 ); + + if ( ry < ly ) + { + c.setY( ((int)py) - 1 ); + } + else + { + c.setY( (int)py ); + } + } + if ( c.y() < 0 ) + { + c.setY(0); + } + else if ( c.y() >= viewLines ) + { + c.setY( viewLines - 1 ); + } + //printf("c: %ix%i \n", cx, cy ); + // + + return c; +} +//---------------------------------------------------------------------------- void QHexEdit::keyPressEvent(QKeyEvent *event) { printf("Hex Window Key Press: 0x%x \n", event->key() ); @@ -754,79 +828,14 @@ void QHexEdit::keyReleaseEvent(QKeyEvent *event) //---------------------------------------------------------------------------- void QHexEdit::mousePressEvent(QMouseEvent * event) { - int cx = 0, cy = 0; - QPoint p = event->pos(); + QPoint c = convPixToCursor( event->pos() ); - //printf("Pos: %ix%i \n", p.x(), p.y() ); - - if ( p.x() < pxHexOffset ) - { - cx = 0; - } - else if ( (p.x() >= pxHexOffset) && (p.x() < pxHexAscii) ) - { - float px = ( (float)p.x() - (float)pxHexOffset) / (float)(pxCharWidth); - float ox = (px/3.0); - float rx = fmodf(px,3.0); - - if ( rx >= 2.50 ) - { - cx = 2*( (int)ox + 1 ); - } - else - { - if ( rx >= 1.0 ) - { - cx = 2*( (int)ox ) + 1; - } - else - { - cx = 2*( (int)ox ); - } - } - } - else - { - cx = 32 + (p.x() - pxHexAscii) / pxCharWidth; - } - if ( cx >= 48 ) - { - cx = 47; - } - - if ( p.y() < pxYoffset ) - { - cy = 0; - } - else - { - float ly = ( (float)pxLineLead / (float)pxLineSpacing ); - float py = ( (float)p.y() - (float)pxLineSpacing) / (float)pxLineSpacing; - float ry = fmod( py, 1.0 ); - - if ( ry < ly ) - { - cy = ((int)py) - 1; - } - else - { - cy = (int)py; - } - } - if ( cy < 0 ) - { - cy = 0; - } - else if ( cy >= viewLines ) - { - cy = viewLines - 1; - } - //printf("c: %ix%i \n", cx, cy ); + //printf("c: %ix%i \n", c.x(), c.y() ); if ( event->button() == Qt::LeftButton ) { - cursorPosX = cx; - cursorPosY = cy; + cursorPosX = c.x(); + cursorPosY = c.y(); resetCursor(); } diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index c49d3ced..3cbaea02 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -62,6 +62,7 @@ class QHexEdit : public QWidget void calcFontData(void); void resetCursor(void); + QPoint convPixToCursor( QPoint p ); QFont font; From c99c729b23c0f2a86b7f30bf8e03ab3df7595ec8 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 14:16:13 -0400 Subject: [PATCH 20/37] Added hex editor view mode menu logic. --- src/drivers/Qt/HexEditor.cpp | 73 +++++++++++++++++++++++++++++++++++- src/drivers/Qt/HexEditor.h | 4 ++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 6ce3ffe7..3ddb4c84 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -282,7 +282,10 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) QGridLayout *grid; QMenuBar *menuBar; QMenu *fileMenu; + QMenu *viewMenu; QAction *saveROM; + QAction *viewRAM, *viewPPU, *viewOAM, *viewROM; + QActionGroup *group; setWindowTitle("Hex Editor"); @@ -298,12 +301,60 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) // File -> Open ROM saveROM = new QAction(tr("Save ROM"), this); - saveROM->setShortcuts(QKeySequence::Open); + //saveROM->setShortcuts(QKeySequence::Open); saveROM->setStatusTip(tr("Save ROM File")); //connect(saveROM, SIGNAL(triggered()), this, SLOT(saveROMFile(void)) ); fileMenu->addAction(saveROM); + // View + viewMenu = menuBar->addMenu(tr("View")); + + group = new QActionGroup(this); + + group->setExclusive(true); + + // View -> RAM + viewRAM = new QAction(tr("RAM"), this); + //viewRAM->setShortcuts(QKeySequence::Open); + viewRAM->setStatusTip(tr("View RAM")); + viewRAM->setCheckable(true); + connect(viewRAM, SIGNAL(triggered()), this, SLOT(setViewRAM(void)) ); + + group->addAction(viewRAM); + viewMenu->addAction(viewRAM); + + // View -> PPU + viewPPU = new QAction(tr("PPU"), this); + //viewPPU->setShortcuts(QKeySequence::Open); + viewPPU->setStatusTip(tr("View PPU")); + viewPPU->setCheckable(true); + connect(viewPPU, SIGNAL(triggered()), this, SLOT(setViewPPU(void)) ); + + group->addAction(viewPPU); + viewMenu->addAction(viewPPU); + + // View -> OAM + viewOAM = new QAction(tr("OAM"), this); + //viewOAM->setShortcuts(QKeySequence::Open); + viewOAM->setStatusTip(tr("View OAM")); + viewOAM->setCheckable(true); + connect(viewOAM, SIGNAL(triggered()), this, SLOT(setViewOAM(void)) ); + + group->addAction(viewOAM); + viewMenu->addAction(viewOAM); + + // View -> ROM + viewROM = new QAction(tr("ROM"), this); + //viewROM->setShortcuts(QKeySequence::Open); + viewROM->setStatusTip(tr("View ROM")); + viewROM->setCheckable(true); + connect(viewROM, SIGNAL(triggered()), this, SLOT(setViewROM(void)) ); + + group->addAction(viewROM); + viewMenu->addAction(viewROM); + + viewRAM->setChecked(true); // Set default view //----------------------------------------------------------------------- // Menu End //----------------------------------------------------------------------- @@ -380,6 +431,26 @@ void HexEditorDialog_t::setMode(int new_mode) } } //---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewRAM(void) +{ + setMode( MODE_NES_RAM ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewPPU(void) +{ + setMode( MODE_NES_PPU ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewOAM(void) +{ + setMode( MODE_NES_OAM ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::setViewROM(void) +{ + setMode( MODE_NES_ROM ); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::showMemViewResults (bool reset) { int memSize; diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 3cbaea02..da497650 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -143,5 +143,9 @@ class HexEditorDialog_t : public QDialog void updatePeriodic(void); void vbarMoved(int value); void vbarChanged(int value); + void setViewRAM(void); + void setViewPPU(void); + void setViewOAM(void); + void setViewROM(void); }; From 6aacaa55953ba80d1fd2ba32277e51c1b727fbf1 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 19:15:56 -0400 Subject: [PATCH 21/37] Added activity color highlight logic. --- src/drivers/Qt/HexEditor.cpp | 34 ++++++++++++++++++++++++++++++++++ src/drivers/Qt/HexEditor.h | 3 +++ 2 files changed, 37 insertions(+) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 3ddb4c84..d28f289c 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -43,6 +43,7 @@ static int getRAM( unsigned int i ) { return GetMem(i); } +//---------------------------------------------------------------------------- static int getPPU( unsigned int i ) { i &= 0x3FFF; @@ -58,10 +59,12 @@ static int getPPU( unsigned int i ) } return 0; } +//---------------------------------------------------------------------------- static int getOAM( unsigned int i ) { return SPRAM[i & 0xFF]; } +//---------------------------------------------------------------------------- static int getROM( unsigned int offset) { if (offset < 16) @@ -78,6 +81,7 @@ static int getROM( unsigned int offset) } return -1; } +//---------------------------------------------------------------------------- static void PalettePoke(uint32 addr, uint8 data) { data = data & 0x3F; @@ -99,6 +103,7 @@ static void PalettePoke(uint32 addr, uint8 data) PALRAM[addr] = data; } } +//---------------------------------------------------------------------------- static int writeMem( int mode, unsigned int addr, int value ) { value = value & 0x000000ff; @@ -168,6 +173,7 @@ static int writeMem( int mode, unsigned int addr, int value ) } return 0; } +//---------------------------------------------------------------------------- static int convToXchar( int i ) { @@ -183,6 +189,7 @@ static int convToXchar( int i ) } return c; } +//---------------------------------------------------------------------------- static int convFromXchar( int i ) { @@ -581,6 +588,23 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) editValue = 0; editMask = 0; + highLightColor[ 0].setRgb( 0x00, 0x00, 0x00 ); + highLightColor[ 1].setRgb( 0x35, 0x40, 0x00 ); + highLightColor[ 2].setRgb( 0x18, 0x52, 0x18 ); + highLightColor[ 3].setRgb( 0x34, 0x5C, 0x5E ); + highLightColor[ 4].setRgb( 0x00, 0x4C, 0x80 ); + highLightColor[ 5].setRgb( 0x00, 0x03, 0xBA ); + highLightColor[ 6].setRgb( 0x38, 0x00, 0xD1 ); + highLightColor[ 7].setRgb( 0x72, 0x12, 0xB2 ); + highLightColor[ 8].setRgb( 0xAB, 0x00, 0xBA ); + highLightColor[ 9].setRgb( 0xB0, 0x00, 0x6F ); + highLightColor[10].setRgb( 0xC2, 0x00, 0x37 ); + highLightColor[11].setRgb( 0xBA, 0x0C, 0x00 ); + highLightColor[12].setRgb( 0xC9, 0x2C, 0x00 ); + highLightColor[13].setRgb( 0xBF, 0x53, 0x00 ); + highLightColor[14].setRgb( 0xCF, 0x72, 0x00 ); + highLightColor[15].setRgb( 0xC7, 0x8B, 0x3C ); + } //---------------------------------------------------------------------------- QHexEdit::~QHexEdit(void) @@ -987,6 +1011,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) { x = pxXoffset; + painter.setPen( this->palette().color(QPalette::WindowText)); sprintf( txt, "%06X", addr ); painter.drawText( x, y, tr(txt) ); @@ -1017,6 +1042,14 @@ void QHexEdit::paintEvent(QPaintEvent *event) } else { + if ( mb->buf[addr].actv > 0 ) + { + painter.setPen( highLightColor[ mb->buf[addr].actv ] ); + } + else + { + painter.setPen( this->palette().color(QPalette::WindowText)); + } txt[0] = convToXchar( (c >> 4) & 0x0F ); txt[1] = convToXchar( c & 0x0F ); txt[2] = 0; @@ -1032,6 +1065,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) } asciiTxt[16] = 0; + painter.setPen( this->palette().color(QPalette::WindowText)); painter.drawText( pxHexAscii, y, tr(asciiTxt) ); //addr += 16; diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index da497650..3fcf4aad 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -53,6 +53,8 @@ class QHexEdit : public QWidget void setLine( int newLineOffset ); void setAddr( int newAddrOffset ); void setScrollBars( QScrollBar *h, QScrollBar *v ); + + static const int HIGHLIGHT_ACTIVITY_NUM_COLORS = 16; protected: void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); @@ -70,6 +72,7 @@ class QHexEdit : public QWidget QScrollBar *vbar; QScrollBar *hbar; + QColor highLightColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ]; int viewMode; int lineOffset; From 6a425f61d183e72948febb4cef1408a59ae8ac41 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 19:54:11 -0400 Subject: [PATCH 22/37] Added activity color options to hex editor menu. --- src/drivers/Qt/HexEditor.cpp | 84 ++++++++++++++++++++++++++++++++++-- src/drivers/Qt/HexEditor.h | 8 +++- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index d28f289c..f39380cf 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -288,10 +288,10 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) //QVBoxLayout *mainLayout; QGridLayout *grid; QMenuBar *menuBar; - QMenu *fileMenu; - QMenu *viewMenu; + QMenu *fileMenu, *viewMenu, *hlgtMenu; QAction *saveROM; QAction *viewRAM, *viewPPU, *viewOAM, *viewROM; + QAction *actHlgt, *actHlgtRV; QActionGroup *group; setWindowTitle("Hex Editor"); @@ -362,6 +362,30 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) viewMenu->addAction(viewROM); viewRAM->setChecked(true); // Set default view + + // Highlighting + hlgtMenu = menuBar->addMenu(tr("Highlight")); + + // Highlighting -> Highlight Activity + actHlgt = new QAction(tr("Highlight Activity"), this); + //actHlgt->setShortcuts(QKeySequence::Open); + actHlgt->setStatusTip(tr("Highlight Activity")); + actHlgt->setCheckable(true); + actHlgt->setChecked(true); + connect(actHlgt, SIGNAL(triggered(bool)), this, SLOT(actvHighlightCB(bool)) ); + + hlgtMenu->addAction(actHlgt); + + // Highlighting -> Highlight Reverse Video + actHlgtRV = new QAction(tr("Highlight Reverse Video"), this); + //actHlgtRV->setShortcuts(QKeySequence::Open); + actHlgtRV->setStatusTip(tr("Highlight Reverse Video")); + actHlgtRV->setCheckable(true); + actHlgtRV->setChecked(false); + connect(actHlgtRV, SIGNAL(triggered(bool)), this, SLOT(actvHighlightRVCB(bool)) ); + + hlgtMenu->addAction(actHlgtRV); + //----------------------------------------------------------------------- // Menu End //----------------------------------------------------------------------- @@ -458,6 +482,18 @@ void HexEditorDialog_t::setViewROM(void) setMode( MODE_NES_ROM ); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::actvHighlightCB(bool enable) +{ + //printf("Highlight: %i \n", enable ); + editor->setHighlightActivity( enable ); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::actvHighlightRVCB(bool enable) +{ + //printf("Highlight: %i \n", enable ); + editor->setHighlightReverseVideo( enable ); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::showMemViewResults (bool reset) { int memSize; @@ -587,6 +623,8 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) editAddr = -1; editValue = 0; editMask = 0; + reverseVideo = false; + actvHighlightEnable = true; highLightColor[ 0].setRgb( 0x00, 0x00, 0x00 ); highLightColor[ 1].setRgb( 0x35, 0x40, 0x00 ); @@ -605,6 +643,26 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) highLightColor[14].setRgb( 0xCF, 0x72, 0x00 ); highLightColor[15].setRgb( 0xC7, 0x8B, 0x3C ); + for (int i=0; i= 0.5 ) + { + grayScale = 0.0; + } + else + { + grayScale = 1.0; + } + rvActvTextColor[i].setRgbF( grayScale, grayScale, grayScale ); + } } //---------------------------------------------------------------------------- QHexEdit::~QHexEdit(void) @@ -636,6 +694,16 @@ void QHexEdit::calcFontData(void) viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; } //---------------------------------------------------------------------------- +void QHexEdit::setHighlightActivity( int enable ) +{ + actvHighlightEnable = enable; +} +//---------------------------------------------------------------------------- +void QHexEdit::setHighlightReverseVideo( int enable ) +{ + reverseVideo = enable; +} +//---------------------------------------------------------------------------- void QHexEdit::setMode( int mode ) { viewMode = mode; @@ -1042,9 +1110,17 @@ void QHexEdit::paintEvent(QPaintEvent *event) } else { - if ( mb->buf[addr].actv > 0 ) + if ( actvHighlightEnable && (mb->buf[addr].actv > 0) ) { - painter.setPen( highLightColor[ mb->buf[addr].actv ] ); + if ( reverseVideo ) + { + painter.setPen( rvActvTextColor[ mb->buf[addr].actv ] ); + painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb->buf[addr].actv ] ); + } + else + { + painter.setPen( highLightColor[ mb->buf[addr].actv ] ); + } } else { diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 3fcf4aad..cd42deab 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -53,6 +53,8 @@ class QHexEdit : public QWidget void setLine( int newLineOffset ); void setAddr( int newAddrOffset ); void setScrollBars( QScrollBar *h, QScrollBar *v ); + void setHighlightActivity( int enable ); + void setHighlightReverseVideo( int enable ); static const int HIGHLIGHT_ACTIVITY_NUM_COLORS = 16; protected: @@ -73,6 +75,7 @@ class QHexEdit : public QWidget QScrollBar *vbar; QScrollBar *hbar; QColor highLightColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ]; + QColor rvActvTextColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ]; int viewMode; int lineOffset; @@ -97,6 +100,8 @@ class QHexEdit : public QWidget int editMask; bool cursorBlink; + bool reverseVideo; + bool actvHighlightEnable; }; class HexEditorDialog_t : public QDialog @@ -150,5 +155,6 @@ class HexEditorDialog_t : public QDialog void setViewPPU(void); void setViewOAM(void); void setViewROM(void); - + void actvHighlightCB(bool value); + void actvHighlightRVCB(bool value); }; From f3af7cc6c8d9807d8c3be91d34250df2373c0e27 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 20:20:18 -0400 Subject: [PATCH 23/37] Added hex editor fore ground and back ground color options. --- src/drivers/Qt/HexEditor.cpp | 91 ++++++++++++++++++++++++++++++++---- src/drivers/Qt/HexEditor.h | 4 ++ 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index f39380cf..feea608f 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "../../types.h" #include "../../fceu.h" @@ -288,10 +289,10 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) //QVBoxLayout *mainLayout; QGridLayout *grid; QMenuBar *menuBar; - QMenu *fileMenu, *viewMenu, *hlgtMenu; + QMenu *fileMenu, *viewMenu, *colorMenu; QAction *saveROM; QAction *viewRAM, *viewPPU, *viewOAM, *viewROM; - QAction *actHlgt, *actHlgtRV; + QAction *actHlgt, *actHlgtRV, *actColorFG, *actColorBG; QActionGroup *group; setWindowTitle("Hex Editor"); @@ -363,10 +364,10 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) viewRAM->setChecked(true); // Set default view - // Highlighting - hlgtMenu = menuBar->addMenu(tr("Highlight")); + // Color Menu + colorMenu = menuBar->addMenu(tr("Color")); - // Highlighting -> Highlight Activity + // Color -> Highlight Activity actHlgt = new QAction(tr("Highlight Activity"), this); //actHlgt->setShortcuts(QKeySequence::Open); actHlgt->setStatusTip(tr("Highlight Activity")); @@ -374,17 +375,33 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) actHlgt->setChecked(true); connect(actHlgt, SIGNAL(triggered(bool)), this, SLOT(actvHighlightCB(bool)) ); - hlgtMenu->addAction(actHlgt); + colorMenu->addAction(actHlgt); - // Highlighting -> Highlight Reverse Video + // Color -> Highlight Reverse Video actHlgtRV = new QAction(tr("Highlight Reverse Video"), this); //actHlgtRV->setShortcuts(QKeySequence::Open); actHlgtRV->setStatusTip(tr("Highlight Reverse Video")); actHlgtRV->setCheckable(true); - actHlgtRV->setChecked(false); + actHlgtRV->setChecked(true); connect(actHlgtRV, SIGNAL(triggered(bool)), this, SLOT(actvHighlightRVCB(bool)) ); - hlgtMenu->addAction(actHlgtRV); + colorMenu->addAction(actHlgtRV); + + // Color -> ForeGround Color + actColorFG = new QAction(tr("ForeGround Color"), this); + //actColorFG->setShortcuts(QKeySequence::Open); + actColorFG->setStatusTip(tr("ForeGround Color")); + connect(actColorFG, SIGNAL(triggered(void)), this, SLOT(pickForeGroundColor(void)) ); + + colorMenu->addAction(actColorFG); + + // Color -> BackGround Color + actColorBG = new QAction(tr("BackGround Color"), this); + //actColorBG->setShortcuts(QKeySequence::Open); + actColorBG->setStatusTip(tr("BackGround Color")); + connect(actColorBG, SIGNAL(triggered(void)), this, SLOT(pickBackGroundColor(void)) ); + + colorMenu->addAction(actColorBG); //----------------------------------------------------------------------- // Menu End @@ -440,6 +457,36 @@ void HexEditorDialog_t::closeWindow(void) done(0); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::pickForeGroundColor(void) +{ + int ret; + QColorDialog dialog( this ); + + dialog.setOption( QColorDialog::DontUseNativeDialog, true ); + dialog.show(); + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + editor->setForeGroundColor( dialog.selectedColor() ); + } +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::pickBackGroundColor(void) +{ + int ret; + QColorDialog dialog( this ); + + dialog.setOption( QColorDialog::DontUseNativeDialog, true ); + dialog.show(); + ret = dialog.exec(); + + if ( ret == QDialog::Accepted ) + { + editor->setBackGroundColor( dialog.selectedColor() ); + } +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::vbarMoved(int value) { //printf("VBar Moved: %i\n", value); @@ -623,7 +670,7 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) editAddr = -1; editValue = 0; editMask = 0; - reverseVideo = false; + reverseVideo = true; actvHighlightEnable = true; highLightColor[ 0].setRgb( 0x00, 0x00, 0x00 ); @@ -704,6 +751,30 @@ void QHexEdit::setHighlightReverseVideo( int enable ) reverseVideo = enable; } //---------------------------------------------------------------------------- +void QHexEdit::setForeGroundColor( QColor fg ) +{ + QPalette pal; + + pal = this->palette(); + //pal.setColor(QPalette::Base , Qt::black); + //pal.setColor(QPalette::Background, Qt::black); + pal.setColor(QPalette::WindowText, fg ); + + this->setPalette(pal); +} +//---------------------------------------------------------------------------- +void QHexEdit::setBackGroundColor( QColor bg ) +{ + QPalette pal; + + pal = this->palette(); + //pal.setColor(QPalette::Base , Qt::black); + pal.setColor(QPalette::Background, bg ); + //pal.setColor(QPalette::WindowText, fg ); + + this->setPalette(pal); +} +//---------------------------------------------------------------------------- void QHexEdit::setMode( int mode ) { viewMode = mode; diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index cd42deab..5892bf3c 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -55,6 +55,8 @@ class QHexEdit : public QWidget void setScrollBars( QScrollBar *h, QScrollBar *v ); void setHighlightActivity( int enable ); void setHighlightReverseVideo( int enable ); + void setForeGroundColor( QColor fg ); + void setBackGroundColor( QColor bg ); static const int HIGHLIGHT_ACTIVITY_NUM_COLORS = 16; protected: @@ -157,4 +159,6 @@ class HexEditorDialog_t : public QDialog void setViewROM(void); void actvHighlightCB(bool value); void actvHighlightRVCB(bool value); + void pickForeGroundColor(void); + void pickBackGroundColor(void); }; From b01b1c7a4cef79f44f2e5293d299dfbe9b0a995c Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 20:42:33 -0400 Subject: [PATCH 24/37] Cursor selection update to Hex editor --- src/drivers/Qt/HexEditor.cpp | 74 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index feea608f..060d83c8 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -833,14 +833,14 @@ QPoint QHexEdit::convPixToCursor( QPoint p ) } else { - if ( rx >= 1.0 ) - { - c.setX( 2*( (int)ox ) + 1 ); - } - else - { + //if ( rx >= 1.0 ) + //{ + // c.setX( 2*( (int)ox ) + 1 ); + //} + //else + //{ c.setX( 2*( (int)ox ) ); - } + //} } } else @@ -1078,8 +1078,8 @@ void QHexEdit::mousePressEvent(QMouseEvent * event) void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; - int c; - char txt[32], asciiTxt[32]; + int c, cx, cy, ca; + char txt[32], asciiTxt[4]; QPainter painter(this); painter.setFont(font); @@ -1121,23 +1121,27 @@ void QHexEdit::paintEvent(QPaintEvent *event) cursorBlinkCount++; } + cy = pxYoffset + (pxLineSpacing*cursorPosY) - pxCursorHeight + pxLineLead; + + if ( cursorPosX < 32 ) + { + int a = (cursorPosX / 2); + int r = (cursorPosX % 2); + cx = pxHexOffset + (a*3*pxCharWidth) + (r*pxCharWidth); + + ca = 16*(lineOffset + cursorPosY) + a; + } + else + { + int a = (cursorPosX-32); + cx = pxHexAscii + (a*pxCharWidth); + + ca = 16*(lineOffset + cursorPosY) + a; + } + if ( cursorBlink ) { - y = pxYoffset + (pxLineSpacing*cursorPosY) - pxCursorHeight + pxLineLead; - - if ( cursorPosX < 32 ) - { - int a = (cursorPosX / 2); - int r = (cursorPosX % 2); - x = pxHexOffset + (a*3*pxCharWidth) + (r*pxCharWidth); - } - else - { - x = pxHexAscii + (cursorPosX - 32)*pxCharWidth; - } - - //painter.setPen( this->palette().color(QPalette::WindowText)); - painter.fillRect( x , y, pxCharWidth, pxCursorHeight, QColor("gray") ); + painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, QColor("gray") ); } painter.setPen( this->palette().color(QPalette::WindowText)); @@ -1164,12 +1168,14 @@ void QHexEdit::paintEvent(QPaintEvent *event) if ( ::isprint(c) ) { - asciiTxt[col] = c; + asciiTxt[0] = c; } else { - asciiTxt[col] = '.'; + asciiTxt[0] = '.'; } + asciiTxt[1] = 0; + if ( addr == editAddr ) { // Set a cell currently being editting to red text painter.setPen( QColor("red") ); @@ -1187,6 +1193,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) { painter.setPen( rvActvTextColor[ mb->buf[addr].actv ] ); painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb->buf[addr].actv ] ); + painter.fillRect( pxHexAscii + (col*pxCharWidth) , y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb->buf[addr].actv ] ); } else { @@ -1200,25 +1207,24 @@ void QHexEdit::paintEvent(QPaintEvent *event) txt[0] = convToXchar( (c >> 4) & 0x0F ); txt[1] = convToXchar( c & 0x0F ); txt[2] = 0; + + if ( cursorBlink && (ca == addr) ) + { + painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, QColor("gray") ); + } painter.drawText( x, y, tr(txt) ); + painter.drawText( pxHexAscii + (col*pxCharWidth), y, tr(asciiTxt) ); } } - else - { - asciiTxt[col] = 0; - } x += (3*pxCharWidth); addr++; } - asciiTxt[16] = 0; - - painter.setPen( this->palette().color(QPalette::WindowText)); - painter.drawText( pxHexAscii, y, tr(asciiTxt) ); //addr += 16; y += pxLineSpacing; } + painter.setPen( this->palette().color(QPalette::WindowText)); painter.drawText( pxHexOffset, pxLineSpacing, "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" ); painter.drawLine( pxHexOffset - (pxCharWidth/2), 0, pxHexOffset - (pxCharWidth/2), h ); painter.drawLine( pxHexAscii - (pxCharWidth/2), 0, pxHexAscii - (pxCharWidth/2), h ); From 66810fdb9dc3ae9e0239cdfe8239ae2becb5739a Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 20:48:31 -0400 Subject: [PATCH 25/37] Changed cursor movement logic to move to nearest hex address. --- src/drivers/Qt/HexEditor.cpp | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 060d83c8..e682dc1b 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -891,8 +891,21 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) if (event->matches(QKeySequence::MoveToNextChar)) { - cursorPosX++; - + if ( cursorPosX < 32 ) + { + if ( cursorPosX % 2 ) + { + cursorPosX++; + } + else + { + cursorPosX += 2; + } + } + else + { + cursorPosX++; + } if ( cursorPosX >= 48 ) { cursorPosX = 47; @@ -901,8 +914,21 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) } else if (event->matches(QKeySequence::MoveToPreviousChar)) { - cursorPosX--; - + if ( cursorPosX < 33 ) + { + if ( cursorPosX % 2 ) + { + cursorPosX -= 3; + } + else + { + cursorPosX -= 2; + } + } + else + { + cursorPosX--; + } if ( cursorPosX < 0 ) { cursorPosX = 0; From 4b92abdb47c473001eee2129e1693b8013445214 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 21:38:09 -0400 Subject: [PATCH 26/37] Added framework for hex editor context menu. --- src/drivers/Qt/HexEditor.cpp | 91 ++++++++++++++++++++++++++++++++++++ src/drivers/Qt/HexEditor.h | 2 + 2 files changed, 93 insertions(+) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index e682dc1b..80b1d34e 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -885,6 +885,28 @@ QPoint QHexEdit::convPixToCursor( QPoint p ) return c; } //---------------------------------------------------------------------------- +int QHexEdit::convPixToAddr( QPoint p ) +{ + int a,addr; + QPoint c = convPixToCursor(p); + + //printf("Cursor: %ix%i\n", c.x(), c.y() ); + + if ( c.x() < 32 ) + { + a = (c.x() / 2); + + addr = 16*(lineOffset + c.y()) + a; + } + else + { + a = (c.x()-32); + + addr = 16*(lineOffset + c.y()) + a; + } + return addr; +} +//---------------------------------------------------------------------------- void QHexEdit::keyPressEvent(QKeyEvent *event) { printf("Hex Window Key Press: 0x%x \n", event->key() ); @@ -1099,6 +1121,75 @@ void QHexEdit::mousePressEvent(QMouseEvent * event) resetCursor(); } +} +//---------------------------------------------------------------------------- +void QHexEdit::contextMenuEvent(QContextMenuEvent *event) +{ + QAction *act; + QMenu menu(this); + int addr; + char stmp[128]; + + addr = convPixToAddr( event->pos() ); + //printf("contextMenuEvent\n"); + + switch ( viewMode ) + { + case HexEditorDialog_t::MODE_NES_RAM: + { + act = new QAction(tr("Add Symbolic Debug Name"), this); + menu.addAction(act); + + sprintf( stmp, "Add Read Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + + sprintf( stmp, "Add Write Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + + sprintf( stmp, "Add Execute Breakpoint for Address $%04X", addr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + + if ( addr > 0x6000 ) + { + int romAddr = GetNesFileAddress(addr); + + if ( romAddr >= 0 ) + { + sprintf( stmp, "Go Here in ROM File: (%08X)", romAddr ); + act = new QAction(tr(stmp), this); + menu.addAction(act); + } + } + + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + } + break; + case HexEditorDialog_t::MODE_NES_PPU: + { + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + } + break; + case HexEditorDialog_t::MODE_NES_OAM: + { + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + } + break; + case HexEditorDialog_t::MODE_NES_ROM: + { + act = new QAction(tr("Add Bookmark"), this); + menu.addAction(act); + } + break; + } + + menu.exec(event->globalPos()); + } //---------------------------------------------------------------------------- void QHexEdit::paintEvent(QPaintEvent *event) diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 5892bf3c..3d35f352 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -65,10 +65,12 @@ class QHexEdit : public QWidget void keyReleaseEvent(QKeyEvent *event); void mousePressEvent(QMouseEvent * event); void resizeEvent(QResizeEvent *event); + void contextMenuEvent(QContextMenuEvent *event); void calcFontData(void); void resetCursor(void); QPoint convPixToCursor( QPoint p ); + int convPixToAddr( QPoint p ); QFont font; From ff3125cbf8afa7a9ab913739a73584150050f528 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 21:42:51 -0400 Subject: [PATCH 27/37] Bug fix for updating vertical bar when using page up/down functions. --- src/drivers/Qt/HexEditor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 80b1d34e..a702747c 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -1012,6 +1012,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { lineOffset = maxLineOffset; } + vbar->setValue( lineOffset ); resetCursor(); } else if (event->matches(QKeySequence::MoveToPreviousPage)) @@ -1022,16 +1023,19 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { lineOffset = 0; } + vbar->setValue( lineOffset ); resetCursor(); } else if (event->matches(QKeySequence::MoveToEndOfDocument)) { lineOffset = maxLineOffset; + vbar->setValue( lineOffset ); resetCursor(); } else if (event->matches(QKeySequence::MoveToStartOfDocument)) { lineOffset = 0; + vbar->setValue( lineOffset ); resetCursor(); } else if (event->key() == Qt::Key_Tab && (cursorPosX < 32) ) From 832a6b0a64676d83290bcbbd2390f43a23c641e2 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 22 Aug 2020 22:01:53 -0400 Subject: [PATCH 28/37] Setting up framework for hex editor bookmarks --- src/drivers/Qt/HexEditor.cpp | 21 +++++++++++++++++++++ src/drivers/Qt/HexEditor.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index a702747c..d0a59e38 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -403,6 +403,11 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) colorMenu->addAction(actColorBG); + // Bookmarks Menu + bookmarkMenu = menuBar->addMenu(tr("Bookmarks")); + + populateBookmarkMenu(); + //----------------------------------------------------------------------- // Menu End //----------------------------------------------------------------------- @@ -451,6 +456,22 @@ HexEditorDialog_t::~HexEditorDialog_t(void) periodicTimer->stop(); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::populateBookmarkMenu(void) +{ + QAction *act; + + bookmarkMenu->clear(); + + // Bookmarks -> Remove All Bookmarks + act = new QAction(tr("Remove All Bookmarks"), this); + //act->setShortcuts(QKeySequence::Open); + act->setStatusTip(tr("Remove All Bookmarks")); + //connect(act, SIGNAL(triggered(void)), this, SLOT(pickBackGroundColor(void)) ); + + bookmarkMenu->addAction(act); + bookmarkMenu->addSeparator(); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::closeWindow(void) { //printf("Close Window\n"); diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 3d35f352..e52eb356 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -131,11 +132,13 @@ class HexEditorDialog_t : public QDialog void showMemViewResults (bool reset); int checkMemActivity(void); int calcVisibleRange( int *start_out, int *end_out, int *center_out ); + void populateBookmarkMenu(void); QScrollBar *vbar; QScrollBar *hbar; QHexEdit *editor; QTimer *periodicTimer; + QMenu *bookmarkMenu; int mode; //int memSize; From a93af6f8218acc06c8623d7f43ef4300fe76c3e8 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 23 Aug 2020 10:00:54 -0400 Subject: [PATCH 29/37] Cleanup of hex editor code, consolidated as much as possible into QHexEdit custom widget. --- src/drivers/Qt/HexEditor.cpp | 300 +++++++++++++++++++---------------- src/drivers/Qt/HexEditor.h | 45 +++--- 2 files changed, 187 insertions(+), 158 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index d0a59e38..bdc6f526 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -33,12 +33,6 @@ #include "Qt/fceuWrapper.h" #include "Qt/HexEditor.h" -//enum { -// MODE_NES_RAM = 0, -// MODE_NES_PPU, -// MODE_NES_OAM, -// MODE_NES_ROM -//}; //---------------------------------------------------------------------------- static int getRAM( unsigned int i ) { @@ -112,7 +106,7 @@ static int writeMem( int mode, unsigned int addr, int value ) switch ( mode ) { default: - case HexEditorDialog_t::MODE_NES_RAM: + case QHexEdit::MODE_NES_RAM: { if ( addr < 0x8000 ) { @@ -132,7 +126,7 @@ static int writeMem( int mode, unsigned int addr, int value ) } } break; - case HexEditorDialog_t::MODE_NES_PPU: + case QHexEdit::MODE_NES_PPU: { addr &= 0x3FFF; if (addr < 0x2000) @@ -149,13 +143,13 @@ static int writeMem( int mode, unsigned int addr, int value ) } } break; - case HexEditorDialog_t::MODE_NES_OAM: + case QHexEdit::MODE_NES_OAM: { addr &= 0xFF; SPRAM[addr] = value; } break; - case HexEditorDialog_t::MODE_NES_ROM: + case QHexEdit::MODE_NES_ROM: { if (addr < 16) { @@ -414,7 +408,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) //mainLayout = new QVBoxLayout(); grid = new QGridLayout(this); - editor = new QHexEdit( &mb, this); + editor = new QHexEdit(this); vbar = new QScrollBar( Qt::Vertical, this ); hbar = new QScrollBar( Qt::Horizontal, this ); @@ -437,12 +431,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) //connect( vbar, SIGNAL(sliderMoved(int)), this, SLOT(vbarMoved(int)) ); connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); - mode = MODE_NES_RAM; - memAccessFunc = getRAM; - redraw = false; - total_instructions_lp = 0; - - showMemViewResults(true); + editor->memModeUpdate(); periodicTimer = new QTimer( this ); @@ -520,34 +509,29 @@ void HexEditorDialog_t::vbarChanged(int value) editor->setLine( value ); } //---------------------------------------------------------------------------- -void HexEditorDialog_t::setMode(int new_mode) +void HexEditorDialog_t::gotoAddress( int newAddr ) { - if ( mode != new_mode ) - { - mode = new_mode; - showMemViewResults(true); - editor->setMode( mode ); - } + editor->setAddr( newAddr ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRAM(void) { - setMode( MODE_NES_RAM ); + editor->setMode( QHexEdit::MODE_NES_RAM ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewPPU(void) { - setMode( MODE_NES_PPU ); + editor->setMode( QHexEdit::MODE_NES_PPU ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewOAM(void) { - setMode( MODE_NES_OAM ); + editor->setMode( QHexEdit::MODE_NES_OAM ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewROM(void) { - setMode( MODE_NES_ROM ); + editor->setMode( QHexEdit::MODE_NES_ROM ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::actvHighlightCB(bool enable) @@ -562,109 +546,22 @@ void HexEditorDialog_t::actvHighlightRVCB(bool enable) editor->setHighlightReverseVideo( enable ); } //---------------------------------------------------------------------------- -void HexEditorDialog_t::showMemViewResults (bool reset) -{ - int memSize; - - switch ( mode ) - { - default: - case MODE_NES_RAM: - memAccessFunc = getRAM; - memSize = 0x10000; - break; - case MODE_NES_PPU: - memAccessFunc = getPPU; - memSize = (GameInfo->type == GIT_NSF ? 0x2000 : 0x4000); - break; - case MODE_NES_OAM: - memAccessFunc = getOAM; - memSize = 0x100; - break; - case MODE_NES_ROM: - - if ( GameInfo != NULL ) - { - memAccessFunc = getROM; - memSize = 16 + CHRsize[0] + PRGsize[0]; - } - else - { // No Game Loaded!!! Get out of Function - memAccessFunc = NULL; - memSize = 0; - return; - } - break; - } - - if ( memSize != mb.size() ) - { - mb.setAccessFunc( memAccessFunc ); - - if ( mb.reAlloc( memSize ) ) - { - printf("Error: Failed to allocate memview buffer size\n"); - return; - } - } -} -//---------------------------------------------------------------------------- void HexEditorDialog_t::updatePeriodic(void) { //printf("Update Periodic\n"); - checkMemActivity(); + editor->checkMemActivity(); - showMemViewResults(false); + editor->memModeUpdate(); editor->update(); } //---------------------------------------------------------------------------- -int HexEditorDialog_t::checkMemActivity(void) -{ - int c; - - // Don't perform memory activity checks when: - // 1. In ROM View Mode - // 2. The simulation is not cycling (paused) - - if ( ( mode == MODE_NES_ROM ) || - ( total_instructions_lp == total_instructions ) ) - { - return -1; - } - - for (int i=0; i 0 ) - { - //mb.buf[i].draw = 1; - mb.buf[i].actv--; - } - } - } - total_instructions_lp = total_instructions; - - return 0; -} -//---------------------------------------------------------------------------- -QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) +QHexEdit::QHexEdit(QWidget *parent) : QWidget( parent ) { QPalette pal; - mb = blkPtr; - this->setFocusPolicy(Qt::StrongFocus); font.setFamily("Courier New"); @@ -681,7 +578,8 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) calcFontData(); - viewMode = HexEditorDialog_t::MODE_NES_RAM; + memAccessFunc = getRAM; + viewMode = MODE_NES_RAM; lineOffset = 0; cursorPosX = 0; cursorPosY = 0; @@ -693,6 +591,7 @@ QHexEdit::QHexEdit(memBlock_t *blkPtr, QWidget *parent) editMask = 0; reverseVideo = true; actvHighlightEnable = true; + total_instructions_lp = 0; highLightColor[ 0].setRgb( 0x00, 0x00, 0x00 ); highLightColor[ 1].setRgb( 0x35, 0x40, 0x00 ); @@ -798,7 +697,11 @@ void QHexEdit::setBackGroundColor( QColor bg ) //---------------------------------------------------------------------------- void QHexEdit::setMode( int mode ) { - viewMode = mode; + if ( viewMode != mode ) + { + viewMode = mode; + memModeUpdate(); + } } //---------------------------------------------------------------------------- void QHexEdit::setLine( int newLineOffset ) @@ -806,6 +709,26 @@ void QHexEdit::setLine( int newLineOffset ) lineOffset = newLineOffset; } //---------------------------------------------------------------------------- +void QHexEdit::setAddr( int newAddr ) +{ + int addr; + lineOffset = newAddr / 16; + + if ( lineOffset < 0 ) + { + lineOffset = 0; + } + else if ( lineOffset >= maxLineOffset ) + { + lineOffset = maxLineOffset; + } + + addr = 16*lineOffset; + + cursorPosX = 2*((newAddr - addr)%16); + cursorPosY = (newAddr - addr)/16; +} +//---------------------------------------------------------------------------- void QHexEdit::setScrollBars( QScrollBar *h, QScrollBar *v ) { hbar = h; vbar = v; @@ -820,7 +743,7 @@ void QHexEdit::resizeEvent(QResizeEvent *event) viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; - maxLineOffset = mb->numLines() - viewLines + 1; + maxLineOffset = mb.numLines() - viewLines + 1; } //---------------------------------------------------------------------------- void QHexEdit::resetCursor(void) @@ -1078,7 +1001,9 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { int offs = (cursorPosX-32); int addr = 16*(lineOffset+cursorPosY) + offs; + fceuWrapperLock(); writeMem( viewMode, addr, key ); + fceuWrapperUnLock(); editAddr = -1; editValue = 0; @@ -1104,7 +1029,9 @@ void QHexEdit::keyPressEvent(QKeyEvent *event) { nibbleValue = editValue | nibbleValue; + fceuWrapperLock(); writeMem( viewMode, editAddr, nibbleValue ); + fceuWrapperUnLock(); editAddr = -1; editValue = 0; @@ -1160,7 +1087,7 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) switch ( viewMode ) { - case HexEditorDialog_t::MODE_NES_RAM: + case MODE_NES_RAM: { act = new QAction(tr("Add Symbolic Debug Name"), this); menu.addAction(act); @@ -1183,9 +1110,11 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) if ( romAddr >= 0 ) { + jumpToRomValue = romAddr; sprintf( stmp, "Go Here in ROM File: (%08X)", romAddr ); act = new QAction(tr(stmp), this); menu.addAction(act); + connect( act, SIGNAL(triggered(void)), this, SLOT(jumpToROM(void)) ); } } @@ -1193,19 +1122,19 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) menu.addAction(act); } break; - case HexEditorDialog_t::MODE_NES_PPU: + case MODE_NES_PPU: { act = new QAction(tr("Add Bookmark"), this); menu.addAction(act); } break; - case HexEditorDialog_t::MODE_NES_OAM: + case MODE_NES_OAM: { act = new QAction(tr("Add Bookmark"), this); menu.addAction(act); } break; - case HexEditorDialog_t::MODE_NES_ROM: + case MODE_NES_ROM: { act = new QAction(tr("Add Bookmark"), this); menu.addAction(act); @@ -1217,6 +1146,111 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) } //---------------------------------------------------------------------------- +void QHexEdit::jumpToROM(void) +{ + setMode( MODE_NES_ROM ); + + maxLineOffset = mb.numLines() - viewLines + 1; + + if ( lineOffset > maxLineOffset ) + { + lineOffset = maxLineOffset; + } + setAddr( jumpToRomValue ); +} +//---------------------------------------------------------------------------- +int QHexEdit::checkMemActivity(void) +{ + int c; + + // Don't perform memory activity checks when: + // 1. In ROM View Mode + // 2. The simulation is not cycling (paused) + + if ( ( viewMode == MODE_NES_ROM ) || + ( total_instructions_lp == total_instructions ) ) + { + return -1; + } + + for (int i=0; i 0 ) + { + //mb.buf[i].draw = 1; + mb.buf[i].actv--; + } + } + } + total_instructions_lp = total_instructions; + + return 0; +} +//---------------------------------------------------------------------------- +void QHexEdit::memModeUpdate(void) +{ + int memSize; + + switch ( getMode() ) + { + default: + case MODE_NES_RAM: + memAccessFunc = getRAM; + memSize = 0x10000; + break; + case MODE_NES_PPU: + memAccessFunc = getPPU; + if ( GameInfo ) + { + memSize = (GameInfo->type == GIT_NSF ? 0x2000 : 0x4000); + } + else + { + memSize = 0x4000; + } + break; + case MODE_NES_OAM: + memAccessFunc = getOAM; + memSize = 0x100; + break; + case MODE_NES_ROM: + + if ( GameInfo != NULL ) + { + memAccessFunc = getROM; + memSize = 16 + CHRsize[0] + PRGsize[0]; + } + else + { // No Game Loaded!!! Get out of Function + memAccessFunc = NULL; + memSize = 0; + return; + } + break; + } + + if ( memSize != mb.size() ) + { + mb.setAccessFunc( memAccessFunc ); + + if ( mb.reAlloc( memSize ) ) + { + printf("Error: Failed to allocate memview buffer size\n"); + return; + } + } +} +//---------------------------------------------------------------------------- void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; @@ -1244,7 +1278,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) } //printf("Draw Area: %ix%i \n", event->rect().width(), event->rect().height() ); // - maxLineOffset = mb->numLines() - nrow + 1; + maxLineOffset = mb.numLines() - nrow + 1; if ( lineOffset > maxLineOffset ) { @@ -1304,9 +1338,9 @@ void QHexEdit::paintEvent(QPaintEvent *event) for (col=0; col<16; col++) { - if ( addr < mb->size() ) + if ( addr < mb.size() ) { - c = mb->buf[addr].data; + c = mb.buf[addr].data; if ( ::isprint(c) ) { @@ -1329,17 +1363,17 @@ void QHexEdit::paintEvent(QPaintEvent *event) } else { - if ( actvHighlightEnable && (mb->buf[addr].actv > 0) ) + if ( actvHighlightEnable && (mb.buf[addr].actv > 0) ) { if ( reverseVideo ) { - painter.setPen( rvActvTextColor[ mb->buf[addr].actv ] ); - painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb->buf[addr].actv ] ); - painter.fillRect( pxHexAscii + (col*pxCharWidth) , y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb->buf[addr].actv ] ); + painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] ); + painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); + painter.fillRect( pxHexAscii + (col*pxCharWidth) , y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); } else { - painter.setPen( highLightColor[ mb->buf[addr].actv ] ); + painter.setPen( highLightColor[ mb.buf[addr].actv ] ); } } else diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index e52eb356..76bf4dd0 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -47,9 +47,10 @@ class QHexEdit : public QWidget Q_OBJECT public: - QHexEdit(memBlock_t *blkPtr, QWidget *parent = 0); + QHexEdit(QWidget *parent = 0); ~QHexEdit(void); + int getMode(void){ return viewMode; }; void setMode( int mode ); void setLine( int newLineOffset ); void setAddr( int newAddrOffset ); @@ -58,7 +59,15 @@ class QHexEdit : public QWidget void setHighlightReverseVideo( int enable ); void setForeGroundColor( QColor fg ); void setBackGroundColor( QColor bg ); + void memModeUpdate(void); + int checkMemActivity(void); + enum { + MODE_NES_RAM = 0, + MODE_NES_PPU, + MODE_NES_OAM, + MODE_NES_ROM + }; static const int HIGHLIGHT_ACTIVITY_NUM_COLORS = 16; protected: void paintEvent(QPaintEvent *event); @@ -75,13 +84,16 @@ class QHexEdit : public QWidget QFont font; - memBlock_t *mb; + memBlock_t mb; + int (*memAccessFunc)( unsigned int offset); QScrollBar *vbar; QScrollBar *hbar; QColor highLightColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ]; QColor rvActvTextColor[ HIGHLIGHT_ACTIVITY_NUM_COLORS ]; + uint64_t total_instructions_lp; + int viewMode; int lineOffset; int pxCharWidth; @@ -103,10 +115,15 @@ class QHexEdit : public QWidget int editAddr; int editValue; int editMask; + int jumpToRomValue; bool cursorBlink; bool reverseVideo; bool actvHighlightEnable; + + private slots: + void jumpToROM(void); + }; class HexEditorDialog_t : public QDialog @@ -117,21 +134,9 @@ class HexEditorDialog_t : public QDialog HexEditorDialog_t(QWidget *parent = 0); ~HexEditorDialog_t(void); - enum { - MODE_NES_RAM = 0, - MODE_NES_PPU, - MODE_NES_OAM, - MODE_NES_ROM - }; - - int getMode(void){ return mode; } protected: - void initMem(void); - void setMode(int new_mode); - void showMemViewResults (bool reset); - int checkMemActivity(void); - int calcVisibleRange( int *start_out, int *end_out, int *center_out ); + void gotoAddress(int newAddr); void populateBookmarkMenu(void); QScrollBar *vbar; @@ -140,16 +145,6 @@ class HexEditorDialog_t : public QDialog QTimer *periodicTimer; QMenu *bookmarkMenu; - int mode; - //int memSize; - //int mbuf_size; - memBlock_t mb; - int (*memAccessFunc)( unsigned int offset); - - uint64_t total_instructions_lp; - - bool redraw; - private: public slots: From e8f1ffdf8d41793f474779bfba503908ebd0e971 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sun, 23 Aug 2020 22:24:54 -0400 Subject: [PATCH 30/37] Added hex editor horizontal scroll logic. --- src/drivers/Qt/ConsoleUtilities.cpp | 32 ++++++++++++++ src/drivers/Qt/ConsoleUtilities.h | 2 + src/drivers/Qt/HexEditor.cpp | 66 ++++++++++++++++++++++++----- src/drivers/Qt/HexEditor.h | 5 +++ 4 files changed, 94 insertions(+), 11 deletions(-) diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp index 6af44d62..50da5de5 100644 --- a/src/drivers/Qt/ConsoleUtilities.cpp +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -2,6 +2,7 @@ #include #include +#include "../../fceu.h" #include "Qt/ConsoleUtilities.h" //--------------------------------------------------------------------------- @@ -35,3 +36,34 @@ int getDirFromFile( const char *path, char *dir ) return 0; } //--------------------------------------------------------------------------- +const char *getRomFile( void ) +{ + if ( GameInfo ) + { + return GameInfo->filename; + } + return NULL; +} +//--------------------------------------------------------------------------- +// TODO Finish writing this func +int getFileBaseName( const char *filepath, char *base ) +{ + int i,j=0, start=0; + if ( filepath == NULL ) + { + return 0; + } + i=0; j=0; + while ( filepath[i] != 0 ) + { + if ( filepath[i] == '/' ) + { + j = i; + } + i++; + } + start = j; + + return 0; +} +//--------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h index 0f4417e2..46496fc1 100644 --- a/src/drivers/Qt/ConsoleUtilities.h +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -1,3 +1,5 @@ // ConsoleUtilities.h int getDirFromFile( const char *path, char *dir ); + +const char *getRomFile( void ); diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index bdc6f526..3172fc8f 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -32,6 +32,7 @@ #include "Qt/keyscan.h" #include "Qt/fceuWrapper.h" #include "Qt/HexEditor.h" +#include "Qt/ConsoleUtilities.h" //---------------------------------------------------------------------------- static int getRAM( unsigned int i ) @@ -301,11 +302,11 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) // File fileMenu = menuBar->addMenu(tr("File")); - // File -> Open ROM + // File -> Save ROM saveROM = new QAction(tr("Save ROM"), this); //saveROM->setShortcuts(QKeySequence::Open); saveROM->setStatusTip(tr("Save ROM File")); - //connect(saveROM, SIGNAL(triggered()), this, SLOT(saveROMFile(void)) ); + connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFile(void)) ); fileMenu->addAction(saveROM); @@ -429,6 +430,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) editor->setScrollBars( hbar, vbar ); //connect( vbar, SIGNAL(sliderMoved(int)), this, SLOT(vbarMoved(int)) ); + connect( hbar, SIGNAL(valueChanged(int)), this, SLOT(hbarChanged(int)) ); connect( vbar, SIGNAL(valueChanged(int)), this, SLOT(vbarChanged(int)) ); editor->memModeUpdate(); @@ -509,11 +511,22 @@ void HexEditorDialog_t::vbarChanged(int value) editor->setLine( value ); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::hbarChanged(int value) +{ + //printf("HBar Changed: %i\n", value); + editor->setHorzScroll( value ); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::gotoAddress( int newAddr ) { editor->setAddr( newAddr ); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::saveRomFile(void) +{ + printf("ROM File: '%s'\n", getRomFile() ); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRAM(void) { editor->setMode( QHexEdit::MODE_NES_RAM ); @@ -592,6 +605,7 @@ QHexEdit::QHexEdit(QWidget *parent) reverseVideo = true; actvHighlightEnable = true; total_instructions_lp = 0; + pxLineXScroll = 0; highLightColor[ 0].setRgb( 0x00, 0x00, 0x00 ); highLightColor[ 1].setRgb( 0x35, 0x40, 0x00 ); @@ -653,6 +667,7 @@ void QHexEdit::calcFontData(void) pxYoffset = pxLineSpacing * 2.0; pxHexOffset = pxXoffset + (7*pxCharWidth); pxHexAscii = pxHexOffset + (16*3*pxCharWidth) + (pxCharWidth); + pxLineWidth = pxHexAscii + (17*pxCharWidth); //_pxGapAdr = _pxCharWidth / 2; //_pxGapAdrHex = _pxCharWidth; //_pxGapHexAscii = 2 * _pxCharWidth; @@ -729,6 +744,23 @@ void QHexEdit::setAddr( int newAddr ) cursorPosY = (newAddr - addr)/16; } //---------------------------------------------------------------------------- +void QHexEdit::setHorzScroll( int value ) +{ + float f; + //printf("Value: %i \n", value); + + if ( viewWidth >= pxLineWidth ) + { + f = 0.0; + } + else + { + f = 0.010f * (float)value * (float)(pxLineWidth - viewWidth); + } + + pxLineXScroll = (int)f; +} +//---------------------------------------------------------------------------- void QHexEdit::setScrollBars( QScrollBar *h, QScrollBar *v ) { hbar = h; vbar = v; @@ -744,6 +776,16 @@ void QHexEdit::resizeEvent(QResizeEvent *event) viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; maxLineOffset = mb.numLines() - viewLines + 1; + + if ( viewWidth >= pxLineWidth ) + { + pxLineXScroll = 0; + } + else + { + pxLineXScroll = (int)(0.010f * (float)hbar->value() * (float)(pxLineWidth - viewWidth) ); + } + } //---------------------------------------------------------------------------- void QHexEdit::resetCursor(void) @@ -760,6 +802,8 @@ QPoint QHexEdit::convPixToCursor( QPoint p ) QPoint c(0,0); //printf("Pos: %ix%i \n", p.x(), p.y() ); + + p.setX( p.x() + pxLineXScroll ); if ( p.x() < pxHexOffset ) { @@ -1303,14 +1347,14 @@ void QHexEdit::paintEvent(QPaintEvent *event) { int a = (cursorPosX / 2); int r = (cursorPosX % 2); - cx = pxHexOffset + (a*3*pxCharWidth) + (r*pxCharWidth); + cx = pxHexOffset + (a*3*pxCharWidth) + (r*pxCharWidth) - pxLineXScroll; ca = 16*(lineOffset + cursorPosY) + a; } else { int a = (cursorPosX-32); - cx = pxHexAscii + (a*pxCharWidth); + cx = pxHexAscii + (a*pxCharWidth) - pxLineXScroll; ca = 16*(lineOffset + cursorPosY) + a; } @@ -1328,13 +1372,13 @@ void QHexEdit::paintEvent(QPaintEvent *event) for ( row=0; row < nrow; row++) { - x = pxXoffset; + x = pxXoffset - pxLineXScroll; painter.setPen( this->palette().color(QPalette::WindowText)); sprintf( txt, "%06X", addr ); painter.drawText( x, y, tr(txt) ); - x = pxHexOffset; + x = pxHexOffset - pxLineXScroll; for (col=0; col<16; col++) { @@ -1369,7 +1413,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) { painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] ); painter.fillRect( x - (0.5*pxCharWidth) , y-pxLineSpacing+pxLineLead, 3*pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); - painter.fillRect( pxHexAscii + (col*pxCharWidth) , y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); + painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y-pxLineSpacing+pxLineLead, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); } else { @@ -1389,7 +1433,7 @@ void QHexEdit::paintEvent(QPaintEvent *event) painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, QColor("gray") ); } painter.drawText( x, y, tr(txt) ); - painter.drawText( pxHexAscii + (col*pxCharWidth), y, tr(asciiTxt) ); + painter.drawText( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y, tr(asciiTxt) ); } } x += (3*pxCharWidth); @@ -1401,9 +1445,9 @@ void QHexEdit::paintEvent(QPaintEvent *event) } painter.setPen( this->palette().color(QPalette::WindowText)); - painter.drawText( pxHexOffset, pxLineSpacing, "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" ); - painter.drawLine( pxHexOffset - (pxCharWidth/2), 0, pxHexOffset - (pxCharWidth/2), h ); - painter.drawLine( pxHexAscii - (pxCharWidth/2), 0, pxHexAscii - (pxCharWidth/2), h ); + painter.drawText( pxHexOffset - pxLineXScroll, pxLineSpacing, "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" ); + painter.drawLine( pxHexOffset - (pxCharWidth/2) - pxLineXScroll, 0, pxHexOffset - (pxCharWidth/2) - pxLineXScroll, h ); + painter.drawLine( pxHexAscii - (pxCharWidth/2) - pxLineXScroll, 0, pxHexAscii - (pxCharWidth/2) - pxLineXScroll, h ); painter.drawLine( 0, pxLineSpacing + (pxLineLead), w, pxLineSpacing + (pxLineLead) ); } diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 76bf4dd0..059a5d86 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -55,6 +55,7 @@ class QHexEdit : public QWidget void setLine( int newLineOffset ); void setAddr( int newAddrOffset ); void setScrollBars( QScrollBar *h, QScrollBar *v ); + void setHorzScroll( int value ); void setHighlightActivity( int enable ); void setHighlightReverseVideo( int enable ); void setForeGroundColor( QColor fg ); @@ -101,6 +102,8 @@ class QHexEdit : public QWidget int pxCursorHeight; int pxLineSpacing; int pxLineLead; + int pxLineWidth; + int pxLineXScroll; int pxXoffset; int pxYoffset; int pxHexOffset; @@ -153,6 +156,8 @@ class HexEditorDialog_t : public QDialog void updatePeriodic(void); void vbarMoved(int value); void vbarChanged(int value); + void hbarChanged(int value); + void saveRomFile(void); void setViewRAM(void); void setViewPPU(void); void setViewOAM(void); From 08feb4710be1131a3562936860cf10076f0a673c Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 24 Aug 2020 19:52:28 -0400 Subject: [PATCH 31/37] Added utility function to strip out a base file name from a full path. --- src/drivers/Qt/CheatsConf.cpp | 21 +++------------------ src/drivers/Qt/ConsoleUtilities.cpp | 26 +++++++++++++++++++++----- src/drivers/Qt/ConsoleUtilities.h | 2 ++ 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/drivers/Qt/CheatsConf.cpp b/src/drivers/Qt/CheatsConf.cpp index 339d18d0..8160cb73 100644 --- a/src/drivers/Qt/CheatsConf.cpp +++ b/src/drivers/Qt/CheatsConf.cpp @@ -743,25 +743,10 @@ void GuiCheatsDialog_t::saveCheatFile(void) if ( GameInfo ) { - char *_filename; - if ((_filename = strrchr(GameInfo->filename, '\\')) || (_filename = strrchr(GameInfo->filename, '/'))) - { - strcpy( dir, _filename + 1); - } - else - { - strcpy( dir, GameInfo->filename); - } + getFileBaseName( GameInfo->filename, dir ); + + strcat( dir, ".cht"); - _filename = strrchr( dir, '.'); - if (_filename) - { - strcpy(_filename, ".cht"); - } - else - { - strcat( dir, ".cht"); - } dialog.selectFile( dir ); } diff --git a/src/drivers/Qt/ConsoleUtilities.cpp b/src/drivers/Qt/ConsoleUtilities.cpp index 50da5de5..fcb9a23c 100644 --- a/src/drivers/Qt/ConsoleUtilities.cpp +++ b/src/drivers/Qt/ConsoleUtilities.cpp @@ -45,25 +45,41 @@ const char *getRomFile( void ) return NULL; } //--------------------------------------------------------------------------- -// TODO Finish writing this func +// Return file base name stripping out preceding path and trailing suffix. int getFileBaseName( const char *filepath, char *base ) { - int i,j=0, start=0; + int i=0,j=0,end=0; if ( filepath == NULL ) { + base[0] = 0; return 0; } i=0; j=0; while ( filepath[i] != 0 ) { - if ( filepath[i] == '/' ) + if ( (filepath[i] == '/') || (filepath[i] == '\\') ) { j = i; } i++; } - start = j; + i = j; - return 0; + j=0; + while ( filepath[i] != 0 ) + { + base[j] = filepath[i]; i++; j++; + } + base[j] = 0; end=j; + + while ( j > 1 ) + { + j--; + if ( base[j] == '.' ) + { + end=j; base[j] = 0; break; + } + } + return end; } //--------------------------------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h index 46496fc1..e55e0361 100644 --- a/src/drivers/Qt/ConsoleUtilities.h +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -3,3 +3,5 @@ int getDirFromFile( const char *path, char *dir ); const char *getRomFile( void ); + +int getFileBaseName( const char *filepath, char *base ); From 14f0da12c7a8d106a9b018b04de71491a4f60faf Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 24 Aug 2020 20:06:36 -0400 Subject: [PATCH 32/37] Added save ROM as hex editor functionality --- src/drivers/Qt/HexEditor.cpp | 56 +++++++++++++++++++++++++++++++++++- src/drivers/Qt/HexEditor.h | 1 + src/ines.cpp | 4 +-- src/ines.h | 4 +-- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 3172fc8f..cc1a59f4 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "../../types.h" @@ -308,6 +309,14 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) saveROM->setStatusTip(tr("Save ROM File")); connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFile(void)) ); + fileMenu->addAction(saveROM); + + // File -> Save ROM As + saveROM = new QAction(tr("Save ROM As"), this); + //saveROM->setShortcuts(QKeySequence::Open); + saveROM->setStatusTip(tr("Save ROM File As")); + connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFileAs(void)) ); + fileMenu->addAction(saveROM); // View @@ -524,7 +533,52 @@ void HexEditorDialog_t::gotoAddress( int newAddr ) //---------------------------------------------------------------------------- void HexEditorDialog_t::saveRomFile(void) { - printf("ROM File: '%s'\n", getRomFile() ); + //FlushUndoBuffer(); + iNesSave(); + //UpdateColorTable(); +} +//---------------------------------------------------------------------------- +void HexEditorDialog_t::saveRomFileAs(void) +{ + int ret, useNativeFileDialogVal; + QString filename; + QFileDialog dialog(this, tr("Save ROM To File") ); + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("NES Files (*.nes *.NES) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + dialog.setFilter( QDir::AllEntries | QDir::Hidden ); + dialog.setLabelText( QFileDialog::Accept, tr("Save") ); + dialog.setDefaultSuffix( tr(".nes") ); + + // Check config option to use native file dialog or not + g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); + + dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + iNesSaveAs( filename.toStdString().c_str() ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRAM(void) diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index 059a5d86..b21a5f82 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -158,6 +158,7 @@ class HexEditorDialog_t : public QDialog void vbarChanged(int value); void hbarChanged(int value); void saveRomFile(void); + void saveRomFileAs(void); void setViewRAM(void); void setViewPPU(void); void setViewOAM(void); diff --git a/src/ines.cpp b/src/ines.cpp index 1b75ae07..00abebeb 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -956,7 +956,7 @@ init_ok: } // bbit edited: the whole function below was added -int iNesSave() { +int iNesSave(void) { char name[2048]; strcpy(name, LoadedRomFName); @@ -967,7 +967,7 @@ int iNesSave() { return iNesSaveAs(name); } -int iNesSaveAs(char* name) +int iNesSaveAs(const char* name) { //adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function //caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename. diff --git a/src/ines.h b/src/ines.h index 6ad2657b..6f9d65e8 100644 --- a/src/ines.h +++ b/src/ines.h @@ -43,8 +43,8 @@ extern uint8 *VROM; extern uint32 VROM_size; extern uint32 ROM_size; extern uint8 *ExtraNTARAM; -extern int iNesSave(); //bbit Edited: line added -extern int iNesSaveAs(char* name); +extern int iNesSave(void); //bbit Edited: line added +extern int iNesSaveAs(const char* name); extern char LoadedRomFName[2048]; //bbit Edited: line added extern const TMasterRomInfo* MasterRomInfo; extern TMasterRomInfoParams MasterRomInfoParams; From 1f09ecca2cd3115a7742e70ff1c41f7175760cb1 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 24 Aug 2020 20:27:12 -0400 Subject: [PATCH 33/37] Added hex editor window close menu option. --- src/drivers/Qt/HexEditor.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index cc1a59f4..7e01f221 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -286,7 +286,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) QGridLayout *grid; QMenuBar *menuBar; QMenu *fileMenu, *viewMenu, *colorMenu; - QAction *saveROM; + QAction *saveROM, *closeAct; QAction *viewRAM, *viewPPU, *viewOAM, *viewROM; QAction *actHlgt, *actHlgtRV, *actColorFG, *actColorBG; QActionGroup *group; @@ -319,6 +319,16 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) fileMenu->addAction(saveROM); + fileMenu->addSeparator(); + + // File -> Close + closeAct = new QAction(tr("Close"), this); + //closeAct->setShortcuts(QKeySequence::Open); + closeAct->setStatusTip(tr("Close Window")); + connect(closeAct, SIGNAL(triggered()), this, SLOT(closeWindow(void)) ); + + fileMenu->addAction(closeAct); + // View viewMenu = menuBar->addMenu(tr("View")); From 67f6be539a0a003476a7a1318f8e8e18fee97c9c Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Mon, 24 Aug 2020 20:50:06 -0400 Subject: [PATCH 34/37] Added TODO comments to hex editor context menu. These menu options can not be finished until other debug features such as the debugger and code/data trace/log functionality has been created. --- src/drivers/Qt/HexEditor.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 7e01f221..88d21506 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -1197,18 +1197,18 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) { case MODE_NES_RAM: { - act = new QAction(tr("Add Symbolic Debug Name"), this); + act = new QAction(tr("TODO Add Symbolic Debug Name"), this); menu.addAction(act); - sprintf( stmp, "Add Read Breakpoint for Address $%04X", addr ); + sprintf( stmp, "TODO Add Read Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), this); menu.addAction(act); - sprintf( stmp, "Add Write Breakpoint for Address $%04X", addr ); + sprintf( stmp, "TODO Add Write Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), this); menu.addAction(act); - sprintf( stmp, "Add Execute Breakpoint for Address $%04X", addr ); + sprintf( stmp, "TODO Add Execute Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), this); menu.addAction(act); @@ -1226,25 +1226,25 @@ void QHexEdit::contextMenuEvent(QContextMenuEvent *event) } } - act = new QAction(tr("Add Bookmark"), this); + act = new QAction(tr("TODO Add Bookmark"), this); menu.addAction(act); } break; case MODE_NES_PPU: { - act = new QAction(tr("Add Bookmark"), this); + act = new QAction(tr("TODO Add Bookmark"), this); menu.addAction(act); } break; case MODE_NES_OAM: { - act = new QAction(tr("Add Bookmark"), this); + act = new QAction(tr("TODO Add Bookmark"), this); menu.addAction(act); } break; case MODE_NES_ROM: { - act = new QAction(tr("Add Bookmark"), this); + act = new QAction(tr("TODO Add Bookmark"), this); menu.addAction(act); } break; From a624278fca9053d1b8ece2a0c51cda739673b380 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 25 Aug 2020 18:41:58 -0400 Subject: [PATCH 35/37] Added native menu option to hex editor. --- src/drivers/Qt/ConsoleWindow.cpp | 2 +- src/drivers/Qt/HexEditor.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index e81e57ed..5e16845b 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -1036,7 +1036,7 @@ void consoleWin_t::openHexEditor(void) delete hexEditWin; - //printf("GUI Cheat Window Destroyed\n"); + //printf("GUI Hex Editor Window Destroyed\n"); } void consoleWin_t::toggleAutoResume(void) diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 88d21506..9ecec382 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -290,6 +290,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) QAction *viewRAM, *viewPPU, *viewOAM, *viewROM; QAction *actHlgt, *actHlgtRV, *actColorFG, *actColorBG; QActionGroup *group; + int useNativeMenuBar; setWindowTitle("Hex Editor"); @@ -297,6 +298,10 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) menuBar = new QMenuBar(this); + // This is needed for menu bar to show up on MacOS + g_config->getOption( "SDL.UseNativeMenuBar", &useNativeMenuBar ); + + menuBar->setNativeMenuBar( useNativeMenuBar ? true : false ); //----------------------------------------------------------------------- // Menu //----------------------------------------------------------------------- From c23fa5dc60542a8b94172f4ec10f18130ba4a3c0 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 25 Aug 2020 20:59:36 -0400 Subject: [PATCH 36/37] Memory management fix for QT dialog windows. Ensure that window is marked for deletion when it is closed. --- src/drivers/Qt/CheatsConf.cpp | 10 +++++ src/drivers/Qt/CheatsConf.h | 1 + src/drivers/Qt/ConsoleSoundConf.cpp | 19 ++++++++- src/drivers/Qt/ConsoleSoundConf.h | 3 ++ src/drivers/Qt/ConsoleVideoConf.cpp | 25 ++++++++--- src/drivers/Qt/ConsoleVideoConf.h | 6 ++- src/drivers/Qt/ConsoleWindow.cpp | 64 +++++++++++------------------ src/drivers/Qt/ConsoleWindow.h | 2 - src/drivers/Qt/GamePadConf.cpp | 31 ++++++++++++++ src/drivers/Qt/GamePadConf.h | 4 ++ src/drivers/Qt/GuiConf.cpp | 11 ++++- src/drivers/Qt/GuiConf.h | 2 + src/drivers/Qt/HexEditor.cpp | 10 +++++ src/drivers/Qt/HexEditor.h | 1 + src/drivers/Qt/HotKeyConf.cpp | 12 +++++- src/drivers/Qt/HotKeyConf.h | 1 + src/drivers/Qt/LuaControl.cpp | 13 +++++- src/drivers/Qt/LuaControl.h | 2 + src/drivers/Qt/PaletteConf.cpp | 11 ++++- src/drivers/Qt/PaletteConf.h | 2 + 20 files changed, 175 insertions(+), 55 deletions(-) diff --git a/src/drivers/Qt/CheatsConf.cpp b/src/drivers/Qt/CheatsConf.cpp index 8160cb73..1f53e556 100644 --- a/src/drivers/Qt/CheatsConf.cpp +++ b/src/drivers/Qt/CheatsConf.cpp @@ -416,12 +416,22 @@ GuiCheatsDialog_t::~GuiCheatsDialog_t(void) } wasPausedByCheats = false; + printf("Destroy Cheat Window Event\n"); +} +//---------------------------------------------------------------------------- +void GuiCheatsDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Cheat Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); } //---------------------------------------------------------------------------- void GuiCheatsDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); + deleteLater(); } //---------------------------------------------------------------------------- int GuiCheatsDialog_t::addSearchResult (uint32_t a, uint8_t last, uint8_t current) diff --git a/src/drivers/Qt/CheatsConf.h b/src/drivers/Qt/CheatsConf.h index d687cb70..fbc46a24 100644 --- a/src/drivers/Qt/CheatsConf.h +++ b/src/drivers/Qt/CheatsConf.h @@ -33,6 +33,7 @@ class GuiCheatsDialog_t : public QDialog int activeCheatListCB (char *name, uint32 a, uint8 v, int c, int s, int type, void *data); protected: + void closeEvent(QCloseEvent *event); QGroupBox *actCheatFrame; QGroupBox *cheatSearchFrame; diff --git a/src/drivers/Qt/ConsoleSoundConf.cpp b/src/drivers/Qt/ConsoleSoundConf.cpp index 9932a7ca..b02c2253 100644 --- a/src/drivers/Qt/ConsoleSoundConf.cpp +++ b/src/drivers/Qt/ConsoleSoundConf.cpp @@ -1,5 +1,7 @@ // ConsoleSoundConf.cpp // +#include + #include "../../fceu.h" #include "../../driver.h" #include "Qt/ConsoleSoundConf.h" @@ -217,7 +219,22 @@ ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent) //---------------------------------------------------- ConsoleSndConfDialog_t::~ConsoleSndConfDialog_t(void) { - + printf("Destroy Sound Config Window\n"); +} +//---------------------------------------------------------------------------- +void ConsoleSndConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Sound Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void ConsoleSndConfDialog_t::closeWindow(void) +{ + //printf("Sound Close Window\n"); + done(0); + deleteLater(); } //---------------------------------------------------- void ConsoleSndConfDialog_t::setCheckBoxFromProperty( QCheckBox *cbx, const char *property ) diff --git a/src/drivers/Qt/ConsoleSoundConf.h b/src/drivers/Qt/ConsoleSoundConf.h index 40e86d2a..40f8de1f 100644 --- a/src/drivers/Qt/ConsoleSoundConf.h +++ b/src/drivers/Qt/ConsoleSoundConf.h @@ -25,6 +25,8 @@ class ConsoleSndConfDialog_t : public QDialog ~ConsoleSndConfDialog_t(void); protected: + void closeEvent(QCloseEvent *event); + QCheckBox *enaChkbox; QCheckBox *enaLowPass; QCheckBox *swapDutyChkbox; @@ -44,6 +46,7 @@ class ConsoleSndConfDialog_t : public QDialog void setSliderFromProperty( QSlider *slider, QLabel *lbl, const char *property ); private slots: + void closeWindow(void); void bufSizeChanged(int value); void volumeChanged(int value); void triangleChanged(int value); diff --git a/src/drivers/Qt/ConsoleVideoConf.cpp b/src/drivers/Qt/ConsoleVideoConf.cpp index 44f4116b..1da2f639 100644 --- a/src/drivers/Qt/ConsoleVideoConf.cpp +++ b/src/drivers/Qt/ConsoleVideoConf.cpp @@ -1,5 +1,7 @@ // ConsoleVideoConf.cpp // +#include + #include "../../fceu.h" #include "Qt/main.h" #include "Qt/dface.h" @@ -105,7 +107,7 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent) button = new QPushButton( tr("Close") ); hbox1->addWidget( button ); - connect(button, SIGNAL(clicked()), this, SLOT(closewindow(void)) ); + connect(button, SIGNAL(clicked()), this, SLOT(closeWindow(void)) ); main_vbox->addLayout( hbox1 ); @@ -115,8 +117,24 @@ ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent) //---------------------------------------------------- ConsoleVideoConfDialog_t::~ConsoleVideoConfDialog_t(void) { + printf("Destroy Video Config Window\n"); } +//---------------------------------------------------------------------------- +void ConsoleVideoConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Video Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- +void ConsoleVideoConfDialog_t::closeWindow(void) +{ + //printf("Video Config Close Window\n"); + done(0); + deleteLater(); +} //---------------------------------------------------- void ConsoleVideoConfDialog_t::resetVideo(void) { @@ -237,8 +255,3 @@ void ConsoleVideoConfDialog_t::applyChanges( void ) resetVideo(); } //---------------------------------------------------- -void ConsoleVideoConfDialog_t::closewindow( void ) -{ - done(0); -} -//---------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleVideoConf.h b/src/drivers/Qt/ConsoleVideoConf.h index 00b38d86..73d86e76 100644 --- a/src/drivers/Qt/ConsoleVideoConf.h +++ b/src/drivers/Qt/ConsoleVideoConf.h @@ -25,6 +25,8 @@ class ConsoleVideoConfDialog_t : public QDialog ~ConsoleVideoConfDialog_t(void); protected: + void closeEvent(QCloseEvent *bar); + QComboBox *driverSelect; QComboBox *regionSelect; QCheckBox *gl_LF_chkBox; @@ -40,6 +42,9 @@ class ConsoleVideoConfDialog_t : public QDialog void resetVideo(void); + public slots: + void closeWindow(void); + private slots: void use_new_PPU_changed( int value ); void frameskip_changed( int value ); @@ -49,7 +54,6 @@ class ConsoleVideoConfDialog_t : public QDialog void regionChanged(int index); void driverChanged(int index); void applyChanges( void ); - void closewindow( void ); }; diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 5e16845b..1dd24854 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -75,8 +75,6 @@ consoleWin_t::consoleWin_t(QWidget *parent) emulatorThread->start(); - gamePadConfWin = NULL; - } consoleWin_t::~consoleWin_t(void) @@ -85,10 +83,8 @@ consoleWin_t::~consoleWin_t(void) gameTimer->stop(); - if ( gamePadConfWin != NULL ) - { - gamePadConfWin->closeWindow(); - } + closeGamePadConfWindow(); + fceuWrapperLock(); fceuWrapperClose(); fceuWrapperUnLock(); @@ -144,11 +140,8 @@ void consoleWin_t::QueueErrorMsgWindow( const char *msg ) void consoleWin_t::closeEvent(QCloseEvent *event) { //printf("Main Window Close Event\n"); - if ( gamePadConfWin != NULL ) - { - //printf("Command Game Pad Close\n"); - gamePadConfWin->closeWindow(); - } + closeGamePadConfWindow(); + event->accept(); closeApp(); @@ -901,9 +894,9 @@ void consoleWin_t::loadLua(void) luaCtrlWin = new LuaControlDialog_t(this); luaCtrlWin->show(); - luaCtrlWin->exec(); + //luaCtrlWin->exec(); - delete luaCtrlWin; + //delete luaCtrlWin; //printf("Lua Control Window Destroyed\n"); #endif @@ -911,20 +904,9 @@ void consoleWin_t::loadLua(void) void consoleWin_t::openGamePadConfWin(void) { - if ( gamePadConfWin != NULL ) - { - printf("GamePad Config Window Already Open\n"); - return; - } //printf("Open GamePad Config Window\n"); - gamePadConfWin = new GamePadConfDialog_t(this); - gamePadConfWin->show(); - gamePadConfWin->exec(); - - delete gamePadConfWin; - gamePadConfWin = NULL; - //printf("GamePad Config Window Destroyed\n"); + openGamePadConfWindow(this); } void consoleWin_t::openGameSndConfWin(void) @@ -936,9 +918,9 @@ void consoleWin_t::openGameSndConfWin(void) sndConfWin = new ConsoleSndConfDialog_t(this); sndConfWin->show(); - sndConfWin->exec(); + //sndConfWin->exec(); - delete sndConfWin; + //delete sndConfWin; //printf("Sound Config Window Destroyed\n"); } @@ -952,9 +934,9 @@ void consoleWin_t::openGameVideoConfWin(void) vidConfWin = new ConsoleVideoConfDialog_t(this); vidConfWin->show(); - vidConfWin->exec(); + //vidConfWin->exec(); - delete vidConfWin; + //delete vidConfWin; //printf("Video Config Window Destroyed\n"); } @@ -968,9 +950,9 @@ void consoleWin_t::openHotkeyConfWin(void) hkConfWin = new HotKeyConfDialog_t(this); hkConfWin->show(); - hkConfWin->exec(); + //hkConfWin->exec(); - delete hkConfWin; + //delete hkConfWin; //printf("Hotkey Config Window Destroyed\n"); } @@ -984,9 +966,9 @@ void consoleWin_t::openPaletteConfWin(void) paletteConfWin = new PaletteConfDialog_t(this); paletteConfWin->show(); - paletteConfWin->exec(); + //paletteConfWin->exec(); - delete paletteConfWin; + //delete paletteConfWin; //printf("Palette Config Window Destroyed\n"); } @@ -1000,9 +982,9 @@ void consoleWin_t::openGuiConfWin(void) guiConfWin = new GuiConfDialog_t(this); guiConfWin->show(); - guiConfWin->exec(); + //guiConfWin->exec(); - delete guiConfWin; + //delete guiConfWin; //printf("GUI Config Window Destroyed\n"); } @@ -1016,9 +998,9 @@ void consoleWin_t::openCheats(void) cheatWin = new GuiCheatsDialog_t(this); cheatWin->show(); - cheatWin->exec(); + //cheatWin->exec(); - delete cheatWin; + //delete cheatWin; //printf("GUI Cheat Window Destroyed\n"); } @@ -1032,9 +1014,9 @@ void consoleWin_t::openHexEditor(void) hexEditWin = new HexEditorDialog_t(this); hexEditWin->show(); - hexEditWin->exec(); + //hexEditWin->exec(); - delete hexEditWin; + //delete hexEditWin; //printf("GUI Hex Editor Window Destroyed\n"); } @@ -1412,9 +1394,9 @@ void consoleWin_t::aboutFCEUX(void) aboutWin = new AboutWindow(this); aboutWin->show(); - aboutWin->exec(); + //aboutWin->exec(); - delete aboutWin; + //delete aboutWin; //printf("About Window Destroyed\n"); return; diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index d2515407..eb5fdddb 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -99,8 +99,6 @@ class consoleWin_t : public QMainWindow emulatorThread_t *emulatorThread; - GamePadConfDialog_t *gamePadConfWin; - std::string errorMsg; bool errorMsgValid; diff --git a/src/drivers/Qt/GamePadConf.cpp b/src/drivers/Qt/GamePadConf.cpp index 03df69bb..2847a01c 100644 --- a/src/drivers/Qt/GamePadConf.cpp +++ b/src/drivers/Qt/GamePadConf.cpp @@ -36,6 +36,30 @@ struct GamePadConfigLocalData_t static GamePadConfigLocalData_t lcl[GAMEPAD_NUM_DEVICES]; +static GamePadConfDialog_t *gamePadConfWin = NULL; + +//---------------------------------------------------- +int openGamePadConfWindow( QWidget *parent ) +{ + if ( gamePadConfWin != NULL ) + { + return -1; + } + gamePadConfWin = new GamePadConfDialog_t(parent); + + gamePadConfWin->show(); + + return 0; +} +//---------------------------------------------------- +int closeGamePadConfWindow(void) +{ + if ( gamePadConfWin != NULL ) + { + gamePadConfWin->closeWindow(); + } + return 0; +} //---------------------------------------------------- GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent) : QDialog( parent ) @@ -56,6 +80,8 @@ GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent) std::string prefix; char stmp[256]; + gamePadConfWin = this; + // Ensure that joysticks are enabled, no harm calling init again. InitJoysticks(); @@ -279,6 +305,9 @@ GamePadConfDialog_t::~GamePadConfDialog_t(void) { inputTimer->stop(); buttonConfigStatus = 0; + gamePadConfWin = NULL; + + printf("GamePad Window Deleted\n"); } void GamePadConfDialog_t::keyPressEvent(QKeyEvent *event) { @@ -500,6 +529,7 @@ void GamePadConfDialog_t::closeEvent(QCloseEvent *event) printf("GamePad Close Window Event\n"); buttonConfigStatus = 0; done(0); + deleteLater(); event->accept(); } //---------------------------------------------------- @@ -510,6 +540,7 @@ void GamePadConfDialog_t::closeWindow(void) printf("Close Window\n"); buttonConfigStatus = 0; done(0); + deleteLater(); } //---------------------------------------------------- void GamePadConfDialog_t::changeButton0(void) diff --git a/src/drivers/Qt/GamePadConf.h b/src/drivers/Qt/GamePadConf.h index 5efafeb3..7d5fabe2 100644 --- a/src/drivers/Qt/GamePadConf.h +++ b/src/drivers/Qt/GamePadConf.h @@ -99,3 +99,7 @@ class GamePadConfDialog_t : public QDialog void updatePeriodic(void); }; + +int openGamePadConfWindow( QWidget *parent ); + +int closeGamePadConfWindow(void); diff --git a/src/drivers/Qt/GuiConf.cpp b/src/drivers/Qt/GuiConf.cpp index 256aacb2..0eab340b 100644 --- a/src/drivers/Qt/GuiConf.cpp +++ b/src/drivers/Qt/GuiConf.cpp @@ -46,13 +46,22 @@ GuiConfDialog_t::GuiConfDialog_t(QWidget *parent) //---------------------------------------------------- GuiConfDialog_t::~GuiConfDialog_t(void) { - + printf("Destroy GUI Config Close Window\n"); +} +//---------------------------------------------------------------------------- +void GuiConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("GUI Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); } //---------------------------------------------------- void GuiConfDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); + deleteLater(); } //---------------------------------------------------- void GuiConfDialog_t::useNativeFileDialogChanged(int state) diff --git a/src/drivers/Qt/GuiConf.h b/src/drivers/Qt/GuiConf.h index 032dd4db..aa0bcc84 100644 --- a/src/drivers/Qt/GuiConf.h +++ b/src/drivers/Qt/GuiConf.h @@ -26,6 +26,8 @@ class GuiConfDialog_t : public QDialog ~GuiConfDialog_t(void); protected: + void closeEvent(QCloseEvent *event); + QCheckBox *useNativeFileDialog; QCheckBox *useNativeMenuBar; private: diff --git a/src/drivers/Qt/HexEditor.cpp b/src/drivers/Qt/HexEditor.cpp index 9ecec382..aefea213 100644 --- a/src/drivers/Qt/HexEditor.cpp +++ b/src/drivers/Qt/HexEditor.cpp @@ -468,6 +468,7 @@ HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) //---------------------------------------------------------------------------- HexEditorDialog_t::~HexEditorDialog_t(void) { + printf("Hex Editor Deleted\n"); periodicTimer->stop(); } //---------------------------------------------------------------------------- @@ -487,10 +488,19 @@ void HexEditorDialog_t::populateBookmarkMenu(void) bookmarkMenu->addSeparator(); } //---------------------------------------------------------------------------- +void HexEditorDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Hex Editor Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------------------------------- void HexEditorDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); + deleteLater(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::pickForeGroundColor(void) diff --git a/src/drivers/Qt/HexEditor.h b/src/drivers/Qt/HexEditor.h index b21a5f82..a2f7079a 100644 --- a/src/drivers/Qt/HexEditor.h +++ b/src/drivers/Qt/HexEditor.h @@ -138,6 +138,7 @@ class HexEditorDialog_t : public QDialog ~HexEditorDialog_t(void); protected: + void closeEvent(QCloseEvent *bar); void gotoAddress(int newAddr); void populateBookmarkMenu(void); diff --git a/src/drivers/Qt/HotKeyConf.cpp b/src/drivers/Qt/HotKeyConf.cpp index 13c33f1c..d1db2131 100644 --- a/src/drivers/Qt/HotKeyConf.cpp +++ b/src/drivers/Qt/HotKeyConf.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "Qt/main.h" #include "Qt/dface.h" @@ -68,13 +69,22 @@ HotKeyConfDialog_t::HotKeyConfDialog_t(QWidget *parent) //---------------------------------------------------------------------------- HotKeyConfDialog_t::~HotKeyConfDialog_t(void) { - + printf("Destroy Hot Key Config Window\n"); +} +//---------------------------------------------------------------------------- +void HotKeyConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Hot Key Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); } //---------------------------------------------------------------------------- void HotKeyConfDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); + deleteLater(); } //---------------------------------------------------------------------------- void HotKeyConfDialog_t::assignHotkey(QKeyEvent *event) diff --git a/src/drivers/Qt/HotKeyConf.h b/src/drivers/Qt/HotKeyConf.h index cba35cee..bf9c8a8f 100644 --- a/src/drivers/Qt/HotKeyConf.h +++ b/src/drivers/Qt/HotKeyConf.h @@ -27,6 +27,7 @@ class HotKeyConfDialog_t : public QDialog ~HotKeyConfDialog_t(void); protected: + void closeEvent(QCloseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void assignHotkey(QKeyEvent *event); diff --git a/src/drivers/Qt/LuaControl.cpp b/src/drivers/Qt/LuaControl.cpp index 28e1bcff..2aa40271 100644 --- a/src/drivers/Qt/LuaControl.cpp +++ b/src/drivers/Qt/LuaControl.cpp @@ -102,6 +102,8 @@ LuaControlDialog_t::~LuaControlDialog_t(void) { std::list ::iterator it; + printf("Destroy Lua Control Window\n"); + for (it = winList.begin(); it != winList.end(); it++) { if ( (*it) == this ) @@ -113,10 +115,19 @@ LuaControlDialog_t::~LuaControlDialog_t(void) } } //---------------------------------------------------- +void LuaControlDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Lua Control Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); +} +//---------------------------------------------------- void LuaControlDialog_t::closeWindow(void) { - //printf("Close Window\n"); + //printf("Lua Control Close Window\n"); done(0); + deleteLater(); } //---------------------------------------------------- void LuaControlDialog_t::openLuaScriptFile(void) diff --git a/src/drivers/Qt/LuaControl.h b/src/drivers/Qt/LuaControl.h index 824f52fa..522e686a 100644 --- a/src/drivers/Qt/LuaControl.h +++ b/src/drivers/Qt/LuaControl.h @@ -29,6 +29,8 @@ class LuaControlDialog_t : public QDialog void refreshState(void); protected: + void closeEvent(QCloseEvent *bar); + QLineEdit *scriptPath; QLineEdit *scriptArgs; QPushButton *browseButton; diff --git a/src/drivers/Qt/PaletteConf.cpp b/src/drivers/Qt/PaletteConf.cpp index 2adbe66e..d799b8ca 100644 --- a/src/drivers/Qt/PaletteConf.cpp +++ b/src/drivers/Qt/PaletteConf.cpp @@ -148,13 +148,22 @@ PaletteConfDialog_t::PaletteConfDialog_t(QWidget *parent) //---------------------------------------------------- PaletteConfDialog_t::~PaletteConfDialog_t(void) { - + printf("Destroy Palette Config Window\n"); +} +//---------------------------------------------------------------------------- +void PaletteConfDialog_t::closeEvent(QCloseEvent *event) +{ + printf("Palette Config Close Window Event\n"); + done(0); + deleteLater(); + event->accept(); } //---------------------------------------------------- void PaletteConfDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); + deleteLater(); } //---------------------------------------------------- void PaletteConfDialog_t::hueChanged(int v) diff --git a/src/drivers/Qt/PaletteConf.h b/src/drivers/Qt/PaletteConf.h index 494d78aa..5b28d9c0 100644 --- a/src/drivers/Qt/PaletteConf.h +++ b/src/drivers/Qt/PaletteConf.h @@ -26,6 +26,8 @@ class PaletteConfDialog_t : public QDialog ~PaletteConfDialog_t(void); protected: + void closeEvent(QCloseEvent *event); + QLineEdit *custom_palette_path; QCheckBox *useCustom; QCheckBox *GrayScale; From 51019a6e06d02d86ec3a4a50b6dcc6d13d777b0b Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 25 Aug 2020 21:24:34 -0400 Subject: [PATCH 37/37] Cleanup up old commented out code in QT GUI main window. --- src/drivers/Qt/ConsoleWindow.cpp | 45 -------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 1dd24854..57102e8e 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -894,11 +894,6 @@ void consoleWin_t::loadLua(void) luaCtrlWin = new LuaControlDialog_t(this); luaCtrlWin->show(); - //luaCtrlWin->exec(); - - //delete luaCtrlWin; - - //printf("Lua Control Window Destroyed\n"); #endif } @@ -918,11 +913,6 @@ void consoleWin_t::openGameSndConfWin(void) sndConfWin = new ConsoleSndConfDialog_t(this); sndConfWin->show(); - //sndConfWin->exec(); - - //delete sndConfWin; - - //printf("Sound Config Window Destroyed\n"); } void consoleWin_t::openGameVideoConfWin(void) @@ -934,11 +924,6 @@ void consoleWin_t::openGameVideoConfWin(void) vidConfWin = new ConsoleVideoConfDialog_t(this); vidConfWin->show(); - //vidConfWin->exec(); - - //delete vidConfWin; - - //printf("Video Config Window Destroyed\n"); } void consoleWin_t::openHotkeyConfWin(void) @@ -950,11 +935,6 @@ void consoleWin_t::openHotkeyConfWin(void) hkConfWin = new HotKeyConfDialog_t(this); hkConfWin->show(); - //hkConfWin->exec(); - - //delete hkConfWin; - - //printf("Hotkey Config Window Destroyed\n"); } void consoleWin_t::openPaletteConfWin(void) @@ -966,11 +946,6 @@ void consoleWin_t::openPaletteConfWin(void) paletteConfWin = new PaletteConfDialog_t(this); paletteConfWin->show(); - //paletteConfWin->exec(); - - //delete paletteConfWin; - - //printf("Palette Config Window Destroyed\n"); } void consoleWin_t::openGuiConfWin(void) @@ -982,11 +957,6 @@ void consoleWin_t::openGuiConfWin(void) guiConfWin = new GuiConfDialog_t(this); guiConfWin->show(); - //guiConfWin->exec(); - - //delete guiConfWin; - - //printf("GUI Config Window Destroyed\n"); } void consoleWin_t::openCheats(void) @@ -998,11 +968,6 @@ void consoleWin_t::openCheats(void) cheatWin = new GuiCheatsDialog_t(this); cheatWin->show(); - //cheatWin->exec(); - - //delete cheatWin; - - //printf("GUI Cheat Window Destroyed\n"); } void consoleWin_t::openHexEditor(void) @@ -1014,11 +979,6 @@ void consoleWin_t::openHexEditor(void) hexEditWin = new HexEditorDialog_t(this); hexEditWin->show(); - //hexEditWin->exec(); - - //delete hexEditWin; - - //printf("GUI Hex Editor Window Destroyed\n"); } void consoleWin_t::toggleAutoResume(void) @@ -1394,11 +1354,6 @@ void consoleWin_t::aboutFCEUX(void) aboutWin = new AboutWindow(this); aboutWin->show(); - //aboutWin->exec(); - - //delete aboutWin; - - //printf("About Window Destroyed\n"); return; }