1
0
Fork 0

Minor usability improvements for hex_viewer

This commit is contained in:
Duncan Ogilvie 2025-06-15 15:00:58 +02:00
parent 0d2259a311
commit 5a7cbc4a7b
6 changed files with 61 additions and 17 deletions

View File

@ -10,6 +10,18 @@ DataTable::DataTable(QWidget *parent)
mTypes.emplace_back(name, std::move(fn)); mTypes.emplace_back(name, std::move(fn));
}; };
type("Address", [this](duint start, duint end) {
auto size = end - start + 1;
if(size > 1)
{
return QString("0x%1 - 0x%2 (0x%3 bytes)").arg(ToHexString(start)).arg(ToHexString(end)).arg(ToHexString(size));
}
else
{
return "0x" + ToHexString(start);
}
});
type("Binary (u8)", [this](duint start, duint end) { type("Binary (u8)", [this](duint start, duint end) {
uint8_t data = 0; uint8_t data = 0;
read(&data, start, sizeof(data)); read(&data, start, sizeof(data));

View File

@ -166,7 +166,7 @@ void MainWindow::setupNavigation()
{ {
case Navigation::Dump: case Navigation::Dump:
qDebug() << "Dump at: " << address; qDebug() << "Dump at: " << address;
mHexDump->printDumpAt(address); gotoHexDump(address, 1);
break; break;
default: default:
qDebug() << "Unknown window: " << window; qDebug() << "Unknown window: " << window;
@ -211,6 +211,7 @@ void MainWindow::setupWidgets()
{ {
mDataTable->selectionChanged(mHexDump->getSelectionStart(), mHexDump->getSelectionEnd()); mDataTable->selectionChanged(mHexDump->getSelectionStart(), mHexDump->getSelectionEnd());
}); });
connect(mStructWidget, &StructWidget::selectionUpdated, this, &MainWindow::gotoHexDump);
auto hl = new QHBoxLayout(); auto hl = new QHBoxLayout();
//hl->addSpacing() //hl->addSpacing()
@ -232,13 +233,13 @@ void MainWindow::setupWidgets()
auto codeSplitter = new QSplitter(Qt::Vertical, this); auto codeSplitter = new QSplitter(Qt::Vertical, this);
codeSplitter->addWidget(codeWidget); codeSplitter->addWidget(codeWidget);
codeSplitter->addWidget(mLogBrowser); codeSplitter->addWidget(mStructWidget);
codeSplitter->setStretchFactor(0, 80); codeSplitter->setStretchFactor(0, 80);
codeSplitter->setStretchFactor(0, 20); codeSplitter->setStretchFactor(0, 20);
mStructTabs = new QTabWidget(this); mStructTabs = new QTabWidget(this);
mStructTabs->addTab(mDataTable, "Data"); mStructTabs->addTab(mDataTable, "Inspector");
mStructTabs->addTab(mStructWidget, "Struct"); mStructTabs->addTab(mLogBrowser, "Console");
auto hexSplitter = new QSplitter(Qt::Vertical, this); auto hexSplitter = new QSplitter(Qt::Vertical, this);
hexSplitter->addWidget(mHexDump); hexSplitter->addWidget(mHexDump);
@ -312,6 +313,27 @@ void MainWindow::evalError(const EvalError & error)
} }
} }
void MainWindow::gotoHexDump(duint address, duint size)
{
duint viewStart = mHexDump->getTableOffset() * mHexDump->getBytePerRowCount();
duint viewSize = mHexDump->getViewableRowsCount() * mHexDump->getBytePerRowCount();
duint viewEnd = viewStart + viewSize;
duint alignedAddress = address - address % 16;
// Make sure the address is in view
if(address < viewStart || address >= viewEnd)
{
mHexDump->printDumpAt(alignedAddress, false, false, true);
}
// Go to the aligned address and then set the selection
mHexDump->printDumpAt(alignedAddress, true, false, false);
mHexDump->setSingleSelection(address);
if(size > 1)
{
mHexDump->expandSelectionUpTo(address + size - 1);
}
mHexDump->updateViewport();
}
void MainWindow::onLogAnchorClicked(const QUrl & url) void MainWindow::onLogAnchorClicked(const QUrl & url)
{ {
if(url.scheme() == "navigate") if(url.scheme() == "navigate")
@ -382,10 +404,7 @@ void MainWindow::onButtonRunPressed()
mCodeEditor->setErrorLine(-1); mCodeEditor->setErrorLine(-1);
auto status = PatternRun(&args); auto status = PatternRun(&args);
emit Bridge::getBridge()->typeUpdateWidget(); emit Bridge::getBridge()->typeUpdateWidget();
if(status == PatternSuccess) mStructTabs->setCurrentIndex(1);
{
mStructTabs->setCurrentIndex(1);
}
} }

View File

@ -30,6 +30,7 @@ public:
private slots: private slots:
void onButtonRunPressed(); void onButtonRunPressed();
void onLogAnchorClicked(const QUrl & url); void onLogAnchorClicked(const QUrl & url);
void gotoHexDump(duint address, duint size);
void on_action_Load_file_triggered(); void on_action_Load_file_triggered();

View File

