Refactored TargetRegistersPane widget to improve memory footprint
This commit is contained in:
@@ -58,9 +58,8 @@ target_sources(
|
|||||||
|
|
||||||
# Target register side pane
|
# Target register side pane
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/ItemWidget.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterGroupItem.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterGroupWidget.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterItem.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.cpp
|
|
||||||
|
|
||||||
# Target register inspector window
|
# Target register inspector window
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.cpp
|
||||||
|
|||||||
@@ -202,25 +202,6 @@ QScrollBar::sub-line:vertical {
|
|||||||
border: none;
|
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 & panels */
|
||||||
#bottom-menu-bar {
|
#bottom-menu-bar {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|||||||
@@ -27,12 +27,11 @@ namespace Bloom::Widgets
|
|||||||
TargetRegisterInspectorWindow::TargetRegisterInspectorWindow(
|
TargetRegisterInspectorWindow::TargetRegisterInspectorWindow(
|
||||||
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
||||||
TargetState currentTargetState,
|
TargetState currentTargetState,
|
||||||
const std::optional<Targets::TargetMemoryBuffer>& registerValue,
|
|
||||||
QWidget* parent
|
QWidget* parent
|
||||||
)
|
)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, registerDescriptor(registerDescriptor)
|
, registerDescriptor(registerDescriptor)
|
||||||
, registerValue(registerValue.value_or(Targets::TargetMemoryBuffer(registerDescriptor.size, 0)))
|
, registerValue(Targets::TargetMemoryBuffer(registerDescriptor.size, 0))
|
||||||
{
|
{
|
||||||
this->setWindowFlag(Qt::Window);
|
this->setWindowFlag(Qt::Window);
|
||||||
auto registerName = QString::fromStdString(this->registerDescriptor.name.value()).toUpper();
|
auto registerName = QString::fromStdString(this->registerDescriptor.name.value()).toUpper();
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ namespace Bloom::Widgets
|
|||||||
TargetRegisterInspectorWindow(
|
TargetRegisterInspectorWindow(
|
||||||
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
||||||
Targets::TargetState currentTargetState,
|
Targets::TargetState currentTargetState,
|
||||||
const std::optional<Targets::TargetMemoryBuffer>& registerValue = std::nullopt,
|
|
||||||
QWidget* parent = nullptr
|
QWidget* parent = nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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) {};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -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(®isterGroupIconPixmap);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -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(®isterIconPixmap);
|
||||||
|
svgRegisterIconRenderer.render(&painter);
|
||||||
|
|
||||||
|
RegisterItem::registerIconPixmap = registerIconPixmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
#include "TargetRegistersPaneWidget.hpp"
|
#include "TargetRegistersPaneWidget.hpp"
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QApplication>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
||||||
#include "src/Insight/InsightSignals.hpp"
|
#include "src/Insight/InsightSignals.hpp"
|
||||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||||
#include "RegisterGroupWidget.hpp"
|
|
||||||
#include "RegisterWidget.hpp"
|
|
||||||
|
|
||||||
#include "src/Services/PathService.hpp"
|
#include "src/Services/PathService.hpp"
|
||||||
#include "src/Exceptions/Exception.hpp"
|
#include "src/Exceptions/Exception.hpp"
|
||||||
@@ -47,6 +48,7 @@ namespace Bloom::Widgets
|
|||||||
auto uiLoader = UiLoader(this);
|
auto uiLoader = UiLoader(this);
|
||||||
this->container = uiLoader.load(&targetRegistersPaneUiFile, this);
|
this->container = uiLoader.load(&targetRegistersPaneUiFile, this);
|
||||||
this->container->setFixedSize(parent->width(), parent->maximumHeight());
|
this->container->setFixedSize(parent->width(), parent->maximumHeight());
|
||||||
|
auto* containerLayout = this->container->findChild<QVBoxLayout*>();
|
||||||
|
|
||||||
auto* layout = new QVBoxLayout(this);
|
auto* layout = new QVBoxLayout(this);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
@@ -70,48 +72,126 @@ namespace Bloom::Widgets
|
|||||||
this->filterRegisters(this->searchInput->text());
|
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 registerDescriptorsByGroupName = std::map<QString, std::set<TargetRegisterDescriptor>>({
|
||||||
auto itemLayout = this->itemContainer->findChild<QVBoxLayout*>();
|
{
|
||||||
|
"CPU General Purpose",
|
||||||
auto& registerDescriptors = targetDescriptor.registerDescriptorsByType;
|
std::set<TargetRegisterDescriptor>(
|
||||||
this->renderedDescriptors = std::set<TargetRegisterDescriptor>(
|
|
||||||
registerDescriptors.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).begin(),
|
registerDescriptors.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).begin(),
|
||||||
registerDescriptors.at(TargetRegisterType::GENERAL_PURPOSE_REGISTER).end()
|
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)) {
|
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)) {
|
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) {
|
for (const auto& [groupName, registerDescriptors] : registerDescriptorsByGroupName) {
|
||||||
auto* registerGroupWidget = new RegisterGroupWidget(
|
this->registerGroupItems.emplace_back(new RegisterGroupItem(
|
||||||
QString::fromStdString(groupName).toUpper(),
|
groupName,
|
||||||
registerDescriptors,
|
registerDescriptors,
|
||||||
|
this->registerItemsByDescriptor
|
||||||
|
));
|
||||||
|
|
||||||
|
this->registerDescriptors.insert(registerDescriptors.begin(), registerDescriptors.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
this->registerListView = new ListView(
|
||||||
|
std::vector<ListItem*>(this->registerGroupItems.begin(), this->registerGroupItems.end()),
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
|
||||||
itemLayout->addWidget(registerGroupWidget, 0, Qt::AlignTop);
|
this->registerListScene = this->registerListView->listScene();
|
||||||
this->registerGroupWidgets.insert(registerGroupWidget);
|
|
||||||
this->renderedDescriptors.insert(registerDescriptors.begin(), registerDescriptors.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
itemLayout->addStretch(1);
|
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();
|
auto* insightSignals = InsightSignals::instance();
|
||||||
|
|
||||||
@@ -142,45 +222,56 @@ namespace Bloom::Widgets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TargetRegistersPaneWidget::filterRegisters(const QString& keyword) {
|
void TargetRegistersPaneWidget::filterRegisters(const QString& keyword) {
|
||||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
for (const auto& groupItem : this->registerGroupItems) {
|
||||||
// If the group name matches the keyword, then don't bother iterating through all the register widgets
|
auto visibleItems = std::uint32_t{0};
|
||||||
if (keyword.isEmpty() || registerGroupWidget->name.contains(keyword, Qt::CaseInsensitive)) {
|
auto displayEntireGroup = keyword.isEmpty() || groupItem->groupName.contains(keyword, Qt::CaseInsensitive);
|
||||||
registerGroupWidget->setVisible(true);
|
|
||||||
registerGroupWidget->setAllRegistersVisible(true);
|
|
||||||
|
|
||||||
if (!keyword.isEmpty()) {
|
for (auto& registerItem : groupItem->registerItems) {
|
||||||
registerGroupWidget->expand();
|
registerItem->excluded = !displayEntireGroup
|
||||||
|
&& !registerItem->searchKeywords.contains(keyword, Qt::CaseInsensitive);
|
||||||
|
|
||||||
} else {
|
if (!registerItem->excluded) {
|
||||||
registerGroupWidget->collapse();
|
++visibleItems;
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
registerGroupWidget->filterRegisters(keyword);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupItem->setVisible(visibleItems > 0 || keyword.isEmpty());
|
||||||
|
groupItem->setExpanded(visibleItems > 0 && !keyword.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
this->registerListScene->refreshGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetRegistersPaneWidget::collapseAllRegisterGroups() {
|
void TargetRegistersPaneWidget::collapseAllRegisterGroups() {
|
||||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
for (auto& registerGroupItem : this->registerGroupItems) {
|
||||||
registerGroupWidget->collapse();
|
registerGroupItem->setExpanded(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->registerListScene->refreshGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetRegistersPaneWidget::expandAllRegisterGroups() {
|
void TargetRegistersPaneWidget::expandAllRegisterGroups() {
|
||||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
for (auto& registerGroupItem : this->registerGroupItems) {
|
||||||
registerGroupWidget->expand();
|
registerGroupItem->setExpanded(true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetRegistersPaneWidget::refreshRegisterValues(std::optional<std::function<void(void)>> callback) {
|
this->registerListScene->refreshGeometry();
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* readRegisterTask = new ReadTargetRegisters(descriptors);
|
auto* readRegisterTask = new ReadTargetRegisters(
|
||||||
|
registerDescriptor.has_value()
|
||||||
|
? Targets::TargetRegisterDescriptors({*registerDescriptor})
|
||||||
|
: this->registerDescriptors
|
||||||
|
);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
readRegisterTask,
|
readRegisterTask,
|
||||||
&ReadTargetRegisters::targetRegistersRead,
|
&ReadTargetRegisters::targetRegistersRead,
|
||||||
@@ -200,17 +291,6 @@ namespace Bloom::Widgets
|
|||||||
InsightWorker::queueTask(readRegisterTask);
|
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) {
|
void TargetRegistersPaneWidget::resizeEvent(QResizeEvent* event) {
|
||||||
const auto parentSize = this->parentPanel->size();
|
const auto parentSize = this->parentPanel->size();
|
||||||
const auto width = parentSize.width() - 1;
|
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
|
* In order to avoid the panel resize handle overlapping the scroll bar handle, we reduce the size of
|
||||||
* the scroll area.
|
* the scroll area.
|
||||||
*/
|
*/
|
||||||
this->itemScrollArea->setFixedWidth(width - this->parentPanel->getHandleSize());
|
this->registerListView->setFixedWidth(width - this->parentPanel->getHandleSize());
|
||||||
|
|
||||||
PaneWidget::resizeEvent(event);
|
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) {
|
void TargetRegistersPaneWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||||
if (this->targetState == newState) {
|
if (this->targetState == newState) {
|
||||||
return;
|
return;
|
||||||
@@ -241,23 +375,121 @@ namespace Bloom::Widgets
|
|||||||
void TargetRegistersPaneWidget::onRegistersRead(const Targets::TargetRegisters& registers) {
|
void TargetRegistersPaneWidget::onRegistersRead(const Targets::TargetRegisters& registers) {
|
||||||
for (const auto& targetRegister : registers) {
|
for (const auto& targetRegister : registers) {
|
||||||
const auto& descriptor = targetRegister.descriptor;
|
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) {
|
if (registerItemIt != this->registerItemsByDescriptor.end()) {
|
||||||
const auto registerWidgetit = registerGroupWidget->registerWidgetsMappedByDescriptor.find(descriptor);
|
auto& registerItem = registerItemIt->second;
|
||||||
|
|
||||||
if (registerWidgetit != registerGroupWidget->registerWidgetsMappedByDescriptor.end()) {
|
registerItem->setValue(targetRegister.value);
|
||||||
registerWidgetit->second->setRegisterValue(targetRegister);
|
registerItem->valueChanged = previousValueIt != this->currentRegisterValues.end()
|
||||||
break;
|
? previousValueIt->second != targetRegister.value
|
||||||
}
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->currentRegisterValues[descriptor] = targetRegister.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->registerListScene->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetRegistersPaneWidget::clearInlineRegisterValues() {
|
void TargetRegistersPaneWidget::clearInlineRegisterValues() {
|
||||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
for (auto& [registerDescriptor, registerItem] : this->registerItemsByDescriptor) {
|
||||||
for (auto* registerWidget : registerGroupWidget->registerWidgets) {
|
registerItem->clearValue();
|
||||||
registerWidget->clearInlineValue();
|
}
|
||||||
}
|
|
||||||
}
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,26 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
|
#include <QAction>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PaneWidget.hpp"
|
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PaneWidget.hpp"
|
||||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.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/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp"
|
||||||
#include "src/Targets/TargetState.hpp"
|
#include "src/Targets/TargetState.hpp"
|
||||||
#include "src/Targets/TargetDescriptor.hpp"
|
#include "src/Targets/TargetDescriptor.hpp"
|
||||||
|
|
||||||
namespace Bloom::Widgets
|
namespace Bloom::Widgets
|
||||||
{
|
{
|
||||||
class RegisterGroupWidget;
|
|
||||||
class TargetRegistersPaneWidget: public PaneWidget
|
class TargetRegistersPaneWidget: public PaneWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -35,9 +39,10 @@ namespace Bloom::Widgets
|
|||||||
void collapseAllRegisterGroups();
|
void collapseAllRegisterGroups();
|
||||||
void expandAllRegisterGroups();
|
void expandAllRegisterGroups();
|
||||||
|
|
||||||
void refreshRegisterValues(std::optional<std::function<void(void)>> callback = std::nullopt);
|
void refreshRegisterValues(
|
||||||
|
std::optional<Targets::TargetRegisterDescriptor> registerDescriptor = std::nullopt,
|
||||||
void onItemSelectionChange(Bloom::Widgets::ItemWidget* newlySelectedWidget);
|
std::optional<std::function<void(void)>> callback = std::nullopt
|
||||||
|
);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
@@ -52,18 +57,36 @@ namespace Bloom::Widgets
|
|||||||
SvgToolButton* expandAllButton = nullptr;
|
SvgToolButton* expandAllButton = nullptr;
|
||||||
|
|
||||||
QLineEdit* searchInput = nullptr;
|
QLineEdit* searchInput = nullptr;
|
||||||
QScrollArea* itemScrollArea = nullptr;
|
ListView* registerListView = nullptr;
|
||||||
QWidget* itemContainer = nullptr;
|
ListScene* registerListScene = nullptr;
|
||||||
|
|
||||||
ItemWidget* selectedItemWidget = nullptr;
|
Targets::TargetRegisterDescriptors registerDescriptors;
|
||||||
|
std::vector<RegisterGroupItem*> registerGroupItems;
|
||||||
std::set<RegisterGroupWidget*> registerGroupWidgets;
|
std::unordered_map<Targets::TargetRegisterDescriptor, RegisterItem*> registerItemsByDescriptor;
|
||||||
Targets::TargetRegisterDescriptors renderedDescriptors;
|
std::unordered_map<Targets::TargetRegisterDescriptor, TargetRegisterInspectorWindow*> inspectionWindowsByDescriptor;
|
||||||
|
std::unordered_map<Targets::TargetRegisterDescriptor, Targets::TargetMemoryBuffer> currentRegisterValues;
|
||||||
|
|
||||||
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
|
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 onTargetStateChanged(Targets::TargetState newState);
|
||||||
void onRegistersRead(const Targets::TargetRegisters& registers);
|
void onRegistersRead(const Targets::TargetRegisters& registers);
|
||||||
void clearInlineRegisterValues();
|
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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,31 +116,6 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
Reference in New Issue
Block a user