Refactored TargetRegistersPane widget to improve memory footprint

This commit is contained in:
Nav
2023-03-05 23:29:03 +00:00
parent 9cceb8b93c
commit 75cbb5cf67
17 changed files with 723 additions and 697 deletions

View File

@@ -202,25 +202,6 @@ QScrollBar::sub-line:vertical {
border: none;
}
#target-registers-side-pane #register-group-header[selected=true],
#target-registers-side-pane #register-item[selected=true] {
background-color: #355A80;
}
#target-registers-side-pane #register-item #value {
font-size: 13px;
color: #8a8a8d;
font-style: italic;
}
#target-registers-side-pane #register-item[selected=false] #value[changed=true] {
color: #547fba;
}
#target-registers-side-pane #register-item[selected=true] #value[changed=true] {
color: #8a8a8d;
}
/* Bottom menu bar & panels */
#bottom-menu-bar {
background-color: transparent;

View File

@@ -27,12 +27,11 @@ namespace Bloom::Widgets
TargetRegisterInspectorWindow::TargetRegisterInspectorWindow(
const Targets::TargetRegisterDescriptor& registerDescriptor,
TargetState currentTargetState,
const std::optional<Targets::TargetMemoryBuffer>& registerValue,
QWidget* parent
)
: QWidget(parent)
, registerDescriptor(registerDescriptor)
, registerValue(registerValue.value_or(Targets::TargetMemoryBuffer(registerDescriptor.size, 0)))
, registerValue(Targets::TargetMemoryBuffer(registerDescriptor.size, 0))
{
this->setWindowFlag(Qt::Window);
auto registerName = QString::fromStdString(this->registerDescriptor.name.value()).toUpper();

View File

@@ -27,7 +27,6 @@ namespace Bloom::Widgets
TargetRegisterInspectorWindow(
const Targets::TargetRegisterDescriptor& registerDescriptor,
Targets::TargetState currentTargetState,
const std::optional<Targets::TargetMemoryBuffer>& registerValue = std::nullopt,
QWidget* parent = nullptr
);

View File

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

View File

@@ -1,23 +0,0 @@
#pragma once
#include "../ClickableWidget.hpp"
namespace Bloom::Widgets
{
class ItemWidget: public ClickableWidget
{
Q_OBJECT
public:
ItemWidget(QWidget *parent);
public slots:
void setSelected(bool selected);
signals:
void selected(ItemWidget*);
protected:
virtual void postSetSelected(bool selected) {};
};
}

View File

@@ -0,0 +1,166 @@
#include "RegisterGroupItem.hpp"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QSvgRenderer>
#include <QPainter>
#include <QString>
#include <QRect>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListScene.hpp"
#include "src/Services/PathService.hpp"
namespace Bloom::Widgets
{
RegisterGroupItem::RegisterGroupItem(
QString name,
const std::set<Targets::TargetRegisterDescriptor>& registerDescriptors,
std::unordered_map<Targets::TargetRegisterDescriptor, RegisterItem*>& registerItemsByDescriptor
)
: groupName(name)
{
for (const auto& registerDescriptor : registerDescriptors) {
auto* registerItem = new RegisterItem(registerDescriptor);
registerItem->setParentItem(this);
registerItem->setVisible(this->isExpanded());
this->registerItems.push_back(registerItem);
registerItemsByDescriptor.insert(std::pair(registerDescriptor, registerItem));
}
if (!RegisterGroupItem::registerGroupIconPixmap.has_value()) {
this->generatePixmaps();
}
}
void RegisterGroupItem::setExpanded(bool expanded) {
if (expanded == this->expanded) {
return;
}
this->expanded = expanded;
for (auto& registerItem : this->registerItems) {
registerItem->setVisible(this->expanded);
}
}
void RegisterGroupItem::refreshGeometry() {
const auto groupWidth = this->size.width();
const auto startXPosition = 0;
auto startYPosition = RegisterGroupItem::GROUP_LIST_ITEM_HEIGHT;
if (this->isExpanded()) {
for (auto& registerItem : this->registerItems) {
if (!registerItem->isVisible() || registerItem->excluded) {
continue;
}
registerItem->size.setWidth(groupWidth);
registerItem->setPos(startXPosition, startYPosition);
registerItem->onGeometryChanged();
startYPosition += registerItem->size.height();
}
}
this->size.setHeight(startYPosition);
}
void RegisterGroupItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
static constexpr auto selectedBackgroundColor = QColor(0x35, 0x5A, 0x80);
static constexpr auto itemLeftPadding = 3;
static constexpr auto itemTopPadding = 4;
static constexpr auto iconLeftMargin = 5;
static constexpr auto labelLeftMargin = 6;
static const auto nameLabelFont = QFont("'Ubuntu', sans-serif", 11);
static constexpr auto nameLabelFontColor = QColor(0xAF, 0xB1, 0xB3);
if (this->selected) {
painter->setBrush(selectedBackgroundColor);
painter->setPen(Qt::PenStyle::NoPen);
painter->drawRect(0, 0, this->size.width(), RegisterGroupItem::GROUP_LIST_ITEM_HEIGHT);
}
const auto& collapsedArrowIconPixmap = *(RegisterGroupItem::collapsedArrowIconPixmap);
const auto& expandedArrowIconPixmap = *(RegisterGroupItem::expandedArrowIconPixmap);
const auto& registerGroupIconPixmap = *(RegisterGroupItem::registerGroupIconPixmap);
const QPixmap& arrowPixmap = this->isExpanded() ? expandedArrowIconPixmap : collapsedArrowIconPixmap;
painter->drawPixmap(itemLeftPadding, itemTopPadding + 2, arrowPixmap);
painter->drawPixmap(
arrowPixmap.width() + itemLeftPadding + iconLeftMargin,
itemTopPadding + 1,
registerGroupIconPixmap
);
painter->setFont(nameLabelFont);
painter->setPen(nameLabelFontColor);
const auto fontMetrics = painter->fontMetrics();
const auto nameLabelSize = fontMetrics.size(Qt::TextSingleLine, this->groupName);
const auto nameLabelRect = QRect(
arrowPixmap.width() + itemLeftPadding + registerGroupIconPixmap.width() + itemLeftPadding + labelLeftMargin,
itemTopPadding,
nameLabelSize.width(),
nameLabelSize.height()
);
painter->drawText(nameLabelRect, Qt::AlignLeft, this->groupName);
}
void RegisterGroupItem::generatePixmaps() const {
auto svgRenderer = QSvgRenderer();
{
svgRenderer.load(QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/register-group.svg"
));
auto registerGroupIconPixmap = QPixmap(svgRenderer.defaultSize());
registerGroupIconPixmap.fill(Qt::GlobalColor::transparent);
auto painter = QPainter(&registerGroupIconPixmap);
svgRenderer.render(&painter);
RegisterGroupItem::registerGroupIconPixmap = registerGroupIconPixmap;
}
{
svgRenderer.load(QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/arrow.svg"
));
const auto iconSize = svgRenderer.defaultSize();
auto arrowIconPixmap = QPixmap(iconSize);
arrowIconPixmap.fill(Qt::GlobalColor::transparent);
auto painter = QPainter(&arrowIconPixmap);
svgRenderer.render(&painter);
RegisterGroupItem::collapsedArrowIconPixmap = arrowIconPixmap;
painter.translate(
std::ceil(static_cast<float>(iconSize.width() / 2)),
std::ceil(static_cast<float>(iconSize.height() / 2))
);
painter.rotate(90);
painter.translate(
-std::ceil(static_cast<float>(iconSize.width() / 2)),
-std::ceil(static_cast<float>(iconSize.height() / 2))
);
arrowIconPixmap.fill(Qt::GlobalColor::transparent);
svgRenderer.render(&painter);
RegisterGroupItem::expandedArrowIconPixmap = arrowIconPixmap;
}
}
}

