Skip to content

Commit 436176e

Browse files
committed
Hex viewer: dynamic layout to fill the available width
1 parent 7cba9b4 commit 436176e

File tree

2 files changed

+50
-16
lines changed

2 files changed

+50
-16
lines changed

plugins/viewer/textviewer/src/clightningfastviewer.cpp

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace Layout {
2222
static constexpr int MIN_OFFSET_DIGITS = 4;
2323
static constexpr int OFFSET_SUFFIX_CHARS = 2; // ": "
2424
static constexpr int HEX_CHARS_PER_BYTE = 3; // "XX "
25-
static constexpr int HEX_MIDDLE_EXTRA_SPACE = 1; // Extra space after byte 7
25+
static constexpr int HEX_MIDDLE_EXTRA_SPACE = 1; // Extra space after each 8 bytes
2626
static constexpr int HEX_ASCII_SEPARATOR_CHARS = 2; // The separator is technically " | ",
2727
// but we get the space on the left by default due to it being included with every byte via HEX_CHARS_PER_BYTE
2828
static constexpr int LEFT_MARGIN_PIXELS = 2;
@@ -380,14 +380,38 @@ void CLightningFastViewerWidget::calculateHexLayout()
380380
// Calculate nDigits once and cache it
381381
_nDigits = static_cast<int>(qCeil(::log10(static_cast<double>(_data.size() + 1))));
382382
_nDigits = qMax(Layout::MIN_OFFSET_DIGITS, _nDigits);
383-
const int offsetWidth = _charWidth * (_nDigits + Layout::OFFSET_SUFFIX_CHARS) + Layout::LEFT_MARGIN_PIXELS;
384383

385-
// Hex area starts after offset
386-
_hexStart = offsetWidth;
384+
// Calculate optimal bytesPerLine that fits viewport width (must be multiple of 4)
385+
const int viewportWidth = viewport()->width();
386+
int optimalBytesPerLine = 4; // Minimum
387+
LineLayout optimalLayout;
387388

388-
// ASCII area starts after hex (16 bytes * 3 chars + extra space at middle)
389-
const int hexWidth = _charWidth * (_bytesPerLine * Layout::HEX_CHARS_PER_BYTE + Layout::HEX_MIDDLE_EXTRA_SPACE);
390-
_asciiStart = _hexStart + hexWidth + _charWidth * Layout::HEX_ASCII_SEPARATOR_CHARS;
389+
// Try increasingly larger values (multiples of 4) until we exceed viewport width
390+
for (int candidate = 4; candidate <= 64; candidate += 4)
391+
{
392+
optimalLayout = calculateHexLineLayout(candidate, _nDigits);
393+
const int lineWidth = optimalLayout.asciiStart + optimalLayout.asciiWidth;
394+
if (lineWidth <= viewportWidth)
395+
optimalBytesPerLine = candidate;
396+
else
397+
break;
398+
}
399+
400+
_bytesPerLine = optimalBytesPerLine;
401+
_hexStart = optimalLayout.hexStart;
402+
_asciiStart = optimalLayout.asciiStart;
403+
}
404+
405+
CLightningFastViewerWidget::LineLayout CLightningFastViewerWidget::calculateHexLineLayout(int bytesPerLine, int nDigits) const
406+
{
407+
LineLayout layout;
408+
409+
layout.hexStart = _charWidth * (nDigits + Layout::OFFSET_SUFFIX_CHARS) + Layout::LEFT_MARGIN_PIXELS;
410+
layout.hexWidth = _charWidth * (bytesPerLine * Layout::HEX_CHARS_PER_BYTE + Layout::HEX_MIDDLE_EXTRA_SPACE * ((bytesPerLine - 1) / 8));
411+
layout.asciiStart = layout.hexStart + layout.hexWidth + _charWidth * Layout::HEX_ASCII_SEPARATOR_CHARS;
412+
layout.asciiWidth = _charWidth * (bytesPerLine + Layout::HEX_ASCII_SEPARATOR_CHARS);
413+
414+
return layout;
391415
}
392416

393417
void CLightningFastViewerWidget::calculateTextLayout()
@@ -440,7 +464,7 @@ void CLightningFastViewerWidget::drawHexLine(QPainter& painter, qsizetype offset
440464
painter.drawText(x - hScroll, y + fm.ascent(), hexByte);
441465
x += _charWidth * Layout::HEX_CHARS_PER_BYTE;
442466

443-
if (i == 7)
467+
if ((i % 8) == 7)
444468
{
445469
x += _charWidth * Layout::HEX_MIDDLE_EXTRA_SPACE;
446470
}
@@ -567,12 +591,14 @@ CLightningFastViewerWidget::Region CLightningFastViewerWidget::regionAtPos(const
567591

568592
qsizetype CLightningFastViewerWidget::hexPosToOffset(const QPoint& pos) const
569593
{
570-
if (_data.isEmpty()) return -1;
594+
if (_data.isEmpty())
595+
return -1;
571596

572-
int line = (pos.y() / _lineHeight) + verticalScrollBar()->value();
573-
if (line < 0 || line >= totalLines()) return -1;
597+
const int line = (pos.y() / _lineHeight) + verticalScrollBar()->value();
598+
if (line < 0 || line >= totalLines())
599+
return -1;
574600

575-
int x = pos.x() + horizontalScrollBar()->value();
601+
const int x = pos.x() + horizontalScrollBar()->value();
576602
Region region = regionAtPos(pos);
577603

578604
qsizetype lineOffset = line * _bytesPerLine;
@@ -583,10 +609,10 @@ qsizetype CLightningFastViewerWidget::hexPosToOffset(const QPoint& pos) const
583609
int relX = x - _hexStart;
584610
byteInLine = relX / (_charWidth * Layout::HEX_CHARS_PER_BYTE);
585611

586-
// Account for extra space at position 8
587-
if (byteInLine >= 8)
612+
// Account for extra space every 8 bytes
613+
if (byteInLine > 8)
588614
{
589-
relX -= _charWidth * Layout::HEX_MIDDLE_EXTRA_SPACE;
615+
relX -= _charWidth * Layout::HEX_MIDDLE_EXTRA_SPACE * ((byteInLine - 1) / 8);
590616
byteInLine = relX / (_charWidth * Layout::HEX_CHARS_PER_BYTE);
591617
}
592618

@@ -920,4 +946,4 @@ void CLightningFastViewerWidget::updateCursorShape(const QPoint& pos)
920946
}
921947

922948
viewport()->setCursor(overText ? Qt::IBeamCursor : Qt::ArrowCursor);
923-
}
949+
}

plugins/viewer/textviewer/src/clightningfastviewer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ class CLightningFastViewerWidget final : public QAbstractScrollArea
5252

5353
// Hex mode methods
5454
void calculateHexLayout();
55+
56+
struct LineLayout {
57+
int hexStart = 0;
58+
int hexWidth = 0;
59+
int asciiStart = 0;
60+
int asciiWidth = 0;
61+
};
62+
[[nodiscard]] LineLayout calculateHexLineLayout(int bytesPerLine, int nDigits) const;
5563
void drawHexLine(QPainter& painter, qsizetype offset, int y, const QFontMetrics& fm);
5664
[[nodiscard]] Region regionAtPos(const QPoint& pos) const;
5765
[[nodiscard]] qsizetype hexPosToOffset(const QPoint& pos) const;

0 commit comments

Comments
 (0)