Register inspection window

This commit is contained in:
Nav
2021-09-18 22:41:08 +01:00
parent d2a8966a0a
commit dcdcd1d114
24 changed files with 1694 additions and 2 deletions

View File

@@ -162,6 +162,17 @@ add_executable(Bloom
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/ItemWidget.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterGroupWidget.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.cpp
# Target register inspector window
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/Item.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/CurrentItem.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryItem.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.cpp
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.cpp
)
set_target_properties(Bloom PROPERTIES OUTPUT_NAME bloom)

View File

@@ -0,0 +1,78 @@
#include "BitBodyWidget.hpp"
#include <QVBoxLayout>
#include <QScrollArea>
#include <QMargins>
using namespace Bloom::Widgets;
BitBodyWidget::BitBodyWidget(
int bitIndex,
std::bitset<std::numeric_limits<unsigned char>::digits>::reference bit,
bool readOnly,
QWidget* parent
): ClickableWidget(parent), bitIndex(bitIndex), bit(bit), readOnly(readOnly) {
this->setFixedSize(BitBodyWidget::WIDTH, BitBodyWidget::HEIGHT);
this->setContentsMargins(0, 0, 0, 0);
}
void BitBodyWidget::mouseReleaseEvent(QMouseEvent* event) {
if (this->isEnabled()) {
if (!this->readOnly && event->button() == Qt::MouseButton::LeftButton) {
this->bit = !this->bit;
this->update();
}
ClickableWidget::mouseReleaseEvent(event);
}
}
bool BitBodyWidget::event(QEvent* event) {
if (this->isEnabled() && !this->readOnly) {
switch (event->type()) {
case QEvent::Enter: {
this->hoverActive = true;
this->update();
break;
}
case QEvent::Leave: {
this->hoverActive = false;
this->update();
break;
}
default: {
break;
}
}
}
return QWidget::event(event);
}
void BitBodyWidget::paintEvent(QPaintEvent* event) {
auto painter = QPainter(this);
this->drawWidget(painter);
}
void BitBodyWidget::drawWidget(QPainter& painter) {
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
auto bodyColor = QColor(this->bit == true ? "#7B5F31" : "#918E86");
if (!this->isEnabled()) {
bodyColor.setAlpha(100);
} else if (!this->hoverActive) {
bodyColor.setAlpha(235);
}
painter.setPen(Qt::PenStyle::NoPen);
painter.setBrush(bodyColor);
painter.drawRect(
0,
0,
BitBodyWidget::WIDTH,
BitBodyWidget::HEIGHT
);
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <QWidget>
#include <bitset>
#include <QLabel>
#include <QSize>
#include <QString>
#include <QEvent>
#include <QPaintEvent>
#include <QPainter>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp"
namespace Bloom::Widgets
{
class BitBodyWidget: public ClickableWidget
{
Q_OBJECT
private:
int bitIndex = 0;
std::bitset<std::numeric_limits<unsigned char>::digits>::reference bit;
bool readOnly = true;
bool hoverActive = false;
protected:
bool event(QEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
public:
constexpr static int WIDTH = 23;
constexpr static int HEIGHT = 30;
BitBodyWidget(
int bitIndex,
std::bitset<std::numeric_limits<unsigned char>::digits>::reference bit,
bool readOnly,
QWidget* parent
);
};
}

View File

@@ -0,0 +1,56 @@
#include "BitWidget.hpp"
#include <QVBoxLayout>
#include <QScrollArea>
#include <QMargins>
#include <set>
#include "BitBodyWidget.hpp"
using namespace Bloom::Widgets;
BitWidget::BitWidget(
int bitIndex,
int bitNumber,
std::bitset<std::numeric_limits<unsigned char>::digits>& bitset,
bool readOnly,
QWidget* parent
): QWidget(parent), bitIndex(bitIndex), bitNumber(bitNumber), bitset(bitset), readOnly(readOnly) {
this->setFixedSize(BitWidget::WIDTH, BitWidget::HEIGHT);
auto layout = new QVBoxLayout(this);
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
layout->setAlignment(Qt::AlignmentFlag::AlignTop);
this->body = new BitBodyWidget(
this->bitIndex,
this->bitset[static_cast<size_t>(this->bitIndex)],
this->readOnly,
this
);
this->bitLabel = new QLabel("Bit", this);
this->bitNumberLabel = new QLabel(QString::number(this->bitNumber), this);
this->bitLabel->setObjectName("register-bit-label");
this->bitNumberLabel->setObjectName("register-bit-number-label");
this->bitLabel->setFixedHeight(BitWidget::LABEL_HEIGHT);
this->bitNumberLabel->setFixedHeight(BitWidget::LABEL_HEIGHT);
this->bitLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
this->bitNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
layout->addWidget(this->bitLabel);
layout->addWidget(this->bitNumberLabel);
layout->addSpacing(BitWidget::VERTICAL_SPACING);
layout->addWidget(this->body);
layout->addStretch(1);
if (!this->readOnly) {
this->connect(this->body, &BitBodyWidget::clicked, this, [this] {
emit this->bitChanged();
});
}
}

View File

@@ -0,0 +1,53 @@
#pragma once
#include <QWidget>
#include <bitset>
#include <QLabel>
#include <QSize>
#include <QString>
#include <QEvent>
#include <QPaintEvent>
#include <QPainter>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp"
#include "BitBodyWidget.hpp"
namespace Bloom::Widgets
{
class BitWidget: public QWidget
{
Q_OBJECT
private:
const static int VERTICAL_SPACING = 3;
int bitIndex = 0;
int bitNumber = 0;
std::bitset<std::numeric_limits<unsigned char>::digits>& bitset;
bool readOnly = true;
BitBodyWidget* body = nullptr;
QLabel* bitLabel = nullptr;
QLabel* bitNumberLabel = nullptr;
public:
constexpr static int LABEL_HEIGHT = 14;
constexpr static int LABEL_COUNT = 2;
constexpr static int WIDTH = BitBodyWidget::WIDTH;
constexpr static int HEIGHT = BitBodyWidget::HEIGHT + (BitWidget::LABEL_HEIGHT * BitWidget::LABEL_COUNT)
+ BitWidget::VERTICAL_SPACING;
constexpr static int SPACING = 6;
BitWidget(
int bitIndex,
int bitNumber,
std::bitset<std::numeric_limits<unsigned char>::digits>& bitset,
bool readOnly,
QWidget* parent
);
signals:
void bitChanged();
};
}

View File

@@ -0,0 +1,105 @@
#include "BitsetWidget.hpp"
#include <QVBoxLayout>
#include <QScrollArea>
#include <QMargins>
#include <QLine>
#include <set>
#include "../TargetRegisterInspectorWindow.hpp"
using namespace Bloom::Widgets;
BitsetWidget::BitsetWidget(int byteNumber, unsigned char& byte, bool readOnly, QWidget* parent):
QWidget(parent), byteNumber(byteNumber), byte(byte), readOnly(readOnly) {
this->setObjectName("bitset-widget");
auto bitLayout = new QHBoxLayout(this);
bitLayout->setSpacing(BitWidget::SPACING);
bitLayout->setContentsMargins(0, 0, 0, 0);
this->setContentsMargins(0, 0, 0, 0);
this->setFixedSize(
static_cast<int>((BitWidget::WIDTH + BitWidget::SPACING) * this->bitset.size() - BitWidget::SPACING),
BitsetWidget::HEIGHT
);
for (int bitIndex = (std::numeric_limits<unsigned char>::digits - 1); bitIndex >= 0; bitIndex--) {
auto bitWidget = new BitWidget(
bitIndex,
(this->byteNumber * 8) + bitIndex,
this->bitset,
this->readOnly,
this
);
bitLayout->addWidget(bitWidget, 0, Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop);
this->connect(
bitWidget,
&BitWidget::bitChanged,
this,
[this] {
this->byte = static_cast<unsigned char>(this->bitset.to_ulong());
this->repaint();
emit this->byteChanged();
}
);
}
}
void BitsetWidget::paintEvent(QPaintEvent* event) {
QWidget::paintEvent(event);
auto painter = QPainter(this);
this->drawWidget(painter);
}
void BitsetWidget::drawWidget(QPainter& painter) {
auto byteHex = "0x" + QString::number(this->byte, 16).toUpper();
painter.setPen(QColor("#474747"));
constexpr int labelHeight = 10;
int containerWidth = this->width();
constexpr int charWidth = 6;
auto labelWidth = (charWidth * byteHex.size()) + 13;
auto width = (containerWidth - (BitWidget::WIDTH) - labelWidth) / 2;
painter.drawLine(QLine(
BitWidget::WIDTH / 2,
BitWidget::HEIGHT,
BitWidget::WIDTH / 2,
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
));
painter.drawLine(QLine(
containerWidth - (BitWidget::WIDTH / 2) - 1,
BitWidget::HEIGHT,
containerWidth - (BitWidget::WIDTH / 2) - 1,
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
));
painter.drawLine(QLine(
BitWidget::WIDTH / 2,
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT,
static_cast<int>((BitWidget::WIDTH / 2) + width),
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
));
painter.drawLine(QLine(
static_cast<int>((BitWidget::WIDTH / 2) + width + labelWidth),
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT,
containerWidth - (BitWidget::WIDTH / 2) - 1,
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
));
painter.setPen(QColor("#8a8a8d"));
painter.drawText(
static_cast<int>(
std::floor((BitWidget::WIDTH / 2) + width + ((labelWidth - (byteHex.size() * charWidth)) / 2))
),
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT + (labelHeight / 2),
byteHex
);
}
void BitsetWidget::updateValue() {
this->bitset = {this->byte};
this->update();
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <QWidget>
#include <bitset>
#include <QLabel>
#include <QSize>
#include <QString>
#include <QEvent>
#include "BitWidget.hpp"
namespace Bloom::Widgets
{
class BitsetWidget: public QWidget
{
Q_OBJECT
private:
int byteNumber = 0;
unsigned char& byte;
std::bitset<std::numeric_limits<unsigned char>::digits> bitset = {byte};
bool readOnly = true;
QWidget* container = nullptr;
protected:
void paintEvent(QPaintEvent* event) override;
void drawWidget(QPainter& painter);
public:
constexpr static int VALUE_GRAPHIC_HEIGHT = 20;
constexpr static int HEIGHT = BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT + 8;
constexpr static int WIDTH = (BitWidget::WIDTH + BitWidget::SPACING) * 8;
BitsetWidget(int byteNumber, unsigned char& byte, bool readOnly, QWidget* parent);
void updateValue();
signals:
void byteChanged();
};
}

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="65"
height="54"
viewBox="0 0 17.197917 14.2875"
version="1.1"
id="svg974"
sodipodi:docname="icon.svg"
inkscape:version="1.0.1 (1.0.1+r75)">
<defs
id="defs968" />
<sodipodi:namedview
id="base"
pagecolor="#343532"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="13.920574"
inkscape:cy="10.048712"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:snap-page="true"
inkscape:window-width="3440"
inkscape:window-height="1353"
inkscape:window-x="2560"
inkscape:window-y="34"
inkscape:window-maximized="1"
fit-margin-top="6"
fit-margin-left="6"
fit-margin-right="6"
fit-margin-bottom="6"
lock-margins="true" />
<metadata
id="metadata971">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(1.3229167,1.0583334)">
<rect
style="fill:#7b5f31;fill-opacity:1;stroke-width:0.318943"
id="rect1537"
width="6.6145835"
height="3.175"
x="0.26458332"
y="0.52916664" />
<rect
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.318943"
id="rect1537-5"
width="6.6145835"
height="3.175"
x="7.6729169"
y="0.52916664" />
<rect
style="fill:#c5c5c5;fill-opacity:0.54471;stroke-width:0.318942"
id="rect1537-6"
width="6.6145835"
height="3.175"
x="0.26458332"
y="4.4979167" />
<rect
style="fill:#c5c5c5;fill-opacity:0.54471;stroke-width:0.318942"
id="rect1537-5-2"
width="6.6145825"
height="3.175"
x="7.6729178"
y="4.4979167" />
<rect
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.318942"
id="rect1537-6-9"
width="6.6145835"
height="3.175"
x="0.26458332"
y="8.4666672" />
<rect
style="fill:#7b5f31;fill-opacity:1;stroke-width:0.318942"
id="rect1537-5-2-1"
width="6.6145825"
height="3.175"
x="7.6729169"
y="8.4666672" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,17 @@
#include "CurrentItem.hpp"
#include <QStyle>
#include <QVBoxLayout>
using namespace Bloom::Widgets;
CurrentItem::CurrentItem(
const Targets::TargetMemoryBuffer& registerValue,
QWidget* parent
): Item(registerValue, parent) {
this->setObjectName("current-item");
this->setFixedHeight(30);
this->titleLabel->setText("Current value");
this->layout->addWidget(titleLabel, 0, Qt::AlignmentFlag::AlignLeft);
this->layout->setContentsMargins(5, 0, 5, 0);
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <QDateTime>
#include <QHBoxLayout>
#include <QLabel>
#include "Item.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgWidget.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::Widgets
{
class CurrentItem: public Item
{
Q_OBJECT
QHBoxLayout* layout = new QHBoxLayout(this);
QLabel* titleLabel = new QLabel(this);
public:
CurrentItem(
const Targets::TargetMemoryBuffer& registerValue,
QWidget *parent
);
};
}

View File

@@ -0,0 +1,27 @@
#include "Item.hpp"
#include <QStyle>
using namespace Bloom::Widgets;
Item::Item(const Targets::TargetMemoryBuffer& registerValue, QWidget* parent):
ClickableWidget(parent), registerValue(registerValue) {
auto onClick = [this] {
this->setSelected(true);
};
this->connect(this, &ClickableWidget::clicked, this, onClick);
this->connect(this, &ClickableWidget::rightClicked, this, onClick);
this->setSelected(false);
}
void Item::setSelected(bool selected) {
this->setProperty("selected", selected);
this->style()->unpolish(this);
this->style()->polish(this);
if (selected) {
emit this->selected(this);
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp"
#include "src/Targets/TargetMemory.hpp"
namespace Bloom::Widgets
{
class Item: public ClickableWidget
{
Q_OBJECT
public:
Targets::TargetMemoryBuffer registerValue;
Item(const Targets::TargetMemoryBuffer& registerValue, QWidget *parent);
public slots:
void setSelected(bool selected);
signals:
void selected(Item*);
};
}

View File

@@ -0,0 +1,45 @@
#include "RegisterHistoryItem.hpp"
#include <QStyle>
#include <QVBoxLayout>
#include <QByteArray>
using namespace Bloom::Widgets;
RegisterHistoryItem::RegisterHistoryItem(
const Targets::TargetMemoryBuffer& registerValue,
const QDateTime& changeDate,
QWidget* parent
): Item(registerValue, parent) {
this->setObjectName("register-history-item");
this->setFixedHeight(50);
this->layout->setContentsMargins(5, 8, 5, 0);
this->dateLabel->setText(changeDate.toString("dd/MM/yyyy hh:mm:ss"));
this->dateLabel->setObjectName("date-label");
this->valueLabel->setText("0x" + QString(QByteArray(
reinterpret_cast<const char*>(registerValue.data()),
static_cast<qsizetype>(registerValue.size())
).toHex()).toUpper());
this->valueLabel->setObjectName("value-label");
auto labelLayout = new QVBoxLayout();
labelLayout->setSpacing(5);
labelLayout->setContentsMargins(0, 0, 0, 0);
labelLayout->addWidget(this->dateLabel, 0, Qt::AlignmentFlag::AlignTop);
labelLayout->addWidget(this->valueLabel, 0, Qt::AlignmentFlag::AlignTop);
labelLayout->addStretch(1);
this->layout->setSpacing(1);
this->layout->addLayout(labelLayout);
auto onClick = [this] {
this->setSelected(true);
};
this->connect(this, &ClickableWidget::clicked, this, onClick);
this->connect(this, &ClickableWidget::rightClicked, this, onClick);
this->setSelected(false);
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <QDateTime>
#include <QHBoxLayout>
#include <QLabel>
#include "Item.hpp"
namespace Bloom::Widgets
{
class RegisterHistoryItem: public Item
{
Q_OBJECT
QHBoxLayout* layout = new QHBoxLayout(this);
QLabel* dateLabel = new QLabel(this);
QLabel* valueLabel = new QLabel(this);
public:
RegisterHistoryItem(
const Targets::TargetMemoryBuffer& registerValue,
const QDateTime& changeDate,
QWidget *parent
);
};
}

View File

@@ -0,0 +1,136 @@
#include "RegisterHistoryWidget.hpp"
#include <QVBoxLayout>
#include <QMargins>
#include <QTableWidget>
#include <QScrollBar>
#include <set>
#include "../../../UiLoader.hpp"
#include "src/Helpers/Paths.hpp"
#include "src/Helpers/DateTime.hpp"
#include "src/Exceptions/Exception.hpp"
using namespace Bloom::Widgets;
using namespace Bloom::Exceptions;
using Bloom::Targets::TargetRegisterDescriptor;
using Bloom::Targets::TargetRegisterDescriptors;
using Bloom::Targets::TargetRegisterType;
RegisterHistoryWidget::RegisterHistoryWidget(
const Targets::TargetRegisterDescriptor& registerDescriptor,
const Targets::TargetMemoryBuffer& currentValue,
InsightWorker& insightWorker,
QWidget* parent
): QWidget(parent), registerDescriptor(registerDescriptor), insightWorker(insightWorker) {
this->setObjectName("target-register-history-widget");
this->setFixedWidth(300);
auto widgetUiFile = QFile(
QString::fromStdString(Paths::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget"
+ "/UiFiles/RegisterHistoryWidget.ui"
)
);
if (!widgetUiFile.open(QFile::ReadOnly)) {
throw Exception("Failed to open RegisterHistoryWidget UI file");
}
auto uiLoader = UiLoader(this);
this->container = uiLoader.load(&widgetUiFile, this);
this->container->setFixedSize(this->size());
this->container->setContentsMargins(1, 1, 1, 1);
this->itemContainer = this->container->findChild<QWidget*>("item-container");
this->itemContainerLayout = this->itemContainer->findChild<QVBoxLayout*>("item-container-layout");
auto titleBar = this->container->findChild<QWidget*>("title-bar");
auto title = titleBar->findChild<QLabel*>("title");
titleBar->setContentsMargins(0, 0, 0, 0);
title->setFixedHeight(titleBar->height());
this->connect(
&insightWorker,
&InsightWorker::targetStateUpdated,
this,
&RegisterHistoryWidget::onTargetStateChanged
);
this->connect(
&insightWorker,
&InsightWorker::targetRegistersWritten,
this,
&RegisterHistoryWidget::onRegistersWritten
);
this->currentItem = new CurrentItem(currentValue, this);
this->connect(this->currentItem, &Item::selected, this, &RegisterHistoryWidget::onItemSelectionChange);
this->itemContainerLayout->addWidget(this->currentItem);
this->currentItem->setSelected(true);
auto separatorWidget = new QWidget(this);
auto separatorLayout = new QHBoxLayout(separatorWidget);
auto separatorLabel = new QLabel("Select an item to restore", separatorWidget);
separatorWidget->setFixedHeight(40);
separatorWidget->setObjectName("separator-widget");
separatorLayout->setContentsMargins(0, 10, 0, 10);
separatorLabel->setObjectName("separator-label");
separatorLayout->addWidget(separatorLabel, 0, Qt::AlignmentFlag::AlignHCenter);
this->itemContainerLayout->addWidget(separatorWidget);
this->show();
}
void RegisterHistoryWidget::updateCurrentItemValue(const Targets::TargetMemoryBuffer& registerValue) {
this->currentItem->registerValue = registerValue;
if (this->selectedItemWidget != nullptr && this->currentItem == this->selectedItemWidget) {
this->selectCurrentItem();
}
}
void RegisterHistoryWidget::selectCurrentItem() {
this->currentItem->setSelected(true);
}
void RegisterHistoryWidget::addItem(const Targets::TargetMemoryBuffer& registerValue, const QDateTime& changeDate) {
auto item = new RegisterHistoryItem(registerValue, changeDate, this->itemContainer);
this->connect(item, &Item::selected, this, &RegisterHistoryWidget::onItemSelectionChange);
this->itemContainerLayout->insertWidget(2, item);
}
void RegisterHistoryWidget::resizeEvent(QResizeEvent* event) {
this->container->setFixedSize(
this->width(),
this->height()
);
}
void RegisterHistoryWidget::onTargetStateChanged(Targets::TargetState newState) {
using Targets::TargetState;
this->targetState = newState;
}
void RegisterHistoryWidget::onItemSelectionChange(Item* newlySelectedWidget) {
if (this->selectedItemWidget != newlySelectedWidget) {
if (this->selectedItemWidget != nullptr) {
this->selectedItemWidget->setSelected(false);
}
this->selectedItemWidget = newlySelectedWidget;
}
emit this->historyItemSelected(newlySelectedWidget->registerValue);
}
void RegisterHistoryWidget::onRegistersWritten(Targets::TargetRegisters targetRegisters, const QDateTime& changeDate) {
for (const auto& targetRegister : targetRegisters) {
if (targetRegister.descriptor == this->registerDescriptor) {
this->addItem(targetRegister.value, changeDate);
this->updateCurrentItemValue(targetRegister.value);
}
}
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <set>
#include <QSize>
#include <QString>
#include <QEvent>
#include <optional>
#include "src/Targets/TargetRegister.hpp"
#include "src/Targets/TargetMemory.hpp"
#include "src/Targets/TargetState.hpp"
#include "Item.hpp"
#include "CurrentItem.hpp"
#include "RegisterHistoryItem.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
namespace Bloom::Widgets
{
class RegisterHistoryWidget: public QWidget
{
Q_OBJECT
private:
Targets::TargetRegisterDescriptor registerDescriptor;
InsightWorker& insightWorker;
QWidget* container = nullptr;
QWidget* itemContainer = nullptr;
QVBoxLayout* itemContainerLayout = nullptr;
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
CurrentItem* currentItem = nullptr;
Item* selectedItemWidget = nullptr;
private slots:
void onTargetStateChanged(Targets::TargetState newState);
void onItemSelectionChange(Item* newlySelectedWidget);
void onRegistersWritten(Targets::TargetRegisters targetRegisters, const QDateTime& changeDate);
protected:
void resizeEvent(QResizeEvent* event) override;
public:
RegisterHistoryWidget(
const Targets::TargetRegisterDescriptor& registerDescriptor,
const Targets::TargetMemoryBuffer& currentValue,
InsightWorker& insightWorker,
QWidget* parent
);
void updateCurrentItemValue(const Targets::TargetMemoryBuffer& registerValue);
void selectCurrentItem();
bool isCurrentItemSelected() {
return this->selectedItemWidget != nullptr && this->selectedItemWidget == this->currentItem;
}
void addItem(const Targets::TargetMemoryBuffer& registerValue, const QDateTime& changeDate);
signals:
void historyItemSelected(const Targets::TargetMemoryBuffer& registerValue);
};
}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<widget class="QWidget" name="container">
<layout class="QVBoxLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item alignment="Qt::AlignCenter">
<widget class="QWidget" name="title-bar">
<property name="minimumHeight">
<number>30</number>
</property>
<widget class="QLabel" name="title">
<property name="text"><string>Register History</string></property>
</widget>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="ExpandingHeightScrollAreaWidget" name="item-scroll-area">
<property name="widgetResizable"><bool>true</bool></property>
<property name="verticalScrollBarPolicy"><enum>Qt::ScrollBarAsNeeded</enum></property>
<property name="sizeAdjustPolicy"><enum>QAbstractScrollArea::AdjustToContents</enum></property>
<property name="horizontalScrollBarPolicy"><enum>Qt::ScrollBarAlwaysOff</enum></property>
<property name="sizePolicy"><enum>QSizePolicy::SetMinAndMaxSize</enum></property>
<widget class="QWidget" name="item-container">
<layout class="QVBoxLayout" name="item-container-layout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</ui>

View File

@@ -0,0 +1,138 @@
* {
color: #afb1b3;
font-family: 'Ubuntu', sans-serif;
font-size: 14px;
}
#target-register-inspector-window {
background-color: #343532;
}
#register-name {
font-size: 15px;
}
#register-value-container,
#register-details-container {
border: 1px solid #2b2b2b;
}
#register-value-text-input-container {
border-top: 1px solid #41423f;
}
QLineEdit {
background-color: #2B2B29;
border: 1px solid #41423f;
padding: 3px;
}
QLineEdit:disabled {
font-style: italic;
color: #7d7d7d;
}
QPushButton {
background-color: #373937;
border: 1px solid #41423f;
padding: 3px 25px;
}
#apply-btn {
background-color: #353C41;
border: 1px solid #3e474c;
}
QPushButton:disabled {
background-color: #303230;
color: #8d8d90;
}
#register-bit-number-label {
font-size: 12px;
color: #a6a7aa;
}
#register-bit-label {
font-size: 11px;
color: #8a8a8d;
}
/* BitsetWidget */
#bitset-widget {
font-size: 12px;
}
/* RegisterHistoryWidget */
#target-register-history-widget #container {
border: 1px solid #2b2b2b;
}
#target-register-history-widget #title-bar {
background-color: #353C41;
border-bottom: 1px solid #2b2b2b;
}
#target-register-history-widget #title {
color: #afb1b3;
padding-top: 0;
padding-bottom: 0;
padding-left: 5px;
}
#target-register-history-widget QScrollArea,
#target-register-history-widget #item-container {
background-color: transparent;
border: none;
}
#target-register-history-widget #current-item[selected=true],
#target-register-history-widget #register-history-item[selected=true] {
background-color: #335883;
}
#target-register-history-widget #separator-widget {
border-top: 1px solid #2e2e2e;
border-bottom: 1px solid #2e2e2e;
}
#target-register-history-widget #register-history-item {
border-bottom: 1px solid #2e2e2e;
background-color: transparent;
}
#target-register-history-widget #register-history-item #date-label {
font-size: 14px
}
#target-register-history-widget #register-history-item #value-label {
font-size: 13px;
font-style: italic;
color: #8a8a8d;
}
#target-register-history-widget #separator-label {
/*font-style: italic;*/
color: #8a8a8d;
}
QScrollBar:vertical {
background-color: transparent;
width: 15px;
margin: 1px 1px 1px 5px;
}
QScrollBar:handle:vertical {
border: none;
background-color: rgba(69, 69, 66, 0.6);
}
QScrollBar:handle:vertical:hover {
background-color: rgba(69, 69, 66, 0.91);
}
QScrollBar::add-line:vertical,
QScrollBar::sub-line:vertical {
border: none;
background: none;
}