View File

@@ -0,0 +1,52 @@
#pragma once
#include <QString>
#include <unordered_map>
#include <vector>
#include <QPixmap>
#include <optional>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListItem.hpp"
#include "RegisterItem.hpp"
#include "src/Targets/TargetRegister.hpp"
namespace Bloom::Widgets
{
class RegisterGroupItem: public ListItem
{
public:
const QString groupName;
std::vector<RegisterItem*> registerItems;
explicit RegisterGroupItem(
QString name,
const std::set<Targets::TargetRegisterDescriptor>& registerDescriptors,
std::unordered_map<Targets::TargetRegisterDescriptor, RegisterItem*>& registerItemsByDescriptor
);
bool isExpanded() const {
return this->expanded;
}
void setExpanded(bool expanded);
void onGeometryChanged() override {
return this->refreshGeometry();
}
void refreshGeometry();
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
static constexpr int GROUP_LIST_ITEM_HEIGHT = 25;
static inline std::optional<QPixmap> registerGroupIconPixmap = std::nullopt;
static inline std::optional<QPixmap> collapsedArrowIconPixmap = std::nullopt;
static inline std::optional<QPixmap> expandedArrowIconPixmap = std::nullopt;
bool expanded = false;
void generatePixmaps() const;
};
}

View File

@@ -1,152 +0,0 @@
#include "RegisterGroupWidget.hpp"
#include <QUiLoader>
#include <QStyle>
#include <utility>
#include "RegisterWidget.hpp"
#include "src/Services/PathService.hpp"
namespace Bloom::Widgets
{
using Bloom::Targets::TargetRegisterDescriptor;
RegisterGroupWidget::RegisterGroupWidget(
QString name,
const std::set<TargetRegisterDescriptor>& registerDescriptors,
TargetRegistersPaneWidget* parent
)
: ItemWidget(parent)
, name(std::move(name))
{
this->setObjectName(this->name);
this->headerWidget->setObjectName("register-group-header");
this->headerWidget->setFixedHeight(25);
auto* headerLayout = new QHBoxLayout(this->headerWidget);
headerLayout->setContentsMargins(5, 0, 0, 0);
this->label->setText(this->name);
this->arrowIcon->setObjectName("arrow-icon");
auto static arrowIconPath = QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/arrow.svg"
);
this->arrowIcon->setSvgFilePath(arrowIconPath);
this->arrowIcon->setContainerHeight(15);
this->arrowIcon->setContainerWidth(14);
this->registerGroupIcon->setObjectName("register-group-icon");
auto static registerIconPath = QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/register-group.svg"
);
this->registerGroupIcon->setSvgFilePath(registerIconPath);
this->registerGroupIcon->setContainerHeight(15);
this->registerGroupIcon->setContainerWidth(15);
headerLayout->addWidget(this->arrowIcon);
headerLayout->addWidget(this->registerGroupIcon);
headerLayout->addWidget(this->label);
auto* bodyLayout = new QVBoxLayout(this->bodyWidget);
bodyLayout->setContentsMargins(0, 0,0,0);
bodyLayout->setSpacing(0);
for (const auto& descriptor : registerDescriptors) {
if (!descriptor.name.has_value()) {
continue;
}
if (!descriptor.readable) {
continue;
}
auto* registerWidget = new RegisterWidget(descriptor, this->bodyWidget);
bodyLayout->addWidget(registerWidget, 0, Qt::AlignmentFlag::AlignTop);
QObject::connect(
registerWidget,
&ItemWidget::selected,
parent,
&TargetRegistersPaneWidget::onItemSelectionChange
);
this->registerWidgets.insert(registerWidget);
this->registerWidgetsMappedByDescriptor.insert(std::pair(descriptor, registerWidget));
}
bodyLayout->addStretch(1);
this->layout->setContentsMargins(0,0,0,0);
this->layout->setSpacing(0);
this->layout->addWidget(this->headerWidget, 0, Qt::AlignmentFlag::AlignTop);
this->layout->addWidget(this->bodyWidget, 0, Qt::AlignmentFlag::AlignTop);
this->layout->addStretch(1);
this->collapse();
QObject::connect(this->headerWidget, &ClickableWidget::doubleClicked, [this] {
if (this->collapsed) {
this->expand();
} else {
this->collapse();
}
});
QObject::connect(
this->headerWidget,
&ItemWidget::selected,
parent,
&TargetRegistersPaneWidget::onItemSelectionChange
);
}
void RegisterGroupWidget::collapse() {
this->arrowIcon->setAngle(0);
this->bodyWidget->setVisible(false);
this->collapsed = true;
}
void RegisterGroupWidget::expand() {
this->arrowIcon->setAngle(90);
this->bodyWidget->setVisible(true);
this->collapsed = false;
}
void RegisterGroupWidget::setAllRegistersVisible(bool visible) {
for (const auto& registerWidget : this->registerWidgets) {
registerWidget->setVisible(visible);
}
}
void RegisterGroupWidget::filterRegisters(const QString& keyword) {
int matchingWidgetCount = 0;
for (const auto& registerWidget : this->registerWidgets) {
if (keyword.isEmpty() || (registerWidget->searchKeywords.contains(keyword, Qt::CaseInsensitive))) {
matchingWidgetCount++;
registerWidget->setVisible(true);
} else {
registerWidget->setVisible(false);
}
}
if (matchingWidgetCount == 0) {
this->collapse();
this->setVisible(false);
} else {
this->setVisible(true);
if (!keyword.isEmpty()) {
this->expand();
} else {
this->collapse();
}
}
}
}

