mirror of
https://github.com/epasveer/seer.git
synced 2026-08-30 00:50:42 +08:00
438 lines
13 KiB
C++
438 lines
13 KiB
C++
// SPDX-FileCopyrightText: 2021 Ernie Pasveer <epasveer@att.net>
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "SeerImageVisualizerWidget.h"
|
|
#include "SeerHelpPageDialog.h"
|
|
#include "SeerUtl.h"
|
|
#include <QtWidgets/QMessageBox>
|
|
#include <QtWidgets/QFileDialog>
|
|
#include <QtGui/QIntValidator>
|
|
#include <QtGui/QIcon>
|
|
#include <QtPrintSupport/QPrinter>
|
|
#include <QtPrintSupport/QPrintDialog>
|
|
#include <QtCore/QSettings>
|
|
#include <QtCore/QDebug>
|
|
|
|
SeerImageVisualizerWidget::SeerImageVisualizerWidget (QWidget* parent) : QWidget(parent) {
|
|
|
|
// Init variables.
|
|
_variableId = Seer::createID(); // Create two id's for queries.
|
|
_memoryId = Seer::createID();
|
|
_imageWidthId = Seer::createID();
|
|
_imageHeightId = 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);
|
|
|
|
// Connect things.
|
|
QObject::connect(refreshToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerImageVisualizerWidget::handleHelpButton);
|
|
QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleVariableNameLineEdit);
|
|
QObject::connect(variableNameLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleVariableNameLineEdit);
|
|
QObject::connect(widthLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(widthLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleWidthLineEdit);
|
|
QObject::connect(heightLineEdit, &SeerHistoryLineEdit::returnPressed, this, &SeerImageVisualizerWidget::handleRefreshButton);
|
|
QObject::connect(heightLineEdit, &SeerHistoryLineEdit::editingFinished, this, &SeerImageVisualizerWidget::handleHeightLineEdit);
|
|
QObject::connect(formatComboBox, QOverload<int>::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::setImageWidth (const QString& width) {
|
|
|
|
widthLineEdit->setText(width);
|
|
}
|
|
|
|
QString SeerImageVisualizerWidget::imageWidth () const {
|
|
|
|
return widthLineEdit->text();
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::setImageHeight (const QString& height) {
|
|
|
|
heightLineEdit->setText(height);
|
|
}
|
|
|
|
QString SeerImageVisualizerWidget::imageHeight () const {
|
|
|
|
return heightLineEdit->text();
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::handleText (const QString& text) {
|
|
|
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
|
|
|
//qDebug() << text;
|
|
|
|
if (text.contains(QRegularExpression("^([0-9]+)\\^done,value="))) {
|
|
|
|
// 10^done,value="1"
|
|
// 11^done,value="0x7fffffffd538"
|
|
|
|
QString id_text = text.section('^', 0,0);
|
|
|
|
if (id_text.toInt() == _variableId) {
|
|
|
|
QStringList words = Seer::filterEscapes(Seer::parseFirst(text, "value=", '"', '"', false)).split(' ', Qt::SkipEmptyParts);
|
|
|
|
setVariableAddress(words.first());
|
|
|
|
}else if (id_text.toInt() == _imageWidthId) {
|
|
|
|
// Set the image width.
|
|
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
|
|
|
|
setImageWidth(value_text);
|
|
|
|
handleRefreshButton();
|
|
|
|
}else if (id_text.toInt() == _imageHeightId) {
|
|
|
|
// Set the image height.
|
|
QString value_text = Seer::parseFirst(text, "value=", '"', '"', false);
|
|
|
|
setImageHeight(value_text);
|
|
|
|
handleRefreshButton();
|
|
}
|
|
|
|
}else if (text.contains(QRegularExpression("^([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; i<contents_text.size(); i += 2) {
|
|
QString num = contents_text.mid(i, 2);
|
|
bool ok = false;
|
|
array.push_back(num.toInt(&ok, 16));
|
|
Q_ASSERT(ok);
|
|
}
|
|
|
|
// Create the image.
|
|
handleCreateImage(array);
|
|
|
|
break; // Take just the first range for now.
|
|
}
|
|
}
|
|
|
|
}else if (text.contains(QRegularExpression("^([0-9]+)\\^error,msg="))) {
|
|
|
|
// 12^error,msg="No symbol \"return\" in current context."
|
|
// 13^error,msg="No symbol \"cout\" in current context."
|
|
// 3^error,msg="Unable to read memory."
|
|
|
|
QString id_text = text.section('^', 0,0);
|
|
|
|
if (id_text.toInt() == _variableId) {
|
|
variableAddressLineEdit->setText( 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 () {
|
|
|
|
SeerHelpPageDialog* help = new SeerHelpPageDialog;
|
|
help->loadFile(":/seer/resources/help/ImageVisualizer.md");
|
|
help->show();
|
|
help->raise();
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::handleVariableNameLineEdit () {
|
|
|
|
setVariableName (variableNameLineEdit->text());
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::handleWidthLineEdit () {
|
|
|
|
if (widthLineEdit->text() == "") {
|
|
return;
|
|
}
|
|
|
|
emit evaluateVariableExpression(_imageWidthId, widthLineEdit->text());
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::handleHeightLineEdit () {
|
|
|
|
if (heightLineEdit->text() == "") {
|
|
return;
|
|
}
|
|
|
|
emit evaluateVariableExpression(_imageHeightId, heightLineEdit->text());
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::handleFormatComboBox (int index) {
|
|
|
|
Q_UNUSED(index);
|
|
|
|
handleRefreshButton();
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::handlePrintButton () {
|
|
|
|
imageViewer->print();
|
|
}
|
|
|
|
void SeerImageVisualizerWidget::handleSaveButton () {
|
|
|
|
imageViewer->saveFileDialog(variableNameLineEdit->text() + ".png");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|