View File

@@ -0,0 +1,325 @@
#include "TargetRegisterInspectorWindow.hpp"
#include <QVBoxLayout>
#include <QMargins>
#include <QTableWidget>
#include <QScrollBar>
#include <set>
#include "../../UiLoader.hpp"
#include "src/Helpers/Paths.hpp"
#include "src/Helpers/DateTime.hpp"
#include "src/Exceptions/Exception.hpp"
#include "src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp"
#include "src/Insight/InsightWorker/Tasks/WriteTargetRegister.hpp"
using namespace Bloom::Widgets;
using namespace Bloom::Exceptions;
using Bloom::Targets::TargetRegisterDescriptor;
using Bloom::Targets::TargetRegisterDescriptors;
using Bloom::Targets::TargetRegisterType;
TargetRegisterInspectorWindow::TargetRegisterInspectorWindow(
const Targets::TargetRegisterDescriptor& registerDescriptor,
InsightWorker& insightWorker,
std::optional<Targets::TargetMemoryBuffer> registerValue
):
registerDescriptor(registerDescriptor),
insightWorker(insightWorker),
registerValue(registerValue.value_or(Targets::TargetMemoryBuffer(registerDescriptor.size, 0))) {
auto registerName = QString::fromStdString(this->registerDescriptor.name.value()).toUpper();
this->setObjectName("target-register-inspector-window");
this->setWindowTitle("Inspect Register");
auto windowUiFile = QFile(
QString::fromStdString(Paths::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/UiFiles/TargetRegisterInspectorWindow.ui"
)
);
auto windowStylesheet = QFile(QString::fromStdString(
Paths::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Stylesheets/TargetRegisterInspectorWindow.qss"
)
);
if (!windowUiFile.open(QFile::ReadOnly)) {
throw Exception("Failed to open TargetRegisterInspectorWindow UI file");
}
if (!windowStylesheet.open(QFile::ReadOnly)) {
throw Exception("Failed to open TargetRegisterInspectorWindow stylesheet file");
}
auto windowSize = QSize(
840,
static_cast<int>(440 + ((BitsetWidget::HEIGHT + 20)
* std::ceil(static_cast<float>(this->registerValue.size()) / 2)))
);
auto containerMargins = QMargins(15, 30, 15, 10);
this->setStyleSheet(windowStylesheet.readAll());
this->setFixedSize(windowSize);
auto uiLoader = UiLoader(this);
this->container = uiLoader.load(&windowUiFile, this);
this->container->setFixedSize(this->size());
this->container->setContentsMargins(containerMargins);
this->registerNameLabel = this->container->findChild<QLabel*>("register-name");
this->registerDescriptionLabel = this->container->findChild<QLabel*>("register-description");
this->contentContainer = this->container->findChild<QWidget*>("content-container");
this->registerValueContainer = this->container->findChild<QWidget*>("register-value-container");
this->registerValueTextInput = this->container->findChild<QLineEdit*>("register-value-text-input");
this->registerValueBitsetWidgetContainer = this->container->findChild<QWidget*>("register-value-bitset-widget-container");
this->closeButton = this->container->findChild<QPushButton*>("close-btn");
this->refreshValueButton = this->container->findChild<QPushButton*>("refresh-value-btn");
this->applyButton = this->container->findChild<QPushButton*>("apply-btn");
this->registerNameLabel->setText(registerName);
if (this->registerDescriptor.description.has_value()) {
this->registerDescriptionLabel->setText(QString::fromStdString(this->registerDescriptor.description.value()));
this->registerDescriptionLabel->setVisible(true);
}
this->registerHistoryWidget = new RegisterHistoryWidget(
this->registerDescriptor,
this->registerValue,
insightWorker,
this->contentContainer
);
auto contentLayout = this->container->findChild<QHBoxLayout*>("content-layout");
contentLayout->insertWidget(0, this->registerHistoryWidget, 0, Qt::AlignmentFlag::AlignTop);
auto registerDetailsContainer = this->container->findChild<QWidget*>("register-details-container");
auto registerValueContainer = this->container->findChild<QWidget*>("register-value-container");
registerValueContainer->setContentsMargins(15, 15, 15, 15);
registerDetailsContainer->setContentsMargins(15, 15, 15, 15);
auto registerDetailsNameInput = registerDetailsContainer->findChild<QLineEdit*>("register-details-name-input");
auto registerDetailsSizeInput = registerDetailsContainer->findChild<QLineEdit*>("register-details-size-input");
auto registerDetailsStartAddressInput = registerDetailsContainer->findChild<QLineEdit*>(
"register-details-start-address-input"
);
registerDetailsNameInput->setText(registerName);
registerDetailsSizeInput->setText(QString::number(this->registerDescriptor.size));
registerDetailsStartAddressInput->setText(
"0x" + QString::number(this->registerDescriptor.startAddress.value(), 16).toUpper()
);
this->registerValueTextInput->setFixedWidth(BitsetWidget::WIDTH * 2);
auto registerBitsetWidgetLayout = this->registerValueBitsetWidgetContainer->findChild<QVBoxLayout*>(
"register-value-bitset-widget-layout"
);
/*
* Each row of the BitsetWidget container should hold two BitsetWidgets. So we have a horizontal layout nested
* within a vertical layout.
*/
auto bitsetSingleHorizontalLayout = new QHBoxLayout();
bitsetSingleHorizontalLayout->setSpacing(BitWidget::SPACING);
bitsetSingleHorizontalLayout->setContentsMargins(0, 0, 0, 0);
// The register value will be in MSB, which is OK for us as we present the bit widgets in MSB.
auto byteNumber = static_cast<int>(this->registerValue.size() - 1);
for (std::uint32_t registerByteIndex = 0; registerByteIndex < this->registerValue.size(); registerByteIndex++) {
auto bitsetWidget = new BitsetWidget(
byteNumber,
this->registerValue.at(registerByteIndex),
!this->registerDescriptor.writable,
this
);
bitsetSingleHorizontalLayout->addWidget(bitsetWidget, 0, Qt::AlignmentFlag::AlignLeft);
this->connect(
bitsetWidget,
&BitsetWidget::byteChanged,
this,
&TargetRegisterInspectorWindow::updateRegisterValueInputField
);
this->bitsetWidgets.push_back(bitsetWidget);
if (((registerByteIndex + 1) % 2) == 0) {
registerBitsetWidgetLayout->addLayout(bitsetSingleHorizontalLayout);
bitsetSingleHorizontalLayout = new QHBoxLayout();
bitsetSingleHorizontalLayout->setSpacing(BitWidget::SPACING);
bitsetSingleHorizontalLayout->setContentsMargins(0, 0, 0, 0);
}
byteNumber--;
}
registerBitsetWidgetLayout->addLayout(bitsetSingleHorizontalLayout);
registerBitsetWidgetLayout->addStretch(1);
this->registerHistoryWidget->setFixedHeight(this->contentContainer->sizeHint().height());
this->connect(this->closeButton, &QPushButton::clicked, this, &QWidget::close);
this->connect(
this->refreshValueButton,
&QPushButton::clicked,
this,
&TargetRegisterInspectorWindow::refreshRegisterValue
);
this->connect(this->applyButton, &QPushButton::clicked, this, &TargetRegisterInspectorWindow::applyChanges);
this->connect(
this->registerHistoryWidget,
&RegisterHistoryWidget::historyItemSelected,
this,
&TargetRegisterInspectorWindow::onHistoryItemSelected
);
this->connect(
this->registerValueTextInput,
&QLineEdit::textEdited,
this,
&TargetRegisterInspectorWindow::onValueTextInputChanged
);
this->connect(
&insightWorker,
&InsightWorker::targetStateUpdated,
this,
&TargetRegisterInspectorWindow::onTargetStateChanged
);
this->updateRegisterValueInputField();
this->show();
}
bool TargetRegisterInspectorWindow::registerSupported(const Targets::TargetRegisterDescriptor& descriptor) {
return (descriptor.size > 0 && descriptor.size <= 8);
}
void TargetRegisterInspectorWindow::onValueTextInputChanged(QString text) {
if (text.isEmpty()) {
text = "0";
}
bool validHexValue = false;
text.toLongLong(&validHexValue, 16);
if (!validHexValue) {
return;
}
auto registerSize = this->registerDescriptor.size;
auto newValue = QByteArray::fromHex(
text.remove("0x", Qt::CaseInsensitive).toLatin1()
).rightJustified(registerSize, 0).right(registerSize);
assert(newValue.size() >= registerSize);
assert(registerValue.size() == registerSize);
for (std::uint32_t byteIndex = 0; byteIndex < registerSize; byteIndex++) {
this->registerValue.at(byteIndex) = static_cast<unsigned char>(newValue.at(byteIndex));
}
for (auto& bitsetWidget : this->bitsetWidgets) {
bitsetWidget->updateValue();
}
}
void TargetRegisterInspectorWindow::onTargetStateChanged(Targets::TargetState newState) {
using Targets::TargetState;
this->targetState = newState;
}
void TargetRegisterInspectorWindow::onHistoryItemSelected(const Targets::TargetMemoryBuffer& selectedRegisterValue) {
this->registerValue = selectedRegisterValue;
this->updateValue();
if (this->registerHistoryWidget->isCurrentItemSelected()) {
this->refreshValueButton->setVisible(true);
} else {
this->refreshValueButton->setVisible(false);
}
}
void TargetRegisterInspectorWindow::updateRegisterValueInputField() {
auto value = QByteArray(
reinterpret_cast<const char*>(this->registerValue.data()),
static_cast<qsizetype>(this->registerValue.size())
);
this->registerValueTextInput->setText("0x" + QString(value.toHex()).toUpper());
}
void TargetRegisterInspectorWindow::updateRegisterValueBitsetWidgets() {
for (auto& bitsetWidget : this->bitsetWidgets) {
bitsetWidget->updateValue();
}
}
void TargetRegisterInspectorWindow::updateValue() {
this->updateRegisterValueInputField();
this->updateRegisterValueBitsetWidgets();
}
void TargetRegisterInspectorWindow::refreshRegisterValue() {
this->registerValueContainer->setDisabled(true);
auto readTargetRegisterTask = new ReadTargetRegisters({this->registerDescriptor});
this->connect(
readTargetRegisterTask,
&ReadTargetRegisters::targetRegistersRead,
this,
[this] (Targets::TargetRegisters targetRegisters) {
this->registerValueContainer->setDisabled(false);
for (const auto& targetRegister : targetRegisters) {
if (targetRegister.descriptor == this->registerDescriptor) {
this->registerValue = targetRegister.value;
this->registerHistoryWidget->updateCurrentItemValue(this->registerValue);
this->registerHistoryWidget->selectCurrentItem();
}
}
}
);
this->connect(
readTargetRegisterTask,
&InsightWorkerTask::failed,
this,
[this] () {
this->registerValueContainer->setDisabled(false);
}
);
this->insightWorker.queueTask(readTargetRegisterTask);
}
void TargetRegisterInspectorWindow::applyChanges() {
this->applyButton->setDisabled(true);
this->registerValueBitsetWidgetContainer->setDisabled(true);
const auto targetRegister = Targets::TargetRegister(this->registerDescriptor, this->registerValue);
auto writeRegisterTask = new WriteTargetRegister(
targetRegister
);
this->connect(writeRegisterTask, &InsightWorkerTask::completed, this, [this, targetRegister] {
this->registerValueBitsetWidgetContainer->setDisabled(false);
this->applyButton->setDisabled(false);
emit this->insightWorker.targetRegistersWritten(
{targetRegister},
DateTime::currentDateTime()
);
this->registerHistoryWidget->updateCurrentItemValue(targetRegister.value);
this->registerHistoryWidget->selectCurrentItem();
});
this->connect(writeRegisterTask, &InsightWorkerTask::failed, this, [this] {
// TODO: Let the user know the write failed.
this->registerValueBitsetWidgetContainer->setDisabled(false);
this->applyButton->setDisabled(false);
});
this->insightWorker.queueTask(writeRegisterTask);
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <set>
#include <QSize>
#include <QString>
#include <QEvent>
#include <optional>
#include "src/Targets/TargetRegister.hpp"
#include "src/Targets/TargetState.hpp"
#include "BitsetWidget/BitsetWidget.hpp"
#include "RegisterHistoryWidget/RegisterHistoryWidget.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
namespace Bloom::Widgets
{
class TargetRegisterInspectorWindow: public QWidget
{
Q_OBJECT
private:
Targets::TargetRegisterDescriptor registerDescriptor;
Targets::TargetMemoryBuffer registerValue;
InsightWorker& insightWorker;
QWidget* container = nullptr;
QLabel* registerNameLabel = nullptr;
QLabel* registerDescriptionLabel = nullptr;
QWidget* contentContainer = nullptr;
RegisterHistoryWidget* registerHistoryWidget = nullptr;
QWidget* registerValueContainer = nullptr;
QLineEdit* registerValueTextInput = nullptr;
QWidget* registerValueBitsetWidgetContainer = nullptr;
std::vector<BitsetWidget*> bitsetWidgets;
QPushButton* closeButton = nullptr;
QPushButton* refreshValueButton = nullptr;
QPushButton* applyButton = nullptr;
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
private slots:
void onValueTextInputChanged(QString text);
void onTargetStateChanged(Targets::TargetState newState);
void onHistoryItemSelected(const Targets::TargetMemoryBuffer& selectedRegisterValue);
void updateRegisterValueInputField();
void updateRegisterValueBitsetWidgets();
void updateValue();
void refreshRegisterValue();
void applyChanges();
public:
TargetRegisterInspectorWindow(
const Targets::TargetRegisterDescriptor& registerDescriptor,
InsightWorker& insightWorker,
std::optional<Targets::TargetMemoryBuffer> registerValue = std::nullopt
);
static bool registerSupported(const Targets::TargetRegisterDescriptor& descriptor);
};
}

View File

@@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<widget class="QWidget" name="container">
<layout class="QVBoxLayout">
<item alignment="Qt::AlignHCenter">
<widget class="SvgWidget" name="icon">
<property name="svgFilePath">
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Images/icon.svg</string>
</property>
<property name="containerHeight">
<number>46</number>
</property>
<property name="containerWidth">
<number>57</number>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="register-name"/>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLabel" name="register-description">
<property name="visible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer name="vertical-spacer">
<property name="sizeHint">
<size>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item alignment="Qt::AlignLeft">
<layout class="QHBoxLayout" name="content-layout">
<property name="spacing">
<number>20</number>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="content-container">
<layout class="QVBoxLayout" name="content-layout">
<property name="spacing">
<number>20</number>
</property>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="register-details-container">
<layout class="QVBoxLayout">
<property name="spacing">
<number>10</number>
</property>
<item alignment="Qt::AlignLeft">
<layout class="QHBoxLayout" name="register-details-row">
<property name="spacing">
<number>20</number>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="register-details-name-label">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QLineEdit" name="register-details-name-input">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumWidth">
<number>350</number>
</property>
</widget>
</item>
</layout>
</item>
<item alignment="Qt::AlignLeft">
<layout class="QHBoxLayout" name="register-details-row">
<property name="spacing">
<number>20</number>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="register-details-size-label">
<property name="text">
<string>Size (bytes):</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QLineEdit" name="register-details-size-input">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumWidth">
<number>350</number>
</property>
</widget>
</item>
</layout>
</item>
<item alignment="Qt::AlignLeft">
<layout class="QHBoxLayout" name="register-details-row">
<property name="spacing">
<number>20</number>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QLabel" name="register-details-start-address-label">
<property name="text">
<string>Start Address:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QLineEdit" name="register-details-start-address-input">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumWidth">
<number>350</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="register-value-container">
<layout class="QVBoxLayout">
<property name="spacing">
<number>20</number>
</property>
<item alignment="Qt::AlignLeft">
<widget class="QLineEdit" name="register-value-text-input"/>
</item>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="register-value-bitset-widget-container">
<property name="minimumHeight">
<number>60</number>
</property>
<layout class="QVBoxLayout" name="register-value-bitset-widget-layout">
<property name="spacing">
<number>15</number>
</property>
</layout>
</widget>
</item>
<item alignment="Qt::AlignLeft">
<layout class="QHBoxLayout">
<property name="spacing">
<number>15</number>
</property>
<item alignment="Qt::AlignCenter">
<widget class="QPushButton" name="refresh-value-btn">
<property name="text">
<string>Refresh Value</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignCenter">
<spacer name="horizontal-spacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item alignment="Qt::AlignCenter">
<widget class="QPushButton" name="apply-btn">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<spacer name="vertical-spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item alignment="Qt::AlignHCenter">
<spacer name="vertical-spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout">
<property name="spacing">
<number>15</number>
</property>
<item alignment="Qt::AlignLeft">
<spacer name="horizontal-spacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="close-btn">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</ui>

View File

@@ -3,11 +3,9 @@
#include <QApplication>
#include <QClipboard>
#include <QMenu>
#include <utility>
#include <QStyle>
#include "src/Helpers/Paths.hpp"
#include "src/Exceptions/Exception.hpp"
#include "src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp"
@@ -45,6 +43,8 @@ RegisterWidget::RegisterWidget(
this->layout->addWidget(this->valueLabel);
this->layout->addStretch(1);
this->connect(this, &ClickableWidget::doubleClicked, this, &RegisterWidget::openInspectionWindow);
this->connect(this->openInspectionWindowAction, &QAction::triggered, this, &RegisterWidget::openInspectionWindow);
this->connect(this->refreshValueAction, &QAction::triggered, this, &RegisterWidget::refreshValue);
this->connect(this->copyValueNameAction, &QAction::triggered, this, &RegisterWidget::copyName);
this->connect(this->copyValueHexAction, &QAction::triggered, this, &RegisterWidget::copyValueHex);
@@ -88,6 +88,23 @@ void RegisterWidget::clearInlineValue() {
this->valueLabel->clear();
}
void RegisterWidget::openInspectionWindow() {
if (!TargetRegisterInspectorWindow::registerSupported(this->descriptor)) {
return;
}
if (this->inspectWindow == nullptr) {
this->inspectWindow = new TargetRegisterInspectorWindow(
this->descriptor,
this->insightWorker,
this->currentRegister.has_value() ? std::optional(this->currentRegister->value) : std::nullopt
);
} else {
this->inspectWindow->show();
}
}
void RegisterWidget::refreshValue() {
auto readRegisterTask = new ReadTargetRegisters({this->descriptor});
@@ -155,6 +172,7 @@ void RegisterWidget::contextMenuEvent(QContextMenuEvent* event) {
this->setSelected(true);
auto menu = new QMenu(this);
menu->addAction(this->openInspectionWindowAction);
menu->addAction(this->refreshValueAction);
menu->addSeparator();
@@ -167,6 +185,8 @@ void RegisterWidget::contextMenuEvent(QContextMenuEvent* event) {
menu->addMenu(copyMenu);
this->openInspectionWindowAction->setEnabled(TargetRegisterInspectorWindow::registerSupported(this->descriptor));
const auto targetStopped = this->targetState == Targets::TargetState::STOPPED;
const auto targetStoppedAndValuePresent = targetStopped && this->currentRegister.has_value();
this->refreshValueAction->setEnabled(targetStopped);

View File

@@ -12,6 +12,9 @@
#include "src/Insight/InsightWorker/InsightWorker.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgWidget.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.hpp"
namespace Bloom::Widgets
{
class RegisterWidget: public ItemWidget
@@ -25,12 +28,15 @@ namespace Bloom::Widgets
QLabel* valueLabel = new QLabel(this);
// Context-menu actions
QAction* openInspectionWindowAction = new QAction("Inspect", this);
QAction* refreshValueAction = new QAction("Refresh Value", this);
QAction* copyValueNameAction = new QAction("Copy Register Name", this);
QAction* copyValueHexAction = new QAction("Copy Hexadecimal Value", this);
QAction* copyValueDecimalAction = new QAction("Copy Decimal Value", this);
QAction* copyValueBinaryAction = new QAction("Copy Binary Value", this);
TargetRegisterInspectorWindow* inspectWindow = nullptr;
void postSetSelected(bool selected) override;
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
@@ -59,6 +65,7 @@ namespace Bloom::Widgets
void contextMenuEvent(QContextMenuEvent* event) override;
public slots:
void openInspectionWindow();
void refreshValue();
void copyName();
void copyValueHex();

View File

@@ -20,12 +20,14 @@
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui">./Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/UiFiles/AboutWindow.ui">./Insight/UserInterfaces/InsightWindow/UiFiles/AboutWindow.ui</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/UiFiles/TargetRegistersSidePane.ui">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/UiFiles/TargetRegistersSidePane.ui</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/UiFiles/TargetRegisterInspectorWindow.ui">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/UiFiles/TargetRegisterInspectorWindow.ui</file>
<!-- QT UI stylesheets for Insight-->
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss">./Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss">./Insight/UserInterfaces/InsightWindow/Stylesheets/AboutWindow.qss</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss">./Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss">./Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Stylesheets/TargetRegisterInspectorWindow.qss">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Stylesheets/TargetRegisterInspectorWindow.qss</file>
<!-- Icons for Insight-->
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg">./Insight/UserInterfaces/InsightWindow/Images/BloomIcon.svg</file>
@@ -40,5 +42,6 @@
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/target-registers.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/target-registers.svg</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/target-registers-disabled.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/target-registers-disabled.svg</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/search-registers.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/search-registers.svg</file>
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Images/icon.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Images/icon.svg</file>
</qresource>
</RCC>