View File

@@ -1,50 +0,0 @@
#pragma once
#include <QWidget>
#include <unordered_set>
#include <QVBoxLayout>
#include <QSize>
#include <set>
#include "TargetRegistersPaneWidget.hpp"
#include "ItemWidget.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgWidget.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/Label.hpp"
namespace Bloom::Widgets
{
class RegisterWidget;
class RegisterGroupWidget: public ItemWidget
{
Q_OBJECT
public:
QString name;
bool collapsed = true;
std::set<RegisterWidget*> registerWidgets;
std::map<Targets::TargetRegisterDescriptor, RegisterWidget*> registerWidgetsMappedByDescriptor;
RegisterGroupWidget(
QString name,
const std::set<Targets::TargetRegisterDescriptor>& registerDescriptors,
TargetRegistersPaneWidget* parent
);
void collapse();
void expand();
void setAllRegistersVisible(bool visible);
void filterRegisters(const QString& keyword);
private:
QVBoxLayout* layout = new QVBoxLayout(this);
ItemWidget* headerWidget = new ItemWidget(this);
SvgWidget* arrowIcon = new SvgWidget(this->headerWidget);
SvgWidget* registerGroupIcon = new SvgWidget(this->headerWidget);
Label* label = new Label(this->headerWidget);
QWidget* bodyWidget = new QWidget(this);
};
}

View File

@@ -0,0 +1,120 @@
#include "RegisterItem.hpp"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QSvgRenderer>
#include <QPainter>
#include <QString>
#include <QRect>
#include "src/Services/PathService.hpp"
namespace Bloom::Widgets
{
RegisterItem::RegisterItem(
const Targets::TargetRegisterDescriptor& registerDescriptor
)
: registerDescriptor(registerDescriptor)
, registerName(QString::fromStdString(registerDescriptor.name.value()).toUpper())
, searchKeywords(this->registerName + " " + QString::fromStdString(registerDescriptor.description.value_or("")))
{
this->size = QSize(0, RegisterItem::HEIGHT);
if (!RegisterItem::registerIconPixmap.has_value()) {
this->generatePixmaps();
}
}
void RegisterItem::setValue(const Targets::TargetMemoryBuffer& value) {
const auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(value.data()),
static_cast<qsizetype>(value.size())
);
auto hexValueByteArray = valueByteArray.toHex();
this->valueText = ": 0x" + QString(hexValueByteArray).toUpper()
+ " | " + QString::number(hexValueByteArray.toUInt(nullptr, 16));
if (value.size() == 1 && value[0] >= 32 && value[0] <= 126) {
this->valueText += " | '" + QString(valueByteArray) + "'";
}
}
void RegisterItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
if (this->excluded) {
return;
}
static constexpr auto selectedBackgroundColor = QColor(0x35, 0x5A, 0x80);
static constexpr auto itemLeftPadding = 41;
static constexpr auto itemTopPadding = 4;
static constexpr auto labelLeftMargin = 5;
static const auto nameLabelFont = QFont("'Ubuntu', sans-serif", 11);
static constexpr auto nameLabelFontColor = QColor(0xAF, 0xB1, 0xB3);
static const auto valueLabelFont = QFont("'Ubuntu', sans-serif", 10, -1, true);
static constexpr auto valueLabelFontColor = QColor(0x8A, 0x8A, 0x8D);
static constexpr auto highlightedValueLabelFontColor = QColor(0x54, 0x7F, 0xBA);
if (this->selected) {
painter->setBrush(selectedBackgroundColor);
painter->setPen(Qt::PenStyle::NoPen);
painter->drawRect(QRect(QPoint(0, 0), this->size));
}
const auto& registerIconPixmap = *(RegisterItem::registerIconPixmap);
painter->drawPixmap(itemLeftPadding, itemTopPadding + 4, registerIconPixmap);
painter->setFont(nameLabelFont);
painter->setPen(nameLabelFontColor);
const auto fontMetrics = painter->fontMetrics();
const auto nameLabelSize = fontMetrics.size(Qt::TextSingleLine, this->registerName);
const auto nameLabelRect = QRect(
registerIconPixmap.width() + itemLeftPadding + labelLeftMargin,
itemTopPadding,
nameLabelSize.width(),
nameLabelSize.height()
);
painter->drawText(nameLabelRect, Qt::AlignLeft, this->registerName);
if (!this->valueText.isEmpty()) {
painter->setFont(valueLabelFont);
painter->setPen(
this->valueChanged && !this->selected ? highlightedValueLabelFontColor : valueLabelFontColor
);
const auto fontMetrics = painter->fontMetrics();
const auto valueLabelSize = fontMetrics.size(Qt::TextSingleLine, this->valueText);
const auto valueLabelRect = QRect(
nameLabelRect.right() + labelLeftMargin,
itemTopPadding + 1,
valueLabelSize.width(),
valueLabelSize.height()
);
painter->drawText(valueLabelRect, Qt::AlignLeft, this->valueText);
}
}
void RegisterItem::generatePixmaps() const {
auto svgRegisterIconRenderer = QSvgRenderer(QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/register.svg"
));
const auto registerIconSize = svgRegisterIconRenderer.defaultSize();
auto registerIconPixmap = QPixmap(registerIconSize);
registerIconPixmap.fill(Qt::GlobalColor::transparent);
auto painter = QPainter(&registerIconPixmap);
svgRegisterIconRenderer.render(&painter);
RegisterItem::registerIconPixmap = registerIconPixmap;
}
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <QString>
#include <QPixmap>
#include <optional>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListItem.hpp"
#include "src/Targets/TargetRegister.hpp"
namespace Bloom::Widgets
{
class RegisterItem: public ListItem
{
public:
const Targets::TargetRegisterDescriptor registerDescriptor;
const QString registerName;
const QString searchKeywords;
bool excluded = false;
bool valueChanged = false;
explicit RegisterItem(
const Targets::TargetRegisterDescriptor& registerDescriptor
);
void setValue(const Targets::TargetMemoryBuffer& value);
void clearValue() {
this->valueText.clear();
}
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
static constexpr int HEIGHT = 25;
static inline std::optional<QPixmap> registerIconPixmap = std::nullopt;
QString valueText = "";
void generatePixmaps() const;
};
}

