/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2020 mjbudd77 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // HexEditor.cpp // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 "../../ppu.h" #include "../../cart.h" #include "../../ines.h" #include "../common/configSys.h" #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" #include "Qt/CheatsConf.h" #include "Qt/SymbolicDebug.h" #include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleUtilities.h" #include "Qt/ConsoleWindow.h" static bool memNeedsCheck = false; static HexBookMarkManager_t hbm; static std::list winList; static const char *memViewNames[] = { "RAM", "PPU", "OAM", "ROM", NULL }; static int getROM( unsigned int offset); static int writeMem( int mode, unsigned int addr, int value ); //---------------------------------------------------------------------------- struct romEditEntry_t { int addr; int size; uint8_t *data; romEditEntry_t(void) { addr = -1; size = 0; data = NULL; } ~romEditEntry_t(void) { if ( data != NULL ) { free(data); data = NULL; } } }; struct romEditList_t { uint8_t *modMem; int modMemSize; std::list undoList; //std::list redoList; // TODO romEditList_t(void) { modMem = NULL; modMemSize = 0; } ~romEditList_t(void) { clear(); } void clear(void) { while ( !undoList.empty() ) { delete undoList.back(); undoList.pop_back(); } if ( modMem != NULL ) { free(modMem); modMem = NULL; modMemSize = 0; } } void applyPatch( int addr, int data ) { uint8_t u8; u8 = data; applyPatch( addr, &u8, 1 ); } void applyPatch( int addr, uint8_t *data, int size ) { int ofs; romEditEntry_t *entry; if ( GameInfo == NULL ) { return; } if ( modMem == NULL ) { modMemSize = 16 + CHRsize[0] + PRGsize[0]; modMem = (uint8_t*)malloc( modMemSize ); if ( modMem == NULL ) { printf("Error: Failed to allocate ROM modification memory buffer\n"); return; } memset( modMem, 0, modMemSize ); } entry = new romEditEntry_t(); entry->addr = addr; entry->size = size; entry->data = (uint8_t*)malloc(sizeof(uint8_t)*size); for (int i = 0; i < size; i++) { ofs = addr+i; entry->data[i] = getROM(ofs); writeMem( QHexEdit::MODE_NES_ROM, ofs, data[i] ); modMem[ofs]++; } undoList.push_back( entry ); } int undoPatch(void) { int ofs, ret = -1; romEditEntry_t *entry; if ( undoList.empty() ) { return ret; } entry = undoList.back(); undoList.pop_back(); ret = entry->addr; for (int i=0; isize; i++) { ofs = entry->addr + i; writeMem( QHexEdit::MODE_NES_ROM, ofs, entry->data[i] ); if ( modMem ) { if ( (ofs >= 0) && (ofs < modMemSize) ) { if ( modMem[ofs] > 0 ) { modMem[ofs]--; } } } } delete entry; return ret; } bool isModified( int addr ) { if ( modMem == NULL ) { return false; } if ( addr < 0 ) { return false; } else if ( addr >= modMemSize ) { return false; } return modMem[addr] ? true : false; } size_t undoQueueSize(void) { return undoList.size(); } }; static romEditList_t romEditList; //---------------------------------------------------------------------------- static int getRAM( unsigned int i ) { return GetMem(i); } //---------------------------------------------------------------------------- static int getPPU( unsigned int i ) { if (GameInfo == NULL ) { return 0; } 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 (GameInfo == NULL ) { return 0; } 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 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] = data; } } else { PALRAM[addr] = data; } } //---------------------------------------------------------------------------- static int writeMem( int mode, unsigned int addr, int value ) { value = value & 0x000000ff; switch ( mode ) { default: case QHexEdit::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 QHexEdit::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 QHexEdit::MODE_NES_OAM: { addr &= 0xFF; SPRAM[addr] = value; } break; case QHexEdit::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; } hexEditorRequestUpdateAll(); 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; } //---------------------------------------------------------------------------- memBlock_t::~memBlock_t(void) { if ( buf != NULL ) { ::free( buf ); buf = NULL; } _size = 0; _maxLines = 0; } //---------------------------------------------------------------------------- int memBlock_t::reAlloc( int newSize ) { if ( newSize == 0 ) { return 0; } if ( _size == newSize ) { return 0; } if ( buf != NULL ) { ::free( buf ); buf = NULL; } _size = 0; _maxLines = 0; buf = (struct memByte_t *)malloc( newSize * sizeof(struct memByte_t) ); if ( buf != NULL ) { _size = newSize; init(); if ( (_size % 16) ) { _maxLines = (_size / 16) + 1; } else { _maxLines = (_size / 16); } } 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; } } //---------------------------------------------------------------------------- HexBookMark::HexBookMark(void) { addr = 0; mode = 0; desc[0] = 0; } //---------------------------------------------------------------------------- HexBookMark::~HexBookMark(void) { } //---------------------------------------------------------------------------- HexBookMarkManager_t::HexBookMarkManager_t(void) { } //---------------------------------------------------------------------------- HexBookMarkManager_t::~HexBookMarkManager_t(void) { removeAll(); } //---------------------------------------------------------------------------- void HexBookMarkManager_t::removeAll(void) { HexBookMark *b; while ( !ls.empty() ) { b = ls.front(); delete b; ls.pop_front(); } v.clear(); } //---------------------------------------------------------------------------- int HexBookMarkManager_t::addBookMark( int addr, int mode, const char *desc ) { HexBookMark *b; b = new HexBookMark(); b->addr = addr; b->mode = mode; if ( desc ) { strncpy( b->desc, desc, 63 ); } b->desc[63] = 0; ls.push_back(b); updateVector(); return 0; } //---------------------------------------------------------------------------- void HexBookMarkManager_t::updateVector(void) { std::list ::iterator it; v.clear(); for (it=ls.begin(); it!=ls.end(); it++) { v.push_back( *it ); } return; } //---------------------------------------------------------------------------- int HexBookMarkManager_t::size(void) { return ls.size(); } //---------------------------------------------------------------------------- HexBookMark *HexBookMarkManager_t::getBookMark( int index ) { if ( index < 0 ) { return NULL; } else if ( index >= (int)v.size() ) { return NULL; } return v[index]; } //---------------------------------------------------------------------------- int HexBookMarkManager_t::loadFromFile(void) { int i,j,mode,addr; FILE *fp; QDir dir; char line[256], fd[256], baseFile[512]; const char *romFile = getRomFile(); const char *baseDir = FCEUI_GetBaseDirectory(); std::string path; if ( romFile == NULL ) { return -1; } path = std::string(baseDir) + "/bookmarks/"; dir.mkpath( QString::fromStdString(path) ); getFileBaseName( romFile, baseFile ); path += std::string(baseFile) + ".txt"; fp = ::fopen( path.c_str(), "r"); if ( fp == NULL ) { return -1; } while ( ::fgets( line, sizeof(line), fp ) != NULL ) { i=0; j=0; //printf("%s\n", line ); // while ( isspace(line[i]) ) i++; while ( isalpha(line[i]) ) { fd[j] = line[i]; i++; j++; } fd[j] = 0; mode = -1; for (j=0; j<4; j++) { if ( strcmp( fd, memViewNames[j] ) == 0 ) { mode = j; break; } } if ( mode < 0 ) continue; while ( isspace(line[i]) ) i++; if ( line[i] == ':' ) i++; while ( isspace(line[i]) ) i++; j=0; while ( isxdigit(line[i]) ) { fd[j] = line[i]; i++; j++; } fd[j] = 0; addr = strtol( fd, NULL, 16 ); while ( isspace(line[i]) ) i++; if ( line[i] == ':' ) i++; while ( isspace(line[i]) ) i++; j=0; while ( line[i] ) { fd[j] = line[i]; i++; j++; } fd[j] = 0; j--; while ( j >= 0 ) { if ( isspace( fd[j] ) ) { fd[j] = 0; } else { break; } j--; } addBookMark( addr, mode, fd ); } ::fclose(fp); return 0; } //---------------------------------------------------------------------------- int HexBookMarkManager_t::saveToFile(void) { FILE *fp; QDir dir; char baseFile[512]; const char *romFile = getRomFile(); const char *baseDir = FCEUI_GetBaseDirectory(); std::string path; if ( romFile == NULL ) { return -1; } path = std::string(baseDir) + "/bookmarks/"; dir.mkpath( QString::fromStdString(path) ); getFileBaseName( romFile, baseFile ); path += std::string(baseFile) + ".txt"; fp = ::fopen( path.c_str(), "w"); if ( fp == NULL ) { return -1; } for (int i=0; imode ], v[i]->addr, v[i]->desc ); } ::fclose(fp); return 0; } //---------------------------------------------------------------------------- HexBookMarkMenuAction::HexBookMarkMenuAction(QString desc, QWidget *parent) : QAction( desc, parent ) { bm = NULL; qedit = NULL; } //---------------------------------------------------------------------------- HexBookMarkMenuAction::~HexBookMarkMenuAction(void) { //printf("Hex Bookmark Menu Action Deleted\n"); } //---------------------------------------------------------------------------- void HexBookMarkMenuAction::activateCB(void) { //printf("Activate Bookmark: %p \n", bm ); qedit->setMode( bm->mode ); qedit->setAddr( bm->addr ); } //---------------------------------------------------------------------------- HexEditorCharTable_t::HexEditorCharTable_t(void) { extAsciiEnable = true; customMapLoaded = false; resetAscii(); } //---------------------------------------------------------------------------- HexEditorCharTable_t::~HexEditorCharTable_t(void) { } //---------------------------------------------------------------------------- void HexEditorCharTable_t::resetAscii(void) { for (int i=0; i<256; i++) { rmap[i] = i; if (i > 127) { // Extended Ascii if ( extAsciiEnable ) { map[i] = i; } else { map[i] = '.'; } } else { // Normal Ascii if ( isprint(i) ) { map[i] = i; } else { map[i] = '.'; } } } customMapLoaded = false; } //---------------------------------------------------------------------------- int HexEditorCharTable_t::loadFromFile( const char *filepath ) { int i,j,hexValue,mapValue,retVal, lineNum = 0; FILE *fp; char line[256]; char tk[64]; char errMsg[256]; int tmpMap[256]; int tmpMapR[256]; retVal = 0; errMsg[0] = 0; fp = ::fopen( filepath, "r"); if ( fp == NULL ) { return -1; } for (i=0; i<256; i++) { tmpMap[i] = -1; tmpMapR[i] = -1; } while ( fgets( line, sizeof(line), fp ) != 0 ) { lineNum++; if ( retVal != 0 ) { break; } //printf("%s\n", line); i=0; while ( isspace(line[i]) ) i++; if ( line[i] == '#' ) { // Comment line, skip it line[i] = 0; continue; } while ( isspace(line[i]) ) i++; j=0; while ( isxdigit(line[i]) ) { tk[j] = line[i]; i++; j++; } tk[j] = 0; if ( j == 0 ) { // Line did not start with a hex character, skip it continue; } hexValue = strtol( tk, NULL, 16 ); if ( hexValue > 255 ) { sprintf( errMsg, "Error: Line %i: Hex Value 0x%X exceeds 0xFF \n", lineNum, hexValue ); retVal = -1; continue; } while ( isspace(line[i]) ) i++; if ( line[i] != '=' ) { sprintf( errMsg, "Error: Line %i: Expected assignment operator '=' but got '%c' \n", lineNum, line[i] ); retVal = -1; continue; } i++; while ( isspace(line[i]) ) i++; mapValue = 0; if (line[i] == '0') { // Hex Value Remap or '0' i++; if ( line[i] == 'x') { i++; j=0; while ( isxdigit(line[i]) ) { tk[j] = line[i]; i++; j++; } tk[j] = 0; mapValue = strtol( tk, NULL, 16 ); } else { mapValue = '0'; } } else if (line[i] == '$') { // Hex Value Remap or '$' i++; if ( isxdigit(line[i]) ) { j=0; while ( isxdigit(line[i]) ) { tk[j] = line[i]; i++; j++; } tk[j] = 0; mapValue = strtol( tk, NULL, 16 ); } else { mapValue = '$'; } } else { // Hex to Character Mapping mapValue = line[i]; } if ( mapValue > 255 ) { sprintf( errMsg, "Error: Line %i: Map Value 0x%X exceeds 0xFF \n", lineNum, mapValue ); retVal = -1; continue; } tmpMap[ hexValue ] = mapValue; if ( mapValue < 256 ) { tmpMapR[ mapValue ] = hexValue; } } if ( retVal == 0 ) { memcpy( map, tmpMap , sizeof( map) ); memcpy( rmap, tmpMapR, sizeof(rmap) ); customMapLoaded = true; } else { if ( errMsg[0] != 0 ) { if ( consoleWindow != NULL ) { consoleWindow->QueueErrorMsgWindow(errMsg); } } } ::fclose(fp); return retVal; } //---------------------------------------------------------------------------- HexEditorFindDialog_t::HexEditorFindDialog_t(QWidget *parent) : QDialog( parent ) { QVBoxLayout *mainLayout, *vbox; QHBoxLayout *hbox; QPushButton *nextBtn; QGroupBox *dirGroup, *typeGroup; QDialog::setWindowTitle( tr("Find") ); this->parent = (HexEditorDialog_t*)parent; mainLayout = new QVBoxLayout(); hbox = new QHBoxLayout(); searchBox = new QLineEdit(); nextBtn = new QPushButton( tr("Find Next") ); dirGroup = new QGroupBox( tr("Direction") ); typeGroup = new QGroupBox( tr("Type") ); hbox->addWidget( new QLabel( tr("Find What:") ) ); hbox->addWidget( searchBox ); hbox->addWidget( nextBtn ); nextBtn->setDefault(true); mainLayout->addLayout( hbox ); hbox = new QHBoxLayout(); hbox->addWidget( dirGroup ); hbox->addWidget( typeGroup ); mainLayout->addLayout( hbox ); vbox = new QVBoxLayout(); upBtn = new QRadioButton( tr("Up") ); dnBtn = new QRadioButton( tr("Down") ); dnBtn->setChecked(true); vbox->addWidget( upBtn ); vbox->addWidget( dnBtn ); dirGroup->setLayout( vbox ); vbox = new QVBoxLayout(); hexBtn = new QRadioButton( tr("Hex") ); txtBtn = new QRadioButton( tr("Text") ); vbox->addWidget( hexBtn ); vbox->addWidget( txtBtn ); hexBtn->setChecked(true); typeGroup->setLayout( vbox ); setLayout( mainLayout ); connect( nextBtn, SIGNAL(clicked(void)), this, SLOT(runSearch(void)) ); } //---------------------------------------------------------------------------- HexEditorFindDialog_t::~HexEditorFindDialog_t(void) { parent->findDialog = NULL; } //---------------------------------------------------------------------------- void HexEditorFindDialog_t::closeEvent(QCloseEvent *event) { printf("Hex Editor Close Window Event\n"); done(0); deleteLater(); event->accept(); } //---------------------------------------------------------------------------- void HexEditorFindDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); deleteLater(); } //---------------------------------------------------------------------------- void HexEditorFindDialog_t::runSearch(void) { int i=0; unsigned char v; std::string s = searchBox->text().toStdString(); std::vector varray; if ( s.size() == 0 ) { return; } //printf("Run Search: '%s'\n", s.c_str() ); if ( hexBtn->isChecked() ) { i=0; while ( s[i] != 0 ) { while ( isspace(s[i]) ) i++; v = 0; if ( isxdigit(s[i]) ) { v = convFromXchar(s[i]) << 4; i++; } else { return; } if ( isxdigit(s[i]) ) { v |= convFromXchar(s[i]); i++; } else { return; } varray.push_back(v); while ( isspace(s[i]) ) i++; } } else { i=0; while ( s[i] != 0 ) { v = s[i]; varray.push_back(v); i++; } } fceuWrapperLock(); parent->editor->findPattern( varray, upBtn->isChecked() ); fceuWrapperUnLock(); } //---------------------------------------------------------------------------- HexEditorDialog_t::HexEditorDialog_t(QWidget *parent) : QDialog( parent, Qt::Window ) { //QVBoxLayout *mainLayout; QGridLayout *grid; QMenuBar *menuBar; QMenu *fileMenu, *editMenu, *viewMenu, *colorMenu, *subMenu; QAction *saveROM, *closeAct; QAction *act, *actHlgt, *actHlgtRV; ColorMenuItem *actColorFG, *actColorBG, *actRowColColor, *actAltColColor; QActionGroup *group; int useNativeMenuBar; QSettings settings; QDialog::setWindowTitle( tr("Hex Editor") ); resize( 512, 512 ); 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 //----------------------------------------------------------------------- // File fileMenu = menuBar->addMenu(tr("&File")); // File -> Save ROM saveROM = new QAction(tr("&Save ROM"), this); saveROM->setShortcut(QKeySequence::Save); 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->setShortcut(QKeySequence::SaveAs); saveROM->setStatusTip(tr("Save ROM File As")); connect(saveROM, SIGNAL(triggered()), this, SLOT(saveRomFileAs(void)) ); fileMenu->addAction(saveROM); // File -> Load Table loadTableAct = new QAction(tr("&Load TBL File"), this); //loadTableAct->setShortcut(QKeySequence::Open); loadTableAct->setStatusTip(tr("Load Table from File")); connect(loadTableAct, SIGNAL(triggered()), this, SLOT(loadTableFromFile(void)) ); fileMenu->addAction(loadTableAct); // File -> Unload Table unloadTableAct = new QAction(tr("&Unload TBL File"), this); //unloadTableAct->setShortcut(QKeySequence::Open); unloadTableAct->setStatusTip(tr("Unload Table")); connect(unloadTableAct, SIGNAL(triggered()), this, SLOT(unloadTable(void)) ); fileMenu->addAction(unloadTableAct); // File -> Goto Address gotoAddrAct = new QAction(tr("&Goto Address"), this); gotoAddrAct->setShortcut(QKeySequence(tr("Ctrl+A"))); gotoAddrAct->setStatusTip(tr("Goto Address")); connect(gotoAddrAct, SIGNAL(triggered()), this, SLOT(openGotoAddrDialog(void)) ); fileMenu->addAction(gotoAddrAct); fileMenu->addSeparator(); // File -> Close closeAct = new QAction(tr("&Close"), this); closeAct->setShortcut(QKeySequence::Close); closeAct->setStatusTip(tr("Close Window")); connect(closeAct, SIGNAL(triggered()), this, SLOT(closeWindow(void)) ); fileMenu->addAction(closeAct); // Edit editMenu = menuBar->addMenu(tr("&Edit")); // Edit -> Undo undoEditAct = new QAction(tr("&Undo"), this); undoEditAct->setShortcut(QKeySequence::Undo); undoEditAct->setStatusTip(tr("Undo Edit")); undoEditAct->setEnabled(false); connect(undoEditAct, SIGNAL(triggered()), this, SLOT(undoRomPatch(void)) ); editMenu->addAction(undoEditAct); editMenu->addSeparator(); // Edit -> Copy act = new QAction(tr("&Copy"), this); act->setShortcut(QKeySequence(tr("Ctrl+C"))); act->setStatusTip(tr("Copy")); connect(act, SIGNAL(triggered()), this, SLOT(copyToClipboard(void)) ); editMenu->addAction(act); // Edit -> Paste act = new QAction(tr("&Paste"), this); act->setShortcut(QKeySequence(tr("Ctrl+V"))); act->setStatusTip(tr("Paste")); connect(act, SIGNAL(triggered()), this, SLOT(pasteFromClipboard(void)) ); editMenu->addAction(act); editMenu->addSeparator(); // Edit -> Find act = new QAction(tr("&Find"), this); act->setShortcut(QKeySequence(tr("Ctrl+F"))); act->setStatusTip(tr("Find")); connect(act, SIGNAL(triggered()), this, SLOT(openFindDialog(void)) ); editMenu->addAction(act); // 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 viewMenu->addSeparator(); // View -> Font act = new QAction(tr("Set &Font..."), this); //act->setShortcuts(QKeySequence::Open); act->setStatusTip(tr("Change Font")); //act->setCheckable(true); connect(act, SIGNAL(triggered()), this, SLOT(changeFontRequest(void)) ); viewMenu->addAction(act); viewMenu->addSeparator(); // View -> Refresh Rate subMenu = viewMenu->addMenu( tr("Re&fresh Rate") ); group = new QActionGroup(this); group->setExclusive(true); // View -> Refresh Rate -> 5 Hz act = new QAction(tr("5 Hz"), this); act->setCheckable(true); connect(act, SIGNAL(triggered()), this, SLOT(setViewRefresh5Hz(void)) ); group->addAction(act); subMenu->addAction(act); // View -> Refresh Rate -> 10 Hz act = new QAction(tr("10 Hz"), this); act->setCheckable(true); act->setChecked(true); connect(act, SIGNAL(triggered()), this, SLOT(setViewRefresh10Hz(void)) ); group->addAction(act); subMenu->addAction(act); // View -> Refresh Rate -> 20 Hz act = new QAction(tr("20 Hz"), this); act->setCheckable(true); connect(act, SIGNAL(triggered()), this, SLOT(setViewRefresh20Hz(void)) ); group->addAction(act); subMenu->addAction(act); // View -> Refresh Rate -> 30 Hz act = new QAction(tr("30 Hz"), this); act->setCheckable(true); connect(act, SIGNAL(triggered()), this, SLOT(setViewRefresh30Hz(void)) ); group->addAction(act); subMenu->addAction(act); // View -> Refresh Rate -> 60 Hz act = new QAction(tr("60 Hz"), this); act->setCheckable(true); connect(act, SIGNAL(triggered()), this, SLOT(setViewRefresh60Hz(void)) ); group->addAction(act); subMenu->addAction(act); // Color Menu colorMenu = menuBar->addMenu(tr("&Color")); // Color -> 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)) ); colorMenu->addAction(actHlgt); // 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(true); connect(actHlgtRV, SIGNAL(triggered(bool)), this, SLOT(actvHighlightRVCB(bool)) ); colorMenu->addAction(actHlgtRV); // Color -> Highlight Reverse Video rolColHlgtAct = new QAction(tr("Highlight &Cursor Row/Column"), this); //rolColHlgtAct->setShortcuts(QKeySequence::Open); rolColHlgtAct->setStatusTip(tr("Highlight Cursor Row/Column")); rolColHlgtAct->setCheckable(true); rolColHlgtAct->setChecked(false); connect(rolColHlgtAct, SIGNAL(triggered(bool)), this, SLOT(rolColHlgtChanged(bool)) ); colorMenu->addAction(rolColHlgtAct); // Color -> Highlight Reverse Video altColHlgtAct = new QAction(tr("&Alternating Column Colors"), this); //altColHlgtAct->setShortcuts(QKeySequence::Open); altColHlgtAct->setStatusTip(tr("&Alternating Column Colors")); altColHlgtAct->setCheckable(true); altColHlgtAct->setChecked(false); connect(altColHlgtAct, SIGNAL(triggered(bool)), this, SLOT(altColHlgtChanged(bool)) ); colorMenu->addAction(altColHlgtAct); colorMenu->addSeparator(); // Color -> ForeGround Color actColorFG = new ColorMenuItem( tr("&ForeGround Color"), "SDL.HexEditFgColor", this); //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 ColorMenuItem( tr("&BackGround Color"), "SDL.HexEditBgColor", this); //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); // Color -> Cursor Row/Column Color actRowColColor = new ColorMenuItem( tr("&Cursor Row/Column Color"), "SDL.HexEditCursorColorRC", this); //act = new QAction(tr("&Cursor Row/Column Color"), this); //act->setShortcuts(QKeySequence::Open); //act->setStatusTip(tr("Cursor Row/Column Color")); //connect(act, SIGNAL(triggered(void)), this, SLOT(pickCursorRowColumnColor(void)) ); colorMenu->addAction(actRowColColor); // Color -> Alternate Column Color actAltColColor = new ColorMenuItem( tr("&Alternate Column Color"), "SDL.HexEditAltColColor", this); //act = new QAction(tr("&Alternate Column Color"), this); //act->setShortcuts(QKeySequence::Open); //act->setStatusTip(tr("Alternate Column Color")); //connect(act, SIGNAL(triggered(void)), this, SLOT(pickAlternateColumnColor(void)) ); colorMenu->addAction(actAltColColor); // Bookmarks Menu bookmarkMenu = menuBar->addMenu(tr("&Bookmarks")); //----------------------------------------------------------------------- // Menu End //----------------------------------------------------------------------- //mainLayout = new QVBoxLayout(); grid = new QGridLayout(this); editor = new QHexEdit(this); vbar = new QScrollBar( Qt::Vertical, this ); hbar = new QScrollBar( Qt::Horizontal, this ); grid->setMenuBar( menuBar ); grid->addWidget( editor, 0, 0 ); grid->addWidget( vbar , 0, 1 ); grid->addWidget( hbar , 1, 0 ); //mainLayout->addLayout( grid ); setLayout( grid ); hbar->setMinimum(0); hbar->setMaximum(100); vbar->setMinimum(0); vbar->setMaximum( 0x1000 / 16 ); editor->setScrollBars( hbar, vbar ); actColorFG->connectColor( &editor->fgColor ); actColorBG->connectColor( &editor->bgColor ); actRowColColor->connectColor( &editor->rowColHlgtColor ); actAltColColor->connectColor( &editor->altColHlgtColor ); //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)) ); findDialog = NULL; editor->memModeUpdate(); periodicTimer = new QTimer( this ); connect( periodicTimer, &QTimer::timeout, this, &HexEditorDialog_t::updatePeriodic ); periodicTimer->start( 100 ); // 10hz // Lock the mutex before adding a new window to the list, // we want to be sure that the emulator is not iterating the list // when we change it. fceuWrapperLock(); winList.push_back(this); fceuWrapperUnLock(); populateBookmarkMenu(); FCEUI_CreateCheatMap(); unloadTableAct->setEnabled( editor->charTable.customMapLoaded ); restoreGeometry(settings.value("hexEditor/geometry").toByteArray()); } //---------------------------------------------------------------------------- HexEditorDialog_t::~HexEditorDialog_t(void) { std::list ::iterator it; printf("Hex Editor Deleted\n"); periodicTimer->stop(); // Lock the emulation thread mutex to ensure // that the emulator is not attempting to update memory values // for window while we are destroying it or editing the window list. fceuWrapperLock(); for (it = winList.begin(); it != winList.end(); it++) { if ( (*it) == this ) { winList.erase(it); //printf("Removing Hex Edit Window\n"); break; } } fceuWrapperUnLock(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setWindowTitle(void) { const char *modeString; char stmp[128]; modeString = memViewNames[ editor->getMode() ]; sprintf( stmp, "Hex Editor - %s: 0x%04X", modeString, editor->getAddr() ); QDialog::setWindowTitle( tr(stmp) ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::removeAllBookmarks(void) { int ret; QMessageBox mbox(this); mbox.setWindowTitle( tr("Bookmarks") ); mbox.setText( tr("Remove All Bookmarks?") ); mbox.setIcon( QMessageBox::Question ); mbox.setStandardButtons( QMessageBox::Cancel | QMessageBox::Ok ); ret = mbox.exec(); //printf("Ret: %i \n", ret ); if ( ret == QMessageBox::Ok ) { hbm.removeAll(); populateBookmarkMenu(); } } //---------------------------------------------------------------------------- void HexEditorDialog_t::populateBookmarkMenu(void) { QAction *act; HexBookMarkMenuAction *hAct; bookmarkMenu->clear(); // Bookmarks -> Remove All Bookmarks act = new QAction(tr("&Remove All Bookmarks"), bookmarkMenu); //act->setShortcuts(QKeySequence::Open); act->setStatusTip(tr("Remove All Bookmarks")); connect(act, SIGNAL(triggered(void)), this, SLOT(removeAllBookmarks(void)) ); bookmarkMenu->addAction(act); bookmarkMenu->addSeparator(); for (int i=0; idesc), bookmarkMenu); bookmarkMenu->addAction(hAct); hAct->bm = b; hAct->qedit = editor; connect(hAct, SIGNAL(triggered(void)), hAct, SLOT(activateCB(void)) ); } } } //---------------------------------------------------------------------------- void HexEditorDialog_t::closeEvent(QCloseEvent *event) { QSettings settings; //printf("Hex Editor Close Window Event\n"); settings.setValue("hexEditor/geometry", saveGeometry()); done(0); deleteLater(); event->accept(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::closeWindow(void) { QSettings settings; //printf("Close Window\n"); settings.setValue("hexEditor/geometry", saveGeometry()); done(0); deleteLater(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::pickForeGroundColor(void) { hexEditColorPickerDialog_t *dialog; dialog = new hexEditColorPickerDialog_t( &editor->fgColor, "Pick Foreground Color", "SDL.HexEditFgColor", editor ); dialog->show(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::pickBackGroundColor(void) { hexEditColorPickerDialog_t *dialog; dialog = new hexEditColorPickerDialog_t( &editor->bgColor, "Pick Background Color", "SDL.HexEditBgColor", editor ); dialog->show(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::pickCursorRowColumnColor(void) { hexEditColorPickerDialog_t *dialog; dialog = new hexEditColorPickerDialog_t( &editor->rowColHlgtColor, "Pick Cursor Row/Column Color", "SDL.HexEditCursorColorRC", editor ); dialog->show(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::pickAlternateColumnColor(void) { hexEditColorPickerDialog_t *dialog; dialog = new hexEditColorPickerDialog_t( &editor->altColHlgtColor, "Pick Alternate Column Color", "SDL.HexEditAltColColor", editor ); dialog->show(); } //---------------------------------------------------------------------------- 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::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) { romEditList.clear(); 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::AllDirs | 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); 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::loadTableFromFile(void) { int ret, useNativeFileDialogVal; QString filename; QFileDialog dialog(this, tr("Load Table From File") ); dialog.setFileMode(QFileDialog::ExistingFile); dialog.setNameFilter(tr("TBL Files (*.tbl *.TBL) ;; All files (*)")); dialog.setViewMode(QFileDialog::List); dialog.setFilter( QDir::AllEntries | QDir::AllDirs | QDir::Hidden ); dialog.setLabelText( QFileDialog::Accept, tr("Load") ); dialog.setDefaultSuffix( tr(".tbl") ); // Check config option to use native file dialog or not g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal); 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(); editor->charTable.loadFromFile( filename.toStdString().c_str() ); unloadTableAct->setEnabled( editor->charTable.customMapLoaded ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::unloadTable(void) { editor->charTable.resetAscii(); unloadTableAct->setEnabled( editor->charTable.customMapLoaded ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRAM(void) { editor->setMode( QHexEdit::MODE_NES_RAM ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewPPU(void) { editor->setMode( QHexEdit::MODE_NES_PPU ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewOAM(void) { editor->setMode( QHexEdit::MODE_NES_OAM ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewROM(void) { editor->setMode( QHexEdit::MODE_NES_ROM ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::changeFontRequest(void) { editor->changeFontRequest(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRefresh5Hz(void) { periodicTimer->stop(); periodicTimer->start(200); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRefresh10Hz(void) { periodicTimer->stop(); periodicTimer->start(100); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRefresh20Hz(void) { periodicTimer->stop(); periodicTimer->start(50); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRefresh30Hz(void) { periodicTimer->stop(); periodicTimer->start(33); } //---------------------------------------------------------------------------- void HexEditorDialog_t::setViewRefresh60Hz(void) { periodicTimer->stop(); periodicTimer->start(16); } //---------------------------------------------------------------------------- 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::rolColHlgtChanged(bool enable) { //printf("Highlight: %i \n", enable ); editor->setRowColHlgtEna( enable ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::altColHlgtChanged(bool enable) { //printf("Highlight: %i \n", enable ); editor->setAltColHlgtEna( enable ); } //---------------------------------------------------------------------------- void HexEditorDialog_t::openDebugSymbolEditWindow( int addr ) { int ret, bank; debugSymbol_t *sym; SymbolEditWindow win(this); if ( addr < 0x8000 ) { bank = -1; } else { bank = getBank( addr ); } sym = debugSymbolTable.getSymbolAtBankOffset( bank, addr ); win.setAddr( addr ); win.setSym( sym ); ret = win.exec(); if ( ret == QDialog::Accepted ) { updateAllDebuggerWindows(); } } //---------------------------------------------------------------------------- void HexEditorDialog_t::updatePeriodic(void) { //printf("Update Periodic\n"); undoEditAct->setEnabled( romEditList.undoQueueSize() > 0 ); if ( fceuWrapperTryLock(0) ) { memNeedsCheck = false; editor->checkMemActivity(); fceuWrapperUnLock(); } else { memNeedsCheck = true; } editor->memModeUpdate(); editor->update(); setWindowTitle(); switch ( editor->getMode() ) { case QHexEdit::MODE_NES_RAM: if ( !viewRAM->isChecked() ) { viewRAM->setChecked(true); } break; case QHexEdit::MODE_NES_PPU: if ( !viewPPU->isChecked() ) { viewPPU->setChecked(true); } break; case QHexEdit::MODE_NES_OAM: if ( !viewOAM->isChecked() ) { viewOAM->setChecked(true); } break; case QHexEdit::MODE_NES_ROM: if ( !viewROM->isChecked() ) { viewROM->setChecked(true); } break; } } //---------------------------------------------------------------------------- void HexEditorDialog_t::undoRomPatch(void) { int addr = romEditList.undoPatch(); if ( addr >= 0 ) { editor->setMode( QHexEdit::MODE_NES_ROM ); editor->setAddr( addr ); } } //---------------------------------------------------------------------------- void HexEditorDialog_t::openFindDialog(void) { if ( findDialog == NULL ) { findDialog = new HexEditorFindDialog_t(this); findDialog->show(); } } //---------------------------------------------------------------------------- void HexEditorDialog_t::openGotoAddrDialog(void) { editor->openGotoAddrDialog(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::copyToClipboard(void) { editor->loadHighlightToClipboard(); } //---------------------------------------------------------------------------- void HexEditorDialog_t::pasteFromClipboard(void) { editor->pasteFromClipboard(); } //---------------------------------------------------------------------------- QHexEdit::QHexEdit(QWidget *parent) : QWidget( parent ) { QPalette pal; std::string fontString, colorString; this->parent = (HexEditorDialog_t*)parent; this->setFocusPolicy(Qt::StrongFocus); g_config->getOption("SDL.HexEditFont", &fontString); if ( fontString.size() > 0 ) { font.fromString( QString::fromStdString( fontString ) ); } else { font.setFamily("Courier New"); font.setStyle( QFont::StyleNormal ); font.setStyleHint( QFont::Monospace ); } g_config->getOption("SDL.HexEditBgColor", &colorString); bgColor.setNamedColor( colorString.c_str() ); g_config->getOption("SDL.HexEditFgColor", &colorString); fgColor.setNamedColor( colorString.c_str() ); g_config->getOption("SDL.HexEditCursorColorRC", &colorString); rowColHlgtColor.setNamedColor( colorString.c_str() ); rolColHlgtEna = false; g_config->getOption("SDL.HexEditAltColColor", &colorString); altColHlgtColor.setNamedColor( colorString.c_str() ); altColHlgtEna = false; pal = this->palette(); pal.setColor(QPalette::Base , bgColor ); pal.setColor(QPalette::Window , bgColor ); pal.setColor(QPalette::WindowText, fgColor ); this->setPalette(pal); calcFontData(); setMinimumWidth( pxLineWidth ); memAccessFunc = getRAM; viewMode = MODE_NES_RAM; lineOffset = 0; cursorPosX = 0; cursorPosY = 0; cursorAddr = 0; cursorBlink = true; cursorBlinkCount = 0; maxLineOffset = 0; editAddr = -1; editValue = 0; editMask = 0; reverseVideo = true; actvHighlightEnable = true; total_instructions_lp = 0; pxLineXScroll = 0; frzRamAddr = -1; frzRamVal = 0; frzRamMode = 0; frzIdx = 0; wheelPixelCounter = 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 ); for (int i=0; i= 0.5 ) { grayScale = 0.0; } else { grayScale = 1.0; } rvActvTextColor[i].setRgbF( grayScale, grayScale, grayScale ); } updateRequested = false; mouseLeftBtnDown = false; txtHlgtAnchorChar = -1; txtHlgtAnchorLine = -1; txtHlgtStartChar = -1; txtHlgtStartLine = -1; txtHlgtStartAddr = -1; txtHlgtEndChar = -1; txtHlgtEndLine = -1; txtHlgtEndAddr = -1; clipboard = QGuiApplication::clipboard(); } //---------------------------------------------------------------------------- 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')); #else pxCharWidth = metrics.width(QLatin1Char('2')); #endif pxCharHeight = metrics.height(); pxLineSpacing = metrics.lineSpacing() * 1.25; pxLineLead = pxLineSpacing - pxCharHeight; pxXoffset = pxCharWidth; 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; pxCursorHeight = pxCharHeight; //_pxSelectionSub = _pxCharHeight / 5; viewLines = (viewHeight - pxLineSpacing) / pxLineSpacing; } //---------------------------------------------------------------------------- void QHexEdit::changeFontRequest(void) { bool ok = false; QFont selFont = QFontDialog::getFont( &ok, font, this, tr("Select Font"), QFontDialog::MonospacedFonts ); if ( ok ) { font = selFont; calcFontData(); //printf("Font Changed to: '%s'\n", font.toString().toStdString().c_str() ); g_config->setOption("SDL.HexEditFont", font.toString().toStdString().c_str() ); } } //---------------------------------------------------------------------------- void QHexEdit::setHighlightActivity( int enable ) { actvHighlightEnable = enable; } //---------------------------------------------------------------------------- void QHexEdit::setHighlightReverseVideo( int enable ) { reverseVideo = enable; } //---------------------------------------------------------------------------- void QHexEdit::setForeGroundColor( QColor fg ) { QPalette pal; pal = this->palette(); pal.setColor(QPalette::WindowText, fg ); this->setPalette(pal); } //---------------------------------------------------------------------------- void QHexEdit::setBackGroundColor( QColor bg ) { QPalette pal; pal = this->palette(); pal.setColor(QPalette::Window , bg ); this->setPalette(pal); } //---------------------------------------------------------------------------- void QHexEdit::setMode( int mode ) { if ( viewMode != mode ) { viewMode = mode; memModeUpdate(); clearHighlight(); } } //---------------------------------------------------------------------------- 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; vbar->setValue( lineOffset ); } //---------------------------------------------------------------------------- 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; } //---------------------------------------------------------------------------- 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; maxLineOffset = mb.numLines() - viewLines + 1; if ( viewWidth >= pxLineWidth ) { pxLineXScroll = 0; hbar->setMaximum(0); hbar->hide(); } else { hbar->setPageStep(viewWidth); hbar->setMaximum(pxLineWidth - viewWidth); hbar->show(); pxLineXScroll = hbar->value(); } vbar->setMaximum( maxLineOffset ); vbar->setPageStep( (3*viewLines)/4 ); } //---------------------------------------------------------------------------- void QHexEdit::openGotoAddrDialog(void) { int ret; char stmp[128]; QDialog dialog(this); QLabel *lbl; QSpinBox *sbox; QVBoxLayout *vbox; QHBoxLayout *hbox; QPushButton *okButton, *cancelButton; sprintf( stmp, "Specify Address [ 0x0 -> 0x%X ]", mb.size()-1 ); vbox = new QVBoxLayout(); hbox = new QHBoxLayout(); lbl = new QLabel( tr(stmp) ); okButton = new QPushButton( tr("Go") ); cancelButton = new QPushButton( tr("Cancel") ); okButton->setIcon( style()->standardIcon( QStyle::SP_DialogApplyButton ) ); cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) ); connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) ); connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) ); sbox = new QSpinBox(); sbox->setRange(0x0000, mb.size()-1); sbox->setDisplayIntegerBase(16); sbox->setValue( 0 ); QFont font = sbox->font(); font.setCapitalization(QFont::AllUppercase); sbox->setFont(font); hbox->addWidget( cancelButton ); hbox->addWidget( okButton ); vbox->addWidget( lbl ); vbox->addWidget( sbox ); vbox->addLayout( hbox ); dialog.setLayout( vbox ); dialog.setWindowTitle( tr("Goto Address") ); okButton->setDefault(true); ret = dialog.exec(); if ( QDialog::Accepted == ret ) { int addr; addr = sbox->value(); parent->gotoAddress(addr); } } //---------------------------------------------------------------------------- void QHexEdit::resetCursor(void) { cursorBlink = true; cursorBlinkCount = 0; editAddr = -1; editValue = 0; editMask = 0; } //---------------------------------------------------------------------------- void QHexEdit::clearHighlight(void) { txtHlgtAnchorChar = -1; txtHlgtAnchorLine = -1; txtHlgtStartChar = -1; txtHlgtStartLine = -1; txtHlgtStartAddr = -1; txtHlgtEndChar = -1; txtHlgtEndLine = -1; txtHlgtEndAddr = -1; } //---------------------------------------------------------------------------- void QHexEdit::loadClipboard( const char *txt ) { //printf("Load Clipboard: '%s'\n", txt ); clipboard->setText( tr(txt), QClipboard::Clipboard ); if ( clipboard->supportsSelection() ) { clipboard->setText( tr(txt), QClipboard::Selection ); } } //---------------------------------------------------------------------------- void QHexEdit::pasteFromClipboard(void) { int i, val, addr; std::string s = clipboard->text().toStdString(); const char *c; fceuWrapperLock(); //printf("Paste: '%s'\n", s.c_str() ); addr = cursorAddr; c = s.c_str(); i=0; while ( c[i] != 0 ) { while ( isspace(c[i]) ) i++; val = 0; if ( isxdigit(c[i]) ) { val = convFromXchar(c[i]) << 4; i++; } else { break; } if ( isxdigit(c[i]) ) { val |= convFromXchar(c[i]); i++; } else { break; } if ( viewMode == QHexEdit::MODE_NES_ROM ) { romEditList.applyPatch( addr, val ); } writeMem( viewMode, addr, val ); addr++; } fceuWrapperUnLock(); } //---------------------------------------------------------------------------- void QHexEdit::loadHighlightToClipboard(void) { int a, startAddr, endAddr; std::string s; char c[8]; fceuWrapperLock(); startAddr = (txtHlgtStartLine*16) + txtHlgtStartChar; endAddr = (txtHlgtEndLine *16) + txtHlgtEndChar; for (a=startAddr; a<=endAddr; a++) { sprintf( c, "%02X ", memAccessFunc(a) ); s.append(c); } fceuWrapperUnLock(); loadClipboard( s.c_str() ); } //---------------------------------------------------------------------------- int QHexEdit::findPattern( std::vector &varray, int dir ) { int addr, inc, match; inc = dir ? -1 : 1; addr = cursorAddr; match = 0; //printf("Looking for pattern %zi\n", varray.size() ); while ( !match ) { addr = (addr + inc); if ( addr < 0 ) { addr = mb.size() - 1; } else if ( addr >= mb.size() ) { addr = 0; } if ( addr == cursorAddr ) { return -1; } match = 1; for (int i=0; i= mb.size() ) { match = 0; break; } if ( memAccessFunc(addr+i) != varray[i] ) { match = 0; break; } } } if ( match ) { int endAddr = addr + varray.size() - 1; //printf("Found Match at $%04X\n", addr ); txtHlgtStartChar = (addr%16); txtHlgtStartLine = (addr/16); txtHlgtStartAddr = addr; txtHlgtEndChar = (endAddr%16); txtHlgtEndLine = (endAddr/16); txtHlgtEndAddr = (endAddr); cursorAddr = addr; cursorPosX = txtHlgtStartChar*2; if ( txtHlgtStartLine < lineOffset ) { lineOffset = txtHlgtStartLine; vbar->setValue( lineOffset ); } else if ( txtHlgtStartLine >= (lineOffset+viewLines-3) ) { lineOffset = txtHlgtStartLine - viewLines + 3; if ( lineOffset >= maxLineOffset ) { lineOffset = maxLineOffset; } vbar->setValue( lineOffset ); } cursorPosY = txtHlgtStartLine - lineOffset; } return 0; } //---------------------------------------------------------------------------- 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 ) { 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; } //---------------------------------------------------------------------------- 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() ); if (event->matches(QKeySequence::MoveToNextChar)) { if ( cursorPosX < 32 ) { if ( cursorPosX % 2 ) { cursorPosX++; } else { cursorPosX += 2; } } else { cursorPosX++; } if ( cursorPosX >= 48 ) { cursorPosX = 47; } resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToPreviousChar)) { if ( cursorPosX < 33 ) { if ( cursorPosX % 2 ) { cursorPosX -= 3; } else { cursorPosX -= 2; } } else { cursorPosX--; } if ( cursorPosX < 0 ) { cursorPosX = 0; } resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToEndOfLine)) { cursorPosX = 47; resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToStartOfLine)) { cursorPosX = 0; resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToPreviousLine)) { cursorPosY--; if ( cursorPosY < 0 ) { lineOffset--; if ( lineOffset < 0 ) { lineOffset = 0; } cursorPosY = 0; vbar->setValue( lineOffset ); } resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToNextLine)) { cursorPosY++; if ( cursorPosY >= viewLines ) { lineOffset++; if ( lineOffset >= maxLineOffset ) { lineOffset = maxLineOffset; } cursorPosY = viewLines-1; vbar->setValue( lineOffset ); } resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToNextPage)) { lineOffset += ( (3 * viewLines) / 4); if ( lineOffset >= maxLineOffset ) { lineOffset = maxLineOffset; } vbar->setValue( lineOffset ); resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToPreviousPage)) { lineOffset -= ( (3 * viewLines) / 4); if ( lineOffset < 0 ) { lineOffset = 0; } vbar->setValue( lineOffset ); resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToEndOfDocument)) { lineOffset = maxLineOffset; vbar->setValue( lineOffset ); resetCursor(); update(); event->accept(); } else if (event->matches(QKeySequence::MoveToStartOfDocument)) { lineOffset = 0; vbar->setValue( lineOffset ); resetCursor(); update(); event->accept(); } else if (Qt::ControlModifier == event->modifiers()) { if ( event->key() == Qt::Key_A ) { openGotoAddrDialog(); event->accept(); } else if ( event->key() == Qt::Key_L ) { frzRamAddr = ctxAddr = cursorAddr; frzRamToggle(); event->accept(); } } else if (event->key() == Qt::Key_Tab && (cursorPosX < 32) ) { // switch from hex to ascii edit cursorPosX = 32 + (cursorPosX / 2); update(); event->accept(); } else if (event->key() == Qt::Key_Backtab && (cursorPosX >= 32) ) { // switch from ascii to hex edit cursorPosX = 2 * (cursorPosX - 32); update(); event->accept(); } else { int key; if ( cursorPosX >= 32 ) { // Edit Area is ASCII key = (int)event->text()[0].toLatin1(); if ( (key >= 0) && (key < 256) ) { if ( charTable.rmap[key] != -1 ) { key = charTable.rmap[key]; int offs = (cursorPosX-32); int addr = 16*(lineOffset+cursorPosY) + offs; fceuWrapperLock(); if ( viewMode == QHexEdit::MODE_NES_ROM ) { romEditList.applyPatch( addr, key ); } writeMem( viewMode, addr, key ); fceuWrapperUnLock(); editAddr = -1; editValue = 0; editMask = 0; update(); event->accept(); } } } 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; fceuWrapperLock(); if ( viewMode == QHexEdit::MODE_NES_ROM ) { romEditList.applyPatch( editAddr, nibbleValue ); } writeMem( viewMode, editAddr, nibbleValue ); fceuWrapperUnLock(); editAddr = -1; editValue = 0; editMask = 0; } else { editValue = (nibbleValue << 4); editMask = 0x00f0; } cursorPosX++; if ( cursorPosX >= 32 ) { cursorPosX = 0; } update(); event->accept(); } } //printf("Key: %c %i \n", key, key); } } //---------------------------------------------------------------------------- void QHexEdit::keyReleaseEvent(QKeyEvent *event) { //printf("Hex Window Key Release: 0x%x \n", event->key() ); } //---------------------------------------------------------------------------- bool QHexEdit::textIsHighlighted(void) { bool set = false; if ( txtHlgtStartLine == txtHlgtEndLine ) { set = (txtHlgtStartChar != txtHlgtEndChar); } else { set = true; } return set; } //---------------------------------------------------------------------------- void QHexEdit::setHighlightEndCoord( int x, int y ) { if ( txtHlgtAnchorLine < y ) { txtHlgtStartLine = txtHlgtAnchorLine; txtHlgtStartChar = txtHlgtAnchorChar; txtHlgtEndLine = y; txtHlgtEndChar = x; } else if ( txtHlgtAnchorLine > y ) { txtHlgtStartLine = y; txtHlgtStartChar = x; txtHlgtEndLine = txtHlgtAnchorLine; txtHlgtEndChar = txtHlgtAnchorChar; } else { txtHlgtStartLine = txtHlgtAnchorLine; txtHlgtEndLine = txtHlgtAnchorLine; if ( txtHlgtAnchorChar < x ) { txtHlgtStartChar = txtHlgtAnchorChar; txtHlgtEndChar = x; } else if ( txtHlgtAnchorChar > x ) { txtHlgtStartChar = x; txtHlgtEndChar = txtHlgtAnchorChar; } else { txtHlgtStartChar = txtHlgtAnchorChar; txtHlgtEndChar = txtHlgtAnchorChar; } } txtHlgtStartAddr = (txtHlgtStartLine*16) + txtHlgtStartChar; txtHlgtEndAddr = (txtHlgtEndLine *16) + txtHlgtEndChar; //printf(" (%i,%i) -> (%i,%i) \n", txtHlgtStartChar, txtHlgtStartLine, txtHlgtEndChar, txtHlgtEndLine ); return; } //---------------------------------------------------------------------------- void QHexEdit::mouseMoveEvent(QMouseEvent * event) { //int line; //QPoint c = convPixToCursor( event->pos() ); int addr = convPixToAddr( event->pos() ); //line = lineOffset + c.y(); //printf("Move c: %ix%i \n", c.x(), c.y() ); if ( mouseLeftBtnDown ) { //printf("Left Button Move: (%i,%i)\n", c.x(), c.y() ); setHighlightEndCoord( addr % 16, addr / 16 ); update(); } } //---------------------------------------------------------------------------- void QHexEdit::mousePressEvent(QMouseEvent * event) { int addr; QPoint c = convPixToCursor( event->pos() ); addr = convPixToAddr( event->pos() ); //line = lineOffset + c.y(); //printf("c: %ix%i \n", c.x(), c.y() ); if ( event->button() == Qt::LeftButton ) { cursorPosX = c.x(); cursorPosY = c.y(); resetCursor(); mouseLeftBtnDown = true; txtHlgtAnchorChar = addr % 16; txtHlgtAnchorLine = addr / 16; setHighlightEndCoord( txtHlgtAnchorChar, txtHlgtAnchorLine ); update(); } } //---------------------------------------------------------------------------- void QHexEdit::mouseReleaseEvent(QMouseEvent * event) { //int line; //QPoint c = convPixToCursor( event->pos() ); int addr = convPixToAddr( event->pos() ); //line = lineOffset + c.y(); //printf("c: %ix%i \n", c.x(), c.y() ); if ( event->button() == Qt::LeftButton ) { mouseLeftBtnDown = false; setHighlightEndCoord( addr % 16, addr / 16 ); if ( textIsHighlighted() ) { loadHighlightToClipboard(); } update(); } } //---------------------------------------------------------------------------- void QHexEdit::wheelEvent(QWheelEvent *event) { QPoint numPixels = event->pixelDelta(); QPoint numDegrees = event->angleDelta(); if (!numPixels.isNull()) { wheelPixelCounter -= numPixels.y(); //printf("numPixels: (%i,%i) \n", numPixels.x(), numPixels.y() ); } else if (!numDegrees.isNull()) { //QPoint numSteps = numDegrees / 15; //printf("numSteps: (%i,%i) \n", numSteps.x(), numSteps.y() ); //printf("numDegrees: (%i,%i) %i\n", numDegrees.x(), numDegrees.y(), pxLineSpacing ); wheelPixelCounter -= (pxLineSpacing * numDegrees.y()) / (15*8); } //printf("Wheel Event: %i\n", wheelPixelCounter); if ( wheelPixelCounter >= pxLineSpacing ) { lineOffset += (wheelPixelCounter / pxLineSpacing); if ( lineOffset > maxLineOffset ) { lineOffset = maxLineOffset; } vbar->setValue( lineOffset ); wheelPixelCounter = wheelPixelCounter % pxLineSpacing; } else if ( wheelPixelCounter <= -pxLineSpacing ) { lineOffset += (wheelPixelCounter / pxLineSpacing); if ( lineOffset < 0 ) { lineOffset = 0; } vbar->setValue( lineOffset ); wheelPixelCounter = wheelPixelCounter % pxLineSpacing; } event->accept(); } //---------------------------------------------------------------------------- void QHexEdit::contextMenuEvent(QContextMenuEvent *event) { QAction *act; QMenu menu(this); int addr; char stmp[128]; QPoint c = convPixToCursor( event->pos() ); cursorPosX = c.x(); cursorPosY = c.y(); resetCursor(); ctxAddr = addr = convPixToAddr( event->pos() ); //printf("contextMenuEvent\n"); switch ( viewMode ) { case MODE_NES_RAM: { QMenu *subMenu; act = new QAction(tr("Add &Symbolic Debug Name"), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addDebugSym(void)) ); subMenu = menu.addMenu(tr("&Freeze/Unfreeze Address")); if ( frzRamAddrValid( addr ) ) { act = new QAction(tr("&Toggle State"), &menu); act->setShortcut( QKeySequence(tr("Ctrl+L"))); subMenu->addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamToggle(void)) ); act = new QAction(tr("&Freeze"), &menu); subMenu->addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamSet(void)) ); act = new QAction(tr("&Unfreeze"), &menu); subMenu->addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamUnset(void)) ); subMenu->addSeparator(); } act = new QAction(tr("Unfreeze &All"), &menu); subMenu->addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(frzRamUnsetAll(void)) ); sprintf( stmp, "Add &Read Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addRamReadBP(void)) ); sprintf( stmp, "Add &Write Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addRamWriteBP(void)) ); sprintf( stmp, "Add &Execute Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addRamExecuteBP(void)) ); if ( addr > 0x6000 ) { int romAddr = GetNesFileAddress(addr); if ( romAddr >= 0 ) { jumpToRomValue = romAddr; sprintf( stmp, "&Go Here in ROM File: (%08X)", romAddr ); act = new QAction(tr(stmp), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(jumpToROM(void)) ); } } act = new QAction(tr("Add Book&mark"), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); } break; case MODE_NES_PPU: { sprintf( stmp, "Add &Read Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addPpuReadBP(void)) ); sprintf( stmp, "Add &Write Breakpoint for Address $%04X", addr ); act = new QAction(tr(stmp), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addPpuWriteBP(void)) ); act = new QAction(tr("Add Book&mark"), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); } break; case MODE_NES_OAM: { act = new QAction(tr("Add Book&mark"), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); } break; case MODE_NES_ROM: { act = new QAction(tr("Add Book&mark"), &menu); menu.addAction(act); connect( act, SIGNAL(triggered(void)), this, SLOT(addBookMarkCB(void)) ); } break; } menu.exec(event->globalPos()); } //---------------------------------------------------------------------------- void QHexEdit::setRowColHlgtEna(bool val) { rolColHlgtEna = val; } //---------------------------------------------------------------------------- void QHexEdit::setAltColHlgtEna(bool val) { altColHlgtEna = val; } //---------------------------------------------------------------------------- void QHexEdit::addBookMarkCB(void) { int ret; char stmp[64]; QInputDialog dialog(this); switch ( viewMode ) { default: case MODE_NES_RAM: sprintf( stmp, "RAM %04X", ctxAddr ); break; case MODE_NES_PPU: sprintf( stmp, "PPU %04X", ctxAddr ); break; case MODE_NES_OAM: sprintf( stmp, "OAM %04X", ctxAddr ); break; case MODE_NES_ROM: sprintf( stmp, "ROM %04X", ctxAddr ); break; } dialog.setWindowTitle( tr("Add Bookmark") ); dialog.setLabelText( tr("Specify New Bookmark Description") ); dialog.setOkButtonText( tr("Add") ); dialog.setTextValue( tr(stmp) ); ret = dialog.exec(); if ( QDialog::Accepted == ret ) { hbm.addBookMark( ctxAddr, viewMode, dialog.textValue().toStdString().c_str() ); parent->populateBookmarkMenu(); } } //---------------------------------------------------------------------------- static int RamFreezeCB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data) { return ((QHexEdit*)data)->FreezeRam( name, a, v, compare, s, type ); } //---------------------------------------------------------------------------- int QHexEdit::FreezeRam( const char *name, uint32_t a, uint8_t v, int c, int s, int type ) { //if ( c >= 0 ) //{ // printf("$%04X?%02X:%02X %i: %s\n", a, c, v, s, name ); //} //else //{ // printf("$%04X:%02X %i: %s\n", a, v, s, name ); //} if ( a == frzRamAddr ) { switch ( frzRamMode ) { case 0: // Toggle if ( s ) { FCEUI_DelCheat( frzIdx ); frzRamAddr = -1; return 0; } break; case 1: // Freeze if ( s ) { // Already Set so there is nothing further to do frzRamAddr = -1; return 0; } break; case 2: // Unfreeze if ( s ) { FCEUI_DelCheat( frzIdx ); frzRamAddr = -1; return 0; } break; default: case 3: // Unfreeze All Handled Below // Nothing to do break; } } if ( frzRamMode == 3 ) { if ( s ) { FCEUI_DelCheat( frzIdx ); } } frzIdx++; return 1; } //---------------------------------------------------------------------------- bool QHexEdit::frzRamAddrValid( int addr ) { if ( addr < 0 ) { return false; } if ( (addr < 0x2000) || ( (addr >= 0x6000) && (addr <= 0x7FFF) ) ) { return true; } return false; } //---------------------------------------------------------------------------- void QHexEdit::frzRamSet(void) { frzIdx = 0; frzRamMode = 1; frzRamAddr = ctxAddr; if ( !frzRamAddrValid( frzRamAddr ) ) { return; } fceuWrapperLock(); FCEUI_ListCheats( RamFreezeCB, this); if ( (frzRamAddr >= 0) && (FrozenAddressCount < 256) ) { FCEUI_AddCheat("", frzRamAddr, GetMem(frzRamAddr), -1, 1); } updateCheatDialog(); fceuWrapperUnLock(); } //---------------------------------------------------------------------------- void QHexEdit::frzRamUnset(void) { frzIdx = 0; frzRamMode = 2; frzRamAddr = ctxAddr; if ( !frzRamAddrValid( frzRamAddr ) ) { return; } fceuWrapperLock(); FCEUI_ListCheats( RamFreezeCB, this); updateCheatDialog(); fceuWrapperUnLock(); } //---------------------------------------------------------------------------- void QHexEdit::frzRamUnsetAll(void) { frzIdx = 0; frzRamMode = 3; frzRamAddr = ctxAddr; if ( !frzRamAddrValid( frzRamAddr ) ) { return; } fceuWrapperLock(); FCEU_DeleteAllCheats(); updateCheatDialog(); fceuWrapperUnLock(); } //---------------------------------------------------------------------------- void QHexEdit::frzRamToggle(void) { frzIdx = 0; frzRamMode = 0; frzRamAddr = ctxAddr; if ( !frzRamAddrValid( frzRamAddr ) ) { return; } fceuWrapperLock(); FCEUI_ListCheats( RamFreezeCB, this); if ( (frzRamAddr >= 0) && (FrozenAddressCount < 256) ) { FCEUI_AddCheat("", frzRamAddr, GetMem(frzRamAddr), -1, 1); } updateCheatDialog(); fceuWrapperUnLock(); } //---------------------------------------------------------------------------- void QHexEdit::addDebugSym(void) { parent->openDebugSymbolEditWindow( ctxAddr ); } //---------------------------------------------------------------------------- void QHexEdit::addRamReadBP(void) { int retval, type; char cond[64], name[64]; type = BT_C | WP_R; cond[0] = 0; name[0] = 0; if ( ctxAddr >= 0x8000 ) { sprintf(cond, "K==#%02X", getBank(ctxAddr)); } retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); if ( (retval == 1) || (retval == 2) ) { printf("Breakpoint Add Failed\n"); } else { numWPs++; } } //---------------------------------------------------------------------------- void QHexEdit::addRamWriteBP(void) { int retval, type; char cond[64], name[64]; type = BT_C | WP_W; cond[0] = 0; name[0] = 0; if ( ctxAddr >= 0x8000 ) { sprintf(cond, "K==#%02X", getBank(ctxAddr)); } retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); if ( (retval == 1) || (retval == 2) ) { printf("Breakpoint Add Failed\n"); } else { numWPs++; } } //---------------------------------------------------------------------------- void QHexEdit::addRamExecuteBP(void) { int retval, type; char cond[64], name[64]; type = BT_C | WP_X; cond[0] = 0; name[0] = 0; if ( ctxAddr >= 0x8000 ) { sprintf(cond, "K==#%02X", getBank(ctxAddr)); } retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); if ( (retval == 1) || (retval == 2) ) { printf("Breakpoint Add Failed\n"); } else { numWPs++; } } //---------------------------------------------------------------------------- void QHexEdit::addPpuReadBP(void) { int retval, type; char cond[64], name[64]; type = BT_P | WP_R; cond[0] = 0; name[0] = 0; retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); if ( (retval == 1) || (retval == 2) ) { printf("Breakpoint Add Failed\n"); } else { numWPs++; } } //---------------------------------------------------------------------------- void QHexEdit::addPpuWriteBP(void) { int retval, type; char cond[64], name[64]; type = BT_P | WP_W; cond[0] = 0; name[0] = 0; retval = NewBreak( name, ctxAddr, -1, type, cond, numWPs, true); if ( (retval == 1) || (retval == 2) ) { printf("Breakpoint Add Failed\n"); } else { numWPs++; } } //---------------------------------------------------------------------------- void QHexEdit::jumpToROM(void) { setMode( MODE_NES_ROM ); maxLineOffset = mb.numLines() - viewLines + 1; if ( lineOffset > maxLineOffset ) { lineOffset = maxLineOffset; } setAddr( jumpToRomValue ); } //---------------------------------------------------------------------------- void QHexEdit::requestUpdate(void) { updateRequested = true; } //---------------------------------------------------------------------------- // Calling of checkMemActivity must always be synchronized with the emulation // thread as calling GetMem while the emulation is executing can mess up certain // registers (especially controller registers $4016 and $4017) 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 ( !updateRequested ) { 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; updateRequested = false; return 0; } //---------------------------------------------------------------------------- int QHexEdit::getRomAddrColor( int addr, QColor &fg, QColor &bg ) { int temp_offset; QColor color, oppColor; fg = fgColor; bg = bgColor; if ( reverseVideo ) { color = bgColor; oppColor = fgColor; } else { color = fgColor; oppColor = bgColor; } if ( viewMode != MODE_NES_ROM ) { return -1; } if ( memAccessFunc ) { mb.buf[addr].data = memAccessFunc(addr); } else { mb.buf[addr].data = 0; } if ( (txtHlgtStartAddr != txtHlgtEndAddr) && (addr >= txtHlgtStartAddr) && (addr <= txtHlgtEndAddr) ) { fg.setRgb( 255, 255, 255 ); // white bg.setRgb( 0, 0, 255 ); // blue return 0; } if ( romEditList.isModified( addr ) ) { fg.setRgb( 255, 255, 255 ); // white bg.setRgb( 255, 0, 0 ); // red return 0; } if (cdloggerdataSize == 0) { return -1; } temp_offset = addr - 16; if (temp_offset >= 0) { if ((unsigned int)temp_offset < cdloggerdataSize) { // PRG if ((cdloggerdata[temp_offset] & 3) == 3) { // the byte is both Code and Data - green color.setRgb(0, 190, 0); } else if ((cdloggerdata[temp_offset] & 3) == 1) { // the byte is Code - dark-yellow color.setRgb(160, 140, 0); oppColor.setRgb( 0, 0, 0 ); } else if ((cdloggerdata[temp_offset] & 3) == 2) { // the byte is Data - blue/cyan if (cdloggerdata[temp_offset] & 0x40) { // PCM data - cyan color.setRgb(0, 130, 160); } else { // non-PCM data - blue color.setRgb(0, 0, 210); } } } else { temp_offset -= cdloggerdataSize; if (((unsigned int)temp_offset < cdloggerVideoDataSize)) { // CHR if ((cdloggervdata[temp_offset] & 3) == 3) { // the byte was both rendered and read programmatically - light-green color.setRgb(5, 255, 5); } else if ((cdloggervdata[temp_offset] & 3) == 1) { // the byte was rendered - yellow color.setRgb(210, 190, 0); oppColor.setRgb( 0, 0, 0 ); } else if ((cdloggervdata[temp_offset] & 3) == 2) { // the byte was read programmatically - light-blue color.setRgb(15, 15, 255); } } } } if ( reverseVideo ) { bg = color; fg = oppColor; } else { fg = color; bg = oppColor; } 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; } maxLineOffset = mb.numLines() - viewLines + 1; //vbar->setMaximum( memSize / 16 ); vbar->setMaximum( maxLineOffset ); vbar->setPageStep( (3*viewLines)/4 ); } } //---------------------------------------------------------------------------- void QHexEdit::paintEvent(QPaintEvent *event) { int x, y, w, h, row, col, nrow, addr; int c, cx, cy, ca, l, recty; int pxCharWidth3; int colHlgtStart = -1, colHlgtEnd = -1; char txt[32]; QString asciiTxt; QPainter painter(this); QColor white("white"), black("black"), blue("blue"); bool txtHlgtSet; pxCharWidth3 = 3*pxCharWidth; painter.setFont(font); w = event->rect().width(); h = event->rect().height(); viewWidth = w; viewHeight = h; //painter.fillRect( 0, 0, w, h, QColor("white") ); 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() ); // maxLineOffset = mb.numLines() - nrow + 1; if ( maxLineOffset < 0 ) { maxLineOffset = 0; } if ( lineOffset < 0 ) { lineOffset = 0; } if ( lineOffset > maxLineOffset ) { lineOffset = maxLineOffset; } painter.fillRect( 0, 0, w, h, bgColor ); if ( cursorBlinkCount >= 5 ) { cursorBlink = !cursorBlink; cursorBlinkCount = 0; } else { cursorBlinkCount++; } cy = pxYoffset + (pxLineSpacing*cursorPosY) - pxCursorHeight + pxLineLead; if ( cursorPosX < 32 ) { int a = (cursorPosX / 2); int r = (cursorPosX % 2); cx = pxHexOffset + (a*pxCharWidth3) + (r*pxCharWidth) - pxLineXScroll; ca = 16*(lineOffset + cursorPosY) + a; } else { int a = (cursorPosX-32); cx = pxHexAscii + (a*pxCharWidth) - pxLineXScroll; ca = 16*(lineOffset + cursorPosY) + a; } cursorAddr = ca; if ( altColHlgtEna ) { for (int i=0; i<16; i++) { if ( (i % 2) == 0 ) { painter.fillRect( pxHexOffset - (0.5*pxCharWidth) + (i*pxCharWidth3) - pxLineXScroll , 0, (3*pxCharWidth), viewHeight, altColHlgtColor ); } } } if ( rolColHlgtEna ) { //painter.fillRect( 0 , cy - pxLineLead, viewWidth, pxLineSpacing, rowColHlgtColor ); painter.fillRect( 0 , cy - pxLineLead/2, viewWidth, pxLineSpacing, rowColHlgtColor ); //painter.fillRect( 0 , cy, viewWidth, pxLineSpacing, rowColHlgtColor ); if ( cursorPosX < 32 ) { painter.fillRect( cx - (0.5*pxCharWidth) , 0, (pxCharWidth3), viewHeight, rowColHlgtColor ); } else { painter.fillRect( cx, 0, (pxCharWidth), viewHeight, rowColHlgtColor ); } } painter.setPen( fgColor ); addr = lineOffset * 16; y = pxYoffset; txtHlgtSet = textIsHighlighted(); for ( row=0; row < nrow; row++) { colHlgtStart = -1; colHlgtEnd = -1; l = lineOffset + row; x = pxXoffset - pxLineXScroll; painter.setPen( fgColor ); sprintf( txt, "%06X", addr ); painter.drawText( x, y, tr(txt) ); x = pxHexOffset - pxLineXScroll; recty = pxYoffset + (pxLineSpacing*row) - pxCursorHeight + pxLineLead - (pxLineLead/2); // This must be this way to avoid rounding error if ( txtHlgtSet && (l >= txtHlgtStartLine) && (l <= txtHlgtEndLine) ) { int hlgtXs, hlgtXe, hlgtXd; if ( l == txtHlgtStartLine ) { hlgtXs = txtHlgtStartChar*3; colHlgtStart = txtHlgtStartChar; } else { hlgtXs = 0; colHlgtStart = 0; } if ( l == txtHlgtEndLine ) { hlgtXe = (txtHlgtEndChar+1)*3; colHlgtEnd = txtHlgtEndChar+1; } else { hlgtXe = 16*3; colHlgtEnd = 16; } hlgtXd = hlgtXe - hlgtXs; x = pxHexOffset - pxLineXScroll; painter.fillRect( x + (hlgtXs*pxCharWidth), recty, hlgtXd*pxCharWidth, pxLineSpacing, blue ); if ( l == txtHlgtStartLine ) { hlgtXs = txtHlgtStartChar; } else { hlgtXs = 0; } if ( l == txtHlgtEndLine ) { hlgtXe = (txtHlgtEndChar+1); } else { hlgtXe = 16; } hlgtXd = hlgtXe - hlgtXs; x = pxHexAscii - pxLineXScroll; painter.fillRect( x + (hlgtXs*pxCharWidth), recty, hlgtXd*pxCharWidth, pxLineSpacing, blue ); } x = pxHexOffset - pxLineXScroll; for (col=0; col<16; col++) { if ( addr < mb.size() ) { c = mb.buf[addr].data; asciiTxt.clear(); if ( charTable.map[c] >= 0x20 ) { asciiTxt += QChar(charTable.map[c]); } else { asciiTxt += QChar('.'); } 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) ); if ( cursorBlink && (ca == addr) ) { painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, fgColor ); painter.setPen( bgColor ); if ( cursorPosX < 32 ) { if ( cursorPosX % 2 ) { txt[0] = convToXchar( c & 0x0F ); txt[1] = 0; } else { txt[0] = convToXchar( (editValue >> 4) & 0x0F ); txt[1] = 0; } painter.drawText( cx, y, tr(txt) ); } else { painter.drawText( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y, asciiTxt ); } } painter.setPen( fgColor ); } else { if ( txtHlgtSet && (col >= colHlgtStart) && (col < colHlgtEnd) ) { // Background is already colored by highlight painter.setPen( fgColor ); } else if ( viewMode == MODE_NES_ROM ) { QColor romBgColor, romFgColor; getRomAddrColor( addr, romFgColor, romBgColor ); if ( reverseVideo ) { painter.setPen( romFgColor ); painter.fillRect( x - (0.5*pxCharWidth) , recty, pxCharWidth3, pxLineSpacing, romBgColor ); painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, recty, pxCharWidth, pxLineSpacing, romBgColor ); } else { painter.setPen( romFgColor ); } } else if ( viewMode == MODE_NES_RAM ) { if ( FCEUI_FindCheatMapByte( addr ) ) { if ( reverseVideo ) { painter.setPen( white ); painter.fillRect( x - (0.5*pxCharWidth) , recty, pxCharWidth3, pxLineSpacing, blue ); painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, recty, pxCharWidth, pxLineSpacing, blue ); } else { painter.setPen( blue ); } } else if ( actvHighlightEnable && (mb.buf[addr].actv > 0) ) { if ( reverseVideo ) { painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] ); painter.fillRect( x - (0.5*pxCharWidth) , recty, pxCharWidth3, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, recty, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); } else { painter.setPen( highLightColor[ mb.buf[addr].actv ] ); } } else { painter.setPen( fgColor ); } } else if ( actvHighlightEnable && (mb.buf[addr].actv > 0) ) { if ( reverseVideo ) { painter.setPen( rvActvTextColor[ mb.buf[addr].actv ] ); painter.fillRect( x - (0.5*pxCharWidth) , recty, pxCharWidth3, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); painter.fillRect( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, recty, pxCharWidth, pxLineSpacing, highLightColor[ mb.buf[addr].actv ] ); } else { painter.setPen( highLightColor[ mb.buf[addr].actv ] ); } } else { painter.setPen( fgColor ); } txt[0] = convToXchar( (c >> 4) & 0x0F ); txt[1] = convToXchar( c & 0x0F ); txt[2] = 0; painter.drawText( x, y, tr(txt) ); //painter.drawText( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y, tr(asciiTxt) ); painter.drawText( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y, asciiTxt ); if ( cursorBlink && (ca == addr) ) { painter.fillRect( cx , cy, pxCharWidth, pxCursorHeight, fgColor ); painter.setPen( bgColor ); if ( cursorPosX < 32 ) { if ( cursorPosX % 2 ) { txt[0] = convToXchar( c & 0x0F ); txt[1] = 0; } else { txt[0] = convToXchar( (c >> 4) & 0x0F ); txt[1] = 0; } painter.drawText( cx, y, tr(txt) ); } else { painter.drawText( pxHexAscii + (col*pxCharWidth) - pxLineXScroll, y, asciiTxt ); } } } } x += (pxCharWidth3); addr++; } y += pxLineSpacing; } painter.setPen( fgColor ); for (x=0; x<16; x++) { txt[0] = '0'; txt[1] = convToXchar( x ); txt[2] = 0; painter.drawText( pxHexOffset - pxLineXScroll + (x * pxCharWidth3), pxLineSpacing, txt ); } 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) ); } //---------------------------------------------------------------------------- void hexEditorLoadBookmarks(void) { std::list ::iterator it; hbm.removeAll(); hbm.loadFromFile(); for (it = winList.begin(); it != winList.end(); it++) { (*it)->populateBookmarkMenu(); } } //---------------------------------------------------------------------------- void hexEditorSaveBookmarks(void) { std::list ::iterator it; hbm.saveToFile(); hbm.removeAll(); for (it = winList.begin(); it != winList.end(); it++) { (*it)->populateBookmarkMenu(); } } //---------------------------------------------------------------------------- void hexEditorRequestUpdateAll(void) { std::list ::iterator it; for (it = winList.begin(); it != winList.end(); it++) { (*it)->editor->requestUpdate(); } } //---------------------------------------------------------------------------- int hexEditorNumWindows(void) { return winList.size(); } //---------------------------------------------------------------------------- int hexEditorOpenFromDebugger( int mode, int addr ) { HexEditorDialog_t *win = NULL; if ( winList.size() > 0 ) { win = winList.front(); } if ( win == NULL ) { win = new HexEditorDialog_t(consoleWindow); win->show(); } win->editor->setMode( mode ); win->editor->setAddr( addr ); return 0; } //---------------------------------------------------------------------------- // This function must be called from within the emulation thread void hexEditorUpdateMemoryValues(void) { std::list ::iterator it; if ( !memNeedsCheck ) { return; } for (it = winList.begin(); it != winList.end(); it++) { (*it)->editor->checkMemActivity(); } memNeedsCheck = false; } //---------------------------------------------------------------------------- // Hed Editor Color Picker //---------------------------------------------------------------------------- hexEditColorPickerDialog_t::hexEditColorPickerDialog_t( QColor *c, const char *title, const char *configName, QWidget *parent ) : QDialog( parent ) { QVBoxLayout *mainLayout; QHBoxLayout *hbox; QPushButton *okButton; QPushButton *cancelButton; QPushButton *resetButton; QStyle *style; //char stmp[128]; style = this->style(); setWindowTitle( title ); colorPtr = c; origColor = *c; if ( configName ) { confName.assign( configName ); } mainLayout = new QVBoxLayout(); setLayout( mainLayout ); colorDialog = new QColorDialog(this); mainLayout->addWidget( colorDialog ); colorDialog->setWindowFlags(Qt::Widget); colorDialog->setOption( QColorDialog::DontUseNativeDialog, true ); colorDialog->setOption( QColorDialog::NoButtons, true ); colorDialog->setCurrentColor( *c ); connect( colorDialog, SIGNAL(colorSelected(const QColor &)) , this, SLOT(colorChanged( const QColor &)) ); connect( colorDialog, SIGNAL(currentColorChanged(const QColor &)), this, SLOT(colorChanged( const QColor &)) ); connect( colorDialog, SIGNAL(accepted(void)), this, SLOT(colorAccepted(void)) ); connect( colorDialog, SIGNAL(rejected(void)), this, SLOT(colorRejected(void)) ); hbox = new QHBoxLayout(); mainLayout->addLayout( hbox ); okButton = new QPushButton( tr("OK") ); cancelButton = new QPushButton( tr("Cancel") ); resetButton = new QPushButton( tr("Reset") ); okButton->setIcon( style->standardIcon( QStyle::SP_DialogApplyButton ) ); cancelButton->setIcon( style->standardIcon( QStyle::SP_DialogCancelButton ) ); resetButton->setIcon( style->standardIcon( QStyle::SP_DialogResetButton ) ); hbox->addWidget( resetButton, 1 ); hbox->addStretch( 10 ); hbox->addWidget( okButton, 1 ); hbox->addWidget( cancelButton, 1 ); connect( okButton , SIGNAL(clicked(void)), this, SLOT(colorAccepted(void)) ); connect( cancelButton, SIGNAL(clicked(void)), this, SLOT(colorRejected(void)) ); connect( resetButton , SIGNAL(clicked(void)), this, SLOT(resetColor(void)) ); } //---------------------------------------------------------------------------- hexEditColorPickerDialog_t::~hexEditColorPickerDialog_t(void) { //printf("nesColorPicker Destroyed\n"); } //---------------------------------------------------------------------------- void hexEditColorPickerDialog_t::closeEvent(QCloseEvent *event) { //printf("nesColorPicker Close Window Event\n"); done(0); deleteLater(); event->accept(); } //---------------------------------------------------------------------------- void hexEditColorPickerDialog_t::closeWindow(void) { //printf("Close Window\n"); done(0); deleteLater(); } //---------------------------------------------------------------------------- void hexEditColorPickerDialog_t::colorChanged( const QColor &color ) { //printf("Color Changed: R:%i G%i B%i \n", color.red(), color.green(), color.blue() ); *colorPtr = color; } //---------------------------------------------------------------------------- void hexEditColorPickerDialog_t::colorAccepted(void) { if ( confName.size() > 0 ) { QString colorText; colorText = colorPtr->name(); //printf("Saving '%s' = Color string '%s'\n", confName.c_str(), colorText.toStdString().c_str() ); g_config->setOption( confName.c_str(), colorText.toStdString().c_str() ); g_config->save(); } //printf("hexColorPicker Accepted\n"); deleteLater(); } //---------------------------------------------------------------------------- void hexEditColorPickerDialog_t::colorRejected(void) { //printf("hexColorPicker Rejected\n"); // Reset to original color *colorPtr = origColor; deleteLater(); } //---------------------------------------------------------------------------- void hexEditColorPickerDialog_t::resetColor(void) { // Reset to original color *colorPtr = origColor; colorDialog->setCurrentColor( origColor ); } //----------------------------------------------------------------------------