From 508ea9e634a6d8bdd80a2f9daa203d401d1b1950 Mon Sep 17 00:00:00 2001 From: Sightem Date: Tue, 7 Oct 2025 21:40:28 -0700 Subject: [PATCH] Improve highlighting in hex editor widget --- gui/qt/debugger.cpp | 3 ++ gui/qt/debugger/hexwidget.cpp | 73 +++++++++++++++++++++++++++++++---- gui/qt/debugger/hexwidget.h | 6 ++- gui/qt/memorywidget.cpp | 1 + 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/gui/qt/debugger.cpp b/gui/qt/debugger.cpp index af212c4e..946a54da 100644 --- a/gui/qt/debugger.cpp +++ b/gui/qt/debugger.cpp @@ -2023,6 +2023,7 @@ HexWidget *MainWindow::gotoMemAddrNoRaise(uint32_t address) { const int offset = static_cast(address - edit->getBase()); if (offset < edit->getSize()) { edit->setOffset(offset); + edit->setHighlight(static_cast(address)); memWidget = edit; didGoto = true; break; @@ -2037,6 +2038,8 @@ HexWidget *MainWindow::gotoMemAddrNoRaise(uint32_t address) { } if (memWidget != Q_NULLPTR && !didGoto) { memGoto(memWidget, address); + } else if (memWidget != Q_NULLPTR) { + memWidget->setHighlight(static_cast(address)); } return memWidget; } diff --git a/gui/qt/debugger/hexwidget.cpp b/gui/qt/debugger/hexwidget.cpp index f1107dff..457dc36a 100644 --- a/gui/qt/debugger/hexwidget.cpp +++ b/gui/qt/debugger/hexwidget.cpp @@ -131,6 +131,19 @@ void HexWidget::setOffset(int offset) { } void HexWidget::setCursorOffset(int offset, bool selection) { + setCursorOffset(offset, selection, true); +} + +void HexWidget::setHighlight(const int address) { + const int normalized = address < 0 ? -1 : address; + if (m_highlightedAddr == normalized) { + return; + } + m_highlightedAddr = normalized; + viewport()->update(); +} + +void HexWidget::setCursorOffset(int offset, bool selection, bool clearHighlight) { if (offset > m_size * 2) { offset = m_size * 2; } @@ -141,6 +154,10 @@ void HexWidget::setCursorOffset(int offset, bool selection) { resetSelection(); } + if (clearHighlight) { + m_highlightedAddr = -1; + } + m_cursorOffset = offset; adjust(); showCursor(); @@ -254,18 +271,19 @@ void HexWidget::setSelection(int addr) { addr = 0; } - if (m_selectStart == -1) { - m_selectStart = addr; - m_selectEnd = addr; - m_selectLen = 0; + if (m_selectAnchor == -1) { + m_selectAnchor = addr; } - if (addr > m_selectStart) { + + if (addr >= m_selectAnchor) { + m_selectStart = m_selectAnchor; m_selectEnd = addr; - m_selectLen = addr - m_selectStart + 1; } else { m_selectStart = addr; - m_selectLen = m_selectEnd - addr + 1; + m_selectEnd = m_selectAnchor; } + + m_selectLen = (m_selectStart == -1 || m_selectEnd == -1) ? 0 : (m_selectEnd - m_selectStart + 1); } void HexWidget::undo() { @@ -310,12 +328,27 @@ void HexWidget::paintEvent(QPaintEvent *event) { const QColor &cSelected = pal.color(QPalette::Highlight); const QColor cModified = QColor(Qt::blue).lighter(160); const QColor cBoth = QColor(Qt::green).lighter(160); + const bool darkMode = isRunningInDarkMode(); + const QColor boxBorder = darkMode ? QColor(0xdb, 0xdb, 0xdb) : QColor(0x66, 0x66, 0x66); + QColor boxFill = darkMode ? QColor(0x55, 0x55, 0x55) : QColor(0xd0, 0xd0, 0xd0); + boxFill.setAlpha(140); const int xOffset = horizontalScrollBar()->value(); const int xAddr = m_addrLoc - xOffset; painter.setRenderHint(QPainter::Antialiasing); painter.fillRect(region, cBg); + const auto drawHighlightBox = [&](const QRect &rect) { + if (!rect.isValid() || rect.isNull()) { + return; + } + painter.save(); + painter.setPen(QPen(boxBorder, 1)); + painter.setBrush(boxFill); + painter.drawRoundedRect(rect.adjusted(0, 0, -1, -1), 2, 2); + painter.restore(); + }; + painter.setPen(Qt::gray); painter.drawLine(m_dataLine - xOffset, region.top(), m_dataLine - xOffset, height()); if (m_asciiArea) { @@ -338,6 +371,22 @@ void HexWidget::paintEvent(QPaintEvent *event) { uint8_t flags = debug.addr[addr + m_base]; bool selected = addr >= m_selectStart && addr <= m_selectEnd; bool modified = !m_modified.isEmpty() && m_modified[addr]; + const bool highlighted = m_highlightedAddr >= 0 && (m_base + addr) == m_highlightedAddr; + const int xDataStart = xData; + const int xAsciiStart = xAscii; + QRect dataHighlightRect; + QRect asciiHighlightRect; + + if (highlighted) { + if (!col) { + dataHighlightRect.setRect(xDataStart, y - m_charHeight + m_margin, 2 * m_charWidth + 3, m_charHeight); + } else { + dataHighlightRect.setRect(xDataStart - m_charWidth, y - m_charHeight + m_margin, 3 * m_charWidth + 3, m_charHeight); + } + if (m_asciiArea) { + asciiHighlightRect.setRect(xAsciiStart, y - m_charHeight + m_margin, m_charWidth + 1, m_charHeight); + } + } QFont font = painter.font(); const QFont fontorig = painter.font(); @@ -367,6 +416,10 @@ void HexWidget::paintEvent(QPaintEvent *event) { painter.fillRect(r, modified ? selected ? cBoth : cModified : cSelected); } + if (highlighted) { + drawHighlightBox(dataHighlightRect); + } + QString hex = int2hex(data, 2); if ((flags & DBG_MASK_READ) && (flags & DBG_MASK_WRITE)) { painter.setPen(Qt::darkGreen); @@ -391,6 +444,9 @@ void HexWidget::paintEvent(QPaintEvent *event) { r.setRect(xAscii, y - m_charHeight + m_margin, m_charWidth, m_charHeight); painter.fillRect(r, modified ? selected ? cBoth : cModified : cSelected); } + if (highlighted) { + drawHighlightBox(asciiHighlightRect); + } painter.drawText(xAscii, y, QChar(ch)); xAscii += m_charWidth; } @@ -421,6 +477,9 @@ void HexWidget::mousePressEvent(QMouseEvent *event) { int addr = getPosition(event->pos()); if (addr >= 0) { setCursorOffset(addr, true); + m_selectAnchor = addr / 2; + m_selectStart = m_selectEnd = -1; + m_selectLen = 0; } } diff --git a/gui/qt/debugger/hexwidget.h b/gui/qt/debugger/hexwidget.h index 86690655..bf79a4a5 100644 --- a/gui/qt/debugger/hexwidget.h +++ b/gui/qt/debugger/hexwidget.h @@ -17,6 +17,7 @@ class HexWidget : public QAbstractScrollArea { void setBytesPerLine(int bytes) { m_bytesPerLine = bytes; adjust(); } void setAsciiArea(bool area) { m_asciiArea = area; adjust(); } void setCursorOffset(int address, bool selection = true); + void setHighlight(int address); void setScrollable(bool state) { m_scrollable = state; adjust(); } void setFont(const QFont &font) { QAbstractScrollArea::setFont(font); adjust(); } void setOffset(int addr); @@ -52,11 +53,12 @@ private slots: void scroll(int value); private: + void setCursorOffset(int offset, bool selection, bool clearHighlight); void redo(); void undo(); void showCursor(); void setSelection(int addr); - void resetSelection() { m_selectStart = m_selectEnd = -1; } + void resetSelection() { m_selectStart = m_selectEnd = -1; m_selectLen = 0; m_selectAnchor = -1; } bool isSelected() const { return m_selectStart != -1; } void setSelected(char n) { overwrite(m_selectStart * 2, QByteArray(m_selectLen, n)); } void overwrite(int pos, char c); @@ -98,11 +100,13 @@ private slots: int m_selectStart; int m_selectEnd; int m_selectLen; + int m_selectAnchor = -1; bool m_scrollable = false; // fetch bytes from memory on scroll bool m_asciiArea = true; // show character representations bool m_scrolled = false; // scrolled while focused bool m_asciiEdit = false; // editing from the ascii side + int m_highlightedAddr = -1; // Address to highlight with a box QStack m_stack; }; diff --git a/gui/qt/memorywidget.cpp b/gui/qt/memorywidget.cpp index 0e56c9be..f0d8ea4d 100644 --- a/gui/qt/memorywidget.cpp +++ b/gui/qt/memorywidget.cpp @@ -208,6 +208,7 @@ void MainWindow::memGoto(HexWidget *edit, uint32_t address) { edit->setBase(static_cast(address)); edit->setOffset(0); memUpdateEdit(edit, true); + edit->setHighlight(static_cast(address)); } void MainWindow::memGotoEdit(HexWidget *edit) {