View File

@@ -1,232 +0,0 @@
#include "RegisterWidget.hpp"
#include <QApplication>
#include <QClipboard>
#include <QMenu>
#include <QStyle>
#include "src/Services/PathService.hpp"
#include "src/Insight/InsightSignals.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
#include "src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp"
namespace Bloom::Widgets
{
using namespace Bloom::Exceptions;
using Bloom::Targets::TargetRegisterDescriptor;
RegisterWidget::RegisterWidget(
TargetRegisterDescriptor descriptor,
QWidget *parent
)
: ItemWidget(parent)
, descriptor(std::move(descriptor))
, searchKeywords(QString::fromStdString(
this->descriptor.name.value_or("") + this->descriptor.description.value_or("")
).toLower())
{
this->setObjectName("register-item");
this->setFixedHeight(25);
this->nameLabel->setText(QString::fromStdString(this->descriptor.name.value()).toUpper());
this->valueLabel->setObjectName("value");
this->registerIcon->setObjectName("register-icon");
auto static registerIconPath = QString::fromStdString(
Services::PathService::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/register.svg"
);
this->registerIcon->setSvgFilePath(registerIconPath);
this->registerIcon->setContainerHeight(15);
this->registerIcon->setContainerWidth(15);
this->layout->setContentsMargins(47, 0, 0, 0);
this->layout->setSpacing(0);
this->layout->addWidget(this->registerIcon);
this->layout->addSpacing(7);
this->layout->addWidget(this->nameLabel);
this->layout->addSpacing(5);
this->layout->addWidget(this->valueLabel);
this->layout->addStretch(1);
QObject::connect(this, &ClickableWidget::doubleClicked, this, &RegisterWidget::openInspectionWindow);
QObject::connect(this->openInspectionWindowAction, &QAction::triggered, this, &RegisterWidget::openInspectionWindow);
QObject::connect(this->refreshValueAction, &QAction::triggered, this, &RegisterWidget::refreshValue);
QObject::connect(this->copyValueNameAction, &QAction::triggered, this, &RegisterWidget::copyName);
QObject::connect(this->copyValueHexAction, &QAction::triggered, this, &RegisterWidget::copyValueHex);
QObject::connect(this->copyValueDecimalAction, &QAction::triggered, this, &RegisterWidget::copyValueDecimal);
QObject::connect(this->copyValueBinaryAction, &QAction::triggered, this, &RegisterWidget::copyValueBinary);
QObject::connect(
InsightSignals::instance(),
&InsightSignals::targetStateUpdated,
this,
&RegisterWidget::onTargetStateChange
);
}
void RegisterWidget::setRegisterValue(const Targets::TargetRegister& targetRegister) {
const auto valueChanged = this->currentRegister.has_value()
&& this->currentRegister.value().value != targetRegister.value;
this->currentRegister = targetRegister;
auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(targetRegister.value.data()),
static_cast<qsizetype>(targetRegister.value.size())
);
auto hexValueByteArray = valueByteArray.toHex();
auto registerValue = ": 0x" + QString(hexValueByteArray).toUpper()
+ " | " + QString::number(hexValueByteArray.toUInt(nullptr, 16));
if (targetRegister.value.size() == 1 && targetRegister.value[0] >= 32 && targetRegister.value[0] <= 126) {
registerValue += " | '" + QString(valueByteArray) + "'";
}
this->valueLabel->setProperty("changed", valueChanged);
this->valueLabel->style()->unpolish(this->valueLabel);
this->valueLabel->style()->polish(this->valueLabel);
this->valueLabel->setText(registerValue);
if (this->inspectWindow != nullptr) {
this->inspectWindow->setValue(targetRegister.value);
}
}
void RegisterWidget::clearInlineValue() {
this->valueLabel->clear();
}
void RegisterWidget::contextMenuEvent(QContextMenuEvent* event) {
this->setSelected(true);
auto* menu = new QMenu(this);
menu->addAction(this->openInspectionWindowAction);
menu->addAction(this->refreshValueAction);
menu->addSeparator();
auto* copyMenu = new QMenu("Copy", this);
copyMenu->addAction(this->copyValueNameAction);
copyMenu->addSeparator();
copyMenu->addAction(this->copyValueDecimalAction);
copyMenu->addAction(this->copyValueHexAction);
copyMenu->addAction(this->copyValueBinaryAction);
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);
this->copyValueDecimalAction->setEnabled(targetStoppedAndValuePresent);
this->copyValueHexAction->setEnabled(targetStoppedAndValuePresent);
this->copyValueBinaryAction->setEnabled(targetStoppedAndValuePresent);
menu->exec(event->globalPos());
}
void RegisterWidget::openInspectionWindow() {
if (!TargetRegisterInspectorWindow::registerSupported(this->descriptor)) {
return;
}
if (this->inspectWindow == nullptr) {
this->inspectWindow = new TargetRegisterInspectorWindow(
this->descriptor,
this->targetState,
this->currentRegister.has_value() ? std::optional(this->currentRegister->value)
: std::nullopt,
this
);
} else {
if (this->currentRegister.has_value()) {
this->inspectWindow->setValue(this->currentRegister->value);
}
if (!this->inspectWindow->isVisible()) {
this->inspectWindow->show();
} else {
this->inspectWindow->activateWindow();
}
}
}
void RegisterWidget::refreshValue() {
auto* readRegisterTask = new ReadTargetRegisters({this->descriptor});
QObject::connect(
readRegisterTask,
&ReadTargetRegisters::targetRegistersRead,
this,
[this] (Targets::TargetRegisters registers) {
for (const auto& targetRegister : registers) {
if (targetRegister.descriptor == this->descriptor) {
this->setRegisterValue(targetRegister);
}
}
}
);
InsightWorker::queueTask(readRegisterTask);
}
void RegisterWidget::copyName() {
if (this->nameLabel != nullptr) {
QApplication::clipboard()->setText(this->nameLabel->text());
}
}
void RegisterWidget::copyValueHex() {
if (this->currentRegister.has_value()) {
auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(this->currentRegister.value().value.data()),
static_cast<qsizetype>(this->currentRegister.value().value.size())
).toHex();
QApplication::clipboard()->setText(QString(valueByteArray).toUpper());
}
}
void RegisterWidget::copyValueDecimal() {
if (this->currentRegister.has_value()) {
auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(this->currentRegister.value().value.data()),
static_cast<qsizetype>(this->currentRegister.value().value.size())
).toHex();
QApplication::clipboard()->setText(QString::number(valueByteArray.toUInt(nullptr, 16)));
}
}
void RegisterWidget::copyValueBinary() {
if (this->currentRegister.has_value()) {
const auto registerValueSize = static_cast<qsizetype>(this->currentRegister.value().size());
auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(this->currentRegister.value().value.data()),
registerValueSize
).toHex();
auto bitString = QString::number(valueByteArray.toUInt(nullptr, 16), 2);
if (bitString.size() < (registerValueSize * 8)) {
bitString = bitString.rightJustified((registerValueSize * 8), '0');
}
QApplication::clipboard()->setText(bitString);
}
}
void RegisterWidget::postSetSelected(bool selected) {
auto valueLabelStyle = this->valueLabel->style();
valueLabelStyle->unpolish(this->valueLabel);
valueLabelStyle->polish(this->valueLabel);
}
void RegisterWidget::onTargetStateChange(Targets::TargetState newState) {
this->targetState = newState;
}
}

