From 32f10b2b5a6f3d0b7d0cebdaebb70c1e5c4c4ac5 Mon Sep 17 00:00:00 2001 From: Ernie Pasveer Date: Sun, 30 Oct 2022 13:16:36 -0500 Subject: [PATCH] Add new Image Visualizer. --- CHANGELOG.md | 2 + src/CMakeLists.txt | 2 + src/SeerGdbWidget.cpp | 29 ++ src/SeerGdbWidget.h | 2 + src/SeerImageVisualizerWidget.cpp | 379 +++++++++++++++++++++++++ src/SeerImageVisualizerWidget.h | 50 ++++ src/SeerImageVisualizerWidget.ui | 220 ++++++++++++++ src/SeerMainWindow.cpp | 7 + src/SeerMainWindow.h | 1 + src/SeerMainWindow.ui | 32 ++- src/SeerMemoryVisualizerWidget.cpp | 32 --- src/SeerMemoryVisualizerWidget.h | 1 - src/SeerMemoryVisualizerWidget.ui | 16 -- src/resource.qrc | 1 + src/resources/help/ImageVisualizer.md | 66 +++++ src/resources/help/MemoryVisualizer.md | 21 -- 16 files changed, 788 insertions(+), 73 deletions(-) create mode 100644 src/SeerImageVisualizerWidget.cpp create mode 100644 src/SeerImageVisualizerWidget.h create mode 100644 src/SeerImageVisualizerWidget.ui create mode 100644 src/resources/help/ImageVisualizer.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c192a3..a5fb230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ## [1.13beta] - 2022-MM-DD * Improve specifying an alternate directory if the source has moved. Fewer mouse clicks. +* Add new Image Visualizer. + - View RGB888 and RGBA8888 images. ## [1.12] - 2022-10-22 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 682ea4f..a31148b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,6 +56,7 @@ set(HEADER_FILES SeerMemoryVisualizerWidget.h SeerStructVisualizerWidget.h SeerVarVisualizerWidget.h + SeerImageVisualizerWidget.h SeerRegisterValuesBrowserWidget.h SeerRegisterEditValueDialog.h SeerRunStatusIndicator.h @@ -142,6 +143,7 @@ set(SOURCE_FILES SeerMemoryVisualizerWidget.cpp SeerStructVisualizerWidget.cpp SeerVarVisualizerWidget.cpp + SeerImageVisualizerWidget.cpp SeerRegisterValuesBrowserWidget.cpp SeerRegisterEditValueDialog.cpp SeerRunStatusIndicator.cpp diff --git a/src/SeerGdbWidget.cpp b/src/SeerGdbWidget.cpp index 3fc848b..167ec88 100644 --- a/src/SeerGdbWidget.cpp +++ b/src/SeerGdbWidget.cpp @@ -4,6 +4,7 @@ #include "SeerArrayVisualizerWidget.h" #include "SeerStructVisualizerWidget.h" #include "SeerVarVisualizerWidget.h" +#include "SeerImageVisualizerWidget.h" #include "SeerHelpPageWidget.h" #include "SeerUtl.h" #include "QHContainerWidget.h" @@ -2059,6 +2060,25 @@ void SeerGdbWidget::handleGdbVarAddExpression (QString expression) { w->setVariableName(expression); } +void SeerGdbWidget::handleGdbImageAddExpression (QString expression) { + + if (executableLaunchMode() == "") { + return; + } + + SeerImageVisualizerWidget* w = new SeerImageVisualizerWidget(0); + w->show(); + + // Connect things. + QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerImageVisualizerWidget::handleText); + QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerImageVisualizerWidget::handleText); + QObject::connect(w, &SeerImageVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression); + QObject::connect(w, &SeerImageVisualizerWidget::evaluateMemoryExpression, this, &SeerGdbWidget::handleGdbMemoryEvaluateExpression); + + // Tell the visualizer what variable to use. + w->setVariableName(expression); +} + void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count) { if (executableLaunchMode() == "") { @@ -2100,21 +2120,30 @@ void SeerGdbWidget::handleGdbGetAssembly (QString address) { } void SeerGdbWidget::handleGdbMemoryVisualizer () { + handleGdbMemoryAddExpression(""); } void SeerGdbWidget::handleGdbArrayVisualizer () { + handleGdbArrayAddExpression(""); } void SeerGdbWidget::handleGdbStructVisualizer () { + handleGdbStructAddExpression(""); } void SeerGdbWidget::handleGdbVarVisualizer () { + handleGdbVarAddExpression(""); } +void SeerGdbWidget::handleGdbImageVisualizer () { + + handleGdbImageAddExpression(""); +} + void SeerGdbWidget::handleSplitterMoved (int pos, int index) { Q_UNUSED(pos); diff --git a/src/SeerGdbWidget.h b/src/SeerGdbWidget.h index 4bd5ccb..0fb4791 100644 --- a/src/SeerGdbWidget.h +++ b/src/SeerGdbWidget.h @@ -267,6 +267,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { void handleGdbArrayAddExpression (QString expression); void handleGdbStructAddExpression (QString expression); void handleGdbVarAddExpression (QString expression); + void handleGdbImageAddExpression (QString expression); void handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count); void handleGdbAsmEvaluateExpression (int expressionid, QString address, int count, int mode); void handleGdbArrayEvaluateExpression (int expressionid, QString address, int count); @@ -275,6 +276,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { void handleGdbArrayVisualizer (); void handleGdbStructVisualizer (); void handleGdbVarVisualizer (); + void handleGdbImageVisualizer (); void handleSplitterMoved (int pos, int index); void handleManualCommandChanged (); void handleLogOuputChanged (); diff --git a/src/SeerImageVisualizerWidget.cpp b/src/SeerImageVisualizerWidget.cpp new file mode 100644 index 0000000..c06cb67 --- /dev/null +++ b/src/SeerImageVisualizerWidget.cpp @@ -0,0 +1,379 @@ +#include "SeerImageVisualizerWidget.h" +#include "SeerHelpPageWidget.h" +#include "SeerUtl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SeerImageVisualizerWidget::SeerImageVisualizerWidget (QWidget* parent) : QWidget(parent) { + + // Init variables. + _variableId = Seer::createID(); // Create two id's for queries. + _memoryId = Seer::createID(); + _formatName = ""; + _format = QImage::Format_Invalid; + _width = 0; + _height = 0; + _bytes = 0; + + // Set up UI. + setupUi(this); + + // Setup the widgets + setWindowIcon(QIcon(":/seer/resources/seergdb_64x64.png")); + setWindowTitle("Seer Image Visualizer"); + setAttribute(Qt::WA_DeleteOnClose); + + widthLineEdit->setValidator(new QIntValidator(1, 9999999, this)); + heightLineEdit->setValidator(new QIntValidator(1, 9999999, this)); + + // Connect things. + QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleRefreshButton); + QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleHelpButton); + QObject::connect(variableNameLineEdit, &QLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleVariableNameLineEdit); + QObject::connect(widthLineEdit, &QLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton); + QObject::connect(heightLineEdit, &QLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton); + QObject::connect(formatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &SeerImageVisualizerWidget::handleFormatComboBox); + QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handlePrintButton); + QObject::connect(saveToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleSaveButton); + + // Restore window settings. + readSettings(); +} + +SeerImageVisualizerWidget::~SeerImageVisualizerWidget () { +} + +void SeerImageVisualizerWidget::setVariableName (const QString& name) { + + setWindowTitle("Seer Image Visualizer - '" + name + "'"); + + variableNameLineEdit->setText(name); + setVariableAddress(""); + + if (variableNameLineEdit->text() == "") { + return; + } + + // Clear old contents. + QByteArray array; + + imageViewer->setImage(QImage()); + + // Send signal to get variable address. + emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); +} + +QString SeerImageVisualizerWidget::variableName () const { + + return variableNameLineEdit->text(); +} + +void SeerImageVisualizerWidget::setVariableAddress (const QString& address) { + + unsigned long offset = 0; + bool ok = false; + bool refresh = false; + + if (address == "") { + + variableAddressLineEdit->setText(""); + offset = 0; + + }else{ + + // Test for base10 + if (ok == false) { + offset = address.toULong(&ok, 10); + if (ok) { + variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); + refresh = true; + } + } + + // Test for base16 + if (ok == false) { + offset = address.toULong(&ok, 16); + if (ok) { + variableAddressLineEdit->setText(QString("0x%1").arg(offset, 0, 16, QLatin1Char( '0' ))); + refresh = true; + } + } + + if (ok == false) { + variableAddressLineEdit->setText("not an address"); + offset = 0; + } + } + + imageViewer->setImage(QImage()); + + // Show results immediately. + if (refresh) { + handleRefreshButton(); + } +} + +QString SeerImageVisualizerWidget::variableAddress () const { + + return variableAddressLineEdit->text(); +} + +void SeerImageVisualizerWidget::handleText (const QString& text) { + + QApplication::setOverrideCursor(Qt::BusyCursor); + + //qDebug() << text; + + if (text.contains(QRegExp("^([0-9]+)\\^done,value="))) { + + // 10^done,value="1" + // 11^done,value="0x7fffffffd538" + + QString id_text = text.section('^', 0,0); + + if (id_text.toInt() == _variableId) { + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QStringList words = Seer::filterEscapes(Seer::parseFirst(text, "value=", '"', '"', false)).split(' ', Qt::SkipEmptyParts); +#else + QStringList words = Seer::filterEscapes(Seer::parseFirst(text, "value=", '"', '"', false)).split(' ', QString::SkipEmptyParts); +#endif + + setVariableAddress(words.first()); + } + + }else if (text.contains(QRegExp("^([0-9]+)\\^done,memory="))) { + + // 3^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613e71",contents="00"}] + // 4^done,memory=[{begin="0x0000000000613e70",offset="0x0000000000000000",end="0x0000000000613ed4",contents="000000000000000000000000"}] + + QString id_text = text.section('^', 0,0); + + if (id_text.toInt() == _memoryId) { + + //qDebug() << text; + + QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); + + QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); + + // Loop through the memory ranges. + for ( const auto& range_text : range_list ) { + + QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); + + // Convert hex string to byte array. + QByteArray array; + + for (int i = 0; isetText( Seer::filterEscapes(Seer::parseFirst(text, "msg=", '"', '"', false)) ); + } + + if (id_text.toInt() == _memoryId) { + // Display the error message. + QString msg_text = Seer::parseFirst(text, "msg=", false); + + if (msg_text != "") { + QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text)); + } + } + + // At a stopping point, refresh. + }else if (text.startsWith("*stopped,reason=\"")) { + + if (autoRefreshCheckBox->isChecked()) { + handleRefreshButton(); + } + + }else{ + // Ignore anything else. + } + + QApplication::restoreOverrideCursor(); +} + +void SeerImageVisualizerWidget::handleRefreshButton () { + + // Clear the status. + messageLineEdit->setText(""); + + if (variableNameLineEdit->text() == "") { + return; + } + + if (variableAddressLineEdit->text() == "") { + return; + } + + if (variableAddressLineEdit->text() == "not an address") { + return; + } + + if (widthLineEdit->text() == "") { + return; + } + + if (heightLineEdit->text() == "") { + return; + } + + // Get image dimensions. + int w = widthLineEdit->text().toInt(); + int h = heightLineEdit->text().toInt(); + + if (w < 1 || h < 1) { + return; + } + + // Get image format. + QString format = formatComboBox->currentText(); + + // Validate the image dimensions vs. the data size. + _formatName = ""; + _format = QImage::Format_Invalid; + _width = w; + _height = h; + _bytes = 0; + + if (format == "RGBA8888") { + + _formatName = format; + _format = QImage::Format_RGBA8888; + _bytes = _width * _height * 4; + + }else if (format == "RGB888") { + + _formatName = format; + _format = QImage::Format_RGB888; + _bytes = _width * _height * 3; + } + + // Unknown format. + if (_bytes <= 0) { + + _formatName = ""; + _format = QImage::Format_Invalid; + _width = w; + _height = h; + _bytes = 0; + + messageLineEdit->setText("Unknown image format of '" + format + "."); + return; + } + + emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), _bytes); +} + +void SeerImageVisualizerWidget::handleHelpButton () { + + SeerHelpPageWidget* help = new SeerHelpPageWidget; + help->loadFile(":/seer/resources/help/ImageVisualizer.md"); + help->show(); +} + +void SeerImageVisualizerWidget::handleVariableNameLineEdit () { + + setVariableName (variableNameLineEdit->text()); +} + +void SeerImageVisualizerWidget::handleFormatComboBox (int index) { + + Q_UNUSED(index); + + handleRefreshButton(); +} + +void SeerImageVisualizerWidget::handlePrintButton () { + + imageViewer->print(); +} + +void SeerImageVisualizerWidget::handleSaveButton () { + + QMessageBox::warning(this, "Note.", "Not implmented yet."); +} + +void SeerImageVisualizerWidget::handleCreateImage (const QByteArray& array) { + + // Clear the status. + messageLineEdit->setText(""); + + // Nothing to do? + if (_bytes == 0) { + return; + } + + if (_format == QImage::Format_Invalid) { + return; + } + + // Data is not large enough for requested image dimensions. + if (_bytes > array.size()) { + messageLineEdit->setText(QString("%1 memory bytes is not enough for the '%2' image (%3x%4). Need at least %5 bytes.").arg(array.size()) + .arg(_formatName) + .arg(_width) + .arg(_height) + .arg(_bytes)); + return; + } + + // Construct image. + QImage image = QImage((const uchar*)array.data(), _width, _height, _format); + + imageViewer->setImage(image); +} + +void SeerImageVisualizerWidget::writeSettings() { + + QSettings settings; + + settings.beginGroup("imagevisualizerwindow"); + settings.setValue("size", size()); + settings.endGroup(); +} + +void SeerImageVisualizerWidget::readSettings() { + + QSettings settings; + + settings.beginGroup("imagevisualizerwindow"); + resize(settings.value("size", QSize(800, 400)).toSize()); + settings.endGroup(); +} + +void SeerImageVisualizerWidget::resizeEvent (QResizeEvent* event) { + + writeSettings(); + + QWidget::resizeEvent(event); +} + diff --git a/src/SeerImageVisualizerWidget.h b/src/SeerImageVisualizerWidget.h new file mode 100644 index 0000000..aff78b4 --- /dev/null +++ b/src/SeerImageVisualizerWidget.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include "ui_SeerImageVisualizerWidget.h" + +class SeerImageVisualizerWidget : public QWidget, protected Ui::SeerImageVisualizerWidgetForm { + + Q_OBJECT + + public: + explicit SeerImageVisualizerWidget (QWidget* parent = 0); + ~SeerImageVisualizerWidget (); + + void setVariableName (const QString& name); + QString variableName () const; + void setVariableAddress (const QString& address); + QString variableAddress () const; + + signals: + void evaluateVariableExpression (int expressionid, QString expression); + void evaluateMemoryExpression (int expressionid, QString address, int count); + + public slots: + void handleText (const QString& text); + + protected slots: + void handleRefreshButton (); + void handleHelpButton (); + void handleVariableNameLineEdit (); + void handleFormatComboBox (int index); + void handlePrintButton (); + void handleSaveButton (); + void handleCreateImage (const QByteArray& array); + + protected: + void writeSettings (); + void readSettings (); + void resizeEvent (QResizeEvent* event); + + private: + int _variableId; + int _memoryId; + + QString _formatName; + QImage::Format _format; + int _width; + int _height; + int _bytes; +}; + diff --git a/src/SeerImageVisualizerWidget.ui b/src/SeerImageVisualizerWidget.ui new file mode 100644 index 0000000..b4c7a40 --- /dev/null +++ b/src/SeerImageVisualizerWidget.ui @@ -0,0 +1,220 @@ + + + SeerImageVisualizerWidgetForm + + + + 0 + 0 + 899 + 683 + + + + Seer Image Visualizer + + + + + + + + Variable expression resulting in an address. + + + Starting address + + + true + + + + + + + Memory address. + + + true + + + Memory address + + + + + + + Qt::Vertical + + + + + + + + RGBA8888 + + + + + RGB888 + + + + + + + + The image width (pixels) + + + width + + + true + + + + + + + The image height (pixels) + + + height + + + true + + + + + + + Qt::Vertical + + + + + + + Print the display. + + + ... + + + + :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg + + + + + + + Save the display to a file. + + + ... + + + + :/seer/resources/RelaxLightIcons/document-save-as.svg:/seer/resources/RelaxLightIcons/document-save-as.svg + + + + + + + Qt::Vertical + + + + + + + Refresh the display. + + + ... + + + + :/seer/resources/RelaxLightIcons/view-refresh.svg:/seer/resources/RelaxLightIcons/view-refresh.svg + + + + + + + Automatically refresh after each stopping point. + + + Auto + + + + + + + Qt::Vertical + + + + + + + Help on Image Visualizer + + + + + + + :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg + + + + + + + + + + 0 + 100 + + + + + + + + true + + + true + + + + + + + + QHistoryLineEdit + QLineEdit +
QHistoryLineEdit.h
+
+ + QImageViewer + QWidget +
QImageViewer.h
+ 1 +
+
+ + + + +
diff --git a/src/SeerMainWindow.cpp b/src/SeerMainWindow.cpp index c899592..434fa0f 100644 --- a/src/SeerMainWindow.cpp +++ b/src/SeerMainWindow.cpp @@ -98,6 +98,7 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { QObject::connect(actionViewMemoryVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewMemoryVisualizer); QObject::connect(actionViewArrayVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewArrayVisualizer); QObject::connect(actionViewStructVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewVarVisualizer); + QObject::connect(actionViewImageVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewImageVisualizer); QObject::connect(actionViewAssembly, &QAction::triggered, this, &SeerMainWindow::handleViewAssembly); QObject::connect(actionConsoleNormal, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleNormal); QObject::connect(actionConsoleHidden, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleHidden); @@ -134,6 +135,7 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { QObject::connect(actionMemoryVisualizer, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMemoryVisualizer); QObject::connect(actionArrayVisualizer, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbArrayVisualizer); QObject::connect(actionStructVisualizer, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbVarVisualizer); + QObject::connect(actionImageVisualizer, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbImageVisualizer); QObject::connect(interruptAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterrupt); QObject::connect(interruptActionSIGINT, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGINT); QObject::connect(interruptActionSIGKILL, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbInterruptSIGKILL); @@ -436,6 +438,11 @@ void SeerMainWindow::handleViewVarVisualizer () { gdbWidget->handleGdbVarVisualizer(); } +void SeerMainWindow::handleViewImageVisualizer () { + + gdbWidget->handleGdbImageVisualizer(); +} + void SeerMainWindow::handleViewAssembly () { gdbWidget->editorManager()->showAssembly(); diff --git a/src/SeerMainWindow.h b/src/SeerMainWindow.h index 4e1ea34..ca8ad5c 100644 --- a/src/SeerMainWindow.h +++ b/src/SeerMainWindow.h @@ -60,6 +60,7 @@ class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { void handleViewArrayVisualizer (); void handleViewStructVisualizer (); void handleViewVarVisualizer (); + void handleViewImageVisualizer (); void handleViewAssembly (); void handleViewConsoleNormal (); void handleViewConsoleHidden (); diff --git a/src/SeerMainWindow.ui b/src/SeerMainWindow.ui index 18e6218..616c167 100644 --- a/src/SeerMainWindow.ui +++ b/src/SeerMainWindow.ui @@ -6,8 +6,8 @@ 0 0 - 984 - 628 + 1206 + 726 @@ -19,7 +19,7 @@ 0 0 - 984 + 1206 28 @@ -70,6 +70,7 @@ + @@ -170,6 +171,7 @@ + @@ -645,6 +647,30 @@ Toggle Gdb Playback direction. + + + + :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg + + + Image Visualizer + + + Launch a blank Image Visualizer. + + + + + + :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg + + + Image + + + Launch a blank Image Visualizer. + + diff --git a/src/SeerMemoryVisualizerWidget.cpp b/src/SeerMemoryVisualizerWidget.cpp index 8847f67..3fd42bc 100644 --- a/src/SeerMemoryVisualizerWidget.cpp +++ b/src/SeerMemoryVisualizerWidget.cpp @@ -17,7 +17,6 @@ SeerMemoryVisualizerWidget::SeerMemoryVisualizerWidget (QWidget* parent) : QWidg _variableId = Seer::createID(); // Create two id's for queries. _memoryId = Seer::createID(); _asmId = Seer::createID(); - _imageId = Seer::createID(); // Set up UI. setupUi(this); @@ -85,7 +84,6 @@ void SeerMemoryVisualizerWidget::setVariableName (const QString& name) { memoryHexEditor->setData(new SeerHexWidget::DataStorageArray(array)); memoryAsmEditor->setData(""); - memoryImageEditor->setData(array); // Send signal to get variable address. emit evaluateVariableExpression(_variableId, variableNameLineEdit->text()); @@ -202,35 +200,6 @@ void SeerMemoryVisualizerWidget::handleText (const QString& text) { // Give the byte array to the hex widget. memoryHexEditor->setData(new SeerHexWidget::DataStorageArray(array)); - break; // Take just the first range for now. - } - - }else if (id_text.toInt() == _imageId) { - - //qDebug() << text; - - QString memory_text = Seer::parseFirst(text, "memory=", '[', ']', false); - - QStringList range_list = Seer::parse(memory_text, "", '{', '}', false); - - // Loop through the memory ranges. - for ( const auto& range_text : range_list ) { - - QString contents_text = Seer::parseFirst(range_text, "contents=", '"', '"', false); - - // Convert hex string to byte array. - QByteArray array; - - for (int i = 0; isetData(array); - break; // Take just the first range for now. } } @@ -301,7 +270,6 @@ void SeerMemoryVisualizerWidget::handleRefreshButton () { emit evaluateMemoryExpression(_memoryId, variableAddressLineEdit->text(), nbytes); emit evaluateAsmExpression(_asmId, variableAddressLineEdit->text(), nbytes, 2); - emit evaluateMemoryExpression(_imageId, variableAddressLineEdit->text(), nbytes); } void SeerMemoryVisualizerWidget::handleHelpButton () { diff --git a/src/SeerMemoryVisualizerWidget.h b/src/SeerMemoryVisualizerWidget.h index 597ba71..91a59d5 100644 --- a/src/SeerMemoryVisualizerWidget.h +++ b/src/SeerMemoryVisualizerWidget.h @@ -43,6 +43,5 @@ class SeerMemoryVisualizerWidget : public QWidget, protected Ui::SeerMemoryVisua int _variableId; int _memoryId; int _asmId; - int _imageId; }; diff --git a/src/SeerMemoryVisualizerWidget.ui b/src/SeerMemoryVisualizerWidget.ui index 55975d4..0203fbe 100644 --- a/src/SeerMemoryVisualizerWidget.ui +++ b/src/SeerMemoryVisualizerWidget.ui @@ -236,16 +236,6 @@ - - - Image - - - - - - - @@ -268,12 +258,6 @@ QLineEdit
QHistoryLineEdit.h
- - SeerImageWidget - QWidget -
SeerImageWidget.h
- 1 -
diff --git a/src/resource.qrc b/src/resource.qrc index 13b2084..6511ed5 100644 --- a/src/resource.qrc +++ b/src/resource.qrc @@ -58,6 +58,7 @@ resources/help/OldStructVisualizer.md resources/help/MemoryVisualizer.md resources/help/ArrayVisualizer.md + resources/help/ImageVisualizer.md resources/help/StackInfoBrowser.md resources/help/VariableRegisterInfoBrowser.md resources/help/SourceSymbolLibraryInfoBrowser.md diff --git a/src/resources/help/ImageVisualizer.md b/src/resources/help/ImageVisualizer.md new file mode 100644 index 0000000..b03dae1 --- /dev/null +++ b/src/resources/help/ImageVisualizer.md @@ -0,0 +1,66 @@ +## Image Visualizer + +### Introduction + +The Image Visualizer shows the contents of a region of memory as a image. + +### Operation + +There are various things to control how the memory is display. + +* Starting address entry field +* Number of bytes entry field +* Image width (in pixels) +* Image height (in pixels) +* Image format +* Refresh +* Auto Refresh + +A check is done to ensure the amount of memory given to the Memory Visualizer will cover the image size. + +### Starting address entry field + +The 'Starting Address' input field takes the name of a variable that is in the current Stack Frame (selected by the Stack Frame browser). This variable should result in an address. For example, take this code: +``` + int var = 10; +``` +To visualize the memory for 'var', the variable should be '&var', not 'var'. As 'var' doesn't resolve to an address. + +Note, the variable name can be an address. Enter the address like: +``` + 0xdeadbeaf +``` +It can also be one of gdb' special variables. Like the program counter. Enter it like: +``` + $pc +``` + +### Number of bytes entry field + +The default number of bytes to display is 256. Fewer or more than this number can be entered. + +### Image format. + +Two supported formats are available: + +* RGBA8888 +* RGB888 + +### Refresh + +This will refresh the memory dump since the last time. + +### Auto mode + +This mode will refresh the memory dump each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). + +### Image interaction + +Avaible Quick keys while in the Image Visualizer: +``` + '+' zoom in + '-' zoom out + reset to default zoom level. + ^P print image. +``` + diff --git a/src/resources/help/MemoryVisualizer.md b/src/resources/help/MemoryVisualizer.md index 2a07d7d..102cffd 100644 --- a/src/resources/help/MemoryVisualizer.md +++ b/src/resources/help/MemoryVisualizer.md @@ -17,7 +17,6 @@ The memory displayed in 3 views. * A memory dump in the chosen Display format. Included in this view is the memory displayed in the Character format. A byte can be selected in this view to highlight it. * A table showing the highlighted byte in different numeric formats (int, float, double, etc...). * A separate tab showing the memory as disassembly. -* A separate tab showing the memory as an image. ### Operation @@ -81,23 +80,3 @@ This will refresh the memory dump since the last time. This mode will refresh the memory dump each time Seer reaches a stopping point (when you 'step' or 'next' or reach a 'breakpoint'). -### Image viewer - -The Image tab can show the memory as an image. Two supported formats are available: - -* RGBA8888 -* RGB888 - -You must enter the width and height of the image, in pixels. A check is done to ensure the amount of memory given to the Memory -Visualizer will cover the image size. - -Avaible Quick keys while in the Image viewer: -``` - '+' zoom in - '-' zoom out - reset to default zoom level. - ^P print image. -``` - -__NOTE__, this viewer is slow!!! Will be fixed. -