123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- #if defined(Hiro_HexEdit)
- namespace hiro {
- auto pHexEdit::construct() -> void {
- qtWidget = qtHexEdit = new QtHexEdit(*this);
- qtHexEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- qtHexEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- qtHexEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
- qtLayout = new QHBoxLayout;
- qtLayout->setAlignment(Qt::AlignRight);
- qtLayout->setMargin(0);
- qtLayout->setSpacing(0);
- qtHexEdit->setLayout(qtLayout);
- qtScrollBar = new QtHexEditScrollBar(*this);
- qtScrollBar->setSingleStep(1);
- qtLayout->addWidget(qtScrollBar);
- qtScrollBar->connect(qtScrollBar, SIGNAL(actionTriggered(int)), SLOT(onScroll()));
- pWidget::construct();
- setBackgroundColor(state().backgroundColor);
- setForegroundColor(state().foregroundColor);
- _setState();
- }
- auto pHexEdit::destruct() -> void {
- delete qtScrollBar;
- delete qtLayout;
- delete qtHexEdit;
- qtWidget = qtHexEdit = nullptr;
- qtLayout = nullptr;
- qtScrollBar = nullptr;
- }
- auto pHexEdit::setAddress(unsigned address) -> void {
- _setState();
- }
- auto pHexEdit::setBackgroundColor(Color color) -> void {
- static auto defaultColor = qtHexEdit->palette().color(QPalette::Base);
- auto palette = qtHexEdit->palette();
- palette.setColor(QPalette::Base, CreateColor(color, defaultColor));
- qtHexEdit->setPalette(palette);
- qtHexEdit->setAutoFillBackground((bool)color);
- }
- auto pHexEdit::setColumns(unsigned columns) -> void {
- _setState();
- }
- auto pHexEdit::setForegroundColor(Color color) -> void {
- static auto defaultColor = qtHexEdit->palette().color(QPalette::Text);
- auto palette = qtHexEdit->palette();
- palette.setColor(QPalette::Text, color ? CreateColor(color) : defaultColor);
- qtHexEdit->setPalette(palette);
- }
- auto pHexEdit::setLength(unsigned length) -> void {
- _setState();
- }
- auto pHexEdit::setRows(unsigned rows) -> void {
- _setState();
- }
- auto pHexEdit::update() -> void {
- if(!state().onRead) {
- qtHexEdit->setPlainText("");
- return;
- }
- unsigned cursorPosition = qtHexEdit->textCursor().position();
- string output;
- unsigned address = state().address;
- for(unsigned row = 0; row < state().rows; row++) {
- output.append(hex(address, 8L));
- output.append(" ");
- string hexdata;
- string ansidata = " ";
- for(unsigned column = 0; column < state().columns; column++) {
- if(address < state().length) {
- uint8_t data = self().doRead(address++);
- hexdata.append(hex(data, 2L));
- hexdata.append(" ");
- ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.');
- } else {
- hexdata.append(" ");
- ansidata.append(" ");
- }
- }
- output.append(hexdata);
- output.append(ansidata);
- if(address >= state().length) break;
- if(row != state().rows - 1) output.append("\n");
- }
- qtHexEdit->setPlainText(QString::fromUtf8(output));
- QTextCursor cursor = qtHexEdit->textCursor();
- cursor.setPosition(cursorPosition);
- qtHexEdit->setTextCursor(cursor);
- }
- auto pHexEdit::_keyPressEvent(QKeyEvent* event) -> void {
- if(!state().onRead) return;
- //allow Ctrl+C (copy)
- if(event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier) {
- qtHexEdit->keyPressEventAcknowledge(event);
- return;
- }
- //disallow other text operations (cut, paste, etc)
- if(event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) return;
- QTextCursor cursor = qtHexEdit->textCursor();
- signed lineWidth = 10 + (state().columns * 3) + 1 + state().columns + 1;
- signed cursorY = cursor.position() / lineWidth;
- signed cursorX = cursor.position() % lineWidth;
- unsigned nibble = 0;
- switch(event->key()) {
- default: return;
- case Qt::Key_Left:
- if(cursorX > 0) {
- cursor.setPosition(cursor.position() - 1);
- qtHexEdit->setTextCursor(cursor);
- }
- return;
- case Qt::Key_Right:
- if(cursorX < lineWidth - 1) {
- cursor.setPosition(cursor.position() + 1);
- qtHexEdit->setTextCursor(cursor);
- }
- return;
- case Qt::Key_Home:
- cursor.setPosition(cursorY * lineWidth + 10);
- qtHexEdit->setTextCursor(cursor);
- return;
- case Qt::Key_End:
- cursor.setPosition(cursorY * lineWidth + 57);
- qtHexEdit->setTextCursor(cursor);
- return;
- case Qt::Key_Up:
- if(cursorY > 0) {
- cursor.setPosition(cursor.position() - lineWidth);
- qtHexEdit->setTextCursor(cursor);
- } else {
- _scrollTo(qtScrollBar->sliderPosition() - 1);
- }
- return;
- case Qt::Key_Down:
- if(cursorY >= _rows() - 1) {
- //cannot scroll down further
- } else if(cursorY < state().rows - 1) {
- cursor.setPosition(cursor.position() + lineWidth);
- qtHexEdit->setTextCursor(cursor);
- } else {
- _scrollTo(qtScrollBar->sliderPosition() + 1);
- }
- return;
- case Qt::Key_PageUp:
- _scrollTo(qtScrollBar->sliderPosition() - state().rows);
- return;
- case Qt::Key_PageDown:
- _scrollTo(qtScrollBar->sliderPosition() + state().rows);
- return;
- case Qt::Key_0: nibble = 0; break;
- case Qt::Key_1: nibble = 1; break;
- case Qt::Key_2: nibble = 2; break;
- case Qt::Key_3: nibble = 3; break;
- case Qt::Key_4: nibble = 4; break;
- case Qt::Key_5: nibble = 5; break;
- case Qt::Key_6: nibble = 6; break;
- case Qt::Key_7: nibble = 7; break;
- case Qt::Key_8: nibble = 8; break;
- case Qt::Key_9: nibble = 9; break;
- case Qt::Key_A: nibble = 10; break;
- case Qt::Key_B: nibble = 11; break;
- case Qt::Key_C: nibble = 12; break;
- case Qt::Key_D: nibble = 13; break;
- case Qt::Key_E: nibble = 14; break;
- case Qt::Key_F: nibble = 15; break;
- }
- if(cursorX >= 10) {
- //not on an offset
- cursorX -= 10;
- if((cursorX % 3) != 2) {
- //not on a space
- bool cursorNibble = (cursorX % 3) == 1; //0 = high, 1 = low
- cursorX /= 3;
- if(cursorX < state().columns) {
- //not in ANSI region
- unsigned address = state().address + (cursorY * state().columns + cursorX);
- if(address >= state().length) return; //do not edit past end of file
- uint8_t data = self().doRead(address);
- //write modified value
- if(cursorNibble == 1) {
- data = (data & 0xf0) | (nibble << 0);
- } else {
- data = (data & 0x0f) | (nibble << 4);
- }
- self().doWrite(address, data);
- //auto-advance cursor to next nibble/byte
- unsigned step = 1;
- if(cursorNibble && cursorX != state().columns - 1) step = 2;
- cursor.setPosition(cursor.position() + step);
- qtHexEdit->setTextCursor(cursor);
- //refresh output to reflect modified data
- update();
- }
- }
- }
- }
- //number of actual rows
- auto pHexEdit::_rows() -> signed {
- return (max(1u, state().length) + state().columns - 1) / state().columns;
- }
- //number of scrollable row positions
- auto pHexEdit::_rowsScrollable() -> signed {
- return max(0u, _rows() - state().rows);
- }
- auto pHexEdit::_scrollTo(signed position) -> void {
- if(position > _rowsScrollable()) position = _rowsScrollable();
- if(position < 0) position = 0;
- qtScrollBar->setSliderPosition(position);
- }
- auto pHexEdit::_setState() -> void {
- auto lock = acquire();
- //add one if last row is not equal to column length (eg only part of the row is present)
- bool indivisible = state().columns == 0 || (state().length % state().columns) != 0;
- qtScrollBar->setRange(0, state().length / state().columns + indivisible - state().rows);
- qtScrollBar->setSliderPosition(state().address / state().columns);
- qtScrollBar->setPageStep(state().rows);
- update();
- }
- auto QtHexEdit::keyPressEvent(QKeyEvent* event) -> void {
- p._keyPressEvent(event);
- }
- auto QtHexEdit::keyPressEventAcknowledge(QKeyEvent* event) -> void {
- QTextEdit::keyPressEvent(event);
- }
- auto QtHexEdit::wheelEvent(QWheelEvent* event) -> void {
- if(event->orientation() == Qt::Vertical) {
- signed offset = event->delta() < 0 ? +1 : -1;
- p._scrollTo(p.qtScrollBar->sliderPosition() + offset);
- event->accept();
- }
- }
- auto QtHexEditScrollBar::event(QEvent* event) -> bool {
- if(event->type() == QEvent::Wheel) {
- auto wheelEvent = (QWheelEvent*)event;
- if(wheelEvent->orientation() == Qt::Vertical) {
- signed offset = wheelEvent->delta() < 0 ? +1 : -1;
- p._scrollTo(sliderPosition() + offset);
- return true;
- }
- }
- return QScrollBar::event(event);
- }
- auto QtHexEditScrollBar::onScroll() -> void {
- if(p.locked()) return;
- unsigned address = sliderPosition();
- p.state().address = address * p.state().columns;
- p.update();
- }
- }
- #endif
|