View File

@@ -1,76 +0,0 @@
#pragma once
#include <QWidget>
#include <unordered_set>
#include <optional>
#include <QHBoxLayout>
#include <QAction>
#include <QSize>
#include <QEvent>
#include <QString>
#include "ItemWidget.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/Label.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
{
Q_OBJECT
public:
Targets::TargetRegisterDescriptor descriptor;
QString searchKeywords;
std::optional<Targets::TargetRegister> currentRegister;
RegisterWidget(
Targets::TargetRegisterDescriptor descriptor,
QWidget *parent
);
[[nodiscard]] QSize minimumSizeHint() const override {
auto size = QSize(this->parentWidget()->width(), 25);
return size;
}
void setRegisterValue(const Targets::TargetRegister& targetRegister);
void clearInlineValue();
void contextMenuEvent(QContextMenuEvent* event) override;
public slots:
void openInspectionWindow();
void refreshValue();
void copyName();
void copyValueHex();
void copyValueDecimal();
void copyValueBinary();
private:
QHBoxLayout* layout = new QHBoxLayout(this);
SvgWidget* registerIcon = new SvgWidget(this);
Label* nameLabel = new Label(this);
Label* valueLabel = new Label(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;
private slots:
void onTargetStateChange(Targets::TargetState newState);
};
}

View File

