2026-01-08 00:35:47 -05:00
|
|
|
#ifndef HEXVIEWERWIDGET_H
|
|
|
|
|
#define HEXVIEWERWIDGET_H
|
|
|
|
|
|
|
|
|
|
#include <QWidget>
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
|
#include <QTreeWidget>
|
|
|
|
|
#include <QSplitter>
|
|
|
|
|
#include <QAbstractScrollArea>
|
|
|
|
|
#include <QFont>
|
|
|
|
|
#include <QScrollBar>
|
|
|
|
|
|
|
|
|
|
#include "settings.h"
|
|
|
|
|
|
2026-01-11 12:08:59 -05:00
|
|
|
// Custom hex view widget with virtualized rendering and selection
|
2026-01-08 00:35:47 -05:00
|
|
|
class HexView : public QAbstractScrollArea
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
2026-01-11 12:08:59 -05:00
|
|
|
enum class SelectionSource { None, Hex, Decoded };
|
|
|
|
|
|
2026-01-08 00:35:47 -05:00
|
|
|
explicit HexView(QWidget *parent = nullptr);
|
|
|
|
|
|
|
|
|
|
void setData(const QByteArray &data);
|
|
|
|
|
void setTheme(const Theme &theme);
|
|
|
|
|
void setBytesPerLine(int bytes);
|
|
|
|
|
int bytesPerLine() const { return mBytesPerLine; }
|
|
|
|
|
|
2026-01-11 12:08:59 -05:00
|
|
|
// Selection
|
|
|
|
|
void clearSelection();
|
|
|
|
|
bool hasSelection() const;
|
|
|
|
|
QString getSelectedHex() const; // Returns hex without spaces
|
|
|
|
|
QString getSelectedDecoded() const; // Returns decoded ASCII/Latin-1
|
|
|
|
|
void copyToClipboard();
|
|
|
|
|
|
2026-01-08 00:35:47 -05:00
|
|
|
protected:
|
|
|
|
|
void paintEvent(QPaintEvent *event) override;
|
|
|
|
|
void resizeEvent(QResizeEvent *event) override;
|
|
|
|
|
void scrollContentsBy(int dx, int dy) override;
|
2026-01-11 12:08:59 -05:00
|
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
|
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
|
|
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
|
|
|
void keyPressEvent(QKeyEvent *event) override;
|
2026-01-08 00:35:47 -05:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void updateScrollBars();
|
|
|
|
|
void recalculateBytesPerLine();
|
|
|
|
|
QColor getByteColor(quint8 byte) const;
|
|
|
|
|
QColor getAsciiColor(quint8 byte) const;
|
2026-01-11 12:08:59 -05:00
|
|
|
int byteIndexAtPos(const QPoint &pos, SelectionSource *source = nullptr) const;
|
|
|
|
|
void updateColumnPositions();
|
2026-01-08 00:35:47 -05:00
|
|
|
|
|
|
|
|
QByteArray mData;
|
|
|
|
|
QFont mMonoFont;
|
|
|
|
|
int mBytesPerLine = 16;
|
|
|
|
|
int mCharWidth = 0;
|
|
|
|
|
int mLineHeight = 0;
|
|
|
|
|
|
2026-01-11 12:08:59 -05:00
|
|
|
// Column positions (calculated once, updated on resize)
|
|
|
|
|
int mOffsetX = 0;
|
|
|
|
|
int mHexX = 0;
|
|
|
|
|
int mAsciiX = 0;
|
|
|
|
|
int mHeaderHeight = 0;
|
|
|
|
|
|
|
|
|
|
// Selection state
|
|
|
|
|
int mSelectionStart = -1;
|
|
|
|
|
int mSelectionEnd = -1;
|
|
|
|
|
SelectionSource mSelectionSource = SelectionSource::None;
|
|
|
|
|
bool mSelecting = false;
|
|
|
|
|
|
2026-01-08 00:35:47 -05:00
|
|
|
// Theme colors
|
|
|
|
|
QColor mBgColor;
|
|
|
|
|
QColor mTextColor;
|
|
|
|
|
QColor mOffsetColor;
|
|
|
|
|
QColor mNullColor;
|
|
|
|
|
QColor mHighColor;
|
|
|
|
|
QColor mPrintableColor;
|
|
|
|
|
QColor mControlColor;
|
|
|
|
|
QColor mNonPrintableColor;
|
|
|
|
|
QColor mBorderColor;
|
2026-01-11 12:08:59 -05:00
|
|
|
QColor mSelectionColor;
|
2026-01-08 00:35:47 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class HexViewerWidget : public QWidget
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit HexViewerWidget(QWidget *parent = nullptr);
|
|
|
|
|
~HexViewerWidget() = default;
|
|
|
|
|
|
|
|
|
|
void setData(const QByteArray &data, const QString &filename);
|
|
|
|
|
void setMetadata(const QVariantMap &metadata);
|
|
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
|
void applyTheme(const Theme &theme);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QByteArray mData;
|
|
|
|
|
QString mFilename;
|
|
|
|
|
|
|
|
|
|
QSplitter *mSplitter;
|
|
|
|
|
QLabel *mInfoLabel;
|
|
|
|
|
HexView *mHexView;
|
|
|
|
|
QTreeWidget *mMetadataTree;
|
|
|
|
|
|
|
|
|
|
Theme mCurrentTheme;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif // HEXVIEWERWIDGET_H
|