@ -6,7 +6,8 @@ MiniHexDump::MiniHexDump(Navigation* navigation, Architecture* architecture, QWi
: HexDump(architecture, parent) : HexDump(architecture, parent)
, mNavigation(navigation) , mNavigation(navigation)
{ {
mUnderliningEnabled = false; mPointerUnderliningEnabled = false;
mSelectionUnderliningEnabled = true;
hexAsciiSlot(); hexAsciiSlot();
setupMenu(); setupMenu();
} }

View File

@ -10,6 +10,10 @@
#include "MiscUtil.h" #include "MiscUtil.h"
#include "RichTextItemDelegate.h" #include "RichTextItemDelegate.h"
#define hasSelection !!ui->treeWidget->selectedItems().count()
#define selectedItem ui->treeWidget->selectedItems()[0]
#define selectedType selectedItem->data(0, Qt::UserRole).value<TypeDescriptor>().type
struct TypeDescriptor struct TypeDescriptor
{ {
TYPEDESCRIPTOR type = {}; TYPEDESCRIPTOR type = {};
@ -34,6 +38,14 @@ StructWidget::StructWidget(QWidget* parent) :
fontsUpdatedSlot(); fontsUpdatedSlot();
setupColumns(); setupColumns();
setupContextMenu(); setupContextMenu();
connect(ui->treeWidget, &QTreeWidget::itemSelectionChanged, [this]()
{
if(hasSelection)
{
emit selectionUpdated(selectedType.addr + selectedType.offset, selectedType.sizeBits / 8);
}
});
} }
StructWidget::~StructWidget() StructWidget::~StructWidget()
@ -113,9 +125,9 @@ void StructWidget::typeAddNode(void* parent, const TYPEDESCRIPTOR* type, void**
text[ColOffset] = "+0x" + ToHexString(dtype.type.offset); text[ColOffset] = "+0x" + ToHexString(dtype.type.offset);
text[ColField] = dtype.name; text[ColField] = dtype.name;
if(dtype.type.offset == 0 && true) if(dtype.type.offset == 0 && true)
text[ColAddress] = QString("<u>%1</u>").arg(ToPtrString(dtype.type.addr + dtype.type.offset)); text[ColAddress] = QString("<u>%1</u>").arg(ToHexString(dtype.type.addr + dtype.type.offset));
else else
text[ColAddress] = ToPtrString(dtype.type.addr + dtype.type.offset); text[ColAddress] = ToHexString(dtype.type.addr + dtype.type.offset);
text[ColSize] = "0x" + ToHexString(dtype.type.sizeBits / 8); text[ColSize] = "0x" + ToHexString(dtype.type.sizeBits / 8);
text[ColValue] = ""; // NOTE: filled in later text[ColValue] = ""; // NOTE: filled in later
QTreeWidgetItem* item = parent ? new QTreeWidgetItem((QTreeWidgetItem*)parent, text) : new QTreeWidgetItem(ui->treeWidget, text); QTreeWidgetItem* item = parent ? new QTreeWidgetItem((QTreeWidgetItem*)parent, text) : new QTreeWidgetItem(ui->treeWidget, text);
@ -142,7 +154,7 @@ void StructWidget::typeUpdateWidget()
type.type.name = name.constData(); type.type.name = name.constData();
auto addr = type.type.addr + type.type.offset; auto addr = type.type.addr + type.type.offset;
item->setText(ColAddress, ToPtrString(addr)); item->setText(ColAddress, ToHexString(addr));
QString valueStr; QString valueStr;
if(type.type.callback) //use the provided callback if(type.type.callback) //use the provided callback
@ -191,7 +203,7 @@ void StructWidget::setupColumns()
auto charWidth = ui->treeWidget->fontMetrics().horizontalAdvance(' '); auto charWidth = ui->treeWidget->fontMetrics().horizontalAdvance(' ');
ui->treeWidget->setColumnWidth(ColField, 4 + charWidth * 35); ui->treeWidget->setColumnWidth(ColField, 4 + charWidth * 35);
ui->treeWidget->setColumnWidth(ColOffset, 6 + charWidth * 7); ui->treeWidget->setColumnWidth(ColOffset, 6 + charWidth * 7);
ui->treeWidget->setColumnWidth(ColAddress, 6 + charWidth * 16); ui->treeWidget->setColumnWidth(ColAddress, 6 + charWidth * 8);
ui->treeWidget->setColumnWidth(ColSize, 4 + charWidth * 6); ui->treeWidget->setColumnWidth(ColSize, 4 + charWidth * 6);
// NOTE: Trick to display the expander icons in the second column // NOTE: Trick to display the expander icons in the second column
@ -199,10 +211,6 @@ void StructWidget::setupColumns()
// ui->treeWidget->header()->moveSection(ColField, ColOffset); // ui->treeWidget->header()->moveSection(ColField, ColOffset);
} }
#define hasSelection !!ui->treeWidget->selectedItems().count()
#define selectedItem ui->treeWidget->selectedItems()[0]
#define selectedType selectedItem->data(0, Qt::UserRole).value<TypeDescriptor>().type
void StructWidget::setupContextMenu() void StructWidget::setupContextMenu()
{ {
auto makeAction = [this](const QIcon & icon, const QString & text, const char* slot) auto makeAction = [this](const QIcon & icon, const QString & text, const char* slot)

View File

@ -31,6 +31,9 @@ public slots:
void typeUpdateWidget(); void typeUpdateWidget();
void dbgStateChangedSlot(DBGSTATE state); void dbgStateChangedSlot(DBGSTATE state);
signals:
void selectionUpdated(duint address, duint size);
private: private:
Ui::StructWidget* ui; Ui::StructWidget* ui;
MenuBuilder* mMenuBuilder; MenuBuilder* mMenuBuilder;