@@ -1,13 +1,14 @@
#include "TargetRegistersPaneWidget.hpp"
#include <QVBoxLayout>
#include <QMenu>
#include <QClipboard>
#include <QApplication>
#include <set>
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
#include "src/Insight/InsightSignals.hpp"
#include "src/Insight/InsightWorker/InsightWorker.hpp"
#include "RegisterGroupWidget.hpp"
#include "RegisterWidget.hpp"
#include "src/Services/PathService.hpp"
#include "src/Exceptions/Exception.hpp"
@@ -47,6 +48,7 @@ namespace Bloom::Widgets
auto uiLoader = UiLoader(this);
this->container = uiLoader.load(&targetRegistersPaneUiFile, this);
this->container->setFixedSize(parent->width(), parent->maximumHeight());
auto* containerLayout = this->container->findChild<QVBoxLayout*>();
auto* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
@@ -70,48 +72,126 @@ namespace Bloom::Widgets
this->filterRegisters(this->searchInput->text());
});
this->itemScrollArea = this->container->findChild<QScrollArea*>("item-scroll-area");
const auto& registerDescriptors = targetDescriptor.registerDescriptorsByType;
this->itemContainer = this->container->findChild<QWidget*>("item-container");
auto itemLayout = this->itemContainer->findChild<QVBoxLayout*>();
auto registerDescriptorsByGroupName = std::map<QString, std::set<TargetRegisterDescriptor>>({
{
"CPU General Purpose",
std::set<TargetRegisterDescriptor>(
registerDescriptors.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).begin(),
registerDescriptors.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).end()
)
}
});
auto& registerDescriptors = targetDescriptor.registerDescriptorsByType;
this->renderedDescriptors = std::set<TargetRegisterDescriptor>(
registerDescriptors.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).begin(),
registerDescriptors.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).end()
);
auto* generalPurposeRegisterGroupWidget = new RegisterGroupWidget(
"CPU General Purpose",
this->renderedDescriptors,
this
);
itemLayout->addWidget(generalPurposeRegisterGroupWidget, 0, Qt::AlignTop);
this->registerGroupWidgets.insert(generalPurposeRegisterGroupWidget);
auto registerDescriptorsByGroupName = std::map<std::string, std::set<TargetRegisterDescriptor>>();
for (const auto& registerDescriptor : registerDescriptors.at(TargetRegisterType::OTHER)) {
registerDescriptorsByGroupName[registerDescriptor.groupName.value_or("other")].insert(registerDescriptor);
const auto groupName = QString::fromStdString(registerDescriptor.groupName.value_or("other")).toUpper();
registerDescriptorsByGroupName[groupName].insert(registerDescriptor);
}
for (const auto& registerDescriptor : registerDescriptors.at(TargetRegisterType::PORT_REGISTER)) {
registerDescriptorsByGroupName[registerDescriptor.groupName.value_or("other")].insert(registerDescriptor);
const auto groupName = QString::fromStdString(registerDescriptor.groupName.value_or("other")).toUpper();
registerDescriptorsByGroupName[groupName].insert(registerDescriptor);
}
for (const auto& [groupName, registerDescriptors] : registerDescriptorsByGroupName) {
auto* registerGroupWidget = new RegisterGroupWidget(
QString::fromStdString(groupName).toUpper(),
this->registerGroupItems.emplace_back(new RegisterGroupItem(
groupName,
registerDescriptors,
this
);
this->registerItemsByDescriptor
));
itemLayout->addWidget(registerGroupWidget, 0, Qt::AlignTop);
this->registerGroupWidgets.insert(registerGroupWidget);
this->renderedDescriptors.insert(registerDescriptors.begin(), registerDescriptors.end());
this->registerDescriptors.insert(registerDescriptors.begin(), registerDescriptors.end());
}
itemLayout->addStretch(1);
this->registerListView = new ListView(
std::vector<ListItem*>(this->registerGroupItems.begin(), this->registerGroupItems.end()),
this
);
this->registerListScene = this->registerListView->listScene();
containerLayout->addWidget(this->registerListView);
QObject::connect(
this->registerListScene,
&ListScene::itemDoubleClicked,
this,
&TargetRegistersPaneWidget::onItemDoubleClicked
);
QObject::connect(
this->registerListScene,
&ListScene::itemContextMenu,
this,
&TargetRegistersPaneWidget::onItemContextMenu
);
QObject::connect(
this->openInspectionWindowAction,
&QAction::triggered,
this,
[this] {
if (this->contextMenuRegisterItem != nullptr) {
this->openInspectionWindow(this->contextMenuRegisterItem->registerDescriptor);
}
}
);
QObject::connect(
this->refreshValueAction,
&QAction::triggered,
this,
[this] {
if (this->contextMenuRegisterItem != nullptr) {
this->refreshRegisterValues(this->contextMenuRegisterItem->registerDescriptor, std::nullopt);
}
}
);
QObject::connect(
this->copyNameAction,
&QAction::triggered,
this,
[this] {
if (this->contextMenuRegisterItem != nullptr) {
this->copyRegisterName(this->contextMenuRegisterItem->registerDescriptor);
}
}
);
QObject::connect(
this->copyValueHexAction,
&QAction::triggered,
this,
[this] {
if (this->contextMenuRegisterItem != nullptr) {
this->copyRegisterValueHex(this->contextMenuRegisterItem->registerDescriptor);
}
}
);
QObject::connect(
this->copyValueDecimalAction,
&QAction::triggered,
this,
[this] {
if (this->contextMenuRegisterItem != nullptr) {
this->copyRegisterValueDecimal(this->contextMenuRegisterItem->registerDescriptor);
}
}
);
QObject::connect(
this->copyValueBinaryAction,
&QAction::triggered,
this,
[this] {
if (this->contextMenuRegisterItem != nullptr) {
this->copyRegisterValueBinary(this->contextMenuRegisterItem->registerDescriptor);
}
}
);
auto* insightSignals = InsightSignals::instance();
@@ -142,45 +222,56 @@ namespace Bloom::Widgets
}
void TargetRegistersPaneWidget::filterRegisters(const QString& keyword) {
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
// If the group name matches the keyword, then don't bother iterating through all the register widgets
if (keyword.isEmpty() || registerGroupWidget->name.contains(keyword, Qt::CaseInsensitive)) {
registerGroupWidget->setVisible(true);
registerGroupWidget->setAllRegistersVisible(true);
for (const auto& groupItem : this->registerGroupItems) {
auto visibleItems = std::uint32_t{0};
auto displayEntireGroup = keyword.isEmpty() || groupItem->groupName.contains(keyword, Qt::CaseInsensitive);
if (!keyword.isEmpty()) {
registerGroupWidget->expand();
for (auto& registerItem : groupItem->registerItems) {
registerItem->excluded = !displayEntireGroup
&& !registerItem->searchKeywords.contains(keyword, Qt::CaseInsensitive);
} else {
registerGroupWidget->collapse();
if (!registerItem->excluded) {
++visibleItems;
}
} else {
registerGroupWidget->filterRegisters(keyword);
}
groupItem->setVisible(visibleItems > 0 || keyword.isEmpty());
groupItem->setExpanded(visibleItems > 0 && !keyword.isEmpty());
}
this->registerListScene->refreshGeometry();
}
void TargetRegistersPaneWidget::collapseAllRegisterGroups() {
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
registerGroupWidget->collapse();
for (auto& registerGroupItem : this->registerGroupItems) {
registerGroupItem->setExpanded(false);
}
this->registerListScene->refreshGeometry();
}
void TargetRegistersPaneWidget::expandAllRegisterGroups() {
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
registerGroupWidget->expand();
for (auto& registerGroupItem : this->registerGroupItems) {
registerGroupItem->setExpanded(true);
}
this->registerListScene->refreshGeometry();
}
void TargetRegistersPaneWidget::refreshRegisterValues(std::optional<std::function<void(void)>> callback) {
auto& descriptors = this->renderedDescriptors;
if (descriptors.empty()) {
void TargetRegistersPaneWidget::refreshRegisterValues(
std::optional<Targets::TargetRegisterDescriptor> registerDescriptor,
std::optional<std::function<void(void)>> callback
) {
if (!registerDescriptor.has_value() && this->registerDescriptors.empty()) {
return;
}
auto* readRegisterTask = new ReadTargetRegisters(descriptors);
auto* readRegisterTask = new ReadTargetRegisters(
registerDescriptor.has_value()
? Targets::TargetRegisterDescriptors({*registerDescriptor})
: this->registerDescriptors
);
QObject::connect(
readRegisterTask,
&ReadTargetRegisters::targetRegistersRead,
@@ -200,17 +291,6 @@ namespace Bloom::Widgets
InsightWorker::queueTask(readRegisterTask);
}
void TargetRegistersPaneWidget::onItemSelectionChange(ItemWidget* newlySelectedWidget) {
// Only one item in the target registers pane can be selected at any given time.
if (this->selectedItemWidget != newlySelectedWidget) {
if (this->selectedItemWidget != nullptr) {
this->selectedItemWidget->setSelected(false);
}
this->selectedItemWidget = newlySelectedWidget;
}
}
void TargetRegistersPaneWidget::resizeEvent(QResizeEvent* event) {
const auto parentSize = this->parentPanel->size();
const auto width = parentSize.width() - 1;
@@ -221,11 +301,65 @@ namespace Bloom::Widgets
* In order to avoid the panel resize handle overlapping the scroll bar handle, we reduce the size of
* the scroll area.
*/
this->itemScrollArea->setFixedWidth(width - this->parentPanel->getHandleSize());
this->registerListView->setFixedWidth(width - this->parentPanel->getHandleSize());
PaneWidget::resizeEvent(event);
}
void TargetRegistersPaneWidget::onItemDoubleClicked(ListItem* clickedItem) {
auto* registerGroupItem = dynamic_cast<RegisterGroupItem*>(clickedItem);
if (registerGroupItem != nullptr) {
registerGroupItem->setExpanded(!registerGroupItem->isExpanded());
this->registerListScene->refreshGeometry();
}
auto* registerItem = dynamic_cast<RegisterItem*>(clickedItem);
if (registerItem != nullptr) {
this->openInspectionWindow(registerItem->registerDescriptor);
}
}
void TargetRegistersPaneWidget::onItemContextMenu(ListItem* item, QPoint sourcePosition) {
auto* registerItem = dynamic_cast<RegisterItem*>(item);
if (registerItem == nullptr) {
return;
}
this->contextMenuRegisterItem = registerItem;
auto* menu = new QMenu(this);
menu->addAction(this->openInspectionWindowAction);
menu->addAction(this->refreshValueAction);
menu->addSeparator();
auto* copyMenu = new QMenu("Copy", this);
copyMenu->addAction(this->copyNameAction);
copyMenu->addSeparator();
copyMenu->addAction(this->copyValueDecimalAction);
copyMenu->addAction(this->copyValueHexAction);
copyMenu->addAction(this->copyValueBinaryAction);
menu->addMenu(copyMenu);
this->openInspectionWindowAction->setEnabled(
TargetRegisterInspectorWindow::registerSupported(this->contextMenuRegisterItem->registerDescriptor)
);
const auto targetStopped = this->targetState == Targets::TargetState::STOPPED;
const auto targetStoppedAndValuePresent = targetStopped
&& this->currentRegisterValues.contains(this->contextMenuRegisterItem->registerDescriptor);
this->refreshValueAction->setEnabled(targetStopped);
this->copyValueDecimalAction->setEnabled(targetStoppedAndValuePresent);
this->copyValueHexAction->setEnabled(targetStoppedAndValuePresent);
this->copyValueBinaryAction->setEnabled(targetStoppedAndValuePresent);
menu->exec(sourcePosition);
}
void TargetRegistersPaneWidget::onTargetStateChanged(Targets::TargetState newState) {
if (this->targetState == newState) {
return;
@@ -241,23 +375,121 @@ namespace Bloom::Widgets
void TargetRegistersPaneWidget::onRegistersRead(const Targets::TargetRegisters& registers) {
for (const auto& targetRegister : registers) {
const auto& descriptor = targetRegister.descriptor;
const auto& previousValueIt = this->currentRegisterValues.find(descriptor);
const auto& registerItemIt = this->registerItemsByDescriptor.find(descriptor);
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
const auto registerWidgetit = registerGroupWidget->registerWidgetsMappedByDescriptor.find(descriptor);
if (registerItemIt != this->registerItemsByDescriptor.end()) {
auto& registerItem = registerItemIt->second;
if (registerWidgetit != registerGroupWidget->registerWidgetsMappedByDescriptor.end()) {
registerWidgetit->second->setRegisterValue(targetRegister);
break;
}
registerItem->setValue(targetRegister.value);
registerItem->valueChanged = previousValueIt != this->currentRegisterValues.end()
? previousValueIt->second != targetRegister.value
: false;
}
this->currentRegisterValues[descriptor] = targetRegister.value;
}
this->registerListScene->update();
}
void TargetRegistersPaneWidget::clearInlineRegisterValues() {
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
for (auto* registerWidget : registerGroupWidget->registerWidgets) {
registerWidget->clearInlineValue();
}
for (auto& [registerDescriptor, registerItem] : this->registerItemsByDescriptor) {
registerItem->clearValue();
}
this->registerListScene->update();
}
void TargetRegistersPaneWidget::openInspectionWindow(const TargetRegisterDescriptor& registerDescriptor) {
if (!TargetRegisterInspectorWindow::registerSupported(registerDescriptor)) {
return;
}
TargetRegisterInspectorWindow* inspectionWindow = nullptr;
const auto& currentValueIt = this->currentRegisterValues.find(registerDescriptor);
const auto& inspectionWindowIt = this->inspectionWindowsByDescriptor.find(registerDescriptor);
if (inspectionWindowIt != this->inspectionWindowsByDescriptor.end()) {
inspectionWindow = inspectionWindowIt->second;
} else {
inspectionWindow = new TargetRegisterInspectorWindow(
registerDescriptor,
this->targetState,
this
);
this->inspectionWindowsByDescriptor.insert(std::pair(
registerDescriptor,
inspectionWindow
));
}
if (currentValueIt != this->currentRegisterValues.end()) {
inspectionWindow->setValue(currentValueIt->second);
}
inspectionWindow->show();
inspectionWindow->activateWindow();
}
void TargetRegistersPaneWidget::copyRegisterName(const TargetRegisterDescriptor& registerDescriptor) {
QApplication::clipboard()->setText(QString::fromStdString(registerDescriptor.name.value_or("")).toUpper());
}
void TargetRegistersPaneWidget::copyRegisterValueHex(const TargetRegisterDescriptor& registerDescriptor) {
const auto& valueIt = this->currentRegisterValues.find(registerDescriptor);
if (valueIt == this->currentRegisterValues.end()) {
return;
}
const auto& value = valueIt->second;
const auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(value.data()),
static_cast<qsizetype>(value.size())
).toHex();
QApplication::clipboard()->setText(QString(valueByteArray).toUpper());
}
void TargetRegistersPaneWidget::copyRegisterValueDecimal(const TargetRegisterDescriptor& registerDescriptor) {
const auto& valueIt = this->currentRegisterValues.find(registerDescriptor);
if (valueIt == this->currentRegisterValues.end()) {
return;
}
const auto& value = valueIt->second;
const auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(value.data()),
static_cast<qsizetype>(value.size())
).toHex();
QApplication::clipboard()->setText(QString::number(valueByteArray.toUInt(nullptr, 16)));
}
void TargetRegistersPaneWidget::copyRegisterValueBinary(const TargetRegisterDescriptor& registerDescriptor) {
const auto& valueIt = this->currentRegisterValues.find(registerDescriptor);
if (valueIt == this->currentRegisterValues.end()) {
return;
}
const auto& value = valueIt->second;
const auto valueByteArray = QByteArray(
reinterpret_cast<const char*>(value.data()),
static_cast<qsizetype>(value.size())
).toHex();
auto bitString = QString::number(valueByteArray.toUInt(nullptr, 16), 2);
if (bitString.size() < (value.size() * 8)) {
bitString = bitString.rightJustified(static_cast<qsizetype>(value.size() * 8), '0');
}
QApplication::clipboard()->setText(bitString);
}
}

View File

@@ -4,22 +4,26 @@
#include <QLineEdit>
#include <QScrollArea>
#include <set>
#include <unordered_map>
#include <QSize>
#include <QString>
#include <QEvent>
#include <QAction>
#include <optional>
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PaneWidget.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.hpp"
#include "ItemWidget.hpp"
#include "RegisterItem.hpp"
#include "RegisterGroupItem.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListView.hpp"
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp"
#include "src/Targets/TargetState.hpp"
#include "src/Targets/TargetDescriptor.hpp"
namespace Bloom::Widgets
{
class RegisterGroupWidget;
class TargetRegistersPaneWidget: public PaneWidget
{
Q_OBJECT
@@ -35,9 +39,10 @@ namespace Bloom::Widgets
void collapseAllRegisterGroups();
void expandAllRegisterGroups();
void refreshRegisterValues(std::optional<std::function<void(void)>> callback = std::nullopt);
void onItemSelectionChange(Bloom::Widgets::ItemWidget* newlySelectedWidget);
void refreshRegisterValues(
std::optional<Targets::TargetRegisterDescriptor> registerDescriptor = std::nullopt,
std::optional<std::function<void(void)>> callback = std::nullopt
);
protected:
void resizeEvent(QResizeEvent* event) override;
@@ -52,18 +57,36 @@ namespace Bloom::Widgets
SvgToolButton* expandAllButton = nullptr;
QLineEdit* searchInput = nullptr;
QScrollArea* itemScrollArea = nullptr;
QWidget* itemContainer = nullptr;
ListView* registerListView = nullptr;
ListScene* registerListScene = nullptr;
ItemWidget* selectedItemWidget = nullptr;
std::set<RegisterGroupWidget*> registerGroupWidgets;
Targets::TargetRegisterDescriptors renderedDescriptors;
Targets::TargetRegisterDescriptors registerDescriptors;
std::vector<RegisterGroupItem*> registerGroupItems;
std::unordered_map<Targets::TargetRegisterDescriptor, RegisterItem*> registerItemsByDescriptor;
std::unordered_map<Targets::TargetRegisterDescriptor, TargetRegisterInspectorWindow*> inspectionWindowsByDescriptor;
std::unordered_map<Targets::TargetRegisterDescriptor, Targets::TargetMemoryBuffer> currentRegisterValues;
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
// Context-menu actions
QAction* openInspectionWindowAction = new QAction("Inspect", this);
QAction* refreshValueAction = new QAction("Refresh Value", this);
QAction* copyNameAction = 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);
RegisterItem* contextMenuRegisterItem = nullptr;
void onItemDoubleClicked(ListItem* clickedItem);
void onItemContextMenu(ListItem* item, QPoint sourcePosition);
void onTargetStateChanged(Targets::TargetState newState);
void onRegistersRead(const Targets::TargetRegisters& registers);
void clearInlineRegisterValues();
void openInspectionWindow(const Targets::TargetRegisterDescriptor& registerDescriptor);
void copyRegisterName(const Targets::TargetRegisterDescriptor& registerDescriptor);
void copyRegisterValueHex(const Targets::TargetRegisterDescriptor& registerDescriptor);
void copyRegisterValueDecimal(const Targets::TargetRegisterDescriptor& registerDescriptor);
void copyRegisterValueBinary(const Targets::TargetRegisterDescriptor& registerDescriptor);
};
}

View File

@@ -116,31 +116,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QScrollArea" 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">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"/>
</property>
<widget class="QWidget" name="item-container">
<layout class="QVBoxLayout">
<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>