Removed using namespace directive for class member function definitions in source files
This commit is contained in:
@@ -1,22 +1,23 @@
|
||||
#include "ClickableWidget.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
void ClickableWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||
if (event->button() == Qt::MouseButton::LeftButton) {
|
||||
emit this->clicked();
|
||||
|
||||
void ClickableWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||
if (event->button() == Qt::MouseButton::LeftButton) {
|
||||
emit this->clicked();
|
||||
} else if (event->button() == Qt::MouseButton::RightButton) {
|
||||
emit this->rightClicked();
|
||||
}
|
||||
|
||||
} else if (event->button() == Qt::MouseButton::RightButton) {
|
||||
emit this->rightClicked();
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
void ClickableWidget::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||
if (event->button() == Qt::MouseButton::LeftButton) {
|
||||
emit this->doubleClicked();
|
||||
}
|
||||
|
||||
void ClickableWidget::mouseDoubleClickEvent(QMouseEvent* event) {
|
||||
if (event->button() == Qt::MouseButton::LeftButton) {
|
||||
emit this->doubleClicked();
|
||||
QWidget::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
QWidget::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
@@ -7,58 +7,64 @@
|
||||
#include "src/Helpers/Paths.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using Bloom::Exceptions::Exception;
|
||||
|
||||
using Bloom::Exceptions::Exception;
|
||||
ErrorDialogue::ErrorDialogue(
|
||||
const QString& windowTitle,
|
||||
const QString& errorMessage,
|
||||
QWidget* parent
|
||||
): QDialog(parent) {
|
||||
this->setObjectName("error-dialogue");
|
||||
this->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
this->setWindowTitle(windowTitle);
|
||||
|
||||
ErrorDialogue::ErrorDialogue(
|
||||
const QString& windowTitle,
|
||||
const QString& errorMessage,
|
||||
QWidget* parent
|
||||
): QDialog(parent) {
|
||||
this->setObjectName("error-dialogue");
|
||||
this->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
this->setWindowTitle(windowTitle);
|
||||
auto dialogueUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/UiFiles/ErrorDialogue.ui"
|
||||
)
|
||||
);
|
||||
|
||||
auto dialogueUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/UiFiles/ErrorDialogue.ui"
|
||||
)
|
||||
);
|
||||
auto dialogueStylesheet = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/Stylesheets/ErrorDialogue.qss"
|
||||
)
|
||||
);
|
||||
|
||||
auto dialogueStylesheet = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/Stylesheets/ErrorDialogue.qss"
|
||||
)
|
||||
);
|
||||
if (!dialogueUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open ErrorDialogue UI file");
|
||||
}
|
||||
|
||||
if (!dialogueUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open ErrorDialogue UI file");
|
||||
if (!dialogueStylesheet.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open ErrorDialogue stylesheet file");
|
||||
}
|
||||
|
||||
this->setStyleSheet(dialogueStylesheet.readAll());
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&dialogueUiFile, this);
|
||||
|
||||
this->errorMessageDescriptionLabel = this->container->findChild<QLabel*>(
|
||||
"error-message-description-label"
|
||||
);
|
||||
this->okButton = this->container->findChild<QPushButton*>("ok-btn");
|
||||
|
||||
this->container->setContentsMargins(15, 10, 15, 15);
|
||||
|
||||
this->errorMessageDescriptionLabel->setText(errorMessage);
|
||||
|
||||
QObject::connect(this->okButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
}
|
||||
|
||||
if (!dialogueStylesheet.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open ErrorDialogue stylesheet file");
|
||||
void ErrorDialogue::showEvent(QShowEvent* event) {
|
||||
const auto containerSize = this->container->sizeHint();
|
||||
const auto windowSize = QSize(
|
||||
std::max(containerSize.width(), 500),
|
||||
std::max(containerSize.height(), 100)
|
||||
);
|
||||
|
||||
this->setFixedSize(windowSize);
|
||||
this->container->setFixedSize(windowSize);
|
||||
}
|
||||
|
||||
this->setStyleSheet(dialogueStylesheet.readAll());
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&dialogueUiFile, this);
|
||||
|
||||
this->errorMessageDescriptionLabel = this->container->findChild<QLabel*>("error-message-description-label");
|
||||
this->okButton = this->container->findChild<QPushButton*>("ok-btn");
|
||||
|
||||
this->container->setContentsMargins(15, 10, 15, 15);
|
||||
|
||||
this->errorMessageDescriptionLabel->setText(errorMessage);
|
||||
|
||||
QObject::connect(this->okButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
}
|
||||
|
||||
void ErrorDialogue::showEvent(QShowEvent* event) {
|
||||
const auto containerSize = this->container->sizeHint();
|
||||
const auto windowSize = QSize(std::max(containerSize.width(), 500), std::max(containerSize.height(), 100));
|
||||
|
||||
this->setFixedSize(windowSize);
|
||||
this->container->setFixedSize(windowSize);
|
||||
}
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
#include "LabeledSeparator.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
LabeledSeparator::LabeledSeparator(QString title, QWidget* parent): title(std::move(title)), QWidget(parent) {
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
this->setFixedHeight(LabeledSeparator::DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
LabeledSeparator::LabeledSeparator(QString title, QWidget* parent): title(std::move(title)), QWidget(parent) {
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
this->setFixedHeight(LabeledSeparator::DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
void LabeledSeparator::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void LabeledSeparator::drawWidget(QPainter& painter) {
|
||||
const auto fontMetrics = painter.fontMetrics();
|
||||
const auto titleSize = fontMetrics.size(Qt::TextFlag::TextSingleLine, this->title);
|
||||
const auto titleRect = QRect(
|
||||
QPoint(this->marginLeft, (this->height() - titleSize.height()) / 2),
|
||||
titleSize
|
||||
);
|
||||
|
||||
const auto lineYPosition = titleRect.y() + (titleRect.height() / 2);
|
||||
const auto line = QLine(
|
||||
titleRect.right() + 8,
|
||||
lineYPosition,
|
||||
this->width() - this->marginRight,
|
||||
lineYPosition
|
||||
);
|
||||
|
||||
painter.drawText(titleRect, Qt::AlignCenter, this->title);
|
||||
|
||||
painter.setPen(this->lineColor);
|
||||
painter.drawLine(line);
|
||||
void LabeledSeparator::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void LabeledSeparator::drawWidget(QPainter& painter) {
|
||||
const auto fontMetrics = painter.fontMetrics();
|
||||
const auto titleSize = fontMetrics.size(Qt::TextFlag::TextSingleLine, this->title);
|
||||
const auto titleRect = QRect(
|
||||
QPoint(this->marginLeft, (this->height() - titleSize.height()) / 2),
|
||||
titleSize
|
||||
);
|
||||
|
||||
const auto lineYPosition = titleRect.y() + (titleRect.height() / 2);
|
||||
const auto line = QLine(
|
||||
titleRect.right() + 8,
|
||||
lineYPosition,
|
||||
this->width() - this->marginRight,
|
||||
lineYPosition
|
||||
);
|
||||
|
||||
painter.drawText(titleRect, Qt::AlignCenter, this->title);
|
||||
|
||||
painter.setPen(this->lineColor);
|
||||
painter.drawLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,138 +2,139 @@
|
||||
|
||||
#include <QLayout>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
PanelWidget::PanelWidget(QWidget* parent): QFrame(parent) {
|
||||
this->setMouseTracking(false);
|
||||
this->setAttribute(Qt::WA_Hover, true);
|
||||
}
|
||||
|
||||
void PanelWidget::setMinimumResize(int minimumResize) {
|
||||
this->minimumResize = minimumResize;
|
||||
|
||||
const auto currentSize = this->size();
|
||||
|
||||
if (this->panelType == PanelWidgetType::LEFT && currentSize.width() < this->minimumResize) {
|
||||
this->setFixedWidth(this->minimumResize);
|
||||
|
||||
} else if (this->panelType == PanelWidgetType::BOTTOM && currentSize.height() < this->minimumResize) {
|
||||
this->setFixedHeight(this->minimumResize);
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
PanelWidget::PanelWidget(QWidget* parent): QFrame(parent) {
|
||||
this->setMouseTracking(false);
|
||||
this->setAttribute(Qt::WA_Hover, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PanelWidget::setMaximumResize(int maximumResize) {
|
||||
this->maximumResize = maximumResize;
|
||||
void PanelWidget::setMinimumResize(int minimumResize) {
|
||||
this->minimumResize = minimumResize;
|
||||
|
||||
const auto currentSize = this->size();
|
||||
const auto currentSize = this->size();
|
||||
|
||||
if (this->panelType == PanelWidgetType::LEFT && currentSize.width() > this->maximumResize) {
|
||||
this->setFixedWidth(this->maximumResize);
|
||||
if (this->panelType == PanelWidgetType::LEFT && currentSize.width() < this->minimumResize) {
|
||||
this->setFixedWidth(this->minimumResize);
|
||||
|
||||
} else if (this->panelType == PanelWidgetType::BOTTOM && currentSize.height() > this->maximumResize) {
|
||||
this->setFixedHeight(this->maximumResize);
|
||||
} else if (this->panelType == PanelWidgetType::BOTTOM && currentSize.height() < this->minimumResize) {
|
||||
this->setFixedHeight(this->minimumResize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PanelWidget::setPanelType(PanelWidgetType panelType) {
|
||||
this->panelType = panelType;
|
||||
void PanelWidget::setMaximumResize(int maximumResize) {
|
||||
this->maximumResize = maximumResize;
|
||||
|
||||
if (this->panelType == PanelWidgetType::LEFT) {
|
||||
this->resizeCursor = Qt::SplitHCursor;
|
||||
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
|
||||
const auto currentSize = this->size();
|
||||
|
||||
} else {
|
||||
this->resizeCursor = Qt::SplitVCursor;
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
if (this->panelType == PanelWidgetType::LEFT && currentSize.width() > this->maximumResize) {
|
||||
this->setFixedWidth(this->maximumResize);
|
||||
|
||||
} else if (this->panelType == PanelWidgetType::BOTTOM && currentSize.height() > this->maximumResize) {
|
||||
this->setFixedHeight(this->maximumResize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PanelWidget::event(QEvent* event) {
|
||||
if (event->type() == QEvent::Type::HoverMove) {
|
||||
auto hoverEvent = static_cast<QHoverEvent*>(event);
|
||||
if (this->resizingActive || this->isPositionWithinHandleArea(hoverEvent->position().toPoint())) {
|
||||
this->setCursor(this->resizeCursor);
|
||||
void PanelWidget::setPanelType(PanelWidgetType panelType) {
|
||||
this->panelType = panelType;
|
||||
|
||||
if (this->panelType == PanelWidgetType::LEFT) {
|
||||
this->resizeCursor = Qt::SplitHCursor;
|
||||
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
|
||||
|
||||
} else {
|
||||
this->resizeCursor = Qt::SplitVCursor;
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
}
|
||||
}
|
||||
|
||||
bool PanelWidget::event(QEvent* event) {
|
||||
if (event->type() == QEvent::Type::HoverMove) {
|
||||
auto hoverEvent = static_cast<QHoverEvent*>(event);
|
||||
if (this->resizingActive || this->isPositionWithinHandleArea(hoverEvent->position().toPoint())) {
|
||||
this->setCursor(this->resizeCursor);
|
||||
|
||||
} else {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
return QFrame::event(event);
|
||||
}
|
||||
|
||||
void PanelWidget::mousePressEvent(QMouseEvent* event) {
|
||||
const auto position = event->pos();
|
||||
|
||||
if (event->buttons() & Qt::LeftButton && this->isPositionWithinHandleArea(position)) {
|
||||
this->resizingActive = true;
|
||||
|
||||
switch (this->panelType) {
|
||||
case PanelWidgetType::LEFT: {
|
||||
this->resizingOffset = this->width() - position.x();
|
||||
break;
|
||||
}
|
||||
case PanelWidgetType::BOTTOM: {
|
||||
this->resizingOffset = position.y();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PanelWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||
if (this->resizingActive) {
|
||||
this->resizingActive = false;
|
||||
this->resizingOffset = 0;
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
return QFrame::event(event);
|
||||
}
|
||||
void PanelWidget::mouseMoveEvent(QMouseEvent* event) {
|
||||
if (this->resizingActive) {
|
||||
const auto position = event->pos();
|
||||
|
||||
void PanelWidget::mousePressEvent(QMouseEvent* event) {
|
||||
const auto position = event->pos();
|
||||
if (this->panelType == PanelWidgetType::LEFT) {
|
||||
this->setFixedWidth(
|
||||
std::max(
|
||||
this->minimumResize,
|
||||
std::min(this->maximumResize, position.x() + this->resizingOffset)
|
||||
)
|
||||
);
|
||||
|
||||
if (event->buttons() & Qt::LeftButton && this->isPositionWithinHandleArea(position)) {
|
||||
this->resizingActive = true;
|
||||
|
||||
switch (this->panelType) {
|
||||
case PanelWidgetType::LEFT: {
|
||||
this->resizingOffset = this->width() - position.x();
|
||||
break;
|
||||
}
|
||||
case PanelWidgetType::BOTTOM: {
|
||||
this->resizingOffset = position.y();
|
||||
break;
|
||||
} else if (this->panelType == PanelWidgetType::BOTTOM) {
|
||||
this->setFixedHeight(
|
||||
std::max(
|
||||
this->minimumResize,
|
||||
std::min(this->maximumResize, this->height() + (-position.y()) + this->resizingOffset)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PanelWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||
if (this->resizingActive) {
|
||||
this->resizingActive = false;
|
||||
this->resizingOffset = 0;
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
void PanelWidget::mouseMoveEvent(QMouseEvent* event) {
|
||||
if (this->resizingActive) {
|
||||
const auto position = event->pos();
|
||||
std::pair<QPoint, QPoint> PanelWidget::getHandleArea() const {
|
||||
const auto currentSize = this->size();
|
||||
|
||||
if (this->panelType == PanelWidgetType::LEFT) {
|
||||
this->setFixedWidth(
|
||||
std::max(
|
||||
this->minimumResize,
|
||||
std::min(this->maximumResize, position.x() + this->resizingOffset)
|
||||
)
|
||||
return std::pair(
|
||||
QPoint(currentSize.width() - this->handleSize, 0),
|
||||
QPoint(currentSize.width(), currentSize.height())
|
||||
);
|
||||
|
||||
} else if (this->panelType == PanelWidgetType::BOTTOM) {
|
||||
this->setFixedHeight(
|
||||
std::max(
|
||||
this->minimumResize,
|
||||
std::min(this->maximumResize, this->height() + (-position.y()) + this->resizingOffset)
|
||||
)
|
||||
} else {
|
||||
return std::pair(
|
||||
QPoint(0, 0),
|
||||
QPoint(currentSize.width(), this->handleSize)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<QPoint, QPoint> PanelWidget::getHandleArea() const {
|
||||
const auto currentSize = this->size();
|
||||
bool PanelWidget::isPositionWithinHandleArea(const QPoint& position) const {
|
||||
const auto handleArea = this->getHandleArea();
|
||||
|
||||
if (this->panelType == PanelWidgetType::LEFT) {
|
||||
return std::pair(
|
||||
QPoint(currentSize.width() - this->handleSize, 0),
|
||||
QPoint(currentSize.width(), currentSize.height())
|
||||
);
|
||||
|
||||
} else {
|
||||
return std::pair(
|
||||
QPoint(0, 0),
|
||||
QPoint(currentSize.width(), this->handleSize)
|
||||
return (
|
||||
position.x() >= handleArea.first.x() && position.x() <= handleArea.second.x()
|
||||
&& position.y() >= handleArea.first.y() && position.y() <= handleArea.second.y()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool PanelWidget::isPositionWithinHandleArea(const QPoint& position) const {
|
||||
const auto handleArea = this->getHandleArea();
|
||||
|
||||
return (
|
||||
position.x() >= handleArea.first.x() && position.x() <= handleArea.second.x()
|
||||
&& position.y() >= handleArea.first.y() && position.y() <= handleArea.second.y()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,60 +2,61 @@
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
void RotatableLabel::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
static auto containerSize = this->getContainerSize();
|
||||
static auto textSize = QLabel::minimumSizeHint();
|
||||
static auto margins = this->contentsMargins();
|
||||
painter.setClipRect(0, 0, containerSize.width(), containerSize.height());
|
||||
painter.save();
|
||||
painter.setPen(Qt::PenStyle::SolidLine);
|
||||
painter.setPen(QColor(this->isEnabled() ? "#afb1b3" : "#808484"));
|
||||
painter.translate(std::ceil(containerSize.width() / 2), std::ceil(containerSize.height() / 2));
|
||||
painter.rotate(this->angle);
|
||||
painter.drawText(
|
||||
-(textSize.width() / 2) + margins.left(),
|
||||
(textSize.height() / 2) + margins.top(),
|
||||
this->text()
|
||||
);
|
||||
|
||||
void RotatableLabel::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
static auto containerSize = this->getContainerSize();
|
||||
static auto textSize = QLabel::minimumSizeHint();
|
||||
static auto margins = this->contentsMargins();
|
||||
painter.setClipRect(0, 0, containerSize.width(), containerSize.height());
|
||||
painter.save();
|
||||
painter.setPen(Qt::PenStyle::SolidLine);
|
||||
painter.setPen(QColor(this->isEnabled() ? "#afb1b3" : "#808484"));
|
||||
painter.translate(std::ceil(containerSize.width() / 2), std::ceil(containerSize.height() / 2));
|
||||
painter.rotate(this->angle);
|
||||
painter.drawText(
|
||||
-(textSize.width() / 2) + margins.left(),
|
||||
(textSize.height() / 2) + margins.top(),
|
||||
this->text()
|
||||
);
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
QSize RotatableLabel::getContainerSize() const {
|
||||
auto size = QSize();
|
||||
auto textSize = QLabel::sizeHint();
|
||||
|
||||
if (this->angle % 360 == 0 || this->angle % 180 == 0) {
|
||||
size = textSize;
|
||||
|
||||
} else if (this->angle % 90 == 0) {
|
||||
size.setHeight(textSize.width());
|
||||
size.setWidth(textSize.height());
|
||||
|
||||
} else {
|
||||
auto angle = this->angle;
|
||||
|
||||
if (angle > 90) {
|
||||
float angleMultiplier = static_cast<float>(angle) / 90;
|
||||
angleMultiplier = static_cast<float>(angleMultiplier) - std::floor(angleMultiplier);
|
||||
angle = static_cast<int>(90 * angleMultiplier);
|
||||
}
|
||||
|
||||
auto angleRadians = angle * (M_PI / 180);
|
||||
|
||||
size.setWidth(static_cast<int>(
|
||||
std::cos(angleRadians) * textSize.width()
|
||||
+ std::ceil(std::sin(angleRadians) * textSize.height())
|
||||
))
|
||||
;
|
||||
size.setHeight(static_cast<int>(
|
||||
std::sin(angleRadians) * textSize.width()
|
||||
+ std::ceil(std::cos(angleRadians) * textSize.height())
|
||||
));
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
return size;
|
||||
QSize RotatableLabel::getContainerSize() const {
|
||||
auto size = QSize();
|
||||
auto textSize = QLabel::sizeHint();
|
||||
|
||||
if (this->angle % 360 == 0 || this->angle % 180 == 0) {
|
||||
size = textSize;
|
||||
|
||||
} else if (this->angle % 90 == 0) {
|
||||
size.setHeight(textSize.width());
|
||||
size.setWidth(textSize.height());
|
||||
|
||||
} else {
|
||||
auto angle = this->angle;
|
||||
|
||||
if (angle > 90) {
|
||||
float angleMultiplier = static_cast<float>(angle) / 90;
|
||||
angleMultiplier = static_cast<float>(angleMultiplier) - std::floor(angleMultiplier);
|
||||
angle = static_cast<int>(90 * angleMultiplier);
|
||||
}
|
||||
|
||||
auto angleRadians = angle * (M_PI / 180);
|
||||
|
||||
size.setWidth(static_cast<int>(
|
||||
std::cos(angleRadians) * textSize.width()
|
||||
+ std::ceil(std::sin(angleRadians) * textSize.height())
|
||||
))
|
||||
;
|
||||
size.setHeight(static_cast<int>(
|
||||
std::sin(angleRadians) * textSize.width()
|
||||
+ std::ceil(std::cos(angleRadians) * textSize.height())
|
||||
));
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,23 @@
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
SvgToolButton::SvgToolButton(QWidget* parent): QToolButton(parent) {
|
||||
this->setButtonWidth(10);
|
||||
this->setButtonHeight(10);
|
||||
}
|
||||
|
||||
SvgToolButton::SvgToolButton(QWidget* parent): QToolButton(parent) {
|
||||
this->setButtonWidth(10);
|
||||
this->setButtonHeight(10);
|
||||
}
|
||||
|
||||
void SvgToolButton::childEvent(QChildEvent* childEvent) {
|
||||
if ((childEvent->added() || childEvent->polished()) && childEvent->child()->isWidgetType()) {
|
||||
/*
|
||||
* If a menu widget has been added as a child to this SvgToolButton, associate the menu with the button
|
||||
* via QToolButton::setMenu().
|
||||
*/
|
||||
auto* menuWidget = qobject_cast<QMenu*>(childEvent->child());
|
||||
if (menuWidget != nullptr && menuWidget != this->menu()) {
|
||||
this->setMenu(menuWidget);
|
||||
void SvgToolButton::childEvent(QChildEvent* childEvent) {
|
||||
if ((childEvent->added() || childEvent->polished()) && childEvent->child()->isWidgetType()) {
|
||||
/*
|
||||
* If a menu widget has been added as a child to this SvgToolButton, associate the menu with the button
|
||||
* via QToolButton::setMenu().
|
||||
*/
|
||||
auto* menuWidget = qobject_cast<QMenu*>(childEvent->child());
|
||||
if (menuWidget != nullptr && menuWidget != this->menu()) {
|
||||
this->setMenu(menuWidget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,71 +3,76 @@
|
||||
#include <QPainter>
|
||||
#include <cmath>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
SvgWidget::SvgWidget(QWidget* parent): QFrame(parent) {
|
||||
this->renderer.setAspectRatioMode(Qt::AspectRatioMode::KeepAspectRatioByExpanding);
|
||||
}
|
||||
|
||||
void SvgWidget::startSpin() {
|
||||
if (this->spinningAnimation == nullptr) {
|
||||
this->spinningAnimation = new QPropertyAnimation(this, "angle", this);
|
||||
this->spinningAnimation->setDuration(2000);
|
||||
this->spinningAnimation->setStartValue(0);
|
||||
this->spinningAnimation->setEndValue(360);
|
||||
|
||||
QObject::connect(this->spinningAnimation, &QPropertyAnimation::finished, this, [this] {
|
||||
this->spinningAnimation->start();
|
||||
});
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
SvgWidget::SvgWidget(QWidget* parent): QFrame(parent) {
|
||||
this->renderer.setAspectRatioMode(Qt::AspectRatioMode::KeepAspectRatioByExpanding);
|
||||
}
|
||||
|
||||
this->spinningAnimation->start();
|
||||
}
|
||||
void SvgWidget::startSpin() {
|
||||
if (this->spinningAnimation == nullptr) {
|
||||
this->spinningAnimation = new QPropertyAnimation(this, "angle", this);
|
||||
this->spinningAnimation->setDuration(2000);
|
||||
this->spinningAnimation->setStartValue(0);
|
||||
this->spinningAnimation->setEndValue(360);
|
||||
|
||||
void SvgWidget::stopSpin() {
|
||||
if (this->spinningAnimation != nullptr) {
|
||||
this->spinningAnimation->stop();
|
||||
this->setAngle(0);
|
||||
}
|
||||
}
|
||||
|
||||
void SvgWidget::paintEvent(QPaintEvent* paintEvent) {
|
||||
auto painter = QPainter(this);
|
||||
auto svgSize = this->renderer.defaultSize();
|
||||
auto margins = this->contentsMargins();
|
||||
const auto containerSize = this->frameSize();
|
||||
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
|
||||
if (this->angle % 360 != 0) {
|
||||
painter.translate(
|
||||
std::ceil(static_cast<float>(containerSize.width() / 2)),
|
||||
std::ceil(static_cast<float>(containerSize.height() / 2))
|
||||
);
|
||||
painter.rotate(this->angle);
|
||||
painter.translate(
|
||||
-std::ceil(static_cast<float>(containerSize.width() / 2)),
|
||||
-std::ceil(static_cast<float>(containerSize.height() / 2))
|
||||
);
|
||||
}
|
||||
|
||||
this->renderer.render(&painter, QRectF(
|
||||
std::ceil(static_cast<float>(containerSize.width() - svgSize.width()) / 2 + static_cast<float>(margins.left())),
|
||||
std::ceil(static_cast<float>(containerSize.height() - svgSize.height()) / 2 + static_cast<float>(margins.top())),
|
||||
svgSize.width(),
|
||||
svgSize.height()
|
||||
));
|
||||
}
|
||||
|
||||
void SvgWidget::changeEvent(QEvent* event) {
|
||||
if (event->type() == QEvent::EnabledChange && !this->disabledSvgFilePath.isEmpty()) {
|
||||
if (!this->isEnabled()) {
|
||||
this->renderer.load(this->disabledSvgFilePath);
|
||||
|
||||
} else {
|
||||
this->renderer.load(this->svgFilePath);
|
||||
QObject::connect(this->spinningAnimation, &QPropertyAnimation::finished, this, [this] {
|
||||
this->spinningAnimation->start();
|
||||
});
|
||||
}
|
||||
|
||||
this->repaint();
|
||||
this->spinningAnimation->start();
|
||||
}
|
||||
|
||||
void SvgWidget::stopSpin() {
|
||||
if (this->spinningAnimation != nullptr) {
|
||||
this->spinningAnimation->stop();
|
||||
this->setAngle(0);
|
||||
}
|
||||
}
|
||||
|
||||
void SvgWidget::paintEvent(QPaintEvent* paintEvent) {
|
||||
auto painter = QPainter(this);
|
||||
auto svgSize = this->renderer.defaultSize();
|
||||
auto margins = this->contentsMargins();
|
||||
const auto containerSize = this->frameSize();
|
||||
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
|
||||
if (this->angle % 360 != 0) {
|
||||
painter.translate(
|
||||
std::ceil(static_cast<float>(containerSize.width() / 2)),
|
||||
std::ceil(static_cast<float>(containerSize.height() / 2))
|
||||
);
|
||||
painter.rotate(this->angle);
|
||||
painter.translate(
|
||||
-std::ceil(static_cast<float>(containerSize.width() / 2)),
|
||||
-std::ceil(static_cast<float>(containerSize.height() / 2))
|
||||
);
|
||||
}
|
||||
|
||||
this->renderer.render(&painter, QRectF(
|
||||
std::ceil(
|
||||
static_cast<float>(containerSize.width() - svgSize.width()) / 2 + static_cast<float>(margins.left())
|
||||
),
|
||||
std::ceil(
|
||||
static_cast<float>(containerSize.height() - svgSize.height()) / 2 + static_cast<float>(margins.top())
|
||||
),
|
||||
svgSize.width(),
|
||||
svgSize.height()
|
||||
));
|
||||
}
|
||||
|
||||
void SvgWidget::changeEvent(QEvent* event) {
|
||||
if (event->type() == QEvent::EnabledChange && !this->disabledSvgFilePath.isEmpty()) {
|
||||
if (!this->isEnabled()) {
|
||||
this->renderer.load(this->disabledSvgFilePath);
|
||||
|
||||
} else {
|
||||
this->renderer.load(this->svgFilePath);
|
||||
}
|
||||
|
||||
this->repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,109 +4,115 @@
|
||||
|
||||
#include "ByteItem.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
AnnotationItem::AnnotationItem(
|
||||
std::uint32_t startAddress,
|
||||
std::size_t size,
|
||||
QString labelText,
|
||||
AnnotationItemPosition position
|
||||
):
|
||||
QGraphicsItem(nullptr),
|
||||
startAddress(startAddress),
|
||||
size(size),
|
||||
endAddress(static_cast<std::uint32_t>(startAddress + size - 1)),
|
||||
labelText(std::move(labelText)),
|
||||
position(position),
|
||||
width(static_cast<int>((ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) * size - ByteItem::RIGHT_MARGIN)),
|
||||
height(position == AnnotationItemPosition::TOP ? AnnotationItem::TOP_HEIGHT : AnnotationItem::BOTTOM_HEIGHT
|
||||
) {
|
||||
this->setAcceptHoverEvents(true);
|
||||
this->setToolTip(this->labelText);
|
||||
}
|
||||
|
||||
AnnotationItem::AnnotationItem(
|
||||
const Targets::TargetMemoryAddressRange& addressRange,
|
||||
const QString& labelText,
|
||||
AnnotationItemPosition position
|
||||
): AnnotationItem(
|
||||
addressRange.startAddress,
|
||||
addressRange.endAddress - addressRange.startAddress + 1,
|
||||
labelText,
|
||||
position
|
||||
) {}
|
||||
|
||||
AnnotationItem::AnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion, AnnotationItemPosition position)
|
||||
: AnnotationItem(
|
||||
focusedMemoryRegion.addressRange,
|
||||
focusedMemoryRegion.name,
|
||||
position
|
||||
) {}
|
||||
|
||||
void AnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
auto lineColor = this->getLineColor();
|
||||
auto labelFontColor = this->getLabelFontColor();
|
||||
|
||||
auto font = painter->font();
|
||||
font.setPixelSize(this->getLabelFontSize());
|
||||
painter->setFont(font);
|
||||
|
||||
const auto isEnabled = this->isEnabled();
|
||||
|
||||
lineColor.setAlpha(isEnabled ? 255 : 100);
|
||||
labelFontColor.setAlpha(isEnabled ? 255 : 100);
|
||||
|
||||
const auto fontMetrics = painter->fontMetrics();
|
||||
auto labelSize = fontMetrics.size(Qt::TextSingleLine, this->labelText);
|
||||
if (labelSize.width() > this->width) {
|
||||
labelSize.setWidth(this->width);
|
||||
this->labelText = fontMetrics.elidedText(this->labelText, Qt::TextElideMode::ElideRight, this->width);
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
AnnotationItem::AnnotationItem(
|
||||
std::uint32_t startAddress,
|
||||
std::size_t size,
|
||||
QString labelText,
|
||||
AnnotationItemPosition position
|
||||
):
|
||||
QGraphicsItem(nullptr),
|
||||
startAddress(startAddress),
|
||||
size(size),
|
||||
endAddress(static_cast<std::uint32_t>(startAddress + size - 1)),
|
||||
labelText(std::move(labelText)),
|
||||
position(position),
|
||||
width(static_cast<int>((ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) * size - ByteItem::RIGHT_MARGIN)),
|
||||
height(position == AnnotationItemPosition::TOP ? AnnotationItem::TOP_HEIGHT : AnnotationItem::BOTTOM_HEIGHT
|
||||
) {
|
||||
this->setAcceptHoverEvents(true);
|
||||
this->setToolTip(this->labelText);
|
||||
}
|
||||
|
||||
constexpr auto verticalLineLength = 5;
|
||||
const auto verticalLineYStart = this->position == AnnotationItemPosition::BOTTOM ? 0 : AnnotationItem::TOP_HEIGHT;
|
||||
const auto verticalLineYEnd = this->position == AnnotationItemPosition::BOTTOM ?
|
||||
verticalLineLength : AnnotationItem::TOP_HEIGHT - verticalLineLength;
|
||||
AnnotationItem::AnnotationItem(
|
||||
const Targets::TargetMemoryAddressRange& addressRange,
|
||||
const QString& labelText,
|
||||
AnnotationItemPosition position
|
||||
): AnnotationItem(
|
||||
addressRange.startAddress,
|
||||
addressRange.endAddress - addressRange.startAddress + 1,
|
||||
labelText,
|
||||
position
|
||||
) {}
|
||||
|
||||
const auto labelRect = QRect(
|
||||
(this->width - labelSize.width()) / 2,
|
||||
verticalLineYEnd - (this->position == AnnotationItemPosition::BOTTOM ? -6: labelSize.height() + 6),
|
||||
labelSize.width(),
|
||||
labelSize.height()
|
||||
);
|
||||
AnnotationItem::AnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion, AnnotationItemPosition position)
|
||||
: AnnotationItem(
|
||||
focusedMemoryRegion.addressRange,
|
||||
focusedMemoryRegion.name,
|
||||
position
|
||||
) {}
|
||||
|
||||
painter->setPen(lineColor);
|
||||
void AnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
auto lineColor = this->getLineColor();
|
||||
auto labelFontColor = this->getLabelFontColor();
|
||||
|
||||
if (this->size > 1) {
|
||||
painter->drawLine(QLine(
|
||||
ByteItem::WIDTH / 2,
|
||||
verticalLineYStart,
|
||||
ByteItem::WIDTH / 2,
|
||||
verticalLineYEnd
|
||||
));
|
||||
auto font = painter->font();
|
||||
font.setPixelSize(this->getLabelFontSize());
|
||||
painter->setFont(font);
|
||||
|
||||
const auto isEnabled = this->isEnabled();
|
||||
|
||||
lineColor.setAlpha(isEnabled ? 255 : 100);
|
||||
labelFontColor.setAlpha(isEnabled ? 255 : 100);
|
||||
|
||||
const auto fontMetrics = painter->fontMetrics();
|
||||
auto labelSize = fontMetrics.size(Qt::TextSingleLine, this->labelText);
|
||||
if (labelSize.width() > this->width) {
|
||||
labelSize.setWidth(this->width);
|
||||
this->labelText = fontMetrics.elidedText(
|
||||
this->labelText,
|
||||
Qt::TextElideMode::ElideRight,
|
||||
this->width
|
||||
);
|
||||
}
|
||||
|
||||
constexpr auto verticalLineLength = 5;
|
||||
const auto verticalLineYStart = this->position == AnnotationItemPosition::BOTTOM ? 0
|
||||
: AnnotationItem::TOP_HEIGHT;
|
||||
const auto verticalLineYEnd = this->position == AnnotationItemPosition::BOTTOM ?
|
||||
verticalLineLength : AnnotationItem::TOP_HEIGHT - verticalLineLength;
|
||||
|
||||
const auto labelRect = QRect(
|
||||
(this->width - labelSize.width()) / 2,
|
||||
verticalLineYEnd - (this->position == AnnotationItemPosition::BOTTOM ? -6: labelSize.height() + 6),
|
||||
labelSize.width(),
|
||||
labelSize.height()
|
||||
);
|
||||
|
||||
painter->setPen(lineColor);
|
||||
|
||||
if (this->size > 1) {
|
||||
painter->drawLine(QLine(
|
||||
ByteItem::WIDTH / 2,
|
||||
verticalLineYStart,
|
||||
ByteItem::WIDTH / 2,
|
||||
verticalLineYEnd
|
||||
));
|
||||
|
||||
painter->drawLine(QLine(
|
||||
this->width - (ByteItem::WIDTH / 2),
|
||||
verticalLineYStart,
|
||||
this->width - (ByteItem::WIDTH / 2),
|
||||
verticalLineYEnd
|
||||
));
|
||||
|
||||
painter->drawLine(QLine(
|
||||
ByteItem::WIDTH / 2,
|
||||
verticalLineYEnd,
|
||||
(ByteItem::WIDTH / 2) + (this->width - ByteItem::WIDTH),
|
||||
verticalLineYEnd
|
||||
));
|
||||
}
|
||||
|
||||
painter->drawLine(QLine(
|
||||
this->width - (ByteItem::WIDTH / 2),
|
||||
verticalLineYStart,
|
||||
this->width - (ByteItem::WIDTH / 2),
|
||||
verticalLineYEnd
|
||||
));
|
||||
|
||||
painter->drawLine(QLine(
|
||||
ByteItem::WIDTH / 2,
|
||||
this->width / 2,
|
||||
verticalLineYEnd,
|
||||
(ByteItem::WIDTH / 2) + (this->width - ByteItem::WIDTH),
|
||||
verticalLineYEnd
|
||||
this->width / 2,
|
||||
(this->position == AnnotationItemPosition::BOTTOM ? verticalLineYEnd + 4 : verticalLineYEnd - 4)
|
||||
));
|
||||
|
||||
painter->setPen(labelFontColor);
|
||||
painter->drawText(labelRect, Qt::AlignCenter, this->labelText);
|
||||
}
|
||||
|
||||
painter->drawLine(QLine(
|
||||
this->width / 2,
|
||||
verticalLineYEnd,
|
||||
this->width / 2,
|
||||
(this->position == AnnotationItemPosition::BOTTOM ? verticalLineYEnd + 4 : verticalLineYEnd - 4)
|
||||
));
|
||||
|
||||
painter->setPen(labelFontColor);
|
||||
painter->drawText(labelRect, Qt::AlignCenter, this->labelText);
|
||||
}
|
||||
|
||||
@@ -1,71 +1,72 @@
|
||||
#include "ByteAddressContainer.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
void ByteAddressContainer::adjustAddressLabels(
|
||||
const std::map<std::size_t, std::vector<ByteItem*>>& byteItemsByRowIndex
|
||||
) {
|
||||
static const auto margins = QMargins(0, 10, 0, 0);
|
||||
|
||||
void ByteAddressContainer::adjustAddressLabels(
|
||||
const std::map<std::size_t, std::vector<ByteItem*>>& byteItemsByRowIndex
|
||||
) {
|
||||
static const auto margins = QMargins(0, 10, 0, 0);
|
||||
const auto newRowCount = byteItemsByRowIndex.size();
|
||||
const auto layoutItemMaxIndex = static_cast<int>(this->addressItemsByRowIndex.size() - 1);
|
||||
|
||||
const auto newRowCount = byteItemsByRowIndex.size();
|
||||
const auto layoutItemMaxIndex = static_cast<int>(this->addressItemsByRowIndex.size() - 1);
|
||||
for (const auto& mappingPair : byteItemsByRowIndex) {
|
||||
const auto rowIndex = static_cast<std::size_t>(mappingPair.first);
|
||||
const auto& byteItems = mappingPair.second;
|
||||
|
||||
for (const auto& mappingPair : byteItemsByRowIndex) {
|
||||
const auto rowIndex = static_cast<std::size_t>(mappingPair.first);
|
||||
const auto& byteItems = mappingPair.second;
|
||||
if (byteItems.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (byteItems.empty()) {
|
||||
continue;
|
||||
ByteAddressItem* addressLabel = nullptr;
|
||||
if (static_cast<int>(rowIndex) > layoutItemMaxIndex) {
|
||||
addressLabel = new ByteAddressItem(this);
|
||||
this->addressItemsByRowIndex.insert(std::pair(rowIndex, addressLabel));
|
||||
|
||||
} else {
|
||||
addressLabel = this->addressItemsByRowIndex.at(rowIndex);
|
||||
}
|
||||
|
||||
const auto& firstByteItem = byteItems.front();
|
||||
addressLabel->setAddressHex(firstByteItem->relativeAddressHex);
|
||||
addressLabel->setPos(
|
||||
0,
|
||||
firstByteItem->pos().y()
|
||||
);
|
||||
}
|
||||
|
||||
ByteAddressItem* addressLabel = nullptr;
|
||||
if (static_cast<int>(rowIndex) > layoutItemMaxIndex) {
|
||||
addressLabel = new ByteAddressItem(this);
|
||||
this->addressItemsByRowIndex.insert(std::pair(rowIndex, addressLabel));
|
||||
// Delete any address items we no longer need
|
||||
const auto addressItemCount = this->addressItemsByRowIndex.size();
|
||||
|
||||
} else {
|
||||
addressLabel = this->addressItemsByRowIndex.at(rowIndex);
|
||||
if (newRowCount > 0 && newRowCount < addressItemCount) {
|
||||
for (auto i = (addressItemCount - 1); i >= newRowCount; i--) {
|
||||
delete this->addressItemsByRowIndex.at(i);
|
||||
this->addressItemsByRowIndex.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
const auto& firstByteItem = byteItems.front();
|
||||
addressLabel->setAddressHex(firstByteItem->relativeAddressHex);
|
||||
addressLabel->setPos(
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ByteAddressContainer::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
static const auto backgroundColor = QColor(0x35, 0x36, 0x33);
|
||||
static const auto borderColor = QColor(0x41, 0x42, 0x3F);
|
||||
|
||||
painter->setPen(Qt::PenStyle::NoPen);
|
||||
painter->setBrush(backgroundColor);
|
||||
painter->drawRect(
|
||||
0,
|
||||
firstByteItem->pos().y()
|
||||
0,
|
||||
ByteAddressContainer::WIDTH,
|
||||
static_cast<int>(this->boundingRect().height())
|
||||
);
|
||||
|
||||
painter->setPen(borderColor);
|
||||
painter->drawLine(
|
||||
ByteAddressContainer::WIDTH - 1,
|
||||
0,
|
||||
ByteAddressContainer::WIDTH - 1,
|
||||
static_cast<int>(this->boundingRect().height())
|
||||
);
|
||||
}
|
||||
|
||||
// Delete any address items we no longer need
|
||||
const auto addressItemCount = this->addressItemsByRowIndex.size();
|
||||
|
||||
if (newRowCount > 0 && newRowCount < addressItemCount) {
|
||||
for (auto i = (addressItemCount - 1); i >= newRowCount; i--) {
|
||||
delete this->addressItemsByRowIndex.at(i);
|
||||
this->addressItemsByRowIndex.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ByteAddressContainer::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
static const auto backgroundColor = QColor(0x35, 0x36, 0x33);
|
||||
static const auto borderColor = QColor(0x41, 0x42, 0x3F);
|
||||
|
||||
painter->setPen(Qt::PenStyle::NoPen);
|
||||
painter->setBrush(backgroundColor);
|
||||
painter->drawRect(
|
||||
0,
|
||||
0,
|
||||
ByteAddressContainer::WIDTH,
|
||||
static_cast<int>(this->boundingRect().height())
|
||||
);
|
||||
|
||||
painter->setPen(borderColor);
|
||||
painter->drawLine(
|
||||
ByteAddressContainer::WIDTH - 1,
|
||||
0,
|
||||
ByteAddressContainer::WIDTH - 1,
|
||||
static_cast<int>(this->boundingRect().height())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,31 @@
|
||||
#include "ByteAddressItem.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
void ByteAddressItem::setAddressHex(const QString& addressHex) {
|
||||
this->setCacheMode(
|
||||
QGraphicsItem::CacheMode::ItemCoordinateCache,
|
||||
QSize(ByteAddressItem::WIDTH, ByteAddressItem::HEIGHT)
|
||||
);
|
||||
this->addressHex = addressHex;
|
||||
}
|
||||
|
||||
void ByteAddressItem::setAddressHex(const QString& addressHex) {
|
||||
this->setCacheMode(
|
||||
QGraphicsItem::CacheMode::ItemCoordinateCache,
|
||||
QSize(ByteAddressItem::WIDTH, ByteAddressItem::HEIGHT)
|
||||
);
|
||||
this->addressHex = addressHex;
|
||||
}
|
||||
|
||||
void ByteAddressItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
|
||||
static const auto widgetRect = this->boundingRect();
|
||||
static auto fontColor = QColor(0x8F, 0x91, 0x92);
|
||||
static auto font = QFont("'Ubuntu', sans-serif");
|
||||
font.setPixelSize(12);
|
||||
fontColor.setAlpha(!this->isEnabled() ? 100 : 255);
|
||||
|
||||
painter->setFont(font);
|
||||
painter->setPen(fontColor);
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, this->addressHex);
|
||||
void ByteAddressItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
painter->setRenderHints(
|
||||
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
|
||||
true
|
||||
);
|
||||
|
||||
static const auto widgetRect = this->boundingRect();
|
||||
static auto fontColor = QColor(0x8F, 0x91, 0x92);
|
||||
static auto font = QFont("'Ubuntu', sans-serif");
|
||||
font.setPixelSize(12);
|
||||
fontColor.setAlpha(!this->isEnabled() ? 100 : 255);
|
||||
|
||||
painter->setFont(font);
|
||||
painter->setPen(fontColor);
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, this->addressHex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,166 +1,175 @@
|
||||
#include "ByteItem.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
ByteItem::ByteItem(
|
||||
std::size_t byteIndex,
|
||||
std::uint32_t address,
|
||||
std::optional<std::uint32_t>& currentStackPointer,
|
||||
std::optional<ByteItem*>& hoveredByteItem,
|
||||
std::optional<AnnotationItem*>& hoveredAnnotationItem,
|
||||
std::set<std::uint32_t>& highlightedAddresses,
|
||||
const HexViewerWidgetSettings& settings
|
||||
):
|
||||
QGraphicsItem(nullptr),
|
||||
byteIndex(byteIndex),
|
||||
address(address),
|
||||
currentStackPointer(currentStackPointer),
|
||||
hoveredByteItem(hoveredByteItem),
|
||||
hoveredAnnotationItem(hoveredAnnotationItem),
|
||||
highlightedAddresses(highlightedAddresses),
|
||||
settings(settings)
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
this->setCacheMode(
|
||||
QGraphicsItem::CacheMode::ItemCoordinateCache,
|
||||
QSize(ByteItem::WIDTH, ByteItem::HEIGHT)
|
||||
);
|
||||
this->setAcceptHoverEvents(true);
|
||||
ByteItem::ByteItem(
|
||||
std::size_t byteIndex,
|
||||
std::uint32_t address,
|
||||
std::optional<std::uint32_t>& currentStackPointer,
|
||||
std::optional<ByteItem*>& hoveredByteItem,
|
||||
std::optional<AnnotationItem*>& hoveredAnnotationItem,
|
||||
std::set<std::uint32_t>& highlightedAddresses,
|
||||
const HexViewerWidgetSettings& settings
|
||||
)
|
||||
: QGraphicsItem(nullptr)
|
||||
, byteIndex(byteIndex)
|
||||
, address(address)
|
||||
, currentStackPointer(currentStackPointer)
|
||||
, hoveredByteItem(hoveredByteItem)
|
||||
, hoveredAnnotationItem(hoveredAnnotationItem)
|
||||
, highlightedAddresses(highlightedAddresses)
|
||||
, settings(settings)
|
||||
{
|
||||
this->setCacheMode(
|
||||
QGraphicsItem::CacheMode::ItemCoordinateCache,
|
||||
QSize(ByteItem::WIDTH, ByteItem::HEIGHT)
|
||||
);
|
||||
this->setAcceptHoverEvents(true);
|
||||
|
||||
this->addressHex = "0x" + QString::number(this->address, 16).rightJustified(8, '0').toUpper();
|
||||
this->relativeAddressHex = "0x" + QString::number(this->byteIndex, 16).rightJustified(8, '0').toUpper();
|
||||
this->addressHex = "0x" + QString::number(this->address, 16).rightJustified(
|
||||
8,
|
||||
'0'
|
||||
).toUpper();
|
||||
this->relativeAddressHex = "0x" + QString::number(this->byteIndex, 16).rightJustified(
|
||||
8,
|
||||
'0'
|
||||
).toUpper();
|
||||
|
||||
this->setSelected(false);
|
||||
}
|
||||
|
||||
void ByteItem::setValue(unsigned char value) {
|
||||
this->valueChanged = this->valueInitialised && this->value != value;
|
||||
|
||||
this->value = value;
|
||||
this->hexValue = QString::number(this->value, 16).rightJustified(2, '0').toUpper();
|
||||
this->asciiValue = (this->value >= 32 && this->value <= 126)
|
||||
? std::optional("'" + QString(QChar(this->value)) + "'") : std::nullopt;
|
||||
|
||||
this->valueInitialised = this->excludedMemoryRegion == nullptr;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ByteItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
painter->setPen(Qt::PenStyle::NoPen);
|
||||
|
||||
// TODO: This code could do with some tidying. It's getting quite messy.
|
||||
|
||||
static const auto widgetRect = this->boundingRect();
|
||||
static const auto standardTextColor = QColor(0xAF, 0xB1, 0xB3);
|
||||
static const auto valueChangedTextColor = QColor(0x54, 0x7F, 0xBA);
|
||||
static auto font = QFont("'Ubuntu', sans-serif");
|
||||
|
||||
static const auto highlightedBackgroundColor = QColor(0x3C, 0x59, 0x5C, 255);
|
||||
static const auto focusedRegionBackgroundColor = QColor(0x44, 0x44, 0x41, 255);
|
||||
static const auto stackMemoryBackgroundColor = QColor(0x67, 0x57, 0x20, 210);
|
||||
static const auto hoveredBackgroundColor = QColor(0x8E, 0x8B, 0x83, 70);
|
||||
static const auto hoveredNeighbourBackgroundColor = QColor(0x8E, 0x8B, 0x83, 30);
|
||||
static const auto hoveredAnnotationBackgroundColor = QColor(0x8E, 0x8B, 0x83, 50);
|
||||
|
||||
const auto isEnabled = this->isEnabled();
|
||||
|
||||
const auto highlightingEnabled = !this->highlightedAddresses.empty();
|
||||
const auto highlightedByte = highlightingEnabled && this->highlightedAddresses.contains(this->address);
|
||||
|
||||
auto textColor = standardTextColor;
|
||||
auto asciiTextColor = QColor(0xA7, 0x77, 0x26);
|
||||
|
||||
auto backgroundColor = std::optional<QColor>();
|
||||
|
||||
font.setPixelSize(11);
|
||||
painter->setFont(font);
|
||||
|
||||
if (highlightedByte) {
|
||||
backgroundColor = highlightedBackgroundColor;
|
||||
asciiTextColor = standardTextColor;
|
||||
|
||||
} else if (this->settings.highlightStackMemory && this->currentStackPointer.has_value()
|
||||
&& this->address > this->currentStackPointer
|
||||
) {
|
||||
// This byte is within the stack memory
|
||||
backgroundColor = stackMemoryBackgroundColor;
|
||||
asciiTextColor = standardTextColor;
|
||||
|
||||
} else if (this->settings.highlightFocusedMemory && this->focusedMemoryRegion != nullptr) {
|
||||
// This byte is within a focused region
|
||||
backgroundColor = focusedRegionBackgroundColor;
|
||||
this->setSelected(false);
|
||||
}
|
||||
|
||||
const auto* hoveredByteItem = this->hoveredByteItem.value_or(nullptr);
|
||||
const auto* hoveredAnnotationItem = this->hoveredAnnotationItem.value_or(nullptr);
|
||||
if (hoveredByteItem != nullptr) {
|
||||
if (hoveredByteItem == this) {
|
||||
if (backgroundColor.has_value()) {
|
||||
backgroundColor->setAlpha(255);
|
||||
void ByteItem::setValue(unsigned char value) {
|
||||
this->valueChanged = this->valueInitialised && this->value != value;
|
||||
|
||||
} else {
|
||||
backgroundColor = hoveredBackgroundColor;
|
||||
}
|
||||
this->value = value;
|
||||
this->hexValue = QString::number(this->value, 16).rightJustified(2, '0').toUpper();
|
||||
this->asciiValue = (this->value >= 32 && this->value <= 126)
|
||||
? std::optional("'" + QString(QChar(this->value)) + "'") : std::nullopt;
|
||||
|
||||
} else if (this->settings.highlightHoveredRowAndCol
|
||||
&& (
|
||||
hoveredByteItem->currentColumnIndex == this->currentColumnIndex
|
||||
|| hoveredByteItem->currentRowIndex == this->currentRowIndex
|
||||
)
|
||||
this->valueInitialised = this->excludedMemoryRegion == nullptr;
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ByteItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
painter->setRenderHints(
|
||||
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
|
||||
true
|
||||
);
|
||||
painter->setPen(Qt::PenStyle::NoPen);
|
||||
|
||||
// TODO: This code could do with some tidying. It's getting quite messy.
|
||||
|
||||
static const auto widgetRect = this->boundingRect();
|
||||
static const auto standardTextColor = QColor(0xAF, 0xB1, 0xB3);
|
||||
static const auto valueChangedTextColor = QColor(0x54, 0x7F, 0xBA);
|
||||
static auto font = QFont("'Ubuntu', sans-serif");
|
||||
|
||||
static const auto highlightedBackgroundColor = QColor(0x3C, 0x59, 0x5C, 255);
|
||||
static const auto focusedRegionBackgroundColor = QColor(0x44, 0x44, 0x41, 255);
|
||||
static const auto stackMemoryBackgroundColor = QColor(0x67, 0x57, 0x20, 210);
|
||||
static const auto hoveredBackgroundColor = QColor(0x8E, 0x8B, 0x83, 70);
|
||||
static const auto hoveredNeighbourBackgroundColor = QColor(0x8E, 0x8B, 0x83, 30);
|
||||
static const auto hoveredAnnotationBackgroundColor = QColor(0x8E, 0x8B, 0x83, 50);
|
||||
|
||||
const auto isEnabled = this->isEnabled();
|
||||
|
||||
const auto highlightingEnabled = !this->highlightedAddresses.empty();
|
||||
const auto highlightedByte = highlightingEnabled && this->highlightedAddresses.contains(this->address);
|
||||
|
||||
auto textColor = standardTextColor;
|
||||
auto asciiTextColor = QColor(0xA7, 0x77, 0x26);
|
||||
|
||||
auto backgroundColor = std::optional<QColor>();
|
||||
|
||||
font.setPixelSize(11);
|
||||
painter->setFont(font);
|
||||
|
||||
if (highlightedByte) {
|
||||
backgroundColor = highlightedBackgroundColor;
|
||||
asciiTextColor = standardTextColor;
|
||||
|
||||
} else if (this->settings.highlightStackMemory && this->currentStackPointer.has_value()
|
||||
&& this->address > this->currentStackPointer
|
||||
) {
|
||||
if (backgroundColor.has_value()) {
|
||||
backgroundColor->setAlpha(220);
|
||||
// This byte is within the stack memory
|
||||
backgroundColor = stackMemoryBackgroundColor;
|
||||
asciiTextColor = standardTextColor;
|
||||
|
||||
} else if (this->settings.highlightFocusedMemory && this->focusedMemoryRegion != nullptr) {
|
||||
// This byte is within a focused region
|
||||
backgroundColor = focusedRegionBackgroundColor;
|
||||
}
|
||||
|
||||
const auto* hoveredByteItem = this->hoveredByteItem.value_or(nullptr);
|
||||
const auto* hoveredAnnotationItem = this->hoveredAnnotationItem.value_or(nullptr);
|
||||
if (hoveredByteItem != nullptr) {
|
||||
if (hoveredByteItem == this) {
|
||||
if (backgroundColor.has_value()) {
|
||||
backgroundColor->setAlpha(255);
|
||||
|
||||
} else {
|
||||
backgroundColor = hoveredBackgroundColor;
|
||||
}
|
||||
|
||||
} else if (this->settings.highlightHoveredRowAndCol
|
||||
&& (
|
||||
hoveredByteItem->currentColumnIndex == this->currentColumnIndex
|
||||
|| hoveredByteItem->currentRowIndex == this->currentRowIndex
|
||||
)
|
||||
) {
|
||||
if (backgroundColor.has_value()) {
|
||||
backgroundColor->setAlpha(220);
|
||||
|
||||
} else {
|
||||
backgroundColor = hoveredNeighbourBackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (
|
||||
!this->settings.highlightFocusedMemory
|
||||
&& hoveredAnnotationItem != nullptr
|
||||
&& this->address >= hoveredAnnotationItem->startAddress
|
||||
&& this->address <= hoveredAnnotationItem->endAddress
|
||||
) {
|
||||
backgroundColor = hoveredAnnotationBackgroundColor;
|
||||
}
|
||||
|
||||
if (backgroundColor.has_value()) {
|
||||
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
|
||||
backgroundColor->setAlpha(100);
|
||||
}
|
||||
|
||||
painter->setBrush(backgroundColor.value());
|
||||
painter->drawRect(widgetRect);
|
||||
}
|
||||
|
||||
if (this->valueInitialised && this->excludedMemoryRegion == nullptr) {
|
||||
if (this->settings.displayAsciiValues && this->asciiValue.has_value()) {
|
||||
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
|
||||
asciiTextColor.setAlpha(100);
|
||||
}
|
||||
|
||||
painter->setPen(asciiTextColor);
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, this->asciiValue.value());
|
||||
|
||||
} else {
|
||||
backgroundColor = hoveredNeighbourBackgroundColor;
|
||||
if (!isEnabled || (highlightingEnabled && !highlightedByte) || this->settings.displayAsciiValues) {
|
||||
textColor.setAlpha(100);
|
||||
}
|
||||
|
||||
painter->setPen(textColor);
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, this->hexValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (
|
||||
!this->settings.highlightFocusedMemory
|
||||
&& hoveredAnnotationItem != nullptr
|
||||
&& this->address >= hoveredAnnotationItem->startAddress
|
||||
&& this->address <= hoveredAnnotationItem->endAddress
|
||||
) {
|
||||
backgroundColor = hoveredAnnotationBackgroundColor;
|
||||
}
|
||||
|
||||
if (backgroundColor.has_value()) {
|
||||
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
|
||||
backgroundColor->setAlpha(100);
|
||||
}
|
||||
|
||||
painter->setBrush(backgroundColor.value());
|
||||
painter->drawRect(widgetRect);
|
||||
}
|
||||
|
||||
if (this->valueInitialised && this->excludedMemoryRegion == nullptr) {
|
||||
if (this->settings.displayAsciiValues && this->asciiValue.has_value()) {
|
||||
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
|
||||
asciiTextColor.setAlpha(100);
|
||||
}
|
||||
|
||||
painter->setPen(asciiTextColor);
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, this->asciiValue.value());
|
||||
|
||||
} else {
|
||||
if (!isEnabled || (highlightingEnabled && !highlightedByte) || this->settings.displayAsciiValues) {
|
||||
textColor.setAlpha(100);
|
||||
}
|
||||
|
||||
textColor.setAlpha(100);
|
||||
painter->setPen(textColor);
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, this->hexValue);
|
||||
return;
|
||||
|
||||
static const auto placeholderString = QString("??");
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, placeholderString);
|
||||
}
|
||||
|
||||
} else {
|
||||
textColor.setAlpha(100);
|
||||
painter->setPen(textColor);
|
||||
|
||||
static const auto placeholderString = QString("??");
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, placeholderString);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,54 @@
|
||||
#include "ByteItemContainerGraphicsView.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
ByteItemContainerGraphicsView::ByteItemContainerGraphicsView(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
InsightWorker& insightWorker,
|
||||
const HexViewerWidgetSettings& settings,
|
||||
QLabel* hoveredAddressLabel,
|
||||
QWidget* parent
|
||||
): QGraphicsView(parent) {
|
||||
this->setObjectName("graphics-view");
|
||||
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
|
||||
this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
|
||||
this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
this->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
|
||||
|
||||
ByteItemContainerGraphicsView::ByteItemContainerGraphicsView(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
InsightWorker& insightWorker,
|
||||
const HexViewerWidgetSettings& settings,
|
||||
QLabel* hoveredAddressLabel,
|
||||
QWidget* parent
|
||||
): QGraphicsView(parent) {
|
||||
this->setObjectName("graphics-view");
|
||||
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
|
||||
this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
|
||||
this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
this->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
|
||||
this->scene = new ByteItemGraphicsScene(
|
||||
targetMemoryDescriptor,
|
||||
focusedMemoryRegions,
|
||||
excludedMemoryRegions,
|
||||
insightWorker,
|
||||
settings,
|
||||
hoveredAddressLabel,
|
||||
this
|
||||
);
|
||||
|
||||
this->scene = new ByteItemGraphicsScene(
|
||||
targetMemoryDescriptor,
|
||||
focusedMemoryRegions,
|
||||
excludedMemoryRegions,
|
||||
insightWorker,
|
||||
settings,
|
||||
hoveredAddressLabel,
|
||||
this
|
||||
);
|
||||
this->setScene(this->scene);
|
||||
|
||||
this->setScene(this->scene);
|
||||
|
||||
}
|
||||
|
||||
void ByteItemContainerGraphicsView::scrollToByteItemAtAddress(std::uint32_t address) {
|
||||
this->centerOn(this->scene->getByteItemPositionByAddress(address));
|
||||
}
|
||||
|
||||
bool ByteItemContainerGraphicsView::event(QEvent* event) {
|
||||
const auto eventType = event->type();
|
||||
if (eventType == QEvent::Type::EnabledChange) {
|
||||
this->scene->setEnabled(this->isEnabled());
|
||||
}
|
||||
|
||||
return QGraphicsView::event(event);
|
||||
}
|
||||
void ByteItemContainerGraphicsView::scrollToByteItemAtAddress(std::uint32_t address) {
|
||||
this->centerOn(this->scene->getByteItemPositionByAddress(address));
|
||||
}
|
||||
|
||||
void ByteItemContainerGraphicsView::resizeEvent(QResizeEvent* event) {
|
||||
QGraphicsView::resizeEvent(event);
|
||||
this->scene->adjustSize();
|
||||
bool ByteItemContainerGraphicsView::event(QEvent* event) {
|
||||
const auto eventType = event->type();
|
||||
if (eventType == QEvent::Type::EnabledChange) {
|
||||
this->scene->setEnabled(this->isEnabled());
|
||||
}
|
||||
|
||||
return QGraphicsView::event(event);
|
||||
}
|
||||
|
||||
void ByteItemContainerGraphicsView::resizeEvent(QResizeEvent* event) {
|
||||
QGraphicsView::resizeEvent(event);
|
||||
this->scene->adjustSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,494 +2,497 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
ByteItemGraphicsScene::ByteItemGraphicsScene(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
InsightWorker& insightWorker,
|
||||
const HexViewerWidgetSettings& settings,
|
||||
QLabel* hoveredAddressLabel,
|
||||
QGraphicsView* parent
|
||||
):
|
||||
QGraphicsScene(parent),
|
||||
targetMemoryDescriptor(targetMemoryDescriptor),
|
||||
focusedMemoryRegions(focusedMemoryRegions),
|
||||
excludedMemoryRegions(excludedMemoryRegions),
|
||||
insightWorker(insightWorker),
|
||||
settings(settings),
|
||||
hoveredAddressLabel(hoveredAddressLabel),
|
||||
parent(parent)
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
this->setObjectName("byte-widget-container");
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
this->byteAddressContainer = new ByteAddressContainer();
|
||||
this->addItem(this->byteAddressContainer);
|
||||
ByteItemGraphicsScene::ByteItemGraphicsScene(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
InsightWorker& insightWorker,
|
||||
const HexViewerWidgetSettings& settings,
|
||||
QLabel* hoveredAddressLabel,
|
||||
QGraphicsView* parent
|
||||
)
|
||||
: QGraphicsScene(parent)
|
||||
, targetMemoryDescriptor(targetMemoryDescriptor)
|
||||
, focusedMemoryRegions(focusedMemoryRegions)
|
||||
, excludedMemoryRegions(excludedMemoryRegions)
|
||||
, insightWorker(insightWorker)
|
||||
, settings(settings)
|
||||
, hoveredAddressLabel(hoveredAddressLabel)
|
||||
, parent(parent)
|
||||
{
|
||||
this->setObjectName("byte-widget-container");
|
||||
|
||||
// Construct ByteWidget objects
|
||||
const auto memorySize = this->targetMemoryDescriptor.size();
|
||||
const auto startAddress = this->targetMemoryDescriptor.addressRange.startAddress;
|
||||
for (std::uint32_t i = 0; i < memorySize; i++) {
|
||||
const auto address = startAddress + i;
|
||||
this->byteAddressContainer = new ByteAddressContainer();
|
||||
this->addItem(this->byteAddressContainer);
|
||||
|
||||
auto* byteWidget = new ByteItem(
|
||||
i,
|
||||
address,
|
||||
this->currentStackPointer,
|
||||
this->hoveredByteWidget,
|
||||
this->hoveredAnnotationItem,
|
||||
this->highlightedAddresses,
|
||||
settings
|
||||
// Construct ByteWidget objects
|
||||
const auto memorySize = this->targetMemoryDescriptor.size();
|
||||
const auto startAddress = this->targetMemoryDescriptor.addressRange.startAddress;
|
||||
for (std::uint32_t i = 0; i < memorySize; i++) {
|
||||
const auto address = startAddress + i;
|
||||
|
||||
auto* byteWidget = new ByteItem(
|
||||
i,
|
||||
address,
|
||||
this->currentStackPointer,
|
||||
this->hoveredByteWidget,
|
||||
this->hoveredAnnotationItem,
|
||||
this->highlightedAddresses,
|
||||
settings
|
||||
);
|
||||
|
||||
this->byteItemsByAddress.insert(std::pair(
|
||||
address,
|
||||
byteWidget
|
||||
));
|
||||
|
||||
this->addItem(byteWidget);
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&ByteItemGraphicsScene::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->byteItemsByAddress.insert(std::pair(
|
||||
address,
|
||||
byteWidget
|
||||
));
|
||||
|
||||
this->addItem(byteWidget);
|
||||
this->refreshRegions();
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&ByteItemGraphicsScene::onTargetStateChanged
|
||||
);
|
||||
void ByteItemGraphicsScene::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
|
||||
byteWidget->setValue(buffer.at(byteWidget->byteIndex));
|
||||
}
|
||||
|
||||
this->refreshRegions();
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
|
||||
byteWidget->setValue(buffer.at(byteWidget->byteIndex));
|
||||
this->updateAnnotationValues(buffer);
|
||||
this->lastValueBuffer = buffer;
|
||||
}
|
||||
|
||||
this->updateAnnotationValues(buffer);
|
||||
this->lastValueBuffer = buffer;
|
||||
}
|
||||
void ByteItemGraphicsScene::updateStackPointer(std::uint32_t stackPointer) {
|
||||
this->currentStackPointer = stackPointer;
|
||||
this->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::updateStackPointer(std::uint32_t stackPointer) {
|
||||
this->currentStackPointer = stackPointer;
|
||||
this->invalidateChildItemCaches();
|
||||
}
|
||||
void ByteItemGraphicsScene::setHighlightedAddresses(const std::set<std::uint32_t>& highlightedAddresses) {
|
||||
this->highlightedAddresses = highlightedAddresses;
|
||||
this->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::setHighlightedAddresses(const std::set<std::uint32_t>& highlightedAddresses) {
|
||||
this->highlightedAddresses = highlightedAddresses;
|
||||
this->invalidateChildItemCaches();
|
||||
}
|
||||
void ByteItemGraphicsScene::refreshRegions() {
|
||||
for (auto& [byteAddress, byteWidget] : this->byteItemsByAddress) {
|
||||
byteWidget->focusedMemoryRegion = nullptr;
|
||||
byteWidget->excludedMemoryRegion = nullptr;
|
||||
|
||||
void ByteItemGraphicsScene::refreshRegions() {
|
||||
for (auto& [byteAddress, byteWidget] : this->byteItemsByAddress) {
|
||||
byteWidget->focusedMemoryRegion = nullptr;
|
||||
byteWidget->excludedMemoryRegion = nullptr;
|
||||
for (const auto& focusedRegion : this->focusedMemoryRegions) {
|
||||
if (byteAddress >= focusedRegion.addressRange.startAddress
|
||||
&& byteAddress <= focusedRegion.addressRange.endAddress
|
||||
) {
|
||||
byteWidget->focusedMemoryRegion = &focusedRegion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& excludedRegion : this->excludedMemoryRegions) {
|
||||
if (byteAddress >= excludedRegion.addressRange.startAddress
|
||||
&& byteAddress <= excludedRegion.addressRange.endAddress
|
||||
) {
|
||||
byteWidget->excludedMemoryRegion = &excludedRegion;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
// Refresh annotation items
|
||||
this->hoveredAnnotationItem = std::nullopt;
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
this->removeItem(annotationItem);
|
||||
delete annotationItem;
|
||||
}
|
||||
|
||||
this->annotationItems.clear();
|
||||
this->valueAnnotationItems.clear();
|
||||
|
||||
for (const auto& focusedRegion : this->focusedMemoryRegions) {
|
||||
if (byteAddress >= focusedRegion.addressRange.startAddress
|
||||
&& byteAddress <= focusedRegion.addressRange.endAddress
|
||||
) {
|
||||
byteWidget->focusedMemoryRegion = &focusedRegion;
|
||||
break;
|
||||
auto* annotationItem = new AnnotationItem(focusedRegion, AnnotationItemPosition::BOTTOM);
|
||||
annotationItem->setEnabled(this->enabled);
|
||||
this->addItem(annotationItem);
|
||||
this->annotationItems.emplace_back(annotationItem);
|
||||
|
||||
if (focusedRegion.dataType != MemoryRegionDataType::UNKNOWN) {
|
||||
auto* valueAnnotationItem = new ValueAnnotationItem(focusedRegion);
|
||||
valueAnnotationItem->setEnabled(this->enabled);
|
||||
this->addItem(valueAnnotationItem);
|
||||
this->annotationItems.emplace_back(valueAnnotationItem);
|
||||
this->valueAnnotationItems.emplace_back(valueAnnotationItem);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& excludedRegion : this->excludedMemoryRegions) {
|
||||
if (byteAddress >= excludedRegion.addressRange.startAddress
|
||||
&& byteAddress <= excludedRegion.addressRange.endAddress
|
||||
) {
|
||||
byteWidget->excludedMemoryRegion = &excludedRegion;
|
||||
break;
|
||||
if (this->targetState == Targets::TargetState::STOPPED && this->enabled && !this->lastValueBuffer.empty()) {
|
||||
this->updateAnnotationValues(this->lastValueBuffer);
|
||||
}
|
||||
|
||||
this->adjustSize(true);
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::adjustSize(bool forced) {
|
||||
const auto width = this->getSceneWidth();
|
||||
|
||||
const auto columnCount = static_cast<std::size_t>(
|
||||
std::floor(
|
||||
(width - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH
|
||||
+ ByteItem::RIGHT_MARGIN) / (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
|
||||
)
|
||||
);
|
||||
const auto rowCount = static_cast<int>(
|
||||
std::ceil(static_cast<double>(this->byteItemsByAddress.size()) / static_cast<double>(columnCount))
|
||||
);
|
||||
|
||||
// Don't bother recalculating the byte & annotation positions if the number of rows & columns haven't changed.
|
||||
if (this->byteItemsByAddress.empty()
|
||||
|| (
|
||||
!forced
|
||||
&& rowCount == this->byteItemsByRowIndex.size()
|
||||
&& columnCount == this->byteItemsByColumnIndex.size()
|
||||
)
|
||||
) {
|
||||
this->setSceneRect(
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
std::max(static_cast<int>(this->sceneRect().height()), this->parent->viewport()->height())
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->byteItemsByAddress.empty()) {
|
||||
this->adjustByteItemPositions();
|
||||
|
||||
if (this->settings.displayAnnotations) {
|
||||
this->adjustAnnotationItemPositions();
|
||||
}
|
||||
|
||||
const auto* lastByteItem = (--this->byteItemsByAddress.end())->second;
|
||||
const auto sceneHeight = static_cast<int>(
|
||||
lastByteItem->pos().y() + ByteItem::HEIGHT + AnnotationItem::BOTTOM_HEIGHT + this->margins.bottom()
|
||||
);
|
||||
|
||||
this->setSceneRect(
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
std::max(sceneHeight, this->parent->height())
|
||||
);
|
||||
}
|
||||
|
||||
byteWidget->update();
|
||||
this->update();
|
||||
}
|
||||
|
||||
// Refresh annotation items
|
||||
this->hoveredAnnotationItem = std::nullopt;
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
this->removeItem(annotationItem);
|
||||
delete annotationItem;
|
||||
}
|
||||
void ByteItemGraphicsScene::setEnabled(bool enabled) {
|
||||
if (this->enabled != enabled) {
|
||||
this->enabled = enabled;
|
||||
|
||||
this->annotationItems.clear();
|
||||
this->valueAnnotationItems.clear();
|
||||
for (auto& [byteAddress, byteItem] : this->byteItemsByAddress) {
|
||||
byteItem->setEnabled(this->enabled);
|
||||
}
|
||||
|
||||
for (const auto& focusedRegion : this->focusedMemoryRegions) {
|
||||
auto* annotationItem = new AnnotationItem(focusedRegion, AnnotationItemPosition::BOTTOM);
|
||||
annotationItem->setEnabled(this->enabled);
|
||||
this->addItem(annotationItem);
|
||||
this->annotationItems.emplace_back(annotationItem);
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
annotationItem->setEnabled(this->enabled);
|
||||
}
|
||||
|
||||
if (focusedRegion.dataType != MemoryRegionDataType::UNKNOWN) {
|
||||
auto* valueAnnotationItem = new ValueAnnotationItem(focusedRegion);
|
||||
valueAnnotationItem->setEnabled(this->enabled);
|
||||
this->addItem(valueAnnotationItem);
|
||||
this->annotationItems.emplace_back(valueAnnotationItem);
|
||||
this->valueAnnotationItems.emplace_back(valueAnnotationItem);
|
||||
this->byteAddressContainer->setEnabled(enabled);
|
||||
this->byteAddressContainer->update();
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->targetState == Targets::TargetState::STOPPED && this->enabled && !this->lastValueBuffer.empty()) {
|
||||
this->updateAnnotationValues(this->lastValueBuffer);
|
||||
}
|
||||
|
||||
this->adjustSize(true);
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::adjustSize(bool forced) {
|
||||
const auto width = this->getSceneWidth();
|
||||
|
||||
const auto columnCount = static_cast<std::size_t>(
|
||||
std::floor(
|
||||
(width - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH + ByteItem::RIGHT_MARGIN)
|
||||
/ (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
|
||||
)
|
||||
);
|
||||
const auto rowCount = static_cast<int>(
|
||||
std::ceil(static_cast<double>(this->byteItemsByAddress.size()) / static_cast<double>(columnCount))
|
||||
);
|
||||
|
||||
// Don't bother recalculating the byte item & annotation positions if the number of rows & columns have not changed.
|
||||
if (this->byteItemsByAddress.empty()
|
||||
|| (
|
||||
!forced
|
||||
&& rowCount == this->byteItemsByRowIndex.size()
|
||||
&& columnCount == this->byteItemsByColumnIndex.size()
|
||||
)
|
||||
) {
|
||||
this->setSceneRect(
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
std::max(static_cast<int>(this->sceneRect().height()), this->parent->viewport()->height())
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->byteItemsByAddress.empty()) {
|
||||
this->adjustByteItemPositions();
|
||||
|
||||
if (this->settings.displayAnnotations) {
|
||||
this->adjustAnnotationItemPositions();
|
||||
}
|
||||
|
||||
const auto* lastByteItem = (--this->byteItemsByAddress.end())->second;
|
||||
const auto sceneHeight = static_cast<int>(
|
||||
lastByteItem->pos().y() + ByteItem::HEIGHT + AnnotationItem::BOTTOM_HEIGHT + this->margins.bottom()
|
||||
);
|
||||
|
||||
this->setSceneRect(
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
std::max(sceneHeight, this->parent->height())
|
||||
);
|
||||
}
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::setEnabled(bool enabled) {
|
||||
if (this->enabled != enabled) {
|
||||
this->enabled = enabled;
|
||||
|
||||
for (auto& [byteAddress, byteItem] : this->byteItemsByAddress) {
|
||||
byteItem->setEnabled(this->enabled);
|
||||
void ByteItemGraphicsScene::invalidateChildItemCaches() {
|
||||
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
annotationItem->setEnabled(this->enabled);
|
||||
annotationItem->update();
|
||||
}
|
||||
}
|
||||
|
||||
QPointF ByteItemGraphicsScene::getByteItemPositionByAddress(std::uint32_t address) {
|
||||
if (this->byteItemsByAddress.contains(address)) {
|
||||
return this->byteItemsByAddress.at(address)->pos();
|
||||
}
|
||||
|
||||
this->byteAddressContainer->setEnabled(enabled);
|
||||
this->byteAddressContainer->update();
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::invalidateChildItemCaches() {
|
||||
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
|
||||
byteWidget->update();
|
||||
return QPointF();
|
||||
}
|
||||
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
annotationItem->update();
|
||||
}
|
||||
}
|
||||
|
||||
QPointF ByteItemGraphicsScene::getByteItemPositionByAddress(std::uint32_t address) {
|
||||
if (this->byteItemsByAddress.contains(address)) {
|
||||
return this->byteItemsByAddress.at(address)->pos();
|
||||
}
|
||||
|
||||
return QPointF();
|
||||
}
|
||||
|
||||
bool ByteItemGraphicsScene::event(QEvent* event) {
|
||||
if (event->type() == QEvent::Type::GraphicsSceneLeave && this->hoveredByteWidget.has_value()) {
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
|
||||
return QGraphicsScene::event(event);
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
|
||||
auto hoveredItems = this->items(mouseEvent->scenePos());
|
||||
ByteItem* hoveredByteItem = nullptr;
|
||||
AnnotationItem* hoveredAnnotationItem = nullptr;
|
||||
|
||||
if (!hoveredItems.empty()) {
|
||||
hoveredByteItem = dynamic_cast<ByteItem*>(hoveredItems.at(0));
|
||||
hoveredAnnotationItem = dynamic_cast<AnnotationItem*>(hoveredItems.at(0));
|
||||
}
|
||||
|
||||
if (hoveredByteItem != nullptr) {
|
||||
this->onByteWidgetEnter(hoveredByteItem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->hoveredByteWidget.has_value()) {
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
|
||||
if (hoveredAnnotationItem != nullptr) {
|
||||
this->onAnnotationItemEnter(hoveredAnnotationItem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->hoveredAnnotationItem.has_value()) {
|
||||
this->onAnnotationItemLeave();
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::updateAnnotationValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
const auto memoryStartAddress = this->targetMemoryDescriptor.addressRange.startAddress;
|
||||
for (auto* valueAnnotationItem : this->valueAnnotationItems) {
|
||||
if (valueAnnotationItem->size > buffer.size()) {
|
||||
continue;
|
||||
bool ByteItemGraphicsScene::event(QEvent* event) {
|
||||
if (event->type() == QEvent::Type::GraphicsSceneLeave && this->hoveredByteWidget.has_value()) {
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
|
||||
const auto relativeStartAddress = valueAnnotationItem->startAddress - memoryStartAddress;
|
||||
const auto relativeEndAddress = valueAnnotationItem->endAddress - memoryStartAddress;
|
||||
|
||||
valueAnnotationItem->setValue(Targets::TargetMemoryBuffer(
|
||||
buffer.begin() + relativeStartAddress,
|
||||
buffer.begin() + relativeEndAddress + 1
|
||||
));
|
||||
return QGraphicsScene::event(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::adjustByteItemPositions() {
|
||||
const auto columnCount = static_cast<std::size_t>(
|
||||
std::floor(
|
||||
(this->getSceneWidth() - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH + ByteItem::RIGHT_MARGIN)
|
||||
/ (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
|
||||
)
|
||||
);
|
||||
void ByteItemGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
|
||||
auto hoveredItems = this->items(mouseEvent->scenePos());
|
||||
ByteItem* hoveredByteItem = nullptr;
|
||||
AnnotationItem* hoveredAnnotationItem = nullptr;
|
||||
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByRowIndex;
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByColumnIndex;
|
||||
if (!hoveredItems.empty()) {
|
||||
hoveredByteItem = dynamic_cast<ByteItem*>(hoveredItems.at(0));
|
||||
hoveredAnnotationItem = dynamic_cast<AnnotationItem*>(hoveredItems.at(0));
|
||||
}
|
||||
|
||||
auto rowIndicesWithTopAnnotations = std::set<std::size_t>();
|
||||
auto rowIndicesWithBottomAnnotations = std::set<std::size_t>();
|
||||
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
|
||||
if (hoveredByteItem != nullptr) {
|
||||
this->onByteWidgetEnter(hoveredByteItem);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
const auto firstByteRowIndex = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>((annotationItem->startAddress - memoryAddressRange.startAddress) + 1)
|
||||
/ static_cast<double>(columnCount)) - 1
|
||||
if (this->hoveredByteWidget.has_value()) {
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
|
||||
if (hoveredAnnotationItem != nullptr) {
|
||||
this->onAnnotationItemEnter(hoveredAnnotationItem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->hoveredAnnotationItem.has_value()) {
|
||||
this->onAnnotationItemLeave();
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::updateAnnotationValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
const auto memoryStartAddress = this->targetMemoryDescriptor.addressRange.startAddress;
|
||||
for (auto* valueAnnotationItem : this->valueAnnotationItems) {
|
||||
if (valueAnnotationItem->size > buffer.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto relativeStartAddress = valueAnnotationItem->startAddress - memoryStartAddress;
|
||||
const auto relativeEndAddress = valueAnnotationItem->endAddress - memoryStartAddress;
|
||||
|
||||
valueAnnotationItem->setValue(Targets::TargetMemoryBuffer(
|
||||
buffer.begin() + relativeStartAddress,
|
||||
buffer.begin() + relativeEndAddress + 1
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::adjustByteItemPositions() {
|
||||
const auto columnCount = static_cast<std::size_t>(
|
||||
std::floor(
|
||||
(this->getSceneWidth() - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH
|
||||
+ ByteItem::RIGHT_MARGIN) / (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
|
||||
)
|
||||
);
|
||||
|
||||
const auto lastByteRowIndex = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>((annotationItem->endAddress - memoryAddressRange.startAddress) + 1)
|
||||
/ static_cast<double>(columnCount)) - 1
|
||||
);
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByRowIndex;
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByColumnIndex;
|
||||
|
||||
// We only display annotations that span a single row.
|
||||
if (this->settings.displayAnnotations && firstByteRowIndex == lastByteRowIndex) {
|
||||
annotationItem->show();
|
||||
auto rowIndicesWithTopAnnotations = std::set<std::size_t>();
|
||||
auto rowIndicesWithBottomAnnotations = std::set<std::size_t>();
|
||||
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
|
||||
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
const auto firstByteRowIndex = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>((annotationItem->startAddress - memoryAddressRange.startAddress) + 1)
|
||||
/ static_cast<double>(columnCount)) - 1
|
||||
);
|
||||
|
||||
const auto lastByteRowIndex = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>((annotationItem->endAddress - memoryAddressRange.startAddress) + 1)
|
||||
/ static_cast<double>(columnCount)) - 1
|
||||
);
|
||||
|
||||
// We only display annotations that span a single row.
|
||||
if (this->settings.displayAnnotations && firstByteRowIndex == lastByteRowIndex) {
|
||||
annotationItem->show();
|
||||
|
||||
if (annotationItem->position == AnnotationItemPosition::TOP) {
|
||||
rowIndicesWithTopAnnotations.insert(firstByteRowIndex);
|
||||
|
||||
} else if (annotationItem->position == AnnotationItemPosition::BOTTOM) {
|
||||
rowIndicesWithBottomAnnotations.insert(firstByteRowIndex);
|
||||
}
|
||||
|
||||
} else {
|
||||
annotationItem->hide();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto annotationTopHeight = AnnotationItem::TOP_HEIGHT;
|
||||
constexpr auto annotationBottomHeight = AnnotationItem::BOTTOM_HEIGHT;
|
||||
|
||||
std::size_t lastRowIndex = 0;
|
||||
int rowYPosition = margins.top();
|
||||
auto currentRowAnnotatedTop = false;
|
||||
|
||||
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
|
||||
const auto rowIndex = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(byteWidget->byteIndex + 1) / static_cast<double>(columnCount)) - 1
|
||||
);
|
||||
const auto columnIndex = static_cast<std::size_t>(
|
||||
static_cast<double>(byteWidget->byteIndex)
|
||||
- (std::floor(byteWidget->byteIndex / columnCount) * static_cast<double>(columnCount))
|
||||
);
|
||||
|
||||
if (rowIndex != lastRowIndex) {
|
||||
rowYPosition += ByteItem::HEIGHT + ByteItem::BOTTOM_MARGIN;
|
||||
currentRowAnnotatedTop = false;
|
||||
|
||||
if (rowIndicesWithBottomAnnotations.contains(lastRowIndex)) {
|
||||
rowYPosition += annotationBottomHeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentRowAnnotatedTop && rowIndicesWithTopAnnotations.contains(rowIndex)) {
|
||||
rowYPosition += annotationTopHeight;
|
||||
currentRowAnnotatedTop = true;
|
||||
}
|
||||
|
||||
byteWidget->setPos(
|
||||
static_cast<int>(
|
||||
columnIndex * (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) + this->margins.left()
|
||||
+ ByteAddressContainer::WIDTH
|
||||
),
|
||||
rowYPosition
|
||||
);
|
||||
|
||||
byteWidget->currentRowIndex = rowIndex;
|
||||
byteWidget->currentColumnIndex = columnIndex;
|
||||
|
||||
byteWidgetsByRowIndex[byteWidget->currentRowIndex].emplace_back(byteWidget);
|
||||
byteWidgetsByColumnIndex[byteWidget->currentColumnIndex].emplace_back(byteWidget);
|
||||
|
||||
lastRowIndex = rowIndex;
|
||||
}
|
||||
|
||||
this->byteItemsByRowIndex = std::move(byteWidgetsByRowIndex);
|
||||
this->byteItemsByColumnIndex = std::move(byteWidgetsByColumnIndex);
|
||||
|
||||
this->byteAddressContainer->adjustAddressLabels(this->byteItemsByRowIndex);
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::adjustAnnotationItemPositions() {
|
||||
if (this->byteItemsByAddress.empty() || !this->settings.displayAnnotations) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
if (!this->byteItemsByAddress.contains(annotationItem->startAddress)) {
|
||||
annotationItem->hide();
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto firstByteItemPosition = this->byteItemsByAddress.at(annotationItem->startAddress)->pos();
|
||||
|
||||
if (annotationItem->position == AnnotationItemPosition::TOP) {
|
||||
rowIndicesWithTopAnnotations.insert(firstByteRowIndex);
|
||||
annotationItem->setPos(
|
||||
firstByteItemPosition.x(),
|
||||
firstByteItemPosition.y() - AnnotationItem::TOP_HEIGHT - 1
|
||||
);
|
||||
|
||||
} else if (annotationItem->position == AnnotationItemPosition::BOTTOM) {
|
||||
rowIndicesWithBottomAnnotations.insert(firstByteRowIndex);
|
||||
annotationItem->setPos(
|
||||
firstByteItemPosition.x(),
|
||||
firstByteItemPosition.y() + ByteItem::HEIGHT
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::onByteWidgetEnter(ByteItem* widget) {
|
||||
if (this->hoveredByteWidget.has_value()) {
|
||||
if (this->hoveredByteWidget.value() == widget) {
|
||||
// This byte item is already marked as hovered
|
||||
return;
|
||||
}
|
||||
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
|
||||
this->hoveredByteWidget = widget;
|
||||
|
||||
this->hoveredAddressLabel->setText(
|
||||
"Relative Address (Absolute Address): " + widget->relativeAddressHex + " (" + widget->addressHex + ")"
|
||||
);
|
||||
|
||||
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
|
||||
for (auto& byteWidget : this->byteItemsByColumnIndex.at(widget->currentColumnIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto& byteWidget : this->byteItemsByRowIndex.at(widget->currentRowIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
} else {
|
||||
annotationItem->hide();
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto annotationTopHeight = AnnotationItem::TOP_HEIGHT;
|
||||
constexpr auto annotationBottomHeight = AnnotationItem::BOTTOM_HEIGHT;
|
||||
void ByteItemGraphicsScene::onByteWidgetLeave() {
|
||||
auto* byteItem = this->hoveredByteWidget.value();
|
||||
this->hoveredByteWidget = std::nullopt;
|
||||
|
||||
std::size_t lastRowIndex = 0;
|
||||
int rowYPosition = margins.top();
|
||||
auto currentRowAnnotatedTop = false;
|
||||
this->hoveredAddressLabel->setText("Relative Address (Absolute Address):");
|
||||
|
||||
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
|
||||
const auto rowIndex = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(byteWidget->byteIndex + 1) / static_cast<double>(columnCount)) - 1
|
||||
);
|
||||
const auto columnIndex = static_cast<std::size_t>(
|
||||
static_cast<double>(byteWidget->byteIndex)
|
||||
- (std::floor(byteWidget->byteIndex / columnCount) * static_cast<double>(columnCount))
|
||||
);
|
||||
|
||||
if (rowIndex != lastRowIndex) {
|
||||
rowYPosition += ByteItem::HEIGHT + ByteItem::BOTTOM_MARGIN;
|
||||
currentRowAnnotatedTop = false;
|
||||
|
||||
if (rowIndicesWithBottomAnnotations.contains(lastRowIndex)) {
|
||||
rowYPosition += annotationBottomHeight;
|
||||
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
|
||||
for (auto& byteWidget : this->byteItemsByColumnIndex.at(byteItem->currentColumnIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto& byteWidget : this->byteItemsByRowIndex.at(byteItem->currentRowIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
} else {
|
||||
byteItem->update();
|
||||
}
|
||||
|
||||
if (!currentRowAnnotatedTop && rowIndicesWithTopAnnotations.contains(rowIndex)) {
|
||||
rowYPosition += annotationTopHeight;
|
||||
currentRowAnnotatedTop = true;
|
||||
}
|
||||
|
||||
byteWidget->setPos(
|
||||
static_cast<int>(
|
||||
columnIndex * (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) + this->margins.left() + ByteAddressContainer::WIDTH),
|
||||
rowYPosition
|
||||
);
|
||||
|
||||
byteWidget->currentRowIndex = rowIndex;
|
||||
byteWidget->currentColumnIndex = columnIndex;
|
||||
|
||||
byteWidgetsByRowIndex[byteWidget->currentRowIndex].emplace_back(byteWidget);
|
||||
byteWidgetsByColumnIndex[byteWidget->currentColumnIndex].emplace_back(byteWidget);
|
||||
|
||||
lastRowIndex = rowIndex;
|
||||
}
|
||||
|
||||
this->byteItemsByRowIndex = std::move(byteWidgetsByRowIndex);
|
||||
this->byteItemsByColumnIndex = std::move(byteWidgetsByColumnIndex);
|
||||
void ByteItemGraphicsScene::onAnnotationItemEnter(AnnotationItem* annotationItem) {
|
||||
if (this->hoveredAnnotationItem.has_value()) {
|
||||
if (this->hoveredAnnotationItem.value() == annotationItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->byteAddressContainer->adjustAddressLabels(this->byteItemsByRowIndex);
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::adjustAnnotationItemPositions() {
|
||||
if (this->byteItemsByAddress.empty() || !this->settings.displayAnnotations) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* annotationItem : this->annotationItems) {
|
||||
if (!this->byteItemsByAddress.contains(annotationItem->startAddress)) {
|
||||
annotationItem->hide();
|
||||
continue;
|
||||
this->onAnnotationItemLeave();
|
||||
}
|
||||
|
||||
const auto firstByteItemPosition = this->byteItemsByAddress.at(annotationItem->startAddress)->pos();
|
||||
this->hoveredAnnotationItem = annotationItem;
|
||||
|
||||
if (annotationItem->position == AnnotationItemPosition::TOP) {
|
||||
annotationItem->setPos(
|
||||
firstByteItemPosition.x(),
|
||||
firstByteItemPosition.y() - AnnotationItem::TOP_HEIGHT - 1
|
||||
);
|
||||
for (
|
||||
auto byteItemAddress = annotationItem->startAddress;
|
||||
byteItemAddress <= annotationItem->endAddress;
|
||||
byteItemAddress++
|
||||
) {
|
||||
this->byteItemsByAddress.at(byteItemAddress)->update();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (annotationItem->position == AnnotationItemPosition::BOTTOM) {
|
||||
annotationItem->setPos(
|
||||
firstByteItemPosition.x(),
|
||||
firstByteItemPosition.y() + ByteItem::HEIGHT
|
||||
);
|
||||
void ByteItemGraphicsScene::onAnnotationItemLeave() {
|
||||
auto* annotationItem = this->hoveredAnnotationItem.value();
|
||||
this->hoveredAnnotationItem = std::nullopt;
|
||||
|
||||
for (
|
||||
auto byteItemAddress = annotationItem->startAddress;
|
||||
byteItemAddress <= annotationItem->endAddress;
|
||||
byteItemAddress++
|
||||
) {
|
||||
this->byteItemsByAddress.at(byteItemAddress)->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::onByteWidgetEnter(ByteItem* widget) {
|
||||
if (this->hoveredByteWidget.has_value()) {
|
||||
if (this->hoveredByteWidget.value() == widget) {
|
||||
// This byte item is already marked as hovered
|
||||
return;
|
||||
}
|
||||
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
|
||||
this->hoveredByteWidget = widget;
|
||||
|
||||
this->hoveredAddressLabel->setText(
|
||||
"Relative Address (Absolute Address): " + widget->relativeAddressHex + " (" + widget->addressHex + ")"
|
||||
);
|
||||
|
||||
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
|
||||
for (auto& byteWidget : this->byteItemsByColumnIndex.at(widget->currentColumnIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto& byteWidget : this->byteItemsByRowIndex.at(widget->currentRowIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
} else {
|
||||
widget->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::onByteWidgetLeave() {
|
||||
auto* byteItem = this->hoveredByteWidget.value();
|
||||
this->hoveredByteWidget = std::nullopt;
|
||||
|
||||
this->hoveredAddressLabel->setText("Relative Address (Absolute Address):");
|
||||
|
||||
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
|
||||
for (auto& byteWidget : this->byteItemsByColumnIndex.at(byteItem->currentColumnIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto& byteWidget : this->byteItemsByRowIndex.at(byteItem->currentRowIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
} else {
|
||||
byteItem->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::onAnnotationItemEnter(AnnotationItem* annotationItem) {
|
||||
if (this->hoveredAnnotationItem.has_value()) {
|
||||
if (this->hoveredAnnotationItem.value() == annotationItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->onAnnotationItemLeave();
|
||||
}
|
||||
|
||||
this->hoveredAnnotationItem = annotationItem;
|
||||
|
||||
for (
|
||||
auto byteItemAddress = annotationItem->startAddress;
|
||||
byteItemAddress <= annotationItem->endAddress;
|
||||
byteItemAddress++
|
||||
) {
|
||||
this->byteItemsByAddress.at(byteItemAddress)->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::onAnnotationItemLeave() {
|
||||
auto* annotationItem = this->hoveredAnnotationItem.value();
|
||||
this->hoveredAnnotationItem = std::nullopt;
|
||||
|
||||
for (
|
||||
auto byteItemAddress = annotationItem->startAddress;
|
||||
byteItemAddress <= annotationItem->endAddress;
|
||||
byteItemAddress++
|
||||
) {
|
||||
this->byteItemsByAddress.at(byteItemAddress)->update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,240 +5,244 @@
|
||||
#include "src/Helpers/Paths.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
HexViewerWidget::HexViewerWidget(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
HexViewerWidgetSettings& settings,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
):
|
||||
QWidget(parent),
|
||||
targetMemoryDescriptor(targetMemoryDescriptor),
|
||||
settings(settings),
|
||||
focusedMemoryRegions(focusedMemoryRegions),
|
||||
excludedMemoryRegions(excludedMemoryRegions),
|
||||
insightWorker(insightWorker)
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
this->setObjectName("hex-viewer-widget");
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
auto widgetUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget"
|
||||
+ "/UiFiles/HexViewerWidget.ui"
|
||||
)
|
||||
);
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
if (!widgetUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open HexViewerWidget UI file");
|
||||
}
|
||||
HexViewerWidget::HexViewerWidget(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
HexViewerWidgetSettings& settings,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
)
|
||||
: QWidget(parent)
|
||||
, targetMemoryDescriptor(targetMemoryDescriptor)
|
||||
, settings(settings)
|
||||
, focusedMemoryRegions(focusedMemoryRegions)
|
||||
, excludedMemoryRegions(excludedMemoryRegions)
|
||||
, insightWorker(insightWorker)
|
||||
{
|
||||
this->setObjectName("hex-viewer-widget");
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&widgetUiFile, this);
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(0, 0, 0, 0);
|
||||
auto widgetUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget"
|
||||
+ "/UiFiles/HexViewerWidget.ui"
|
||||
)
|
||||
);
|
||||
|
||||
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
|
||||
this->bottomBar = this->container->findChild<QWidget*>("bottom-bar");
|
||||
if (!widgetUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open HexViewerWidget UI file");
|
||||
}
|
||||
|
||||
this->refreshButton = this->toolBar->findChild<SvgToolButton*>("refresh-memory-btn");
|
||||
this->highlightStackMemoryButton = this->toolBar->findChild<SvgToolButton*>("highlight-stack-memory-btn");
|
||||
this->highlightHoveredRowAndColumnButton = this->toolBar->findChild<SvgToolButton*>(
|
||||
"highlight-hovered-rows-columns-btn"
|
||||
);
|
||||
this->highlightFocusedMemoryButton = this->container->findChild<SvgToolButton*>(
|
||||
"highlight-focused-memory-btn"
|
||||
);
|
||||
this->displayAnnotationsButton = this->container->findChild<SvgToolButton*>("display-annotations-btn");
|
||||
this->displayAsciiButton = this->container->findChild<SvgToolButton*>("display-ascii-btn");
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&widgetUiFile, this);
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
this->goToAddressInput = this->container->findChild<TextInput*>("go-to-address-input");
|
||||
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
|
||||
this->bottomBar = this->container->findChild<QWidget*>("bottom-bar");
|
||||
|
||||
this->toolBar->setContentsMargins(0, 0, 0, 0);
|
||||
this->toolBar->layout()->setContentsMargins(5, 0, 5, 1);
|
||||
this->refreshButton = this->toolBar->findChild<SvgToolButton*>("refresh-memory-btn");
|
||||
this->highlightStackMemoryButton = this->toolBar->findChild<SvgToolButton*>(
|
||||
"highlight-stack-memory-btn"
|
||||
);
|
||||
this->highlightHoveredRowAndColumnButton = this->toolBar->findChild<SvgToolButton*>(
|
||||
"highlight-hovered-rows-columns-btn"
|
||||
);
|
||||
this->highlightFocusedMemoryButton = this->container->findChild<SvgToolButton*>(
|
||||
"highlight-focused-memory-btn"
|
||||
);
|
||||
this->displayAnnotationsButton = this->container->findChild<SvgToolButton*>("display-annotations-btn");
|
||||
this->displayAsciiButton = this->container->findChild<SvgToolButton*>("display-ascii-btn");
|
||||
|
||||
this->bottomBar->setContentsMargins(0, 0, 0, 0);
|
||||
this->bottomBar->layout()->setContentsMargins(5, 0, 5, 0);
|
||||
this->goToAddressInput = this->container->findChild<TextInput*>("go-to-address-input");
|
||||
|
||||
this->hoveredAddressLabel = this->bottomBar->findChild<QLabel*>("byte-address-label");
|
||||
this->toolBar->setContentsMargins(0, 0, 0, 0);
|
||||
this->toolBar->layout()->setContentsMargins(5, 0, 5, 1);
|
||||
|
||||
this->byteItemGraphicsViewContainer = this->container->findChild<QWidget*>("graphics-view-container");
|
||||
this->byteItemGraphicsView = new ByteItemContainerGraphicsView(
|
||||
this->targetMemoryDescriptor,
|
||||
this->focusedMemoryRegions,
|
||||
this->excludedMemoryRegions,
|
||||
this->insightWorker,
|
||||
this->settings,
|
||||
this->hoveredAddressLabel,
|
||||
this->byteItemGraphicsViewContainer
|
||||
);
|
||||
this->byteItemGraphicsScene = this->byteItemGraphicsView->getScene();
|
||||
this->bottomBar->setContentsMargins(0, 0, 0, 0);
|
||||
this->bottomBar->layout()->setContentsMargins(5, 0, 5, 0);
|
||||
|
||||
this->setHoveredRowAndColumnHighlightingEnabled(this->settings.highlightHoveredRowAndCol);
|
||||
this->setFocusedMemoryHighlightingEnabled(this->settings.highlightFocusedMemory);
|
||||
this->setAnnotationsEnabled(this->settings.displayAnnotations);
|
||||
this->setDisplayAsciiEnabled(this->settings.displayAsciiValues);
|
||||
this->hoveredAddressLabel = this->bottomBar->findChild<QLabel*>("byte-address-label");
|
||||
|
||||
if (this->targetMemoryDescriptor.type == Targets::TargetMemoryType::RAM) {
|
||||
this->highlightStackMemoryButton->show();
|
||||
this->setStackMemoryHighlightingEnabled(this->settings.highlightStackMemory);
|
||||
this->byteItemGraphicsViewContainer = this->container->findChild<QWidget*>("graphics-view-container");
|
||||
this->byteItemGraphicsView = new ByteItemContainerGraphicsView(
|
||||
this->targetMemoryDescriptor,
|
||||
this->focusedMemoryRegions,
|
||||
this->excludedMemoryRegions,
|
||||
this->insightWorker,
|
||||
this->settings,
|
||||
this->hoveredAddressLabel,
|
||||
this->byteItemGraphicsViewContainer
|
||||
);
|
||||
this->byteItemGraphicsScene = this->byteItemGraphicsView->getScene();
|
||||
|
||||
this->setHoveredRowAndColumnHighlightingEnabled(this->settings.highlightHoveredRowAndCol);
|
||||
this->setFocusedMemoryHighlightingEnabled(this->settings.highlightFocusedMemory);
|
||||
this->setAnnotationsEnabled(this->settings.displayAnnotations);
|
||||
this->setDisplayAsciiEnabled(this->settings.displayAsciiValues);
|
||||
|
||||
if (this->targetMemoryDescriptor.type == Targets::TargetMemoryType::RAM) {
|
||||
this->highlightStackMemoryButton->show();
|
||||
this->setStackMemoryHighlightingEnabled(this->settings.highlightStackMemory);
|
||||
|
||||
QObject::connect(
|
||||
this->highlightStackMemoryButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setStackMemoryHighlightingEnabled(!this->settings.highlightStackMemory);
|
||||
}
|
||||
);
|
||||
|
||||
} else {
|
||||
this->highlightStackMemoryButton->hide();
|
||||
this->setStackMemoryHighlightingEnabled(false);
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
this->highlightStackMemoryButton,
|
||||
this->highlightHoveredRowAndColumnButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setStackMemoryHighlightingEnabled(!this->settings.highlightStackMemory);
|
||||
this->setHoveredRowAndColumnHighlightingEnabled(!this->settings.highlightHoveredRowAndCol);
|
||||
}
|
||||
);
|
||||
|
||||
} else {
|
||||
this->highlightStackMemoryButton->hide();
|
||||
this->setStackMemoryHighlightingEnabled(false);
|
||||
QObject::connect(
|
||||
this->highlightFocusedMemoryButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setFocusedMemoryHighlightingEnabled(!this->settings.highlightFocusedMemory);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->displayAnnotationsButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setAnnotationsEnabled(!this->settings.displayAnnotations);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->displayAsciiButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setDisplayAsciiEnabled(!this->settings.displayAsciiValues);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->goToAddressInput,
|
||||
&QLineEdit::textEdited,
|
||||
this,
|
||||
&HexViewerWidget::onGoToAddressInputChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->goToAddressInput,
|
||||
&TextInput::focusChanged,
|
||||
this,
|
||||
&HexViewerWidget::onGoToAddressInputChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&HexViewerWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
QObject::connect(
|
||||
this->highlightHoveredRowAndColumnButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setHoveredRowAndColumnHighlightingEnabled(!this->settings.highlightHoveredRowAndCol);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->highlightFocusedMemoryButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setFocusedMemoryHighlightingEnabled(!this->settings.highlightFocusedMemory);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->displayAnnotationsButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setAnnotationsEnabled(!this->settings.displayAnnotations);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->displayAsciiButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setDisplayAsciiEnabled(!this->settings.displayAsciiValues);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->goToAddressInput,
|
||||
&QLineEdit::textEdited,
|
||||
this,
|
||||
&HexViewerWidget::onGoToAddressInputChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->goToAddressInput,
|
||||
&TextInput::focusChanged,
|
||||
this,
|
||||
&HexViewerWidget::onGoToAddressInputChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&HexViewerWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
void HexViewerWidget::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
this->byteItemGraphicsScene->updateValues(buffer);
|
||||
}
|
||||
|
||||
void HexViewerWidget::refreshRegions() {
|
||||
this->byteItemGraphicsScene->refreshRegions();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setStackPointer(std::uint32_t stackPointer) {
|
||||
this->byteItemGraphicsScene->updateStackPointer(stackPointer);
|
||||
}
|
||||
|
||||
void HexViewerWidget::resizeEvent(QResizeEvent* event) {
|
||||
this->container->setFixedSize(
|
||||
this->width(),
|
||||
this->height()
|
||||
);
|
||||
|
||||
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
|
||||
}
|
||||
|
||||
void HexViewerWidget::showEvent(QShowEvent* event) {
|
||||
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
|
||||
}
|
||||
|
||||
void HexViewerWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void HexViewerWidget::setStackMemoryHighlightingEnabled(bool enabled) {
|
||||
this->highlightStackMemoryButton->setChecked(enabled);
|
||||
this->settings.highlightStackMemory = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setHoveredRowAndColumnHighlightingEnabled(bool enabled) {
|
||||
this->highlightHoveredRowAndColumnButton->setChecked(enabled);
|
||||
this->settings.highlightHoveredRowAndCol = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setFocusedMemoryHighlightingEnabled(bool enabled) {
|
||||
this->highlightFocusedMemoryButton->setChecked(enabled);
|
||||
this->settings.highlightFocusedMemory = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setAnnotationsEnabled(bool enabled) {
|
||||
this->displayAnnotationsButton->setChecked(enabled);
|
||||
this->settings.displayAnnotations = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->adjustSize(true);
|
||||
}
|
||||
|
||||
void HexViewerWidget::setDisplayAsciiEnabled(bool enabled) {
|
||||
this->displayAsciiButton->setChecked(enabled);
|
||||
this->settings.displayAsciiValues = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::onGoToAddressInputChanged() {
|
||||
auto addressConversionOk = false;
|
||||
const auto address = this->goToAddressInput->text().toUInt(&addressConversionOk, 16);
|
||||
|
||||
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
|
||||
|
||||
if (addressConversionOk && memoryAddressRange.contains(address) && this->goToAddressInput->hasFocus()) {
|
||||
this->byteItemGraphicsScene->setHighlightedAddresses({address});
|
||||
this->byteItemGraphicsView->scrollToByteItemAtAddress(address);
|
||||
return;
|
||||
void HexViewerWidget::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
this->byteItemGraphicsScene->updateValues(buffer);
|
||||
}
|
||||
|
||||
this->byteItemGraphicsScene->setHighlightedAddresses({});
|
||||
void HexViewerWidget::refreshRegions() {
|
||||
this->byteItemGraphicsScene->refreshRegions();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setStackPointer(std::uint32_t stackPointer) {
|
||||
this->byteItemGraphicsScene->updateStackPointer(stackPointer);
|
||||
}
|
||||
|
||||
void HexViewerWidget::resizeEvent(QResizeEvent* event) {
|
||||
this->container->setFixedSize(
|
||||
this->width(),
|
||||
this->height()
|
||||
);
|
||||
|
||||
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
|
||||
}
|
||||
|
||||
void HexViewerWidget::showEvent(QShowEvent* event) {
|
||||
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
|
||||
}
|
||||
|
||||
void HexViewerWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void HexViewerWidget::setStackMemoryHighlightingEnabled(bool enabled) {
|
||||
this->highlightStackMemoryButton->setChecked(enabled);
|
||||
this->settings.highlightStackMemory = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setHoveredRowAndColumnHighlightingEnabled(bool enabled) {
|
||||
this->highlightHoveredRowAndColumnButton->setChecked(enabled);
|
||||
this->settings.highlightHoveredRowAndCol = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setFocusedMemoryHighlightingEnabled(bool enabled) {
|
||||
this->highlightFocusedMemoryButton->setChecked(enabled);
|
||||
this->settings.highlightFocusedMemory = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::setAnnotationsEnabled(bool enabled) {
|
||||
this->displayAnnotationsButton->setChecked(enabled);
|
||||
this->settings.displayAnnotations = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->adjustSize(true);
|
||||
}
|
||||
|
||||
void HexViewerWidget::setDisplayAsciiEnabled(bool enabled) {
|
||||
this->displayAsciiButton->setChecked(enabled);
|
||||
this->settings.displayAsciiValues = enabled;
|
||||
|
||||
this->byteItemGraphicsScene->invalidateChildItemCaches();
|
||||
}
|
||||
|
||||
void HexViewerWidget::onGoToAddressInputChanged() {
|
||||
auto addressConversionOk = false;
|
||||
const auto address = this->goToAddressInput->text().toUInt(&addressConversionOk, 16);
|
||||
|
||||
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
|
||||
|
||||
if (addressConversionOk && memoryAddressRange.contains(address) && this->goToAddressInput->hasFocus()) {
|
||||
this->byteItemGraphicsScene->setHighlightedAddresses({address});
|
||||
this->byteItemGraphicsView->scrollToByteItemAtAddress(address);
|
||||
return;
|
||||
}
|
||||
|
||||
this->byteItemGraphicsScene->setHighlightedAddresses({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,68 +2,46 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
ValueAnnotationItem::ValueAnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion)
|
||||
: AnnotationItem(focusedMemoryRegion, AnnotationItemPosition::TOP)
|
||||
, focusedMemoryRegion(focusedMemoryRegion)
|
||||
, endianness(focusedMemoryRegion.endianness)
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
|
||||
}
|
||||
|
||||
void ValueAnnotationItem::setValue(const Targets::TargetMemoryBuffer& value) {
|
||||
this->value = value;
|
||||
|
||||
if (this->endianness == Targets::TargetMemoryEndianness::LITTLE) {
|
||||
std::reverse(this->value.begin(), this->value.end());
|
||||
}
|
||||
|
||||
this->refreshLabelText();
|
||||
this->setToolTip(this->labelText);
|
||||
}
|
||||
|
||||
void ValueAnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
auto font = painter->font();
|
||||
font.setItalic(true);
|
||||
painter->setFont(font);
|
||||
|
||||
AnnotationItem::paint(painter, option, widget);
|
||||
}
|
||||
|
||||
void ValueAnnotationItem::refreshLabelText() {
|
||||
this->update();
|
||||
|
||||
if (this->value.empty()) {
|
||||
ValueAnnotationItem::ValueAnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion)
|
||||
: AnnotationItem(focusedMemoryRegion, AnnotationItemPosition::TOP)
|
||||
, focusedMemoryRegion(focusedMemoryRegion)
|
||||
, endianness(focusedMemoryRegion.endianness)
|
||||
{
|
||||
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this->focusedMemoryRegion.dataType) {
|
||||
case MemoryRegionDataType::UNSIGNED_INTEGER: {
|
||||
std::uint64_t integerValue = 0;
|
||||
for (const auto& byte : this->value) {
|
||||
integerValue = (integerValue << 8) | byte;
|
||||
}
|
||||
void ValueAnnotationItem::setValue(const Targets::TargetMemoryBuffer& value) {
|
||||
this->value = value;
|
||||
|
||||
this->labelText = QString::number(integerValue);
|
||||
break;
|
||||
if (this->endianness == Targets::TargetMemoryEndianness::LITTLE) {
|
||||
std::reverse(this->value.begin(), this->value.end());
|
||||
}
|
||||
case MemoryRegionDataType::SIGNED_INTEGER: {
|
||||
const auto valueSize = this->value.size();
|
||||
|
||||
if (valueSize == 1) {
|
||||
this->labelText = QString::number(static_cast<int8_t>(this->value[0]));
|
||||
break;
|
||||
}
|
||||
this->refreshLabelText();
|
||||
this->setToolTip(this->labelText);
|
||||
}
|
||||
|
||||
if (valueSize == 2) {
|
||||
this->labelText = QString::number(static_cast<int16_t>((this->value[0] << 8) | this->value[1]));
|
||||
break;
|
||||
}
|
||||
void ValueAnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
auto font = painter->font();
|
||||
font.setItalic(true);
|
||||
painter->setFont(font);
|
||||
|
||||
if (valueSize <= 4) {
|
||||
std::int32_t integerValue = 0;
|
||||
AnnotationItem::paint(painter, option, widget);
|
||||
}
|
||||
|
||||
void ValueAnnotationItem::refreshLabelText() {
|
||||
this->update();
|
||||
|
||||
if (this->value.empty()) {
|
||||
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this->focusedMemoryRegion.dataType) {
|
||||
case MemoryRegionDataType::UNSIGNED_INTEGER: {
|
||||
std::uint64_t integerValue = 0;
|
||||
for (const auto& byte : this->value) {
|
||||
integerValue = (integerValue << 8) | byte;
|
||||
}
|
||||
@@ -71,42 +49,65 @@ void ValueAnnotationItem::refreshLabelText() {
|
||||
this->labelText = QString::number(integerValue);
|
||||
break;
|
||||
}
|
||||
case MemoryRegionDataType::SIGNED_INTEGER: {
|
||||
const auto valueSize = this->value.size();
|
||||
|
||||
std::int64_t integerValue = 0;
|
||||
for (const auto& byte : this->value) {
|
||||
integerValue = (integerValue << 8) | byte;
|
||||
if (valueSize == 1) {
|
||||
this->labelText = QString::number(static_cast<int8_t>(this->value[0]));
|
||||
break;
|
||||
}
|
||||
|
||||
if (valueSize == 2) {
|
||||
this->labelText = QString::number(static_cast<int16_t>((this->value[0] << 8) | this->value[1]));
|
||||
break;
|
||||
}
|
||||
|
||||
if (valueSize <= 4) {
|
||||
std::int32_t integerValue = 0;
|
||||
for (const auto& byte : this->value) {
|
||||
integerValue = (integerValue << 8) | byte;
|
||||
}
|
||||
|
||||
this->labelText = QString::number(integerValue);
|
||||
break;
|
||||
}
|
||||
|
||||
std::int64_t integerValue = 0;
|
||||
for (const auto& byte : this->value) {
|
||||
integerValue = (integerValue << 8) | byte;
|
||||
}
|
||||
|
||||
this->labelText = QString::number(integerValue);
|
||||
break;
|
||||
}
|
||||
case MemoryRegionDataType::ASCII_STRING: {
|
||||
// Replace non-ASCII chars with '?'
|
||||
auto asciiData = this->value;
|
||||
|
||||
this->labelText = QString::number(integerValue);
|
||||
break;
|
||||
}
|
||||
case MemoryRegionDataType::ASCII_STRING: {
|
||||
// Replace non-ASCII chars with '?'
|
||||
auto asciiData = this->value;
|
||||
std::replace_if(
|
||||
asciiData.begin(),
|
||||
asciiData.end(),
|
||||
[] (unsigned char value) {
|
||||
/*
|
||||
* We only care about non-control characters (with the exception of the white space character) in
|
||||
* the standard ASCII range.
|
||||
*/
|
||||
constexpr auto asciiRangeStart = 32;
|
||||
constexpr auto asciiRangeEnd = 126;
|
||||
return value < asciiRangeStart || value > asciiRangeEnd;
|
||||
},
|
||||
'?'
|
||||
);
|
||||
|
||||
std::replace_if(
|
||||
asciiData.begin(),
|
||||
asciiData.end(),
|
||||
[] (unsigned char value) {
|
||||
/*
|
||||
* We only care about non-control characters (with the exception of the white space character) in
|
||||
* the standard ASCII range.
|
||||
*/
|
||||
constexpr auto asciiRangeStart = 32;
|
||||
constexpr auto asciiRangeEnd = 126;
|
||||
return value < asciiRangeStart || value > asciiRangeEnd;
|
||||
},
|
||||
'?'
|
||||
);
|
||||
|
||||
this->labelText = "'" + QString::fromLatin1(
|
||||
reinterpret_cast<const char*>(asciiData.data()),
|
||||
static_cast<qsizetype>(asciiData.size())
|
||||
) + "'";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
|
||||
this->labelText = "'" + QString::fromLatin1(
|
||||
reinterpret_cast<const char*>(asciiData.data()),
|
||||
static_cast<qsizetype>(asciiData.size())
|
||||
) + "'";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,41 +6,42 @@
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
||||
|
||||
using namespace Bloom;
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
ExcludedRegionItem::ExcludedRegionItem(
|
||||
const ExcludedMemoryRegion& region,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent
|
||||
): memoryRegion(region), RegionItem(region, memoryDescriptor, parent) {
|
||||
auto formUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/UiFiles/ExcludedMemoryRegionForm.ui"
|
||||
)
|
||||
);
|
||||
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
if (!formUiFile.open(QFile::ReadOnly)) {
|
||||
throw Bloom::Exceptions::Exception("Failed to open excluded region item form UI file");
|
||||
}
|
||||
|
||||
ExcludedRegionItem::ExcludedRegionItem(
|
||||
const ExcludedMemoryRegion& region,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent
|
||||
): memoryRegion(region), RegionItem(region, memoryDescriptor, parent) {
|
||||
auto formUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/UiFiles/ExcludedMemoryRegionForm.ui"
|
||||
)
|
||||
);
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->formWidget = uiLoader.load(&formUiFile, this);
|
||||
|
||||
if (!formUiFile.open(QFile::ReadOnly)) {
|
||||
throw Bloom::Exceptions::Exception("Failed to open excluded region item form UI file");
|
||||
this->initFormInputs();
|
||||
}
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->formWidget = uiLoader.load(&formUiFile, this);
|
||||
void ExcludedRegionItem::applyChanges() {
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
|
||||
this->initFormInputs();
|
||||
}
|
||||
|
||||
void ExcludedRegionItem::applyChanges() {
|
||||
this->memoryRegion.name = this->nameInput->text();
|
||||
|
||||
const auto inputAddressRange = TargetMemoryAddressRange(
|
||||
this->startAddressInput->text().toUInt(nullptr, 16),
|
||||
this->endAddressInput->text().toUInt(nullptr, 16)
|
||||
);
|
||||
this->memoryRegion.addressRangeInputType = this->getSelectedAddressInputType();
|
||||
this->memoryRegion.addressRange = this->memoryRegion.addressRangeInputType == MemoryRegionAddressInputType::RELATIVE ?
|
||||
this->convertRelativeToAbsoluteAddressRange(inputAddressRange) : inputAddressRange;
|
||||
this->memoryRegion.name = this->nameInput->text();
|
||||
|
||||
const auto inputAddressRange = TargetMemoryAddressRange(
|
||||
this->startAddressInput->text().toUInt(nullptr, 16),
|
||||
this->endAddressInput->text().toUInt(nullptr, 16)
|
||||
);
|
||||
this->memoryRegion.addressRangeInputType = this->getSelectedAddressInputType();
|
||||
this->memoryRegion.addressRange =
|
||||
this->memoryRegion.addressRangeInputType == MemoryRegionAddressInputType::RELATIVE ?
|
||||
this->convertRelativeToAbsoluteAddressRange(inputAddressRange) : inputAddressRange;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,99 +6,105 @@
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
||||
|
||||
using namespace Bloom;
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
FocusedRegionItem::FocusedRegionItem(
|
||||
const FocusedMemoryRegion& region,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent
|
||||
): memoryRegion(region), RegionItem(region, memoryDescriptor, parent) {
|
||||
auto formUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/UiFiles/FocusedMemoryRegionForm.ui"
|
||||
)
|
||||
);
|
||||
|
||||
FocusedRegionItem::FocusedRegionItem(
|
||||
const FocusedMemoryRegion& region,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent
|
||||
): memoryRegion(region), RegionItem(region, memoryDescriptor, parent) {
|
||||
auto formUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/UiFiles/FocusedMemoryRegionForm.ui"
|
||||
)
|
||||
);
|
||||
|
||||
if (!formUiFile.open(QFile::ReadOnly)) {
|
||||
throw Bloom::Exceptions::Exception("Failed to open focused region item form UI file");
|
||||
}
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->formWidget = uiLoader.load(&formUiFile, this);
|
||||
|
||||
this->initFormInputs();
|
||||
}
|
||||
|
||||
void FocusedRegionItem::applyChanges() {
|
||||
this->memoryRegion.name = this->nameInput->text();
|
||||
|
||||
const auto inputAddressRange = TargetMemoryAddressRange(
|
||||
this->startAddressInput->text().toUInt(nullptr, 16),
|
||||
this->endAddressInput->text().toUInt(nullptr, 16)
|
||||
);
|
||||
this->memoryRegion.addressRangeInputType = this->getSelectedAddressInputType();
|
||||
this->memoryRegion.addressRange =
|
||||
this->memoryRegion.addressRangeInputType == MemoryRegionAddressInputType::RELATIVE ?
|
||||
this->convertRelativeToAbsoluteAddressRange(inputAddressRange) : inputAddressRange;
|
||||
|
||||
auto selectedDataTypeOptionName = this->dataTypeInput->currentData().toString();
|
||||
if (FocusedRegionItem::dataTypeOptionsByName.contains(selectedDataTypeOptionName)) {
|
||||
this->memoryRegion.dataType = FocusedRegionItem::dataTypeOptionsByName.at(selectedDataTypeOptionName).dataType;
|
||||
}
|
||||
|
||||
auto selectedEndiannessOptionName = this->endiannessInput->currentData().toString();
|
||||
if (FocusedRegionItem::endiannessOptionsByName.contains(selectedEndiannessOptionName)) {
|
||||
this->memoryRegion.endianness = FocusedRegionItem::endiannessOptionsByName.at(
|
||||
selectedEndiannessOptionName
|
||||
).endianness;
|
||||
}
|
||||
}
|
||||
|
||||
void FocusedRegionItem::initFormInputs() {
|
||||
RegionItem::initFormInputs();
|
||||
const auto& region = this->memoryRegion;
|
||||
|
||||
this->dataTypeInput = this->formWidget->findChild<QComboBox*>("data-type-input");
|
||||
this->endiannessInput = this->formWidget->findChild<QComboBox*>("endianness-input");
|
||||
|
||||
for (const auto& [optionName, option] : FocusedRegionItem::dataTypeOptionsByName) {
|
||||
this->dataTypeInput->addItem(option.text, optionName);
|
||||
}
|
||||
|
||||
for (const auto& [optionName, option] : FocusedRegionItem::endiannessOptionsByName) {
|
||||
this->endiannessInput->addItem(option.text, optionName);
|
||||
}
|
||||
|
||||
switch (region.dataType) {
|
||||
case MemoryRegionDataType::UNSIGNED_INTEGER: {
|
||||
this->dataTypeInput->setCurrentText(FocusedRegionItem::dataTypeOptionsByName.at("unsigned_integer").text);
|
||||
break;
|
||||
if (!formUiFile.open(QFile::ReadOnly)) {
|
||||
throw Bloom::Exceptions::Exception("Failed to open focused region item form UI file");
|
||||
}
|
||||
case MemoryRegionDataType::SIGNED_INTEGER: {
|
||||
this->dataTypeInput->setCurrentText(FocusedRegionItem::dataTypeOptionsByName.at("signed_integer").text);
|
||||
break;
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->formWidget = uiLoader.load(&formUiFile, this);
|
||||
|
||||
this->initFormInputs();
|
||||
}
|
||||
|
||||
void FocusedRegionItem::applyChanges() {
|
||||
this->memoryRegion.name = this->nameInput->text();
|
||||
|
||||
const auto inputAddressRange = TargetMemoryAddressRange(
|
||||
this->startAddressInput->text().toUInt(nullptr, 16),
|
||||
this->endAddressInput->text().toUInt(nullptr, 16)
|
||||
);
|
||||
this->memoryRegion.addressRangeInputType = this->getSelectedAddressInputType();
|
||||
this->memoryRegion.addressRange =
|
||||
this->memoryRegion.addressRangeInputType == MemoryRegionAddressInputType::RELATIVE ?
|
||||
this->convertRelativeToAbsoluteAddressRange(inputAddressRange) : inputAddressRange;
|
||||
|
||||
auto selectedDataTypeOptionName = this->dataTypeInput->currentData().toString();
|
||||
if (FocusedRegionItem::dataTypeOptionsByName.contains(selectedDataTypeOptionName)) {
|
||||
this->memoryRegion.dataType = FocusedRegionItem::dataTypeOptionsByName.at(
|
||||
selectedDataTypeOptionName
|
||||
).dataType;
|
||||
}
|
||||
case MemoryRegionDataType::ASCII_STRING: {
|
||||
this->dataTypeInput->setCurrentText(FocusedRegionItem::dataTypeOptionsByName.at("ascii").text);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this->dataTypeInput->setCurrentText(FocusedRegionItem::dataTypeOptionsByName.at("other").text);
|
||||
|
||||
auto selectedEndiannessOptionName = this->endiannessInput->currentData().toString();
|
||||
if (FocusedRegionItem::endiannessOptionsByName.contains(selectedEndiannessOptionName)) {
|
||||
this->memoryRegion.endianness = FocusedRegionItem::endiannessOptionsByName.at(
|
||||
selectedEndiannessOptionName
|
||||
).endianness;
|
||||
}
|
||||
}
|
||||
|
||||
switch (region.endianness) {
|
||||
case Targets::TargetMemoryEndianness::LITTLE: {
|
||||
this->endiannessInput->setCurrentText(FocusedRegionItem::endiannessOptionsByName.at("little").text);
|
||||
break;
|
||||
void FocusedRegionItem::initFormInputs() {
|
||||
RegionItem::initFormInputs();
|
||||
const auto& region = this->memoryRegion;
|
||||
|
||||
this->dataTypeInput = this->formWidget->findChild<QComboBox*>("data-type-input");
|
||||
this->endiannessInput = this->formWidget->findChild<QComboBox*>("endianness-input");
|
||||
|
||||
for (const auto& [optionName, option] : FocusedRegionItem::dataTypeOptionsByName) {
|
||||
this->dataTypeInput->addItem(option.text, optionName);
|
||||
}
|
||||
case Targets::TargetMemoryEndianness::BIG: {
|
||||
this->endiannessInput->setCurrentText(FocusedRegionItem::endiannessOptionsByName.at("big").text);
|
||||
break;
|
||||
|
||||
for (const auto& [optionName, option] : FocusedRegionItem::endiannessOptionsByName) {
|
||||
this->endiannessInput->addItem(option.text, optionName);
|
||||
}
|
||||
|
||||
switch (region.dataType) {
|
||||
case MemoryRegionDataType::UNSIGNED_INTEGER: {
|
||||
this->dataTypeInput->setCurrentText(
|
||||
FocusedRegionItem::dataTypeOptionsByName.at("unsigned_integer").text
|
||||
);
|
||||
break;
|
||||
}
|
||||
case MemoryRegionDataType::SIGNED_INTEGER: {
|
||||
this->dataTypeInput->setCurrentText(
|
||||
FocusedRegionItem::dataTypeOptionsByName.at("signed_integer").text
|
||||
);
|
||||
break;
|
||||
}
|
||||
case MemoryRegionDataType::ASCII_STRING: {
|
||||
this->dataTypeInput->setCurrentText(FocusedRegionItem::dataTypeOptionsByName.at("ascii").text);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this->dataTypeInput->setCurrentText(FocusedRegionItem::dataTypeOptionsByName.at("other").text);
|
||||
}
|
||||
}
|
||||
|
||||
switch (region.endianness) {
|
||||
case Targets::TargetMemoryEndianness::LITTLE: {
|
||||
this->endiannessInput->setCurrentText(FocusedRegionItem::endiannessOptionsByName.at("little").text);
|
||||
break;
|
||||
}
|
||||
case Targets::TargetMemoryEndianness::BIG: {
|
||||
this->endiannessInput->setCurrentText(FocusedRegionItem::endiannessOptionsByName.at("big").text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,383 +10,401 @@
|
||||
#include "src/Helpers/Paths.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
using namespace Bloom;
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
using Bloom::Exceptions::Exception;
|
||||
|
||||
MemoryRegionManagerWindow::MemoryRegionManagerWindow(
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
QWidget* parent
|
||||
):
|
||||
QWidget(parent),
|
||||
memoryDescriptor(memoryDescriptor),
|
||||
focusedMemoryRegions(focusedMemoryRegions),
|
||||
excludedMemoryRegions(excludedMemoryRegions)
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
this->setWindowFlag(Qt::Window);
|
||||
this->setObjectName("memory-region-manager-window");
|
||||
this->setWindowTitle(
|
||||
"Memory Regions - "
|
||||
+ QString(this->memoryDescriptor.type == Targets::TargetMemoryType::EEPROM ? "EEPROM" : "RAM")
|
||||
);
|
||||
using Bloom::Exceptions::Exception;
|
||||
|
||||
auto windowUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/UiFiles/MemoryRegionManagerWindow.ui"
|
||||
)
|
||||
);
|
||||
|
||||
auto windowStylesheet = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/Stylesheets/MemoryRegionManagerWindow.qss"
|
||||
)
|
||||
);
|
||||
|
||||
if (!windowUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open MemoryRegionManagerWindow UI file");
|
||||
}
|
||||
|
||||
if (!windowStylesheet.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open MemoryRegionManagerWindow stylesheet file");
|
||||
}
|
||||
|
||||
this->setStyleSheet(windowStylesheet.readAll());
|
||||
this->setFixedSize(QSize(970, 540));
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&windowUiFile, this);
|
||||
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
this->regionSelector = this->container->findChild<QWidget*>("region-selector");
|
||||
auto* regionSelectorToolBar = this->regionSelector->findChild<QWidget*>("region-selector-tool-bar");
|
||||
this->addRegionButton = this->regionSelector->findChild<SvgToolButton*>("add-region-btn");
|
||||
this->removeRegionButton = this->regionSelector->findChild<SvgToolButton*>("remove-region-btn");
|
||||
this->addFocusedRegionMenuAction = this->addRegionButton->findChild<QAction*>("add-focused-region");
|
||||
this->addExcludedRegionMenuAction = this->addRegionButton->findChild<QAction*>("add-excluded-region");
|
||||
this->regionItemScrollArea = this->regionSelector->findChild<QScrollArea*>("region-item-scroll-area");
|
||||
this->regionItemScrollAreaViewport = this->regionItemScrollArea->findChild<QWidget*>("item-container");
|
||||
this->regionItemScrollAreaViewportLayout = this->regionItemScrollAreaViewport->findChild<QVBoxLayout*>(
|
||||
"item-container-layout"
|
||||
);
|
||||
|
||||
this->stackedFormLayout = this->container->findChild<QStackedLayout*>("stacked-form-layout");
|
||||
|
||||
this->applyButton = this->container->findChild<QPushButton*>("apply-btn");
|
||||
this->helpButton = this->container->findChild<QPushButton*>("help-btn");
|
||||
this->closeButton = this->container->findChild<QPushButton*>("close-btn");
|
||||
|
||||
regionSelectorToolBar->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollArea->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollAreaViewport->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollAreaViewportLayout->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollAreaViewportLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
|
||||
QObject::connect(
|
||||
this->addFocusedRegionMenuAction,
|
||||
&QAction::triggered,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onNewFocusedRegionTrigger
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->addExcludedRegionMenuAction,
|
||||
&QAction::triggered,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onNewExcludedRegionTrigger
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->removeRegionButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onDeleteRegionTrigger
|
||||
);
|
||||
|
||||
QObject::connect(this->closeButton, &QPushButton::clicked, this, &QWidget::close);
|
||||
QObject::connect(this->applyButton, &QPushButton::clicked, this, &MemoryRegionManagerWindow::applyChanges);
|
||||
QObject::connect(this->helpButton, &QPushButton::clicked, this, &MemoryRegionManagerWindow::openHelpPage);
|
||||
|
||||
this->refreshRegions();
|
||||
|
||||
// Position the inspection window at the center of the main Insight window
|
||||
this->move(parent->window()->geometry().center() - this->rect().center());
|
||||
this->show();
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::refreshRegions() {
|
||||
this->clearRegions();
|
||||
|
||||
for (const auto& focusedRegion: this->focusedMemoryRegions) {
|
||||
this->addFocusedRegion(focusedRegion);
|
||||
}
|
||||
|
||||
for (const auto& excludedRegion: this->excludedMemoryRegions) {
|
||||
this->addExcludedRegion(excludedRegion);
|
||||
}
|
||||
|
||||
this->sortRegionItems();
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::showEvent(QShowEvent* event) {
|
||||
if (this->selectedRegion == nullptr && this->regionItemScrollAreaViewportLayout->count() > 0) {
|
||||
auto* firstRegionItem = qobject_cast<RegionItem*>(
|
||||
this->regionItemScrollAreaViewportLayout->itemAt(0)->widget()
|
||||
MemoryRegionManagerWindow::MemoryRegionManagerWindow(
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
QWidget* parent
|
||||
)
|
||||
: QWidget(parent)
|
||||
, memoryDescriptor(memoryDescriptor)
|
||||
, focusedMemoryRegions(focusedMemoryRegions)
|
||||
, excludedMemoryRegions(excludedMemoryRegions)
|
||||
{
|
||||
this->setWindowFlag(Qt::Window);
|
||||
this->setObjectName("memory-region-manager-window");
|
||||
this->setWindowTitle(
|
||||
"Memory Regions - "
|
||||
+ QString(this->memoryDescriptor.type == Targets::TargetMemoryType::EEPROM ? "EEPROM" : "RAM")
|
||||
);
|
||||
|
||||
if (firstRegionItem != nullptr) {
|
||||
firstRegionItem->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::clearRegions() {
|
||||
this->selectedRegion = nullptr;
|
||||
|
||||
for (auto* focusedRegionItem: this->focusedRegionItems) {
|
||||
this->regionItemScrollAreaViewportLayout->removeWidget(focusedRegionItem);
|
||||
|
||||
focusedRegionItem->getFormWidget()->deleteLater();
|
||||
focusedRegionItem->deleteLater();
|
||||
}
|
||||
|
||||
for (auto* excludedRegionItem: this->excludedRegionItems) {
|
||||
this->regionItemScrollAreaViewportLayout->removeWidget(excludedRegionItem);
|
||||
|
||||
excludedRegionItem->getFormWidget()->deleteLater();
|
||||
excludedRegionItem->deleteLater();
|
||||
}
|
||||
|
||||
this->focusedRegionItems.clear();
|
||||
this->excludedRegionItems.clear();
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::sortRegionItems() {
|
||||
/*
|
||||
* This isn't very pretty.
|
||||
*
|
||||
* Because the insertion order is persisted in QBoxLayouts, sorting the items requires removing them from the
|
||||
* layout, and then re-inserting them in the correct order.
|
||||
*/
|
||||
auto regionItemCompare = [] (RegionItem* itemA, RegionItem* itemB) {
|
||||
return itemA->getMemoryRegion().createdDate < itemB->getMemoryRegion().createdDate;
|
||||
};
|
||||
auto sortedRegionItems = std::set<RegionItem*, decltype(regionItemCompare)>(regionItemCompare);
|
||||
|
||||
QLayoutItem* layoutItem = nullptr;
|
||||
while ((layoutItem = this->regionItemScrollAreaViewportLayout->takeAt(0)) != nullptr) {
|
||||
auto* regionItem = qobject_cast<RegionItem*>(layoutItem->widget());
|
||||
if (regionItem != nullptr) {
|
||||
sortedRegionItems.insert(regionItem);
|
||||
}
|
||||
|
||||
delete layoutItem;
|
||||
}
|
||||
|
||||
for (auto* regionItem: sortedRegionItems) {
|
||||
this->regionItemScrollAreaViewportLayout->addWidget(regionItem);
|
||||
}
|
||||
}
|
||||
|
||||
FocusedRegionItem* MemoryRegionManagerWindow::addFocusedRegion(const FocusedMemoryRegion& region) {
|
||||
auto* focusedRegionItem = new FocusedRegionItem(region, this->memoryDescriptor, this->regionItemScrollAreaViewport);
|
||||
this->focusedRegionItems.insert(focusedRegionItem);
|
||||
|
||||
this->regionItemScrollAreaViewportLayout->addWidget(focusedRegionItem);
|
||||
this->stackedFormLayout->addWidget(focusedRegionItem->getFormWidget());
|
||||
|
||||
QObject::connect(focusedRegionItem, &RegionItem::selected, this, &MemoryRegionManagerWindow::onRegionSelected);
|
||||
|
||||
return focusedRegionItem;
|
||||
}
|
||||
|
||||
ExcludedRegionItem* MemoryRegionManagerWindow::addExcludedRegion(const ExcludedMemoryRegion& region) {
|
||||
auto* excludedRegionItem = new ExcludedRegionItem(region, this->memoryDescriptor, this->regionItemScrollAreaViewport);
|
||||
this->excludedRegionItems.insert(excludedRegionItem);
|
||||
|
||||
this->regionItemScrollAreaViewportLayout->addWidget(excludedRegionItem);
|
||||
this->stackedFormLayout->addWidget(excludedRegionItem->getFormWidget());
|
||||
|
||||
QObject::connect(excludedRegionItem, &RegionItem::selected, this, &MemoryRegionManagerWindow::onRegionSelected);
|
||||
|
||||
return excludedRegionItem;
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onRegionSelected(RegionItem* selectedRegion) {
|
||||
if (this->selectedRegion != nullptr && this->selectedRegion != selectedRegion) {
|
||||
this->selectedRegion->setSelected(false);
|
||||
}
|
||||
|
||||
this->selectedRegion = selectedRegion;
|
||||
this->stackedFormLayout->setCurrentWidget(this->selectedRegion->getFormWidget());
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onNewFocusedRegionTrigger() {
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
|
||||
auto* region = this->addFocusedRegion(FocusedMemoryRegion(
|
||||
"Untitled Region",
|
||||
TargetMemoryAddressRange(
|
||||
this->memoryDescriptor.addressRange.startAddress,
|
||||
this->memoryDescriptor.addressRange.startAddress + 10
|
||||
)
|
||||
));
|
||||
|
||||
region->setSelected(true);
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onNewExcludedRegionTrigger() {
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
|
||||
auto* region = this->addExcludedRegion(ExcludedMemoryRegion(
|
||||
"Untitled Region",
|
||||
TargetMemoryAddressRange(
|
||||
this->memoryDescriptor.addressRange.startAddress,
|
||||
this->memoryDescriptor.addressRange.startAddress + 10
|
||||
)
|
||||
));
|
||||
|
||||
region->setSelected(true);
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onDeleteRegionTrigger() {
|
||||
if (this->selectedRegion == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* regionItem = this->selectedRegion;
|
||||
const auto& region = regionItem->getMemoryRegion();
|
||||
|
||||
if (region.type == MemoryRegionType::FOCUSED) {
|
||||
auto* focusedRegionItem = qobject_cast<FocusedRegionItem*>(regionItem);
|
||||
|
||||
if (focusedRegionItem != nullptr) {
|
||||
this->focusedRegionItems.erase(focusedRegionItem);
|
||||
}
|
||||
|
||||
} else {
|
||||
auto* excludedRegionItem = qobject_cast<ExcludedRegionItem*>(regionItem);
|
||||
|
||||
if (excludedRegionItem != nullptr) {
|
||||
this->excludedRegionItems.erase(excludedRegionItem);
|
||||
}
|
||||
}
|
||||
|
||||
regionItem->getFormWidget()->deleteLater();
|
||||
this->regionItemScrollAreaViewportLayout->removeWidget(regionItem);
|
||||
regionItem->deleteLater();
|
||||
|
||||
this->selectedRegion = nullptr;
|
||||
|
||||
if (this->regionItemScrollAreaViewportLayout->count() > 0) {
|
||||
auto* regionItem = qobject_cast<RegionItem*>(
|
||||
this->regionItemScrollAreaViewportLayout->itemAt(0)->widget()
|
||||
auto windowUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/UiFiles/MemoryRegionManagerWindow.ui"
|
||||
)
|
||||
);
|
||||
|
||||
if (regionItem != nullptr) {
|
||||
regionItem->setSelected(true);
|
||||
auto windowStylesheet = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/MemoryRegionManager/Stylesheets/MemoryRegionManagerWindow.qss"
|
||||
)
|
||||
);
|
||||
|
||||
if (!windowUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open MemoryRegionManagerWindow UI file");
|
||||
}
|
||||
|
||||
if (!windowStylesheet.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open MemoryRegionManagerWindow stylesheet file");
|
||||
}
|
||||
|
||||
this->setStyleSheet(windowStylesheet.readAll());
|
||||
this->setFixedSize(QSize(970, 540));
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&windowUiFile, this);
|
||||
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
this->regionSelector = this->container->findChild<QWidget*>("region-selector");
|
||||
auto* regionSelectorToolBar = this->regionSelector->findChild<QWidget*>("region-selector-tool-bar");
|
||||
this->addRegionButton = this->regionSelector->findChild<SvgToolButton*>("add-region-btn");
|
||||
this->removeRegionButton = this->regionSelector->findChild<SvgToolButton*>("remove-region-btn");
|
||||
this->addFocusedRegionMenuAction = this->addRegionButton->findChild<QAction*>("add-focused-region");
|
||||
this->addExcludedRegionMenuAction = this->addRegionButton->findChild<QAction*>("add-excluded-region");
|
||||
this->regionItemScrollArea = this->regionSelector->findChild<QScrollArea*>("region-item-scroll-area");
|
||||
this->regionItemScrollAreaViewport = this->regionItemScrollArea->findChild<QWidget*>("item-container");
|
||||
this->regionItemScrollAreaViewportLayout = this->regionItemScrollAreaViewport->findChild<QVBoxLayout*>(
|
||||
"item-container-layout"
|
||||
);
|
||||
|
||||
this->stackedFormLayout = this->container->findChild<QStackedLayout*>("stacked-form-layout");
|
||||
|
||||
this->applyButton = this->container->findChild<QPushButton*>("apply-btn");
|
||||
this->helpButton = this->container->findChild<QPushButton*>("help-btn");
|
||||
this->closeButton = this->container->findChild<QPushButton*>("close-btn");
|
||||
|
||||
regionSelectorToolBar->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollArea->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollAreaViewport->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollAreaViewportLayout->setContentsMargins(0, 0, 0, 0);
|
||||
this->regionItemScrollAreaViewportLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
|
||||
QObject::connect(
|
||||
this->addFocusedRegionMenuAction,
|
||||
&QAction::triggered,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onNewFocusedRegionTrigger
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->addExcludedRegionMenuAction,
|
||||
&QAction::triggered,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onNewExcludedRegionTrigger
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->removeRegionButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onDeleteRegionTrigger
|
||||
);
|
||||
|
||||
QObject::connect(this->closeButton, &QPushButton::clicked, this, &QWidget::close);
|
||||
QObject::connect(this->applyButton, &QPushButton::clicked, this, &MemoryRegionManagerWindow::applyChanges);
|
||||
QObject::connect(this->helpButton, &QPushButton::clicked, this, &MemoryRegionManagerWindow::openHelpPage);
|
||||
|
||||
this->refreshRegions();
|
||||
|
||||
// Position the inspection window at the center of the main Insight window
|
||||
this->move(parent->window()->geometry().center() - this->rect().center());
|
||||
this->show();
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::applyChanges() {
|
||||
auto processedFocusedMemoryRegions = std::vector<FocusedMemoryRegion>();
|
||||
auto processedExcludedMemoryRegions = std::vector<ExcludedMemoryRegion>();
|
||||
void MemoryRegionManagerWindow::refreshRegions() {
|
||||
this->clearRegions();
|
||||
|
||||
for (auto* focusedRegionItem : this->focusedRegionItems) {
|
||||
const auto validationFailures = focusedRegionItem->getValidationFailures();
|
||||
for (const auto& focusedRegion: this->focusedMemoryRegions) {
|
||||
this->addFocusedRegion(focusedRegion);
|
||||
}
|
||||
|
||||
if (!validationFailures.empty()) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Invalid Memory Region",
|
||||
"Invalid memory region \"" + focusedRegionItem->getRegionNameInputValue() + "\""
|
||||
+ "<br/><br/>- " + validationFailures.join("<br/>- "),
|
||||
this
|
||||
for (const auto& excludedRegion: this->excludedMemoryRegions) {
|
||||
this->addExcludedRegion(excludedRegion);
|
||||
}
|
||||
|
||||
this->sortRegionItems();
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::showEvent(QShowEvent* event) {
|
||||
if (this->selectedRegion == nullptr && this->regionItemScrollAreaViewportLayout->count() > 0) {
|
||||
auto* firstRegionItem = qobject_cast<RegionItem*>(
|
||||
this->regionItemScrollAreaViewportLayout->itemAt(0)->widget()
|
||||
);
|
||||
errorDialogue->show();
|
||||
|
||||
if (firstRegionItem != nullptr) {
|
||||
firstRegionItem->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::clearRegions() {
|
||||
this->selectedRegion = nullptr;
|
||||
|
||||
for (auto* focusedRegionItem: this->focusedRegionItems) {
|
||||
this->regionItemScrollAreaViewportLayout->removeWidget(focusedRegionItem);
|
||||
|
||||
focusedRegionItem->getFormWidget()->deleteLater();
|
||||
focusedRegionItem->deleteLater();
|
||||
}
|
||||
|
||||
for (auto* excludedRegionItem: this->excludedRegionItems) {
|
||||
this->regionItemScrollAreaViewportLayout->removeWidget(excludedRegionItem);
|
||||
|
||||
excludedRegionItem->getFormWidget()->deleteLater();
|
||||
excludedRegionItem->deleteLater();
|
||||
}
|
||||
|
||||
this->focusedRegionItems.clear();
|
||||
this->excludedRegionItems.clear();
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::sortRegionItems() {
|
||||
/*
|
||||
* This isn't very pretty.
|
||||
*
|
||||
* Because the insertion order is persisted in QBoxLayouts, sorting the items requires removing them from the
|
||||
* layout, and then re-inserting them in the correct order.
|
||||
*/
|
||||
auto regionItemCompare = [] (RegionItem* itemA, RegionItem* itemB) {
|
||||
return itemA->getMemoryRegion().createdDate < itemB->getMemoryRegion().createdDate;
|
||||
};
|
||||
auto sortedRegionItems = std::set<RegionItem*, decltype(regionItemCompare)>(regionItemCompare);
|
||||
|
||||
QLayoutItem* layoutItem = nullptr;
|
||||
while ((layoutItem = this->regionItemScrollAreaViewportLayout->takeAt(0)) != nullptr) {
|
||||
auto* regionItem = qobject_cast<RegionItem*>(layoutItem->widget());
|
||||
if (regionItem != nullptr) {
|
||||
sortedRegionItems.insert(regionItem);
|
||||
}
|
||||
|
||||
delete layoutItem;
|
||||
}
|
||||
|
||||
for (auto* regionItem: sortedRegionItems) {
|
||||
this->regionItemScrollAreaViewportLayout->addWidget(regionItem);
|
||||
}
|
||||
}
|
||||
|
||||
FocusedRegionItem* MemoryRegionManagerWindow::addFocusedRegion(const FocusedMemoryRegion& region) {
|
||||
auto* focusedRegionItem = new FocusedRegionItem(
|
||||
region,
|
||||
this->memoryDescriptor,
|
||||
this->regionItemScrollAreaViewport
|
||||
);
|
||||
this->focusedRegionItems.insert(focusedRegionItem);
|
||||
|
||||
this->regionItemScrollAreaViewportLayout->addWidget(focusedRegionItem);
|
||||
this->stackedFormLayout->addWidget(focusedRegionItem->getFormWidget());
|
||||
|
||||
QObject::connect(
|
||||
focusedRegionItem,
|
||||
&RegionItem::selected,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onRegionSelected
|
||||
);
|
||||
|
||||
return focusedRegionItem;
|
||||
}
|
||||
|
||||
ExcludedRegionItem* MemoryRegionManagerWindow::addExcludedRegion(const ExcludedMemoryRegion& region) {
|
||||
auto* excludedRegionItem = new ExcludedRegionItem(
|
||||
region,
|
||||
this->memoryDescriptor,
|
||||
this->regionItemScrollAreaViewport
|
||||
);
|
||||
this->excludedRegionItems.insert(excludedRegionItem);
|
||||
|
||||
this->regionItemScrollAreaViewportLayout->addWidget(excludedRegionItem);
|
||||
this->stackedFormLayout->addWidget(excludedRegionItem->getFormWidget());
|
||||
|
||||
QObject::connect(
|
||||
excludedRegionItem,
|
||||
&RegionItem::selected,
|
||||
this,
|
||||
&MemoryRegionManagerWindow::onRegionSelected
|
||||
);
|
||||
|
||||
return excludedRegionItem;
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onRegionSelected(RegionItem* selectedRegion) {
|
||||
if (this->selectedRegion != nullptr && this->selectedRegion != selectedRegion) {
|
||||
this->selectedRegion->setSelected(false);
|
||||
}
|
||||
|
||||
this->selectedRegion = selectedRegion;
|
||||
this->stackedFormLayout->setCurrentWidget(this->selectedRegion->getFormWidget());
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onNewFocusedRegionTrigger() {
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
|
||||
auto* region = this->addFocusedRegion(FocusedMemoryRegion(
|
||||
"Untitled Region",
|
||||
TargetMemoryAddressRange(
|
||||
this->memoryDescriptor.addressRange.startAddress,
|
||||
this->memoryDescriptor.addressRange.startAddress + 10
|
||||
)
|
||||
));
|
||||
|
||||
region->setSelected(true);
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onNewExcludedRegionTrigger() {
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
|
||||
auto* region = this->addExcludedRegion(ExcludedMemoryRegion(
|
||||
"Untitled Region",
|
||||
TargetMemoryAddressRange(
|
||||
this->memoryDescriptor.addressRange.startAddress,
|
||||
this->memoryDescriptor.addressRange.startAddress + 10
|
||||
)
|
||||
));
|
||||
|
||||
region->setSelected(true);
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::onDeleteRegionTrigger() {
|
||||
if (this->selectedRegion == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
focusedRegionItem->applyChanges();
|
||||
const auto& focusedRegion = focusedRegionItem->getMemoryRegion();
|
||||
for (const auto& processedFocusedRegion : processedFocusedMemoryRegions) {
|
||||
if (processedFocusedRegion.intersectsWith(focusedRegion)) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Intersecting Region Found",
|
||||
"Region \"" + focusedRegionItem->getRegionNameInputValue()
|
||||
+ "\" intersects with region \"" + processedFocusedRegion.name + "\". "
|
||||
+ "Regions cannot intersect. Please review the relevant address ranges.",
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
auto* regionItem = this->selectedRegion;
|
||||
const auto& region = regionItem->getMemoryRegion();
|
||||
|
||||
if (region.type == MemoryRegionType::FOCUSED) {
|
||||
auto* focusedRegionItem = qobject_cast<FocusedRegionItem*>(regionItem);
|
||||
|
||||
if (focusedRegionItem != nullptr) {
|
||||
this->focusedRegionItems.erase(focusedRegionItem);
|
||||
}
|
||||
|
||||
} else {
|
||||
auto* excludedRegionItem = qobject_cast<ExcludedRegionItem*>(regionItem);
|
||||
|
||||
if (excludedRegionItem != nullptr) {
|
||||
this->excludedRegionItems.erase(excludedRegionItem);
|
||||
}
|
||||
}
|
||||
|
||||
processedFocusedMemoryRegions.emplace_back(focusedRegion);
|
||||
}
|
||||
regionItem->getFormWidget()->deleteLater();
|
||||
this->regionItemScrollAreaViewportLayout->removeWidget(regionItem);
|
||||
regionItem->deleteLater();
|
||||
|
||||
for (auto* excludedRegionItem : this->excludedRegionItems) {
|
||||
const auto validationFailures = excludedRegionItem->getValidationFailures();
|
||||
this->selectedRegion = nullptr;
|
||||
|
||||
if (!validationFailures.empty()) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Invalid Memory Region",
|
||||
"Invalid memory region \"" + excludedRegionItem->getRegionNameInputValue() + "\""
|
||||
+ "<br/><br/>- " + validationFailures.join("<br/>- "),
|
||||
this
|
||||
if (this->regionItemScrollAreaViewportLayout->count() > 0) {
|
||||
auto* regionItem = qobject_cast<RegionItem*>(
|
||||
this->regionItemScrollAreaViewportLayout->itemAt(0)->widget()
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
}
|
||||
|
||||
excludedRegionItem->applyChanges();
|
||||
auto excludedRegion = excludedRegionItem->getMemoryRegion();
|
||||
for (const auto& processedFocusedRegion : processedFocusedMemoryRegions) {
|
||||
if (processedFocusedRegion.intersectsWith(excludedRegion)) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Intersecting Region Found",
|
||||
"Region \"" + excludedRegionItem->getRegionNameInputValue()
|
||||
+ "\" intersects with region \"" + processedFocusedRegion.name + "\". "
|
||||
+ "Regions cannot intersect. Please review the relevant address ranges.",
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
if (regionItem != nullptr) {
|
||||
regionItem->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& processedExcludedRegion : processedExcludedMemoryRegions) {
|
||||
if (processedExcludedRegion.intersectsWith(excludedRegion)) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Intersecting Region Found",
|
||||
"Region \"" + excludedRegionItem->getRegionNameInputValue()
|
||||
+ "\" intersects with region \"" + processedExcludedRegion.name + "\". "
|
||||
+ "Regions cannot intersect. Please review the relevant address ranges.",
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
processedExcludedMemoryRegions.emplace_back(excludedRegion);
|
||||
}
|
||||
|
||||
this->focusedMemoryRegions = std::move(processedFocusedMemoryRegions);
|
||||
this->excludedMemoryRegions = std::move(processedExcludedMemoryRegions);
|
||||
this->close();
|
||||
emit this->changesApplied();
|
||||
}
|
||||
void MemoryRegionManagerWindow::applyChanges() {
|
||||
auto processedFocusedMemoryRegions = std::vector<FocusedMemoryRegion>();
|
||||
auto processedExcludedMemoryRegions = std::vector<ExcludedMemoryRegion>();
|
||||
|
||||
void MemoryRegionManagerWindow::openHelpPage() {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QString::fromStdString(Paths::homeDomainName() + "/docs/manage-memory-regions"))
|
||||
);
|
||||
for (auto* focusedRegionItem : this->focusedRegionItems) {
|
||||
const auto validationFailures = focusedRegionItem->getValidationFailures();
|
||||
|
||||
if (!validationFailures.empty()) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Invalid Memory Region",
|
||||
"Invalid memory region \"" + focusedRegionItem->getRegionNameInputValue() + "\""
|
||||
+ "<br/><br/>- " + validationFailures.join("<br/>- "),
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
}
|
||||
|
||||
focusedRegionItem->applyChanges();
|
||||
const auto& focusedRegion = focusedRegionItem->getMemoryRegion();
|
||||
for (const auto& processedFocusedRegion : processedFocusedMemoryRegions) {
|
||||
if (processedFocusedRegion.intersectsWith(focusedRegion)) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Intersecting Region Found",
|
||||
"Region \"" + focusedRegionItem->getRegionNameInputValue()
|
||||
+ "\" intersects with region \"" + processedFocusedRegion.name + "\". "
|
||||
+ "Regions cannot intersect. Please review the relevant address ranges.",
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
processedFocusedMemoryRegions.emplace_back(focusedRegion);
|
||||
}
|
||||
|
||||
for (auto* excludedRegionItem : this->excludedRegionItems) {
|
||||
const auto validationFailures = excludedRegionItem->getValidationFailures();
|
||||
|
||||
if (!validationFailures.empty()) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Invalid Memory Region",
|
||||
"Invalid memory region \"" + excludedRegionItem->getRegionNameInputValue() + "\""
|
||||
+ "<br/><br/>- " + validationFailures.join("<br/>- "),
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
}
|
||||
|
||||
excludedRegionItem->applyChanges();
|
||||
auto excludedRegion = excludedRegionItem->getMemoryRegion();
|
||||
for (const auto& processedFocusedRegion : processedFocusedMemoryRegions) {
|
||||
if (processedFocusedRegion.intersectsWith(excludedRegion)) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Intersecting Region Found",
|
||||
"Region \"" + excludedRegionItem->getRegionNameInputValue()
|
||||
+ "\" intersects with region \"" + processedFocusedRegion.name + "\". "
|
||||
+ "Regions cannot intersect. Please review the relevant address ranges.",
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& processedExcludedRegion : processedExcludedMemoryRegions) {
|
||||
if (processedExcludedRegion.intersectsWith(excludedRegion)) {
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Intersecting Region Found",
|
||||
"Region \"" + excludedRegionItem->getRegionNameInputValue()
|
||||
+ "\" intersects with region \"" + processedExcludedRegion.name + "\". "
|
||||
+ "Regions cannot intersect. Please review the relevant address ranges.",
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
processedExcludedMemoryRegions.emplace_back(excludedRegion);
|
||||
}
|
||||
|
||||
this->focusedMemoryRegions = std::move(processedFocusedMemoryRegions);
|
||||
this->excludedMemoryRegions = std::move(processedExcludedMemoryRegions);
|
||||
this->close();
|
||||
emit this->changesApplied();
|
||||
}
|
||||
|
||||
void MemoryRegionManagerWindow::openHelpPage() {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QString::fromStdString(Paths::homeDomainName() + "/docs/manage-memory-regions"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,217 +3,228 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QString>
|
||||
|
||||
using namespace Bloom;
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
|
||||
using Targets::TargetMemoryAddressRange;
|
||||
RegionItem::RegionItem(
|
||||
const MemoryRegion& region,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent
|
||||
): memoryDescriptor(memoryDescriptor), ClickableWidget(parent) {
|
||||
this->setObjectName("region-item");
|
||||
this->setFixedHeight(50);
|
||||
this->layout->setContentsMargins(5, 5, 5, 0);
|
||||
|
||||
RegionItem::RegionItem(
|
||||
const MemoryRegion& region,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent
|
||||
): memoryDescriptor(memoryDescriptor), ClickableWidget(parent) {
|
||||
this->setObjectName("region-item");
|
||||
this->setFixedHeight(50);
|
||||
this->layout->setContentsMargins(5, 5, 5, 0);
|
||||
this->timeLabel->setText(region.createdDate.toString("hh:mm"));
|
||||
this->timeLabel->setObjectName("time-label");
|
||||
|
||||
this->timeLabel->setText(region.createdDate.toString("hh:mm"));
|
||||
this->timeLabel->setObjectName("time-label");
|
||||
auto regionName = region.name;
|
||||
regionName.truncate(RegionItem::NAME_LABEL_MAX_LENGTH);
|
||||
this->nameLabel->setText(regionName);
|
||||
this->nameLabel->setObjectName("name-label");
|
||||
|
||||
auto regionName = region.name;
|
||||
regionName.truncate(RegionItem::NAME_LABEL_MAX_LENGTH);
|
||||
this->nameLabel->setText(regionName);
|
||||
this->nameLabel->setObjectName("name-label");
|
||||
this->typeLabel->setText(region.type == MemoryRegionType::FOCUSED ? "Focused" : "Excluded");
|
||||
this->typeLabel->setObjectName("type-label");
|
||||
|
||||
this->typeLabel->setText(region.type == MemoryRegionType::FOCUSED ? "Focused" : "Excluded");
|
||||
this->typeLabel->setObjectName("type-label");
|
||||
this->addressRangeLabel->setText(
|
||||
"0x" + QString::number(region.addressRange.startAddress, 16).toUpper() + QString(" -> ")
|
||||
+ "0x" + QString::number(region.addressRange.endAddress, 16).toUpper()
|
||||
);
|
||||
this->addressRangeLabel->setObjectName("address-label");
|
||||
|
||||
this->addressRangeLabel->setText(
|
||||
"0x" + QString::number(region.addressRange.startAddress, 16).toUpper() + QString(" -> ")
|
||||
+ "0x" + QString::number(region.addressRange.endAddress, 16).toUpper()
|
||||
);
|
||||
this->addressRangeLabel->setObjectName("address-label");
|
||||
auto* topLabelLayout = new QHBoxLayout();
|
||||
topLabelLayout->setSpacing(0);
|
||||
topLabelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
topLabelLayout->addWidget(this->nameLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
topLabelLayout->addStretch(1);
|
||||
topLabelLayout->addWidget(this->typeLabel, 0, Qt::AlignmentFlag::AlignRight);
|
||||
|
||||
auto* topLabelLayout = new QHBoxLayout();
|
||||
topLabelLayout->setSpacing(0);
|
||||
topLabelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
topLabelLayout->addWidget(this->nameLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
topLabelLayout->addStretch(1);
|
||||
topLabelLayout->addWidget(this->typeLabel, 0, Qt::AlignmentFlag::AlignRight);
|
||||
auto* bottomLabelLayout = new QHBoxLayout();
|
||||
bottomLabelLayout->setSpacing(0);
|
||||
bottomLabelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
bottomLabelLayout->addWidget(this->addressRangeLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
bottomLabelLayout->addStretch(1);
|
||||
bottomLabelLayout->addWidget(this->timeLabel, 0, Qt::AlignmentFlag::AlignRight);
|
||||
|
||||
auto* bottomLabelLayout = new QHBoxLayout();
|
||||
bottomLabelLayout->setSpacing(0);
|
||||
bottomLabelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
bottomLabelLayout->addWidget(this->addressRangeLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
bottomLabelLayout->addStretch(1);
|
||||
bottomLabelLayout->addWidget(this->timeLabel, 0, Qt::AlignmentFlag::AlignRight);
|
||||
this->layout->setSpacing(5);
|
||||
this->layout->addLayout(topLabelLayout);
|
||||
this->layout->addLayout(bottomLabelLayout);
|
||||
this->layout->addStretch(1);
|
||||
|
||||
this->layout->setSpacing(5);
|
||||
this->layout->addLayout(topLabelLayout);
|
||||
this->layout->addLayout(bottomLabelLayout);
|
||||
this->layout->addStretch(1);
|
||||
auto onClick = [this] {
|
||||
this->setSelected(true);
|
||||
};
|
||||
|
||||
auto onClick = [this] {
|
||||
this->setSelected(true);
|
||||
};
|
||||
QObject::connect(this, &ClickableWidget::clicked, this, onClick);
|
||||
QObject::connect(this, &ClickableWidget::rightClicked, this, onClick);
|
||||
|
||||
QObject::connect(this, &ClickableWidget::clicked, this, onClick);
|
||||
QObject::connect(this, &ClickableWidget::rightClicked, this, onClick);
|
||||
|
||||
this->setSelected(false);
|
||||
}
|
||||
|
||||
void RegionItem::setSelected(bool selected) {
|
||||
this->setProperty("selected", selected);
|
||||
this->style()->unpolish(this);
|
||||
this->style()->polish(this);
|
||||
|
||||
if (selected) {
|
||||
emit this->selected(this);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList RegionItem::getValidationFailures() const {
|
||||
auto validationFailures = QStringList();
|
||||
|
||||
if (this->nameInput->text().isEmpty()) {
|
||||
validationFailures.emplace_back("Missing region name.");
|
||||
this->setSelected(false);
|
||||
}
|
||||
|
||||
bool conversionOk = false;
|
||||
void RegionItem::setSelected(bool selected) {
|
||||
this->setProperty("selected", selected);
|
||||
this->style()->unpolish(this);
|
||||
this->style()->polish(this);
|
||||
|
||||
std::uint32_t startAddress = this->startAddressInput->text().toUInt(&conversionOk, 16);
|
||||
if (!conversionOk) {
|
||||
validationFailures.emplace_back("Invalid start address.");
|
||||
if (selected) {
|
||||
emit this->selected(this);
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t endAddress = this->endAddressInput->text().toUInt(&conversionOk, 16);
|
||||
if (!conversionOk) {
|
||||
validationFailures.emplace_back("Invalid end address.");
|
||||
QStringList RegionItem::getValidationFailures() const {
|
||||
auto validationFailures = QStringList();
|
||||
|
||||
if (this->nameInput->text().isEmpty()) {
|
||||
validationFailures.emplace_back("Missing region name.");
|
||||
}
|
||||
|
||||
bool conversionOk = false;
|
||||
|
||||
std::uint32_t startAddress = this->startAddressInput->text().toUInt(&conversionOk, 16);
|
||||
if (!conversionOk) {
|
||||
validationFailures.emplace_back("Invalid start address.");
|
||||
}
|
||||
|
||||
std::uint32_t endAddress = this->endAddressInput->text().toUInt(&conversionOk, 16);
|
||||
if (!conversionOk) {
|
||||
validationFailures.emplace_back("Invalid end address.");
|
||||
}
|
||||
|
||||
if (startAddress > endAddress) {
|
||||
validationFailures.emplace_back("The start address exceeds the end address.");
|
||||
}
|
||||
|
||||
auto addressType = this->getSelectedAddressInputType();
|
||||
const auto memoryAddressRange = this->memoryDescriptor.addressRange;
|
||||
|
||||
const auto memoryAddressRangeStr = QString(
|
||||
"0x" + QString::number(memoryAddressRange.startAddress, 16).toUpper() + QString(" -> ")
|
||||
+ "0x" + QString::number(memoryAddressRange.endAddress, 16).toUpper()
|
||||
);
|
||||
|
||||
const auto absoluteAddressRange = addressType == MemoryRegionAddressInputType::RELATIVE ?
|
||||
this->convertRelativeToAbsoluteAddressRange(
|
||||
TargetMemoryAddressRange(startAddress, endAddress)
|
||||
) : TargetMemoryAddressRange(startAddress, endAddress);
|
||||
|
||||
if (absoluteAddressRange.startAddress < memoryAddressRange.startAddress
|
||||
|| absoluteAddressRange.startAddress > memoryAddressRange.endAddress
|
||||
) {
|
||||
validationFailures.emplace_back(
|
||||
"The start address is not within the absolute memory address range (" + memoryAddressRangeStr + ")."
|
||||
);
|
||||
}
|
||||
|
||||
if (absoluteAddressRange.endAddress < memoryAddressRange.startAddress
|
||||
|| absoluteAddressRange.endAddress > memoryAddressRange.endAddress
|
||||
) {
|
||||
validationFailures.emplace_back(
|
||||
"The end address not within the absolute memory address range (" + memoryAddressRangeStr + ")."
|
||||
);
|
||||
}
|
||||
|
||||
return validationFailures;
|
||||
}
|
||||
|
||||
if (startAddress > endAddress) {
|
||||
validationFailures.emplace_back("The start address exceeds the end address.");
|
||||
void RegionItem::initFormInputs() {
|
||||
const auto& region = this->getMemoryRegion();
|
||||
|
||||
this->nameInput = this->formWidget->findChild<TextInput*>("name-input");
|
||||
this->addressTypeInput = this->formWidget->findChild<QComboBox*>("address-type-input");
|
||||
this->startAddressInput = this->formWidget->findChild<TextInput*>("start-address-input");
|
||||
this->endAddressInput = this->formWidget->findChild<TextInput*>("end-address-input");
|
||||
this->sizeInput = this->formWidget->findChild<TextInput*>("size-input");
|
||||
|
||||
this->nameInput->setText(region.name);
|
||||
this->sizeInput->setText(
|
||||
QString::number((region.addressRange.endAddress - region.addressRange.startAddress) + 1)
|
||||
);
|
||||
|
||||
for (const auto& [optionName, option] : RegionItem::addressRangeTypeOptionsByName) {
|
||||
this->addressTypeInput->addItem(option.text, optionName);
|
||||
}
|
||||
|
||||
if (region.addressRangeInputType == MemoryRegionAddressInputType::RELATIVE) {
|
||||
auto relativeAddressRange = this->convertAbsoluteToRelativeAddressRange(region.addressRange);
|
||||
this->addressTypeInput->setCurrentText(RegionItem::addressRangeTypeOptionsByName.at("relative").text);
|
||||
|
||||
this->startAddressInput->setText(
|
||||
"0x" + QString::number(relativeAddressRange.startAddress, 16).toUpper()
|
||||
);
|
||||
this->endAddressInput->setText(
|
||||
"0x" + QString::number(relativeAddressRange.endAddress, 16).toUpper()
|
||||
);
|
||||
|
||||
} else {
|
||||
this->addressTypeInput->setCurrentText(RegionItem::addressRangeTypeOptionsByName.at("absolute").text);
|
||||
|
||||
this->startAddressInput->setText(
|
||||
"0x" + QString::number(region.addressRange.startAddress, 16).toUpper()
|
||||
);
|
||||
this->endAddressInput->setText(
|
||||
"0x" + QString::number(region.addressRange.endAddress, 16).toUpper()
|
||||
);
|
||||
}
|
||||
|
||||
QObject::connect(this->startAddressInput, &QLineEdit::textEdited, this, &RegionItem::onAddressRangeInputChange);
|
||||
QObject::connect(this->endAddressInput, &QLineEdit::textEdited, this, &RegionItem::onAddressRangeInputChange);
|
||||
QObject::connect(this->sizeInput, &QLineEdit::textEdited, this, &RegionItem::onSizeInputChange);
|
||||
QObject::connect(this->nameInput, &QLineEdit::textEdited, this, &RegionItem::onNameInputChange);
|
||||
}
|
||||
|
||||
auto addressType = this->getSelectedAddressInputType();
|
||||
const auto memoryAddressRange = this->memoryDescriptor.addressRange;
|
||||
MemoryRegionAddressInputType RegionItem::getSelectedAddressInputType() const {
|
||||
auto selectedAddressTypeOptionName = this->addressTypeInput->currentData().toString();
|
||||
if (RegionItem::addressRangeTypeOptionsByName.contains(selectedAddressTypeOptionName)) {
|
||||
return RegionItem::addressRangeTypeOptionsByName.at(selectedAddressTypeOptionName).addressType;
|
||||
}
|
||||
|
||||
const auto memoryAddressRangeStr = QString(
|
||||
"0x" + QString::number(memoryAddressRange.startAddress, 16).toUpper() + QString(" -> ")
|
||||
+ "0x" + QString::number(memoryAddressRange.endAddress, 16).toUpper()
|
||||
);
|
||||
return MemoryRegionAddressInputType::ABSOLUTE;
|
||||
}
|
||||
|
||||
const auto absoluteAddressRange = addressType == MemoryRegionAddressInputType::RELATIVE ?
|
||||
this->convertRelativeToAbsoluteAddressRange(TargetMemoryAddressRange(startAddress, endAddress))
|
||||
: TargetMemoryAddressRange(startAddress, endAddress);
|
||||
|
||||
if (absoluteAddressRange.startAddress < memoryAddressRange.startAddress
|
||||
|| absoluteAddressRange.startAddress > memoryAddressRange.endAddress
|
||||
) {
|
||||
validationFailures.emplace_back(
|
||||
"The start address is not within the absolute memory address range (" + memoryAddressRangeStr + ")."
|
||||
TargetMemoryAddressRange RegionItem::convertAbsoluteToRelativeAddressRange(
|
||||
const TargetMemoryAddressRange& absoluteAddressRange
|
||||
) const {
|
||||
return TargetMemoryAddressRange(
|
||||
absoluteAddressRange.startAddress - this->memoryDescriptor.addressRange.startAddress,
|
||||
absoluteAddressRange.endAddress - this->memoryDescriptor.addressRange.startAddress
|
||||
);
|
||||
}
|
||||
|
||||
if (absoluteAddressRange.endAddress < memoryAddressRange.startAddress
|
||||
|| absoluteAddressRange.endAddress > memoryAddressRange.endAddress
|
||||
) {
|
||||
validationFailures.emplace_back(
|
||||
"The end address not within the absolute memory address range (" + memoryAddressRangeStr + ")."
|
||||
TargetMemoryAddressRange RegionItem::convertRelativeToAbsoluteAddressRange(
|
||||
const TargetMemoryAddressRange& relativeAddressRange
|
||||
) const {
|
||||
return TargetMemoryAddressRange(
|
||||
relativeAddressRange.startAddress + this->memoryDescriptor.addressRange.startAddress,
|
||||
relativeAddressRange.endAddress + this->memoryDescriptor.addressRange.startAddress
|
||||
);
|
||||
}
|
||||
|
||||
return validationFailures;
|
||||
}
|
||||
void RegionItem::onAddressRangeInputChange() {
|
||||
bool startAddressConversionOk = false;
|
||||
bool endAddressConversionOk = false;
|
||||
std::uint32_t startAddress = this->startAddressInput->text().toUInt(&startAddressConversionOk, 16);
|
||||
std::uint32_t endAddress = this->endAddressInput->text().toUInt(&endAddressConversionOk, 16);
|
||||
|
||||
void RegionItem::initFormInputs() {
|
||||
const auto& region = this->getMemoryRegion();
|
||||
|
||||
this->nameInput = this->formWidget->findChild<TextInput*>("name-input");
|
||||
this->addressTypeInput = this->formWidget->findChild<QComboBox*>("address-type-input");
|
||||
this->startAddressInput = this->formWidget->findChild<TextInput*>("start-address-input");
|
||||
this->endAddressInput = this->formWidget->findChild<TextInput*>("end-address-input");
|
||||
this->sizeInput = this->formWidget->findChild<TextInput*>("size-input");
|
||||
|
||||
this->nameInput->setText(region.name);
|
||||
this->sizeInput->setText(QString::number((region.addressRange.endAddress - region.addressRange.startAddress) + 1));
|
||||
|
||||
for (const auto& [optionName, option] : RegionItem::addressRangeTypeOptionsByName) {
|
||||
this->addressTypeInput->addItem(option.text, optionName);
|
||||
if (startAddressConversionOk && endAddressConversionOk && startAddress <= endAddress) {
|
||||
this->sizeInput->setText(QString::number((endAddress - startAddress) + 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (region.addressRangeInputType == MemoryRegionAddressInputType::RELATIVE) {
|
||||
auto relativeAddressRange = this->convertAbsoluteToRelativeAddressRange(region.addressRange);
|
||||
this->addressTypeInput->setCurrentText(RegionItem::addressRangeTypeOptionsByName.at("relative").text);
|
||||
void RegionItem::onSizeInputChange() {
|
||||
bool startAddressConversionOk = false;
|
||||
bool sizeConversionOk = false;
|
||||
std::uint32_t startAddress = this->startAddressInput->text().toUInt(&startAddressConversionOk, 16);
|
||||
std::uint32_t size = this->sizeInput->text().toUInt(&sizeConversionOk, 10);
|
||||
|
||||
this->startAddressInput->setText("0x" + QString::number(relativeAddressRange.startAddress, 16).toUpper());
|
||||
this->endAddressInput->setText("0x" + QString::number(relativeAddressRange.endAddress, 16).toUpper());
|
||||
|
||||
} else {
|
||||
this->addressTypeInput->setCurrentText(RegionItem::addressRangeTypeOptionsByName.at("absolute").text);
|
||||
|
||||
this->startAddressInput->setText("0x" + QString::number(region.addressRange.startAddress, 16).toUpper());
|
||||
this->endAddressInput->setText("0x" + QString::number(region.addressRange.endAddress, 16).toUpper());
|
||||
if (startAddressConversionOk && sizeConversionOk && size > 0) {
|
||||
this->endAddressInput->setText("0x" + QString::number((startAddress + size) - 1, 16).toUpper());
|
||||
}
|
||||
}
|
||||
|
||||
QObject::connect(this->startAddressInput, &QLineEdit::textEdited, this, &RegionItem::onAddressRangeInputChange);
|
||||
QObject::connect(this->endAddressInput, &QLineEdit::textEdited, this, &RegionItem::onAddressRangeInputChange);
|
||||
QObject::connect(this->sizeInput, &QLineEdit::textEdited, this, &RegionItem::onSizeInputChange);
|
||||
QObject::connect(this->nameInput, &QLineEdit::textEdited, this, &RegionItem::onNameInputChange);
|
||||
}
|
||||
|
||||
MemoryRegionAddressInputType RegionItem::getSelectedAddressInputType() const {
|
||||
auto selectedAddressTypeOptionName = this->addressTypeInput->currentData().toString();
|
||||
if (RegionItem::addressRangeTypeOptionsByName.contains(selectedAddressTypeOptionName)) {
|
||||
return RegionItem::addressRangeTypeOptionsByName.at(selectedAddressTypeOptionName).addressType;
|
||||
}
|
||||
|
||||
return MemoryRegionAddressInputType::ABSOLUTE;
|
||||
}
|
||||
|
||||
TargetMemoryAddressRange RegionItem::convertAbsoluteToRelativeAddressRange(
|
||||
const TargetMemoryAddressRange& absoluteAddressRange
|
||||
) const {
|
||||
return TargetMemoryAddressRange(
|
||||
absoluteAddressRange.startAddress - this->memoryDescriptor.addressRange.startAddress,
|
||||
absoluteAddressRange.endAddress - this->memoryDescriptor.addressRange.startAddress
|
||||
);
|
||||
}
|
||||
|
||||
TargetMemoryAddressRange RegionItem::convertRelativeToAbsoluteAddressRange(
|
||||
const TargetMemoryAddressRange& relativeAddressRange
|
||||
) const {
|
||||
return TargetMemoryAddressRange(
|
||||
relativeAddressRange.startAddress + this->memoryDescriptor.addressRange.startAddress,
|
||||
relativeAddressRange.endAddress + this->memoryDescriptor.addressRange.startAddress
|
||||
);
|
||||
}
|
||||
|
||||
void RegionItem::onAddressRangeInputChange() {
|
||||
bool startAddressConversionOk = false;
|
||||
bool endAddressConversionOk = false;
|
||||
std::uint32_t startAddress = this->startAddressInput->text().toUInt(&startAddressConversionOk, 16);
|
||||
std::uint32_t endAddress = this->endAddressInput->text().toUInt(&endAddressConversionOk, 16);
|
||||
|
||||
if (startAddressConversionOk && endAddressConversionOk && startAddress <= endAddress) {
|
||||
this->sizeInput->setText(QString::number((endAddress - startAddress) + 1));
|
||||
void RegionItem::onNameInputChange() {
|
||||
auto newName = this->nameInput->text();
|
||||
newName.truncate(RegionItem::NAME_LABEL_MAX_LENGTH);
|
||||
this->nameLabel->setText(newName);
|
||||
}
|
||||
}
|
||||
|
||||
void RegionItem::onSizeInputChange() {
|
||||
bool startAddressConversionOk = false;
|
||||
bool sizeConversionOk = false;
|
||||
std::uint32_t startAddress = this->startAddressInput->text().toUInt(&startAddressConversionOk, 16);
|
||||
std::uint32_t size = this->sizeInput->text().toUInt(&sizeConversionOk, 10);
|
||||
|
||||
if (startAddressConversionOk && sizeConversionOk && size > 0) {
|
||||
this->endAddressInput->setText("0x" + QString::number((startAddress + size) - 1, 16).toUpper());
|
||||
}
|
||||
}
|
||||
|
||||
void RegionItem::onNameInputChange() {
|
||||
auto newName = this->nameInput->text();
|
||||
newName.truncate(RegionItem::NAME_LABEL_MAX_LENGTH);
|
||||
this->nameLabel->setText(newName);
|
||||
}
|
||||
|
||||
@@ -4,75 +4,79 @@
|
||||
#include <QScrollArea>
|
||||
#include <QMargins>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
BitBodyWidget::BitBodyWidget(
|
||||
int bitIndex,
|
||||
std::bitset<std::numeric_limits<unsigned char>::digits>::reference bit,
|
||||
bool readOnly,
|
||||
QWidget* parent
|
||||
): ClickableWidget(parent), bitIndex(bitIndex), bit(bit), readOnly(readOnly) {
|
||||
this->setFixedSize(BitBodyWidget::WIDTH, BitBodyWidget::HEIGHT);
|
||||
this->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
BitBodyWidget::BitBodyWidget(
|
||||
int bitIndex,
|
||||
std::bitset<std::numeric_limits<unsigned char>::digits>::reference bit,
|
||||
bool readOnly,
|
||||
QWidget* parent
|
||||
): ClickableWidget(parent), bitIndex(bitIndex), bit(bit), readOnly(readOnly) {
|
||||
this->setFixedSize(BitBodyWidget::WIDTH, BitBodyWidget::HEIGHT);
|
||||
this->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
bool BitBodyWidget::event(QEvent* event) {
|
||||
if (this->isEnabled() && !this->readOnly) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Enter: {
|
||||
this->hoverActive = true;
|
||||
this->update();
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave: {
|
||||
this->hoverActive = false;
|
||||
this->update();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BitBodyWidget::event(QEvent* event) {
|
||||
if (this->isEnabled() && !this->readOnly) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Enter: {
|
||||
this->hoverActive = true;
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
void BitBodyWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||
if (this->isEnabled()) {
|
||||
if (!this->readOnly && event->button() == Qt::MouseButton::LeftButton) {
|
||||
this->bit = !this->bit;
|
||||
this->update();
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave: {
|
||||
this->hoverActive = false;
|
||||
this->update();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
|
||||
ClickableWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::event(event);
|
||||
}
|
||||
void BitBodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void BitBodyWidget::mouseReleaseEvent(QMouseEvent* event) {
|
||||
if (this->isEnabled()) {
|
||||
if (!this->readOnly && event->button() == Qt::MouseButton::LeftButton) {
|
||||
this->bit = !this->bit;
|
||||
this->update();
|
||||
void BitBodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(
|
||||
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
|
||||
true
|
||||
);
|
||||
|
||||
auto bodyColor = QColor(this->bit == true ? "#7B5E38" : "#908D85");
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
bodyColor.setAlpha(100);
|
||||
|
||||
} else if (!this->hoverActive) {
|
||||
bodyColor.setAlpha(235);
|
||||
}
|
||||
|
||||
ClickableWidget::mouseReleaseEvent(event);
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(bodyColor);
|
||||
|
||||
painter.drawRect(
|
||||
0,
|
||||
0,
|
||||
BitBodyWidget::WIDTH,
|
||||
BitBodyWidget::HEIGHT
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void BitBodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void BitBodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
|
||||
auto bodyColor = QColor(this->bit == true ? "#7B5E38" : "#908D85");
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
bodyColor.setAlpha(100);
|
||||
|
||||
} else if (!this->hoverActive) {
|
||||
bodyColor.setAlpha(235);
|
||||
}
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(bodyColor);
|
||||
|
||||
painter.drawRect(
|
||||
0,
|
||||
0,
|
||||
BitBodyWidget::WIDTH,
|
||||
BitBodyWidget::HEIGHT
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,50 +6,51 @@
|
||||
|
||||
#include "BitBodyWidget.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
BitWidget::BitWidget(
|
||||
int bitIndex,
|
||||
int bitNumber,
|
||||
std::bitset<std::numeric_limits<unsigned char>::digits>& bitset,
|
||||
bool readOnly,
|
||||
QWidget* parent
|
||||
): QWidget(parent), bitIndex(bitIndex), bitNumber(bitNumber), bitset(bitset), readOnly(readOnly) {
|
||||
this->setFixedSize(BitWidget::WIDTH, BitWidget::HEIGHT);
|
||||
|
||||
BitWidget::BitWidget(
|
||||
int bitIndex,
|
||||
int bitNumber,
|
||||
std::bitset<std::numeric_limits<unsigned char>::digits>& bitset,
|
||||
bool readOnly,
|
||||
QWidget* parent
|
||||
): QWidget(parent), bitIndex(bitIndex), bitNumber(bitNumber), bitset(bitset), readOnly(readOnly) {
|
||||
this->setFixedSize(BitWidget::WIDTH, BitWidget::HEIGHT);
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(0);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setAlignment(Qt::AlignmentFlag::AlignTop);
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(0);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setAlignment(Qt::AlignmentFlag::AlignTop);
|
||||
this->body = new BitBodyWidget(
|
||||
this->bitIndex,
|
||||
this->bitset[static_cast<size_t>(this->bitIndex)],
|
||||
this->readOnly,
|
||||
this
|
||||
);
|
||||
|
||||
this->body = new BitBodyWidget(
|
||||
this->bitIndex,
|
||||
this->bitset[static_cast<size_t>(this->bitIndex)],
|
||||
this->readOnly,
|
||||
this
|
||||
);
|
||||
this->bitLabel = new QLabel("Bit", this);
|
||||
this->bitNumberLabel = new QLabel(QString::number(this->bitNumber), this);
|
||||
|
||||
this->bitLabel = new QLabel("Bit", this);
|
||||
this->bitNumberLabel = new QLabel(QString::number(this->bitNumber), this);
|
||||
this->bitLabel->setObjectName("register-bit-label");
|
||||
this->bitNumberLabel->setObjectName("register-bit-number-label");
|
||||
|
||||
this->bitLabel->setObjectName("register-bit-label");
|
||||
this->bitNumberLabel->setObjectName("register-bit-number-label");
|
||||
this->bitLabel->setFixedHeight(BitWidget::LABEL_HEIGHT);
|
||||
this->bitNumberLabel->setFixedHeight(BitWidget::LABEL_HEIGHT);
|
||||
|
||||
this->bitLabel->setFixedHeight(BitWidget::LABEL_HEIGHT);
|
||||
this->bitNumberLabel->setFixedHeight(BitWidget::LABEL_HEIGHT);
|
||||
this->bitLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
this->bitNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
|
||||
this->bitLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
this->bitNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
layout->addWidget(this->bitLabel);
|
||||
layout->addWidget(this->bitNumberLabel);
|
||||
layout->addSpacing(BitWidget::VERTICAL_SPACING);
|
||||
layout->addWidget(this->body);
|
||||
layout->addStretch(1);
|
||||
|
||||
layout->addWidget(this->bitLabel);
|
||||
layout->addWidget(this->bitNumberLabel);
|
||||
layout->addSpacing(BitWidget::VERTICAL_SPACING);
|
||||
layout->addWidget(this->body);
|
||||
layout->addStretch(1);
|
||||
|
||||
if (!this->readOnly) {
|
||||
QObject::connect(this->body, &BitBodyWidget::clicked, this, [this] {
|
||||
emit this->bitChanged();
|
||||
});
|
||||
if (!this->readOnly) {
|
||||
QObject::connect(this->body, &BitBodyWidget::clicked, this, [this] {
|
||||
emit this->bitChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,101 +8,102 @@
|
||||
|
||||
#include "../TargetRegisterInspectorWindow.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
BitsetWidget::BitsetWidget(int byteNumber, unsigned char& byte, bool readOnly, QWidget* parent):
|
||||
QWidget(parent), byteNumber(byteNumber), byte(byte), readOnly(readOnly) {
|
||||
this->setObjectName("bitset-widget");
|
||||
auto* bitLayout = new QHBoxLayout(this);
|
||||
bitLayout->setSpacing(BitWidget::SPACING);
|
||||
bitLayout->setContentsMargins(0, 0, 0, 0);
|
||||
this->setContentsMargins(0, 0, 0, 0);
|
||||
this->setFixedSize(
|
||||
static_cast<int>((BitWidget::WIDTH + BitWidget::SPACING) * this->bitset.size() - BitWidget::SPACING),
|
||||
BitsetWidget::HEIGHT
|
||||
);
|
||||
|
||||
for (int bitIndex = (std::numeric_limits<unsigned char>::digits - 1); bitIndex >= 0; bitIndex--) {
|
||||
auto* bitWidget = new BitWidget(
|
||||
bitIndex,
|
||||
(this->byteNumber * 8) + bitIndex,
|
||||
this->bitset,
|
||||
this->readOnly,
|
||||
this
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
BitsetWidget::BitsetWidget(int byteNumber, unsigned char& byte, bool readOnly, QWidget* parent)
|
||||
: QWidget(parent), byteNumber(byteNumber), byte(byte), readOnly(readOnly) {
|
||||
this->setObjectName("bitset-widget");
|
||||
auto* bitLayout = new QHBoxLayout(this);
|
||||
bitLayout->setSpacing(BitWidget::SPACING);
|
||||
bitLayout->setContentsMargins(0, 0, 0, 0);
|
||||
this->setContentsMargins(0, 0, 0, 0);
|
||||
this->setFixedSize(
|
||||
static_cast<int>((BitWidget::WIDTH + BitWidget::SPACING) * this->bitset.size() - BitWidget::SPACING),
|
||||
BitsetWidget::HEIGHT
|
||||
);
|
||||
|
||||
bitLayout->addWidget(bitWidget, 0, Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop);
|
||||
QObject::connect(
|
||||
bitWidget,
|
||||
&BitWidget::bitChanged,
|
||||
this,
|
||||
[this] {
|
||||
this->byte = static_cast<unsigned char>(this->bitset.to_ulong());
|
||||
this->repaint();
|
||||
emit this->byteChanged();
|
||||
}
|
||||
for (int bitIndex = (std::numeric_limits<unsigned char>::digits - 1); bitIndex >= 0; bitIndex--) {
|
||||
auto* bitWidget = new BitWidget(
|
||||
bitIndex,
|
||||
(this->byteNumber * 8) + bitIndex,
|
||||
this->bitset,
|
||||
this->readOnly,
|
||||
this
|
||||
);
|
||||
|
||||
bitLayout->addWidget(bitWidget, 0, Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop);
|
||||
QObject::connect(
|
||||
bitWidget,
|
||||
&BitWidget::bitChanged,
|
||||
this,
|
||||
[this] {
|
||||
this->byte = static_cast<unsigned char>(this->bitset.to_ulong());
|
||||
this->repaint();
|
||||
emit this->byteChanged();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void BitsetWidget::updateValue() {
|
||||
this->bitset = {this->byte};
|
||||
this->update();
|
||||
}
|
||||
|
||||
void BitsetWidget::paintEvent(QPaintEvent* event) {
|
||||
QWidget::paintEvent(event);
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void BitsetWidget::drawWidget(QPainter& painter) {
|
||||
auto byteHex = "0x" + QString::number(this->byte, 16).toUpper();
|
||||
|
||||
painter.setPen(QColor("#474747"));
|
||||
constexpr int labelHeight = 11;
|
||||
int containerWidth = this->width();
|
||||
constexpr int charWidth = 6;
|
||||
auto labelWidth = static_cast<int>(charWidth * byteHex.size()) + 13;
|
||||
auto width = (containerWidth - (BitWidget::WIDTH) - labelWidth) / 2;
|
||||
|
||||
painter.drawLine(QLine(
|
||||
BitWidget::WIDTH / 2,
|
||||
BitWidget::HEIGHT,
|
||||
BitWidget::WIDTH / 2,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.drawLine(QLine(
|
||||
containerWidth - (BitWidget::WIDTH / 2) - 1,
|
||||
BitWidget::HEIGHT,
|
||||
containerWidth - (BitWidget::WIDTH / 2) - 1,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.drawLine(QLine(
|
||||
BitWidget::WIDTH / 2,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT,
|
||||
static_cast<int>((BitWidget::WIDTH / 2) + width),
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.drawLine(QLine(
|
||||
static_cast<int>((BitWidget::WIDTH / 2) + width + labelWidth),
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT,
|
||||
containerWidth - (BitWidget::WIDTH / 2) - 1,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.setPen(QColor("#8a8a8d"));
|
||||
painter.drawText(
|
||||
QRect(
|
||||
static_cast<int>((BitWidget::WIDTH / 2) + width),
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT - (labelHeight / 2),
|
||||
labelWidth,
|
||||
labelHeight
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
byteHex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void BitsetWidget::updateValue() {
|
||||
this->bitset = {this->byte};
|
||||
this->update();
|
||||
}
|
||||
|
||||
void BitsetWidget::paintEvent(QPaintEvent* event) {
|
||||
QWidget::paintEvent(event);
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void BitsetWidget::drawWidget(QPainter& painter) {
|
||||
auto byteHex = "0x" + QString::number(this->byte, 16).toUpper();
|
||||
|
||||
painter.setPen(QColor("#474747"));
|
||||
constexpr int labelHeight = 11;
|
||||
int containerWidth = this->width();
|
||||
constexpr int charWidth = 6;
|
||||
auto labelWidth = static_cast<int>(charWidth * byteHex.size()) + 13;
|
||||
auto width = (containerWidth - (BitWidget::WIDTH) - labelWidth) / 2;
|
||||
|
||||
painter.drawLine(QLine(
|
||||
BitWidget::WIDTH / 2,
|
||||
BitWidget::HEIGHT,
|
||||
BitWidget::WIDTH / 2,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.drawLine(QLine(
|
||||
containerWidth - (BitWidget::WIDTH / 2) - 1,
|
||||
BitWidget::HEIGHT,
|
||||
containerWidth - (BitWidget::WIDTH / 2) - 1,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.drawLine(QLine(
|
||||
BitWidget::WIDTH / 2,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT,
|
||||
static_cast<int>((BitWidget::WIDTH / 2) + width),
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.drawLine(QLine(
|
||||
static_cast<int>((BitWidget::WIDTH / 2) + width + labelWidth),
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT,
|
||||
containerWidth - (BitWidget::WIDTH / 2) - 1,
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT
|
||||
));
|
||||
|
||||
painter.setPen(QColor("#8a8a8d"));
|
||||
painter.drawText(
|
||||
QRect(
|
||||
static_cast<int>((BitWidget::WIDTH / 2) + width),
|
||||
BitWidget::HEIGHT + BitsetWidget::VALUE_GRAPHIC_HEIGHT - (labelHeight / 2),
|
||||
labelWidth,
|
||||
labelHeight
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
byteHex
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
#include <QStyle>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
CurrentItem::CurrentItem(
|
||||
const Targets::TargetMemoryBuffer& registerValue,
|
||||
QWidget* parent
|
||||
): Item(registerValue, parent) {
|
||||
this->setObjectName("current-item");
|
||||
this->setFixedHeight(30);
|
||||
this->titleLabel->setText("Current value");
|
||||
this->layout->addWidget(titleLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
this->layout->setContentsMargins(5, 0, 5, 0);
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
CurrentItem::CurrentItem(
|
||||
const Targets::TargetMemoryBuffer& registerValue,
|
||||
QWidget* parent
|
||||
): Item(registerValue, parent) {
|
||||
this->setObjectName("current-item");
|
||||
this->setFixedHeight(30);
|
||||
this->titleLabel->setText("Current value");
|
||||
this->layout->addWidget(titleLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
this->layout->setContentsMargins(5, 0, 5, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,26 +2,27 @@
|
||||
|
||||
#include <QStyle>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
Item::Item(const Targets::TargetMemoryBuffer& registerValue, QWidget* parent)
|
||||
: ClickableWidget(parent), registerValue(registerValue) {
|
||||
auto onClick = [this] {
|
||||
this->setSelected(true);
|
||||
};
|
||||
|
||||
Item::Item(const Targets::TargetMemoryBuffer& registerValue, QWidget* parent):
|
||||
ClickableWidget(parent), registerValue(registerValue) {
|
||||
auto onClick = [this] {
|
||||
this->setSelected(true);
|
||||
};
|
||||
QObject::connect(this, &ClickableWidget::clicked, this, onClick);
|
||||
QObject::connect(this, &ClickableWidget::rightClicked, this, onClick);
|
||||
|
||||
QObject::connect(this, &ClickableWidget::clicked, this, onClick);
|
||||
QObject::connect(this, &ClickableWidget::rightClicked, this, onClick);
|
||||
this->setSelected(false);
|
||||
}
|
||||
|
||||
this->setSelected(false);
|
||||
}
|
||||
void Item::setSelected(bool selected) {
|
||||
this->setProperty("selected", selected);
|
||||
this->style()->unpolish(this);
|
||||
this->style()->polish(this);
|
||||
|
||||
void Item::setSelected(bool selected) {
|
||||
this->setProperty("selected", selected);
|
||||
this->style()->unpolish(this);
|
||||
this->style()->polish(this);
|
||||
|
||||
if (selected) {
|
||||
emit this->selected(this);
|
||||
if (selected) {
|
||||
emit this->selected(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,38 +4,39 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QByteArray>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
RegisterHistoryItem::RegisterHistoryItem(
|
||||
const Targets::TargetMemoryBuffer& registerValue,
|
||||
const QDateTime& changeDate,
|
||||
QWidget* parent
|
||||
): Item(registerValue, parent) {
|
||||
this->setObjectName("register-history-item");
|
||||
this->setFixedHeight(50);
|
||||
this->layout->setContentsMargins(5, 8, 5, 0);
|
||||
|
||||
RegisterHistoryItem::RegisterHistoryItem(
|
||||
const Targets::TargetMemoryBuffer& registerValue,
|
||||
const QDateTime& changeDate,
|
||||
QWidget* parent
|
||||
): Item(registerValue, parent) {
|
||||
this->setObjectName("register-history-item");
|
||||
this->setFixedHeight(50);
|
||||
this->layout->setContentsMargins(5, 8, 5, 0);
|
||||
this->dateLabel->setText(changeDate.toString("dd/MM/yyyy hh:mm:ss"));
|
||||
this->dateLabel->setObjectName("date-label");
|
||||
|
||||
this->dateLabel->setText(changeDate.toString("dd/MM/yyyy hh:mm:ss"));
|
||||
this->dateLabel->setObjectName("date-label");
|
||||
this->valueLabel->setText("0x" + QString(QByteArray(
|
||||
reinterpret_cast<const char*>(registerValue.data()),
|
||||
static_cast<qsizetype>(registerValue.size())
|
||||
).toHex()).toUpper());
|
||||
this->valueLabel->setObjectName("value-label");
|
||||
|
||||
this->valueLabel->setText("0x" + QString(QByteArray(
|
||||
reinterpret_cast<const char*>(registerValue.data()),
|
||||
static_cast<qsizetype>(registerValue.size())
|
||||
).toHex()).toUpper());
|
||||
this->valueLabel->setObjectName("value-label");
|
||||
this->descriptionLabel->setText("Register Written");
|
||||
this->descriptionLabel->setObjectName("description-label");
|
||||
|
||||
this->descriptionLabel->setText("Register Written");
|
||||
this->descriptionLabel->setObjectName("description-label");
|
||||
auto* subLabelLayout = new QHBoxLayout();
|
||||
subLabelLayout->setSpacing(0);
|
||||
subLabelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
subLabelLayout->addWidget(this->valueLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
subLabelLayout->addStretch(1);
|
||||
subLabelLayout->addWidget(this->descriptionLabel, 0, Qt::AlignmentFlag::AlignRight);
|
||||
|
||||
auto* subLabelLayout = new QHBoxLayout();
|
||||
subLabelLayout->setSpacing(0);
|
||||
subLabelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
subLabelLayout->addWidget(this->valueLabel, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
subLabelLayout->addStretch(1);
|
||||
subLabelLayout->addWidget(this->descriptionLabel, 0, Qt::AlignmentFlag::AlignRight);
|
||||
|
||||
this->layout->setSpacing(5);
|
||||
this->layout->addWidget(this->dateLabel, 0, Qt::AlignmentFlag::AlignTop);
|
||||
this->layout->addLayout(subLabelLayout);
|
||||
this->layout->addStretch(1);
|
||||
this->layout->setSpacing(5);
|
||||
this->layout->addWidget(this->dateLabel, 0, Qt::AlignmentFlag::AlignTop);
|
||||
this->layout->addLayout(subLabelLayout);
|
||||
this->layout->addStretch(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,125 +12,130 @@
|
||||
#include "src/Helpers/DateTime.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetRegisterType;
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetRegisterType;
|
||||
|
||||
RegisterHistoryWidget::RegisterHistoryWidget(
|
||||
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
||||
const Targets::TargetMemoryBuffer& currentValue,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): QWidget(parent), registerDescriptor(registerDescriptor), insightWorker(insightWorker) {
|
||||
this->setObjectName("target-register-history-widget");
|
||||
this->setFixedWidth(300);
|
||||
RegisterHistoryWidget::RegisterHistoryWidget(
|
||||
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
||||
const Targets::TargetMemoryBuffer& currentValue,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): QWidget(parent), registerDescriptor(registerDescriptor), insightWorker(insightWorker) {
|
||||
this->setObjectName("target-register-history-widget");
|
||||
this->setFixedWidth(300);
|
||||
|
||||
auto widgetUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget"
|
||||
+ "/UiFiles/RegisterHistoryWidget.ui"
|
||||
)
|
||||
);
|
||||
auto widgetUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget"
|
||||
+ "/UiFiles/RegisterHistoryWidget.ui"
|
||||
)
|
||||
);
|
||||
|
||||
if (!widgetUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open RegisterHistoryWidget UI file");
|
||||
}
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&widgetUiFile, this);
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(1, 1, 1, 1);
|
||||
|
||||
this->itemContainer = this->container->findChild<QWidget*>("item-container");
|
||||
this->itemContainerLayout = this->itemContainer->findChild<QVBoxLayout*>("item-container-layout");
|
||||
auto titleBar = this->container->findChild<QWidget*>("title-bar");
|
||||
auto title = titleBar->findChild<QLabel*>("title");
|
||||
|
||||
titleBar->setContentsMargins(0, 0, 0, 0);
|
||||
title->setFixedHeight(titleBar->height());
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&RegisterHistoryWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetRegistersWritten,
|
||||
this,
|
||||
&RegisterHistoryWidget::onRegistersWritten
|
||||
);
|
||||
|
||||
this->currentItem = new CurrentItem(currentValue, this);
|
||||
QObject::connect(this->currentItem, &Item::selected, this, &RegisterHistoryWidget::onItemSelectionChange);
|
||||
this->itemContainerLayout->addWidget(this->currentItem);
|
||||
this->currentItem->setSelected(true);
|
||||
|
||||
auto* separatorWidget = new QWidget(this);
|
||||
auto* separatorLayout = new QHBoxLayout(separatorWidget);
|
||||
auto* separatorLabel = new QLabel("Select an item to restore", separatorWidget);
|
||||
separatorWidget->setFixedHeight(40);
|
||||
separatorWidget->setObjectName("separator-widget");
|
||||
separatorLayout->setContentsMargins(0, 10, 0, 10);
|
||||
separatorLabel->setObjectName("separator-label");
|
||||
separatorLayout->addWidget(separatorLabel, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
this->itemContainerLayout->addWidget(separatorWidget);
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::updateCurrentItemValue(const Targets::TargetMemoryBuffer& registerValue) {
|
||||
this->currentItem->registerValue = registerValue;
|
||||
|
||||
if (this->selectedItemWidget != nullptr && this->currentItem == this->selectedItemWidget) {
|
||||
this->selectCurrentItem();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::selectCurrentItem() {
|
||||
this->currentItem->setSelected(true);
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::addItem(const Targets::TargetMemoryBuffer& registerValue, const QDateTime& changeDate) {
|
||||
auto* item = new RegisterHistoryItem(registerValue, changeDate, this->itemContainer);
|
||||
QObject::connect(item, &Item::selected, this, &RegisterHistoryWidget::onItemSelectionChange);
|
||||
this->itemContainerLayout->insertWidget(2, item);
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::resizeEvent(QResizeEvent* event) {
|
||||
this->container->setFixedSize(
|
||||
this->width(),
|
||||
this->height()
|
||||
);
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::onItemSelectionChange(Item* newlySelectedWidget) {
|
||||
if (this->selectedItemWidget != newlySelectedWidget) {
|
||||
if (this->selectedItemWidget != nullptr) {
|
||||
this->selectedItemWidget->setSelected(false);
|
||||
if (!widgetUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open RegisterHistoryWidget UI file");
|
||||
}
|
||||
|
||||
this->selectedItemWidget = newlySelectedWidget;
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&widgetUiFile, this);
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(1, 1, 1, 1);
|
||||
|
||||
this->itemContainer = this->container->findChild<QWidget*>("item-container");
|
||||
this->itemContainerLayout = this->itemContainer->findChild<QVBoxLayout*>("item-container-layout");
|
||||
auto titleBar = this->container->findChild<QWidget*>("title-bar");
|
||||
auto title = titleBar->findChild<QLabel*>("title");
|
||||
|
||||
titleBar->setContentsMargins(0, 0, 0, 0);
|
||||
title->setFixedHeight(titleBar->height());
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&RegisterHistoryWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetRegistersWritten,
|
||||
this,
|
||||
&RegisterHistoryWidget::onRegistersWritten
|
||||
);
|
||||
|
||||
this->currentItem = new CurrentItem(currentValue, this);
|
||||
QObject::connect(this->currentItem, &Item::selected, this, &RegisterHistoryWidget::onItemSelectionChange);
|
||||
this->itemContainerLayout->addWidget(this->currentItem);
|
||||
this->currentItem->setSelected(true);
|
||||
|
||||
auto* separatorWidget = new QWidget(this);
|
||||
auto* separatorLayout = new QHBoxLayout(separatorWidget);
|
||||
auto* separatorLabel = new QLabel("Select an item to restore", separatorWidget);
|
||||
separatorWidget->setFixedHeight(40);
|
||||
separatorWidget->setObjectName("separator-widget");
|
||||
separatorLayout->setContentsMargins(0, 10, 0, 10);
|
||||
separatorLabel->setObjectName("separator-label");
|
||||
separatorLayout->addWidget(separatorLabel, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
this->itemContainerLayout->addWidget(separatorWidget);
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
emit this->historyItemSelected(newlySelectedWidget->registerValue);
|
||||
}
|
||||
void RegisterHistoryWidget::updateCurrentItemValue(const Targets::TargetMemoryBuffer& registerValue) {
|
||||
this->currentItem->registerValue = registerValue;
|
||||
|
||||
void RegisterHistoryWidget::onRegistersWritten(Targets::TargetRegisters targetRegisters, const QDateTime& changeDate) {
|
||||
for (const auto& targetRegister : targetRegisters) {
|
||||
if (targetRegister.descriptor == this->registerDescriptor) {
|
||||
this->addItem(targetRegister.value, changeDate);
|
||||
this->updateCurrentItemValue(targetRegister.value);
|
||||
if (this->selectedItemWidget != nullptr && this->currentItem == this->selectedItemWidget) {
|
||||
this->selectCurrentItem();
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::selectCurrentItem() {
|
||||
this->currentItem->setSelected(true);
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::addItem(const Targets::TargetMemoryBuffer& registerValue, const QDateTime& changeDate) {
|
||||
auto* item = new RegisterHistoryItem(registerValue, changeDate, this->itemContainer);
|
||||
QObject::connect(item, &Item::selected, this, &RegisterHistoryWidget::onItemSelectionChange);
|
||||
this->itemContainerLayout->insertWidget(2, item);
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::resizeEvent(QResizeEvent* event) {
|
||||
this->container->setFixedSize(
|
||||
this->width(),
|
||||
this->height()
|
||||
);
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::onItemSelectionChange(Item* newlySelectedWidget) {
|
||||
if (this->selectedItemWidget != newlySelectedWidget) {
|
||||
if (this->selectedItemWidget != nullptr) {
|
||||
this->selectedItemWidget->setSelected(false);
|
||||
}
|
||||
|
||||
this->selectedItemWidget = newlySelectedWidget;
|
||||
}
|
||||
|
||||
emit this->historyItemSelected(newlySelectedWidget->registerValue);
|
||||
}
|
||||
|
||||
void RegisterHistoryWidget::onRegistersWritten(
|
||||
Targets::TargetRegisters targetRegisters,
|
||||
const QDateTime& changeDate
|
||||
) {
|
||||
for (const auto& targetRegister : targetRegisters) {
|
||||
if (targetRegister.descriptor == this->registerDescriptor) {
|
||||
this->addItem(targetRegister.value, changeDate);
|
||||
this->updateCurrentItemValue(targetRegister.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,360 +14,380 @@
|
||||
#include "src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp"
|
||||
#include "src/Insight/InsightWorker/Tasks/WriteTargetRegister.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
using Bloom::Exceptions::Exception;
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetRegisterType;
|
||||
using Bloom::Targets::TargetState;
|
||||
|
||||
TargetRegisterInspectorWindow::TargetRegisterInspectorWindow(
|
||||
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
TargetState currentTargetState,
|
||||
std::optional<Targets::TargetMemoryBuffer> registerValue,
|
||||
QWidget* parent
|
||||
):
|
||||
QWidget(parent),
|
||||
registerDescriptor(registerDescriptor),
|
||||
insightWorker(insightWorker),
|
||||
registerValue(registerValue.value_or(Targets::TargetMemoryBuffer(registerDescriptor.size, 0)))
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
this->setWindowFlag(Qt::Window);
|
||||
auto registerName = QString::fromStdString(this->registerDescriptor.name.value()).toUpper();
|
||||
this->setObjectName("target-register-inspector-window");
|
||||
this->setWindowTitle("Inspect Register");
|
||||
using Bloom::Exceptions::Exception;
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetRegisterType;
|
||||
using Bloom::Targets::TargetState;
|
||||
|
||||
auto windowUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/UiFiles/TargetRegisterInspectorWindow.ui"
|
||||
)
|
||||
);
|
||||
TargetRegisterInspectorWindow::TargetRegisterInspectorWindow(
|
||||
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
TargetState currentTargetState,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& registerValue,
|
||||
QWidget* parent
|
||||
)
|
||||
: QWidget(parent)
|
||||
, registerDescriptor(registerDescriptor)
|
||||
, insightWorker(insightWorker)
|
||||
, registerValue(registerValue.value_or(Targets::TargetMemoryBuffer(registerDescriptor.size, 0)))
|
||||
{
|
||||
this->setWindowFlag(Qt::Window);
|
||||
auto registerName = QString::fromStdString(this->registerDescriptor.name.value()).toUpper();
|
||||
this->setObjectName("target-register-inspector-window");
|
||||
this->setWindowTitle("Inspect Register");
|
||||
|
||||
auto windowStylesheet = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Stylesheets/TargetRegisterInspectorWindow.qss"
|
||||
)
|
||||
);
|
||||
|
||||
if (!windowUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open TargetRegisterInspectorWindow UI file");
|
||||
}
|
||||
|
||||
if (!windowStylesheet.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open TargetRegisterInspectorWindow stylesheet file");
|
||||
}
|
||||
|
||||
auto windowSize = QSize(
|
||||
840,
|
||||
static_cast<int>(
|
||||
440
|
||||
+ ((BitsetWidget::HEIGHT + 20) * std::ceil(static_cast<float>(this->registerValue.size()) / 2))
|
||||
+ (!this->registerDescriptor.writable ? 50 : 0)
|
||||
)
|
||||
);
|
||||
auto containerMargins = QMargins(15, 30, 15, 10);
|
||||
|
||||
this->setStyleSheet(windowStylesheet.readAll());
|
||||
this->setFixedSize(windowSize);
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&windowUiFile, this);
|
||||
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(containerMargins);
|
||||
|
||||
this->registerNameLabel = this->container->findChild<QLabel*>("register-name");
|
||||
this->registerDescriptionLabel = this->container->findChild<QLabel*>("register-description");
|
||||
this->contentContainer = this->container->findChild<QWidget*>("content-container");
|
||||
this->registerValueContainer = this->container->findChild<QWidget*>("register-value-container");
|
||||
this->registerValueTextInput = this->container->findChild<QLineEdit*>("register-value-text-input");
|
||||
this->registerValueBitsetWidgetContainer = this->container->findChild<QWidget*>("register-value-bitset-widget-container");
|
||||
this->refreshValueButton = this->container->findChild<QPushButton*>("refresh-value-btn");
|
||||
this->applyButton = this->container->findChild<QPushButton*>("apply-btn");
|
||||
this->helpButton = this->container->findChild<QPushButton*>("help-btn");
|
||||
this->closeButton = this->container->findChild<QPushButton*>("close-btn");
|
||||
|
||||
this->registerNameLabel->setText(registerName);
|
||||
|
||||
if (this->registerDescriptor.description.has_value()) {
|
||||
this->registerDescriptionLabel->setText(QString::fromStdString(this->registerDescriptor.description.value()));
|
||||
this->registerDescriptionLabel->setVisible(true);
|
||||
}
|
||||
|
||||
this->registerHistoryWidget = new RegisterHistoryWidget(
|
||||
this->registerDescriptor,
|
||||
this->registerValue,
|
||||
insightWorker,
|
||||
this->container
|
||||
);
|
||||
|
||||
auto* contentLayout = this->container->findChild<QHBoxLayout*>("content-layout");
|
||||
contentLayout->insertWidget(0, this->registerHistoryWidget, 0, Qt::AlignmentFlag::AlignTop);
|
||||
|
||||
auto* registerDetailsContainer = this->container->findChild<QWidget*>("register-details-container");
|
||||
auto* registerValueContainer = this->container->findChild<QWidget*>("register-value-container");
|
||||
registerValueContainer->setContentsMargins(15, 15, 15, 15);
|
||||
registerDetailsContainer->setContentsMargins(15, 15, 15, 15);
|
||||
|
||||
auto* registerDetailsNameInput = registerDetailsContainer->findChild<QLineEdit*>("register-details-name-input");
|
||||
auto* registerDetailsSizeInput = registerDetailsContainer->findChild<QLineEdit*>("register-details-size-input");
|
||||
auto* registerDetailsStartAddressInput = registerDetailsContainer->findChild<QLineEdit*>(
|
||||
"register-details-start-address-input"
|
||||
);
|
||||
registerDetailsNameInput->setText(registerName);
|
||||
registerDetailsSizeInput->setText(QString::number(this->registerDescriptor.size));
|
||||
registerDetailsStartAddressInput->setText(
|
||||
"0x" + QString::number(this->registerDescriptor.startAddress.value(), 16).toUpper()
|
||||
);
|
||||
|
||||
this->registerValueTextInput->setFixedWidth(BitsetWidget::WIDTH * 2);
|
||||
|
||||
if (!this->registerDescriptor.writable) {
|
||||
this->registerValueTextInput->setDisabled(true);
|
||||
this->applyButton->setVisible(false);
|
||||
|
||||
auto* readOnlyIndicatorLabel = this->registerValueContainer->findChild<QLabel*>("read-only-indicator-label");
|
||||
readOnlyIndicatorLabel->show();
|
||||
}
|
||||
|
||||
auto* registerBitsetWidgetLayout = this->registerValueBitsetWidgetContainer->findChild<QVBoxLayout*>(
|
||||
"register-value-bitset-widget-layout"
|
||||
);
|
||||
|
||||
/*
|
||||
* Each row of the BitsetWidget container should hold two BitsetWidgets. So we have a horizontal layout nested
|
||||
* within a vertical layout.
|
||||
*/
|
||||
auto* bitsetSingleHorizontalLayout = new QHBoxLayout();
|
||||
bitsetSingleHorizontalLayout->setSpacing(BitWidget::SPACING);
|
||||
bitsetSingleHorizontalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// The register value will be in MSB, which is OK for us as we present the bit widgets in MSB.
|
||||
auto byteNumber = static_cast<int>(this->registerValue.size() - 1);
|
||||
for (std::uint32_t registerByteIndex = 0; registerByteIndex < this->registerValue.size(); registerByteIndex++) {
|
||||
auto* bitsetWidget = new BitsetWidget(
|
||||
byteNumber,
|
||||
this->registerValue.at(registerByteIndex),
|
||||
!this->registerDescriptor.writable,
|
||||
this
|
||||
auto windowUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/UiFiles/"
|
||||
"TargetRegisterInspectorWindow.ui"
|
||||
)
|
||||
);
|
||||
|
||||
bitsetSingleHorizontalLayout->addWidget(bitsetWidget, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
auto windowStylesheet = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Stylesheets/"
|
||||
"TargetRegisterInspectorWindow.qss"
|
||||
)
|
||||
);
|
||||
|
||||
if (!windowUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open TargetRegisterInspectorWindow UI file");
|
||||
}
|
||||
|
||||
if (!windowStylesheet.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open TargetRegisterInspectorWindow stylesheet file");
|
||||
}
|
||||
|
||||
auto windowSize = QSize(
|
||||
840,
|
||||
static_cast<int>(
|
||||
440
|
||||
+ ((BitsetWidget::HEIGHT + 20) * std::ceil(static_cast<float>(this->registerValue.size()) / 2))
|
||||
+ (!this->registerDescriptor.writable ? 50 : 0)
|
||||
)
|
||||
);
|
||||
auto containerMargins = QMargins(15, 30, 15, 10);
|
||||
|
||||
this->setStyleSheet(windowStylesheet.readAll());
|
||||
this->setFixedSize(windowSize);
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&windowUiFile, this);
|
||||
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(containerMargins);
|
||||
|
||||
this->registerNameLabel = this->container->findChild<QLabel*>("register-name");
|
||||
this->registerDescriptionLabel = this->container->findChild<QLabel*>("register-description");
|
||||
this->contentContainer = this->container->findChild<QWidget*>("content-container");
|
||||
this->registerValueContainer = this->container->findChild<QWidget*>("register-value-container");
|
||||
this->registerValueTextInput = this->container->findChild<QLineEdit*>("register-value-text-input");
|
||||
this->registerValueBitsetWidgetContainer = this->container->findChild<QWidget*>(
|
||||
"register-value-bitset-widget-container"
|
||||
);
|
||||
this->refreshValueButton = this->container->findChild<QPushButton*>("refresh-value-btn");
|
||||
this->applyButton = this->container->findChild<QPushButton*>("apply-btn");
|
||||
this->helpButton = this->container->findChild<QPushButton*>("help-btn");
|
||||
this->closeButton = this->container->findChild<QPushButton*>("close-btn");
|
||||
|
||||
this->registerNameLabel->setText(registerName);
|
||||
|
||||
if (this->registerDescriptor.description.has_value()) {
|
||||
this->registerDescriptionLabel->setText(
|
||||
QString::fromStdString(this->registerDescriptor.description.value())
|
||||
);
|
||||
this->registerDescriptionLabel->setVisible(true);
|
||||
}
|
||||
|
||||
this->registerHistoryWidget = new RegisterHistoryWidget(
|
||||
this->registerDescriptor,
|
||||
this->registerValue,
|
||||
insightWorker,
|
||||
this->container
|
||||
);
|
||||
|
||||
auto* contentLayout = this->container->findChild<QHBoxLayout*>("content-layout");
|
||||
contentLayout->insertWidget(0, this->registerHistoryWidget, 0, Qt::AlignmentFlag::AlignTop);
|
||||
|
||||
auto* registerDetailsContainer = this->container->findChild<QWidget*>("register-details-container");
|
||||
auto* registerValueContainer = this->container->findChild<QWidget*>("register-value-container");
|
||||
registerValueContainer->setContentsMargins(15, 15, 15, 15);
|
||||
registerDetailsContainer->setContentsMargins(15, 15, 15, 15);
|
||||
|
||||
auto* registerDetailsNameInput = registerDetailsContainer->findChild<QLineEdit*>(
|
||||
"register-details-name-input"
|
||||
);
|
||||
auto* registerDetailsSizeInput = registerDetailsContainer->findChild<QLineEdit*>(
|
||||
"register-details-size-input"
|
||||
);
|
||||
auto* registerDetailsStartAddressInput = registerDetailsContainer->findChild<QLineEdit*>(
|
||||
"register-details-start-address-input"
|
||||
);
|
||||
registerDetailsNameInput->setText(registerName);
|
||||
registerDetailsSizeInput->setText(QString::number(this->registerDescriptor.size));
|
||||
registerDetailsStartAddressInput->setText(
|
||||
"0x" + QString::number(this->registerDescriptor.startAddress.value(), 16).toUpper()
|
||||
);
|
||||
|
||||
this->registerValueTextInput->setFixedWidth(BitsetWidget::WIDTH * 2);
|
||||
|
||||
if (!this->registerDescriptor.writable) {
|
||||
this->registerValueTextInput->setDisabled(true);
|
||||
this->applyButton->setVisible(false);
|
||||
|
||||
auto* readOnlyIndicatorLabel = this->registerValueContainer->findChild<QLabel*>(
|
||||
"read-only-indicator-label"
|
||||
);
|
||||
readOnlyIndicatorLabel->show();
|
||||
}
|
||||
|
||||
auto* registerBitsetWidgetLayout = this->registerValueBitsetWidgetContainer->findChild<QVBoxLayout*>(
|
||||
"register-value-bitset-widget-layout"
|
||||
);
|
||||
|
||||
/*
|
||||
* Each row of the BitsetWidget container should hold two BitsetWidgets. So we have a horizontal layout nested
|
||||
* within a vertical layout.
|
||||
*/
|
||||
auto* bitsetSingleHorizontalLayout = new QHBoxLayout();
|
||||
bitsetSingleHorizontalLayout->setSpacing(BitWidget::SPACING);
|
||||
bitsetSingleHorizontalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// The register value will be in MSB, which is OK for us as we present the bit widgets in MSB.
|
||||
auto byteNumber = static_cast<int>(this->registerValue.size() - 1);
|
||||
for (std::uint32_t registerByteIndex = 0; registerByteIndex < this->registerValue.size(); registerByteIndex++) {
|
||||
auto* bitsetWidget = new BitsetWidget(
|
||||
byteNumber,
|
||||
this->registerValue.at(registerByteIndex),
|
||||
!this->registerDescriptor.writable,
|
||||
this
|
||||
);
|
||||
|
||||
bitsetSingleHorizontalLayout->addWidget(bitsetWidget, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
QObject::connect(
|
||||
bitsetWidget,
|
||||
&BitsetWidget::byteChanged,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::updateRegisterValueInputField
|
||||
);
|
||||
this->bitsetWidgets.push_back(bitsetWidget);
|
||||
|
||||
if (((registerByteIndex + 1) % 2) == 0) {
|
||||
registerBitsetWidgetLayout->addLayout(bitsetSingleHorizontalLayout);
|
||||
bitsetSingleHorizontalLayout = new QHBoxLayout();
|
||||
bitsetSingleHorizontalLayout->setSpacing(BitWidget::SPACING);
|
||||
bitsetSingleHorizontalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
byteNumber--;
|
||||
}
|
||||
|
||||
registerBitsetWidgetLayout->addLayout(bitsetSingleHorizontalLayout);
|
||||
registerBitsetWidgetLayout->addStretch(1);
|
||||
|
||||
this->registerHistoryWidget->setFixedHeight(this->contentContainer->sizeHint().height());
|
||||
|
||||
QObject::connect(this->helpButton, &QPushButton::clicked, this, &TargetRegisterInspectorWindow::openHelpPage);
|
||||
QObject::connect(this->closeButton, &QPushButton::clicked, this, &QWidget::close);
|
||||
QObject::connect(
|
||||
bitsetWidget,
|
||||
&BitsetWidget::byteChanged,
|
||||
this->refreshValueButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::updateRegisterValueInputField
|
||||
&TargetRegisterInspectorWindow::refreshRegisterValue
|
||||
);
|
||||
this->bitsetWidgets.push_back(bitsetWidget);
|
||||
QObject::connect(this->applyButton, &QPushButton::clicked, this, &TargetRegisterInspectorWindow::applyChanges);
|
||||
|
||||
if (((registerByteIndex + 1) % 2) == 0) {
|
||||
registerBitsetWidgetLayout->addLayout(bitsetSingleHorizontalLayout);
|
||||
bitsetSingleHorizontalLayout = new QHBoxLayout();
|
||||
bitsetSingleHorizontalLayout->setSpacing(BitWidget::SPACING);
|
||||
bitsetSingleHorizontalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
QObject::connect(
|
||||
this->registerHistoryWidget,
|
||||
&RegisterHistoryWidget::historyItemSelected,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::onHistoryItemSelected
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->registerValueTextInput,
|
||||
&QLineEdit::textEdited,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::onValueTextInputChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->updateRegisterValueInputField();
|
||||
this->onTargetStateChanged(currentTargetState);
|
||||
|
||||
// Position the inspection window at the center of the main Insight window
|
||||
this->move(parent->window()->geometry().center() - this->rect().center());
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
bool TargetRegisterInspectorWindow::registerSupported(const Targets::TargetRegisterDescriptor& descriptor) {
|
||||
return (descriptor.size > 0 && descriptor.size <= 8);
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::setValue(const Targets::TargetMemoryBuffer& registerValue) {
|
||||
this->registerValue = registerValue;
|
||||
this->registerHistoryWidget->updateCurrentItemValue(this->registerValue);
|
||||
this->registerHistoryWidget->selectCurrentItem();
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::onValueTextInputChanged(QString text) {
|
||||
if (text.isEmpty()) {
|
||||
text = "0";
|
||||
}
|
||||
|
||||
byteNumber--;
|
||||
}
|
||||
bool validHexValue = false;
|
||||
text.toLongLong(&validHexValue, 16);
|
||||
if (!validHexValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerBitsetWidgetLayout->addLayout(bitsetSingleHorizontalLayout);
|
||||
registerBitsetWidgetLayout->addStretch(1);
|
||||
auto registerSize = this->registerDescriptor.size;
|
||||
auto newValue = QByteArray::fromHex(
|
||||
text.remove("0x", Qt::CaseInsensitive).toLatin1()
|
||||
).rightJustified(registerSize, 0).right(registerSize);
|
||||
|
||||
this->registerHistoryWidget->setFixedHeight(this->contentContainer->sizeHint().height());
|
||||
assert(newValue.size() >= registerSize);
|
||||
assert(registerValue.size() == registerSize);
|
||||
for (std::uint32_t byteIndex = 0; byteIndex < registerSize; byteIndex++) {
|
||||
this->registerValue.at(byteIndex) = static_cast<unsigned char>(newValue.at(byteIndex));
|
||||
}
|
||||
|
||||
QObject::connect(this->helpButton, &QPushButton::clicked, this, &TargetRegisterInspectorWindow::openHelpPage);
|
||||
QObject::connect(this->closeButton, &QPushButton::clicked, this, &QWidget::close);
|
||||
QObject::connect(
|
||||
this->refreshValueButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::refreshRegisterValue
|
||||
);
|
||||
QObject::connect(this->applyButton, &QPushButton::clicked, this, &TargetRegisterInspectorWindow::applyChanges);
|
||||
|
||||
QObject::connect(
|
||||
this->registerHistoryWidget,
|
||||
&RegisterHistoryWidget::historyItemSelected,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::onHistoryItemSelected
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->registerValueTextInput,
|
||||
&QLineEdit::textEdited,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::onValueTextInputChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&TargetRegisterInspectorWindow::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->updateRegisterValueInputField();
|
||||
this->onTargetStateChanged(currentTargetState);
|
||||
|
||||
// Position the inspection window at the center of the main Insight window
|
||||
this->move(parent->window()->geometry().center() - this->rect().center());
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
bool TargetRegisterInspectorWindow::registerSupported(const Targets::TargetRegisterDescriptor& descriptor) {
|
||||
return (descriptor.size > 0 && descriptor.size <= 8);
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::setValue(const Targets::TargetMemoryBuffer& registerValue) {
|
||||
this->registerValue = registerValue;
|
||||
this->registerHistoryWidget->updateCurrentItemValue(this->registerValue);
|
||||
this->registerHistoryWidget->selectCurrentItem();
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::onValueTextInputChanged(QString text) {
|
||||
if (text.isEmpty()) {
|
||||
text = "0";
|
||||
}
|
||||
|
||||
bool validHexValue = false;
|
||||
text.toLongLong(&validHexValue, 16);
|
||||
if (!validHexValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto registerSize = this->registerDescriptor.size;
|
||||
auto newValue = QByteArray::fromHex(
|
||||
text.remove("0x", Qt::CaseInsensitive).toLatin1()
|
||||
).rightJustified(registerSize, 0).right(registerSize);
|
||||
|
||||
assert(newValue.size() >= registerSize);
|
||||
assert(registerValue.size() == registerSize);
|
||||
for (std::uint32_t byteIndex = 0; byteIndex < registerSize; byteIndex++) {
|
||||
this->registerValue.at(byteIndex) = static_cast<unsigned char>(newValue.at(byteIndex));
|
||||
}
|
||||
|
||||
for (auto& bitsetWidget : this->bitsetWidgets) {
|
||||
bitsetWidget->updateValue();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::onTargetStateChanged(TargetState newState) {
|
||||
if (newState != TargetState::STOPPED) {
|
||||
this->registerValueTextInput->setDisabled(true);
|
||||
this->registerValueBitsetWidgetContainer->setDisabled(true);
|
||||
this->applyButton->setDisabled(true);
|
||||
this->refreshValueButton->setDisabled(true);
|
||||
|
||||
} else if (this->targetState != TargetState::STOPPED && this->registerValueContainer->isEnabled()) {
|
||||
this->registerValueBitsetWidgetContainer->setDisabled(false);
|
||||
this->refreshValueButton->setDisabled(false);
|
||||
|
||||
if (this->registerDescriptor.writable) {
|
||||
this->registerValueTextInput->setDisabled(false);
|
||||
this->applyButton->setDisabled(false);
|
||||
for (auto& bitsetWidget : this->bitsetWidgets) {
|
||||
bitsetWidget->updateValue();
|
||||
}
|
||||
}
|
||||
|
||||
this->targetState = newState;
|
||||
}
|
||||
void TargetRegisterInspectorWindow::onTargetStateChanged(TargetState newState) {
|
||||
if (newState != TargetState::STOPPED) {
|
||||
this->registerValueTextInput->setDisabled(true);
|
||||
this->registerValueBitsetWidgetContainer->setDisabled(true);
|
||||
this->applyButton->setDisabled(true);
|
||||
this->refreshValueButton->setDisabled(true);
|
||||
|
||||
void TargetRegisterInspectorWindow::onHistoryItemSelected(const Targets::TargetMemoryBuffer& selectedRegisterValue) {
|
||||
this->registerValue = selectedRegisterValue;
|
||||
this->updateValue();
|
||||
} else if (this->targetState != TargetState::STOPPED && this->registerValueContainer->isEnabled()) {
|
||||
this->registerValueBitsetWidgetContainer->setDisabled(false);
|
||||
this->refreshValueButton->setDisabled(false);
|
||||
|
||||
if (this->registerHistoryWidget->isCurrentItemSelected()) {
|
||||
this->refreshValueButton->setVisible(true);
|
||||
|
||||
} else {
|
||||
this->refreshValueButton->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::updateRegisterValueInputField() {
|
||||
auto value = QByteArray(
|
||||
reinterpret_cast<const char*>(this->registerValue.data()),
|
||||
static_cast<qsizetype>(this->registerValue.size())
|
||||
);
|
||||
|
||||
this->registerValueTextInput->setText("0x" + QString(value.toHex()).toUpper());
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::updateRegisterValueBitsetWidgets() {
|
||||
for (auto& bitsetWidget : this->bitsetWidgets) {
|
||||
bitsetWidget->updateValue();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::updateValue() {
|
||||
this->updateRegisterValueInputField();
|
||||
this->updateRegisterValueBitsetWidgets();
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::refreshRegisterValue() {
|
||||
this->registerValueContainer->setDisabled(true);
|
||||
auto* readTargetRegisterTask = new ReadTargetRegisters({this->registerDescriptor});
|
||||
|
||||
QObject::connect(
|
||||
readTargetRegisterTask,
|
||||
&ReadTargetRegisters::targetRegistersRead,
|
||||
this,
|
||||
[this] (Targets::TargetRegisters targetRegisters) {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
|
||||
for (const auto& targetRegister : targetRegisters) {
|
||||
if (targetRegister.descriptor == this->registerDescriptor) {
|
||||
this->setValue(targetRegister.value);
|
||||
}
|
||||
if (this->registerDescriptor.writable) {
|
||||
this->registerValueTextInput->setDisabled(false);
|
||||
this->applyButton->setDisabled(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
readTargetRegisterTask,
|
||||
&InsightWorkerTask::failed,
|
||||
this,
|
||||
[this] {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::onHistoryItemSelected(
|
||||
const Targets::TargetMemoryBuffer& selectedRegisterValue
|
||||
) {
|
||||
this->registerValue = selectedRegisterValue;
|
||||
this->updateValue();
|
||||
|
||||
if (this->registerHistoryWidget->isCurrentItemSelected()) {
|
||||
this->refreshValueButton->setVisible(true);
|
||||
|
||||
} else {
|
||||
this->refreshValueButton->setVisible(false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this->insightWorker.queueTask(readTargetRegisterTask);
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::applyChanges() {
|
||||
this->registerValueContainer->setDisabled(true);
|
||||
const auto targetRegister = Targets::TargetRegister(this->registerDescriptor, this->registerValue);
|
||||
auto* writeRegisterTask = new WriteTargetRegister(targetRegister);
|
||||
|
||||
QObject::connect(writeRegisterTask, &InsightWorkerTask::completed, this, [this, targetRegister] {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
emit this->insightWorker.targetRegistersWritten(
|
||||
{targetRegister},
|
||||
DateTime::currentDateTime()
|
||||
void TargetRegisterInspectorWindow::updateRegisterValueInputField() {
|
||||
auto value = QByteArray(
|
||||
reinterpret_cast<const char*>(this->registerValue.data()),
|
||||
static_cast<qsizetype>(this->registerValue.size())
|
||||
);
|
||||
this->registerHistoryWidget->updateCurrentItemValue(targetRegister.value);
|
||||
this->registerHistoryWidget->selectCurrentItem();
|
||||
});
|
||||
|
||||
QObject::connect(writeRegisterTask, &InsightWorkerTask::failed, this, [this] (QString errorMessage) {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Error",
|
||||
"Failed to update " + QString::fromStdString(
|
||||
this->registerDescriptor.name.value_or("")
|
||||
).toUpper() + " register value - " + errorMessage,
|
||||
this
|
||||
this->registerValueTextInput->setText("0x" + QString(value.toHex()).toUpper());
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::updateRegisterValueBitsetWidgets() {
|
||||
for (auto& bitsetWidget : this->bitsetWidgets) {
|
||||
bitsetWidget->updateValue();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::updateValue() {
|
||||
this->updateRegisterValueInputField();
|
||||
this->updateRegisterValueBitsetWidgets();
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::refreshRegisterValue() {
|
||||
this->registerValueContainer->setDisabled(true);
|
||||
auto* readTargetRegisterTask = new ReadTargetRegisters({this->registerDescriptor});
|
||||
|
||||
QObject::connect(
|
||||
readTargetRegisterTask,
|
||||
&ReadTargetRegisters::targetRegistersRead,
|
||||
this,
|
||||
[this] (Targets::TargetRegisters targetRegisters) {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
|
||||
for (const auto& targetRegister : targetRegisters) {
|
||||
if (targetRegister.descriptor == this->registerDescriptor) {
|
||||
this->setValue(targetRegister.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
errorDialogue->show();
|
||||
});
|
||||
|
||||
this->insightWorker.queueTask(writeRegisterTask);
|
||||
}
|
||||
QObject::connect(
|
||||
readTargetRegisterTask,
|
||||
&InsightWorkerTask::failed,
|
||||
this,
|
||||
[this] {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
}
|
||||
);
|
||||
|
||||
void TargetRegisterInspectorWindow::openHelpPage() {
|
||||
QDesktopServices::openUrl(QUrl(QString::fromStdString(Paths::homeDomainName() + "/docs/register-inspection")));
|
||||
this->insightWorker.queueTask(readTargetRegisterTask);
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::applyChanges() {
|
||||
this->registerValueContainer->setDisabled(true);
|
||||
const auto targetRegister = Targets::TargetRegister(
|
||||
this->registerDescriptor,
|
||||
this->registerValue
|
||||
);
|
||||
auto* writeRegisterTask = new WriteTargetRegister(targetRegister);
|
||||
|
||||
QObject::connect(writeRegisterTask, &InsightWorkerTask::completed, this, [this, targetRegister] {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
emit this->insightWorker.targetRegistersWritten(
|
||||
{targetRegister},
|
||||
DateTime::currentDateTime()
|
||||
);
|
||||
this->registerHistoryWidget->updateCurrentItemValue(targetRegister.value);
|
||||
this->registerHistoryWidget->selectCurrentItem();
|
||||
});
|
||||
|
||||
QObject::connect(writeRegisterTask, &InsightWorkerTask::failed, this, [this] (QString errorMessage) {
|
||||
this->registerValueContainer->setDisabled(false);
|
||||
auto* errorDialogue = new ErrorDialogue(
|
||||
"Error",
|
||||
"Failed to update " + QString::fromStdString(
|
||||
this->registerDescriptor.name.value_or("")
|
||||
).toUpper() + " register value - " + errorMessage,
|
||||
this
|
||||
);
|
||||
errorDialogue->show();
|
||||
});
|
||||
|
||||
this->insightWorker.queueTask(writeRegisterTask);
|
||||
}
|
||||
|
||||
void TargetRegisterInspectorWindow::openHelpPage() {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QString::fromStdString(Paths::homeDomainName() + "/docs/register-inspection"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Bloom::Widgets
|
||||
const Targets::TargetRegisterDescriptor& registerDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
Targets::TargetState currentTargetState,
|
||||
std::optional<Targets::TargetMemoryBuffer> registerValue = std::nullopt,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& registerValue = std::nullopt,
|
||||
QWidget* parent = nullptr
|
||||
);
|
||||
|
||||
|
||||
@@ -2,27 +2,28 @@
|
||||
|
||||
#include <QStyle>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
ItemWidget::ItemWidget(QWidget* parent): ClickableWidget(parent) {
|
||||
auto onClick = [this] {
|
||||
this->setSelected(true);
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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->setSelected(false);
|
||||
}
|
||||
|
||||
this->postSetSelected(selected);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,143 +8,145 @@
|
||||
|
||||
#include "src/Helpers/Paths.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
|
||||
RegisterGroupWidget::RegisterGroupWidget(
|
||||
QString name,
|
||||
const std::set<TargetRegisterDescriptor>& registerDescriptors,
|
||||
InsightWorker& insightWorker,
|
||||
TargetRegistersPaneWidget* parent
|
||||
): ItemWidget(parent), name(std::move(name)) {
|
||||
this->setObjectName(this->name);
|
||||
RegisterGroupWidget::RegisterGroupWidget(
|
||||
QString name,
|
||||
const std::set<TargetRegisterDescriptor>& registerDescriptors,
|
||||
InsightWorker& insightWorker,
|
||||
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->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->label->setText(this->name);
|
||||
|
||||
this->arrowIcon->setObjectName("arrow-icon");
|
||||
auto static arrowIconPath = QString::fromStdString(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/arrow.svg"
|
||||
);
|
||||
this->arrowIcon->setSvgFilePath(arrowIconPath);
|
||||
this->arrowIcon->setContainerHeight(15);
|
||||
this->arrowIcon->setContainerWidth(14);
|
||||
this->arrowIcon->setObjectName("arrow-icon");
|
||||
auto static arrowIconPath = QString::fromStdString(
|
||||
Paths::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(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/register-group.svg"
|
||||
);
|
||||
this->registerGroupIcon->setSvgFilePath(registerIconPath);
|
||||
this->registerGroupIcon->setContainerHeight(15);
|
||||
this->registerGroupIcon->setContainerWidth(15);
|
||||
this->registerGroupIcon->setObjectName("register-group-icon");
|
||||
auto static registerIconPath = QString::fromStdString(
|
||||
Paths::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);
|
||||
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);
|
||||
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;
|
||||
for (const auto& descriptor : registerDescriptors) {
|
||||
if (!descriptor.name.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!descriptor.readable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* registerWidget = new RegisterWidget(descriptor, insightWorker, 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));
|
||||
}
|
||||
|
||||
if (!descriptor.readable) {
|
||||
continue;
|
||||
}
|
||||
bodyLayout->addStretch(1);
|
||||
|
||||
auto* registerWidget = new RegisterWidget(descriptor, insightWorker, this->bodyWidget);
|
||||
bodyLayout->addWidget(registerWidget, 0, Qt::AlignmentFlag::AlignTop);
|
||||
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(
|
||||
registerWidget,
|
||||
this->headerWidget,
|
||||
&ItemWidget::selected,
|
||||
parent,
|
||||
&TargetRegistersPaneWidget::onItemSelectionChange
|
||||
);
|
||||
|
||||
this->registerWidgets.insert(registerWidget);
|
||||
this->registerWidgetsMappedByDescriptor.insert(std::pair(descriptor, registerWidget));
|
||||
}
|
||||
|
||||
bodyLayout->addStretch(1);
|
||||
void RegisterGroupWidget::collapse() {
|
||||
this->arrowIcon->setAngle(0);
|
||||
this->bodyWidget->setVisible(false);
|
||||
this->collapsed = true;
|
||||
}
|
||||
|
||||
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);
|
||||
void RegisterGroupWidget::expand() {
|
||||
this->arrowIcon->setAngle(90);
|
||||
this->bodyWidget->setVisible(true);
|
||||
this->collapsed = false;
|
||||
}
|
||||
|
||||
this->collapse();
|
||||
void RegisterGroupWidget::setAllRegistersVisible(bool visible) {
|
||||
for (const auto& registerWidget : this->registerWidgets) {
|
||||
registerWidget->setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
QObject::connect(this->headerWidget, &ClickableWidget::doubleClicked, [this] {
|
||||
if (this->collapsed) {
|
||||
this->expand();
|
||||
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 {
|
||||
} else {
|
||||
registerWidget->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingWidgetCount == 0) {
|
||||
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);
|
||||
this->setVisible(false);
|
||||
|
||||
} else {
|
||||
registerWidget->setVisible(false);
|
||||
}
|
||||
}
|
||||
this->setVisible(true);
|
||||
if (!keyword.isEmpty()) {
|
||||
this->expand();
|
||||
|
||||
if (matchingWidgetCount == 0) {
|
||||
this->collapse();
|
||||
this->setVisible(false);
|
||||
|
||||
} else {
|
||||
this->setVisible(true);
|
||||
if (!keyword.isEmpty()) {
|
||||
this->expand();
|
||||
|
||||
} else {
|
||||
this->collapse();
|
||||
} else {
|
||||
this->collapse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,226 +9,229 @@
|
||||
|
||||
#include "src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
|
||||
RegisterWidget::RegisterWidget(
|
||||
TargetRegisterDescriptor descriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget *parent
|
||||
)
|
||||
: ItemWidget(parent)
|
||||
, descriptor(std::move(descriptor))
|
||||
, searchKeywords(QString::fromStdString(
|
||||
this->descriptor.name.value_or("") + this->descriptor.description.value_or("")
|
||||
).toLower())
|
||||
, insightWorker(insightWorker)
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
this->setObjectName("register-item");
|
||||
this->setFixedHeight(25);
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
this->nameLabel->setText(QString::fromStdString(this->descriptor.name.value()).toUpper());
|
||||
this->valueLabel->setObjectName("value");
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
|
||||
this->registerIcon->setObjectName("register-icon");
|
||||
auto static registerIconPath = QString::fromStdString(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/register.svg"
|
||||
);
|
||||
this->registerIcon->setSvgFilePath(registerIconPath);
|
||||
this->registerIcon->setContainerHeight(15);
|
||||
this->registerIcon->setContainerWidth(15);
|
||||
RegisterWidget::RegisterWidget(
|
||||
TargetRegisterDescriptor descriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget *parent
|
||||
)
|
||||
: ItemWidget(parent)
|
||||
, descriptor(std::move(descriptor))
|
||||
, searchKeywords(QString::fromStdString(
|
||||
this->descriptor.name.value_or("") + this->descriptor.description.value_or("")
|
||||
).toLower())
|
||||
, insightWorker(insightWorker)
|
||||
{
|
||||
this->setObjectName("register-item");
|
||||
this->setFixedHeight(25);
|
||||
|
||||
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);
|
||||
this->nameLabel->setText(QString::fromStdString(this->descriptor.name.value()).toUpper());
|
||||
this->valueLabel->setObjectName("value");
|
||||
|
||||
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);
|
||||
this->registerIcon->setObjectName("register-icon");
|
||||
auto static registerIconPath = QString::fromStdString(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/register.svg"
|
||||
);
|
||||
this->registerIcon->setSvgFilePath(registerIconPath);
|
||||
this->registerIcon->setContainerHeight(15);
|
||||
this->registerIcon->setContainerWidth(15);
|
||||
|
||||
QObject::connect(
|
||||
&(this->insightWorker),
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&RegisterWidget::onTargetStateChange
|
||||
);
|
||||
}
|
||||
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);
|
||||
|
||||
void RegisterWidget::setRegisterValue(const Targets::TargetRegister& targetRegister) {
|
||||
const auto valueChanged = this->currentRegister.has_value()
|
||||
&& this->currentRegister.value().value != targetRegister.value;
|
||||
this->currentRegister = targetRegister;
|
||||
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);
|
||||
|
||||
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) + "'";
|
||||
QObject::connect(
|
||||
&(this->insightWorker),
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&RegisterWidget::onTargetStateChange
|
||||
);
|
||||
}
|
||||
|
||||
this->valueLabel->setProperty("changed", valueChanged);
|
||||
this->valueLabel->style()->unpolish(this->valueLabel);
|
||||
this->valueLabel->style()->polish(this->valueLabel);
|
||||
void RegisterWidget::setRegisterValue(const Targets::TargetRegister& targetRegister) {
|
||||
const auto valueChanged = this->currentRegister.has_value()
|
||||
&& this->currentRegister.value().value != targetRegister.value;
|
||||
this->currentRegister = targetRegister;
|
||||
|
||||
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->insightWorker,
|
||||
this->targetState,
|
||||
this->currentRegister.has_value() ? std::optional(this->currentRegister->value) : std::nullopt,
|
||||
this
|
||||
auto valueByteArray = QByteArray(
|
||||
reinterpret_cast<const char*>(targetRegister.value.data()),
|
||||
static_cast<qsizetype>(targetRegister.value.size())
|
||||
);
|
||||
|
||||
} else {
|
||||
if (this->currentRegister.has_value()) {
|
||||
this->inspectWindow->setValue(this->currentRegister->value);
|
||||
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) + "'";
|
||||
}
|
||||
|
||||
if (!this->inspectWindow->isVisible()) {
|
||||
this->inspectWindow->show();
|
||||
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->insightWorker,
|
||||
this->targetState,
|
||||
this->currentRegister.has_value() ? std::optional(this->currentRegister->value)
|
||||
: std::nullopt,
|
||||
this
|
||||
);
|
||||
|
||||
} else {
|
||||
this->inspectWindow->activateWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->currentRegister.has_value()) {
|
||||
this->inspectWindow->setValue(this->currentRegister->value);
|
||||
}
|
||||
|
||||
void RegisterWidget::refreshValue() {
|
||||
auto* readRegisterTask = new ReadTargetRegisters({this->descriptor});
|
||||
if (!this->inspectWindow->isVisible()) {
|
||||
this->inspectWindow->show();
|
||||
|
||||
QObject::connect(
|
||||
readRegisterTask,
|
||||
&ReadTargetRegisters::targetRegistersRead,
|
||||
this,
|
||||
[this] (Targets::TargetRegisters registers) {
|
||||
for (const auto& targetRegister : registers) {
|
||||
if (targetRegister.descriptor == this->descriptor) {
|
||||
this->setRegisterValue(targetRegister);
|
||||
}
|
||||
} else {
|
||||
this->inspectWindow->activateWindow();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this->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::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this->insightWorker.queueTask(readRegisterTask);
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
void RegisterWidget::copyName() {
|
||||
if (this->nameLabel != nullptr) {
|
||||
QApplication::clipboard()->setText(this->nameLabel->text());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (this->targetState == Targets::TargetState::RUNNING) {
|
||||
this->clearInlineValue();
|
||||
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;
|
||||
|
||||
if (this->targetState == Targets::TargetState::RUNNING) {
|
||||
this->clearInlineValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,239 +12,244 @@
|
||||
|
||||
#include "src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetRegisterType;
|
||||
using Bloom::Targets::TargetDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptor;
|
||||
using Bloom::Targets::TargetRegisterDescriptors;
|
||||
using Bloom::Targets::TargetRegisterType;
|
||||
|
||||
TargetRegistersPaneWidget::TargetRegistersPaneWidget(
|
||||
const TargetDescriptor& targetDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
PanelWidget* parent
|
||||
): QWidget(parent), parent(parent), targetDescriptor(targetDescriptor), insightWorker(insightWorker) {
|
||||
this->setObjectName("target-registers-side-pane");
|
||||
TargetRegistersPaneWidget::TargetRegistersPaneWidget(
|
||||
const TargetDescriptor& targetDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
PanelWidget* parent
|
||||
): QWidget(parent), parent(parent), targetDescriptor(targetDescriptor), insightWorker(insightWorker) {
|
||||
this->setObjectName("target-registers-side-pane");
|
||||
|
||||
auto targetRegistersPaneUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/UiFiles/TargetRegistersSidePane.ui"
|
||||
)
|
||||
);
|
||||
auto targetRegistersPaneUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/UiFiles/"
|
||||
"TargetRegistersSidePane.ui"
|
||||
)
|
||||
);
|
||||
|
||||
if (!targetRegistersPaneUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open TargetRegistersSidePane UI file");
|
||||
}
|
||||
if (!targetRegistersPaneUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open TargetRegistersSidePane UI file");
|
||||
}
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&targetRegistersPaneUiFile, this);
|
||||
this->container->setFixedSize(parent->width(), parent->maximumHeight());
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&targetRegistersPaneUiFile, this);
|
||||
this->container->setFixedSize(parent->width(), parent->maximumHeight());
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(this->container);
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(this->container);
|
||||
|
||||
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
|
||||
this->collapseAllButton = this->toolBar->findChild<SvgToolButton*>("collapse-all-btn");
|
||||
this->expandAllButton = this->toolBar->findChild<SvgToolButton*>("expand-all-btn");
|
||||
this->toolBar->layout()->setContentsMargins(5, 0, 5, 0);
|
||||
this->searchInput = this->container->findChild<QLineEdit*>("search-input");
|
||||
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
|
||||
this->collapseAllButton = this->toolBar->findChild<SvgToolButton*>("collapse-all-btn");
|
||||
this->expandAllButton = this->toolBar->findChild<SvgToolButton*>("expand-all-btn");
|
||||
this->toolBar->layout()->setContentsMargins(5, 0, 5, 0);
|
||||
this->searchInput = this->container->findChild<QLineEdit*>("search-input");
|
||||
|
||||
QObject::connect(this->expandAllButton, &QToolButton::clicked, [this] {
|
||||
this->expandAllRegisterGroups();
|
||||
});
|
||||
QObject::connect(this->expandAllButton, &QToolButton::clicked, [this] {
|
||||
this->expandAllRegisterGroups();
|
||||
});
|
||||
|
||||
QObject::connect(this->collapseAllButton, &QToolButton::clicked, [this] {
|
||||
this->collapseAllRegisterGroups();
|
||||
});
|
||||
QObject::connect(this->collapseAllButton, &QToolButton::clicked, [this] {
|
||||
this->collapseAllRegisterGroups();
|
||||
});
|
||||
|
||||
QObject::connect(this->searchInput, &QLineEdit::textChanged, [this] {
|
||||
this->filterRegisters(this->searchInput->text());
|
||||
});
|
||||
QObject::connect(this->searchInput, &QLineEdit::textChanged, [this] {
|
||||
this->filterRegisters(this->searchInput->text());
|
||||
});
|
||||
|
||||
this->itemScrollArea = this->container->findChild<QScrollArea*>("item-scroll-area");
|
||||
this->itemScrollArea = this->container->findChild<QScrollArea*>("item-scroll-area");
|
||||
|
||||
this->itemContainer = this->container->findChild<QWidget*>("item-container");
|
||||
auto itemLayout = this->itemContainer->findChild<QVBoxLayout*>();
|
||||
this->itemContainer = this->container->findChild<QWidget*>("item-container");
|
||||
auto itemLayout = this->itemContainer->findChild<QVBoxLayout*>();
|
||||
|
||||
auto& registerDescriptors = targetDescriptor.registerDescriptorsByType;
|
||||
this->renderedDescriptors = 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,
|
||||
insightWorker,
|
||||
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);
|
||||
}
|
||||
|
||||
for (const auto& registerDescriptor : registerDescriptors.at(TargetRegisterType::PORT_REGISTER)) {
|
||||
registerDescriptorsByGroupName[registerDescriptor.groupName.value_or("other")].insert(registerDescriptor);
|
||||
}
|
||||
|
||||
for (const auto& [groupName, registerDescriptors] : registerDescriptorsByGroupName) {
|
||||
auto* registerGroupWidget = new RegisterGroupWidget(
|
||||
QString::fromStdString(groupName).toUpper(),
|
||||
registerDescriptors,
|
||||
auto* generalPurposeRegisterGroupWidget = new RegisterGroupWidget(
|
||||
"CPU General Purpose",
|
||||
this->renderedDescriptors,
|
||||
insightWorker,
|
||||
this
|
||||
);
|
||||
|
||||
itemLayout->addWidget(registerGroupWidget, 0, Qt::AlignTop);
|
||||
this->registerGroupWidgets.insert(registerGroupWidget);
|
||||
this->renderedDescriptors.insert(registerDescriptors.begin(), registerDescriptors.end());
|
||||
}
|
||||
itemLayout->addWidget(generalPurposeRegisterGroupWidget, 0, Qt::AlignTop);
|
||||
this->registerGroupWidgets.insert(generalPurposeRegisterGroupWidget);
|
||||
|
||||
itemLayout->addStretch(1);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&TargetRegistersPaneWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetRegistersWritten,
|
||||
this,
|
||||
&TargetRegistersPaneWidget::onRegistersRead
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!keyword.isEmpty()) {
|
||||
registerGroupWidget->expand();
|
||||
|
||||
} else {
|
||||
registerGroupWidget->collapse();
|
||||
}
|
||||
|
||||
} else {
|
||||
registerGroupWidget->filterRegisters(keyword);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::collapseAllRegisterGroups() {
|
||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
||||
registerGroupWidget->collapse();
|
||||
}
|
||||
}
|
||||
for (const auto& registerDescriptor : registerDescriptors.at(TargetRegisterType::PORT_REGISTER)) {
|
||||
registerDescriptorsByGroupName[registerDescriptor.groupName.value_or("other")].insert(registerDescriptor);
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::expandAllRegisterGroups() {
|
||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
||||
registerGroupWidget->expand();
|
||||
}
|
||||
}
|
||||
for (const auto& [groupName, registerDescriptors] : registerDescriptorsByGroupName) {
|
||||
auto* registerGroupWidget = new RegisterGroupWidget(
|
||||
QString::fromStdString(groupName).toUpper(),
|
||||
registerDescriptors,
|
||||
insightWorker,
|
||||
this
|
||||
);
|
||||
|
||||
void TargetRegistersPaneWidget::refreshRegisterValues(std::optional<std::function<void(void)>> callback) {
|
||||
auto& descriptors = this->renderedDescriptors;
|
||||
itemLayout->addWidget(registerGroupWidget, 0, Qt::AlignTop);
|
||||
this->registerGroupWidgets.insert(registerGroupWidget);
|
||||
this->renderedDescriptors.insert(registerDescriptors.begin(), registerDescriptors.end());
|
||||
}
|
||||
|
||||
if (descriptors.empty()) {
|
||||
return;
|
||||
}
|
||||
itemLayout->addStretch(1);
|
||||
|
||||
auto* readRegisterTask = new ReadTargetRegisters(descriptors);
|
||||
QObject::connect(
|
||||
readRegisterTask,
|
||||
&ReadTargetRegisters::targetRegistersRead,
|
||||
this,
|
||||
&TargetRegistersPaneWidget::onRegistersRead
|
||||
);
|
||||
|
||||
if (callback.has_value()) {
|
||||
QObject::connect(
|
||||
readRegisterTask,
|
||||
&InsightWorkerTask::completed,
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
callback.value()
|
||||
&TargetRegistersPaneWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetRegistersWritten,
|
||||
this,
|
||||
&TargetRegistersPaneWidget::onRegistersRead
|
||||
);
|
||||
}
|
||||
|
||||
this->insightWorker.queueTask(readRegisterTask);
|
||||
}
|
||||
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);
|
||||
|
||||
void TargetRegistersPaneWidget::activate() {
|
||||
this->show();
|
||||
this->activated = true;
|
||||
this->postActivate();
|
||||
}
|
||||
if (!keyword.isEmpty()) {
|
||||
registerGroupWidget->expand();
|
||||
|
||||
void TargetRegistersPaneWidget::deactivate() {
|
||||
this->hide();
|
||||
this->activated = false;
|
||||
this->postDeactivate();
|
||||
}
|
||||
} else {
|
||||
registerGroupWidget->collapse();
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
registerGroupWidget->filterRegisters(keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::collapseAllRegisterGroups() {
|
||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
||||
registerGroupWidget->collapse();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::expandAllRegisterGroups() {
|
||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
||||
registerGroupWidget->expand();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::refreshRegisterValues(std::optional<std::function<void(void)>> callback) {
|
||||
auto& descriptors = this->renderedDescriptors;
|
||||
|
||||
if (descriptors.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->selectedItemWidget = newlySelectedWidget;
|
||||
auto* readRegisterTask = new ReadTargetRegisters(descriptors);
|
||||
QObject::connect(
|
||||
readRegisterTask,
|
||||
&ReadTargetRegisters::targetRegistersRead,
|
||||
this,
|
||||
&TargetRegistersPaneWidget::onRegistersRead
|
||||
);
|
||||
|
||||
if (callback.has_value()) {
|
||||
QObject::connect(
|
||||
readRegisterTask,
|
||||
&InsightWorkerTask::completed,
|
||||
this,
|
||||
callback.value()
|
||||
);
|
||||
}
|
||||
|
||||
this->insightWorker.queueTask(readRegisterTask);
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::resizeEvent(QResizeEvent* event) {
|
||||
const auto parentSize = this->parent->size();
|
||||
const auto width = parentSize.width() - 1;
|
||||
this->container->setFixedWidth(width);
|
||||
this->searchInput->setFixedWidth(width - 20);
|
||||
|
||||
/*
|
||||
* 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->parent->getHandleSize());
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::postActivate() {
|
||||
if (this->targetState == Targets::TargetState::STOPPED) {
|
||||
this->refreshRegisterValues();
|
||||
void TargetRegistersPaneWidget::activate() {
|
||||
this->show();
|
||||
this->activated = true;
|
||||
this->postActivate();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::postDeactivate() {
|
||||
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
|
||||
if (newState == TargetState::STOPPED && this->activated) {
|
||||
this->refreshRegisterValues();
|
||||
void TargetRegistersPaneWidget::deactivate() {
|
||||
this->hide();
|
||||
this->activated = false;
|
||||
this->postDeactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::onRegistersRead(const Targets::TargetRegisters& registers) {
|
||||
for (const auto& targetRegister : registers) {
|
||||
auto& descriptor = targetRegister.descriptor;
|
||||
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);
|
||||
}
|
||||
|
||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
||||
if (registerGroupWidget->registerWidgetsMappedByDescriptor.contains(descriptor)) {
|
||||
registerGroupWidget->registerWidgetsMappedByDescriptor.at(descriptor)->setRegisterValue(targetRegister);
|
||||
break;
|
||||
this->selectedItemWidget = newlySelectedWidget;
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::resizeEvent(QResizeEvent* event) {
|
||||
const auto parentSize = this->parent->size();
|
||||
const auto width = parentSize.width() - 1;
|
||||
this->container->setFixedWidth(width);
|
||||
this->searchInput->setFixedWidth(width - 20);
|
||||
|
||||
/*
|
||||
* 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->parent->getHandleSize());
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::postActivate() {
|
||||
if (this->targetState == Targets::TargetState::STOPPED) {
|
||||
this->refreshRegisterValues();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::postDeactivate() {
|
||||
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
|
||||
if (newState == TargetState::STOPPED && this->activated) {
|
||||
this->refreshRegisterValues();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetRegistersPaneWidget::onRegistersRead(const Targets::TargetRegisters& registers) {
|
||||
for (const auto& targetRegister : registers) {
|
||||
auto& descriptor = targetRegister.descriptor;
|
||||
|
||||
for (const auto& registerGroupWidget : this->registerGroupWidgets) {
|
||||
if (registerGroupWidget->registerWidgetsMappedByDescriptor.contains(descriptor)) {
|
||||
registerGroupWidget->registerWidgetsMappedByDescriptor.at(
|
||||
descriptor
|
||||
)->setRegisterValue(targetRegister);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,81 +1,85 @@
|
||||
#include "BodyWidget.hpp"
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Dip;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Dip
|
||||
{
|
||||
BodyWidget::BodyWidget(QWidget* parent, std::size_t pinCount): QWidget(parent) {
|
||||
this->setObjectName("target-body");
|
||||
|
||||
BodyWidget::BodyWidget(QWidget* parent, std::size_t pinCount): QWidget(parent) {
|
||||
this->setObjectName("target-body");
|
||||
|
||||
/*
|
||||
* The DIP package widget looks awkward when the body height is fixed. For this reason, the body height and
|
||||
* indicator sizes are proportional to the pin count.
|
||||
*
|
||||
* The proportionality constants used below were chosen because they look the nicest. No other reason.
|
||||
*/
|
||||
this->setFixedHeight(
|
||||
std::min(
|
||||
BodyWidget::MAXIMUM_BODY_HEIGHT,
|
||||
std::max(
|
||||
BodyWidget::MINIMUM_BODY_HEIGHT,
|
||||
static_cast<int>(std::ceil(3.6 * static_cast<double>(pinCount)))
|
||||
/*
|
||||
* The DIP package widget looks awkward when the body height is fixed. For this reason, the body height and
|
||||
* indicator sizes are proportional to the pin count.
|
||||
*
|
||||
* The proportionality constants used below were chosen because they look the nicest. No other reason.
|
||||
*/
|
||||
this->setFixedHeight(
|
||||
std::min(
|
||||
BodyWidget::MAXIMUM_BODY_HEIGHT,
|
||||
std::max(
|
||||
BodyWidget::MINIMUM_BODY_HEIGHT,
|
||||
static_cast<int>(std::ceil(3.6 * static_cast<double>(pinCount)))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
this->firstPinIndicatorDiameter = std::min(
|
||||
BodyWidget::MAXIMUM_FIRST_PIN_INDICATOR_HEIGHT,
|
||||
std::max(BodyWidget::MINIMUM_FIRST_PIN_INDICATOR_HEIGHT, static_cast<int>(std::floor(pinCount / 2)))
|
||||
);
|
||||
this->firstPinIndicatorDiameter = std::min(
|
||||
BodyWidget::MAXIMUM_FIRST_PIN_INDICATOR_HEIGHT,
|
||||
std::max(BodyWidget::MINIMUM_FIRST_PIN_INDICATOR_HEIGHT, static_cast<int>(std::floor(pinCount / 2)))
|
||||
);
|
||||
|
||||
this->orientationIndicatorDiameter = this->firstPinIndicatorDiameter % 2 == 0 ?
|
||||
this->firstPinIndicatorDiameter + 3
|
||||
: this->firstPinIndicatorDiameter + 2;
|
||||
}
|
||||
|
||||
void BodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void BodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
const auto bodyHeight = this->height();
|
||||
const auto bodyRect = QRectF(
|
||||
0,
|
||||
0,
|
||||
this->width(),
|
||||
bodyHeight
|
||||
);
|
||||
|
||||
// The first pin indicator is just a circle positioned close to the first pin
|
||||
const auto firstPinIndicatorRect = QRectF(
|
||||
6,
|
||||
(bodyHeight - this->firstPinIndicatorDiameter - 6),
|
||||
this->firstPinIndicatorDiameter,
|
||||
this->firstPinIndicatorDiameter
|
||||
);
|
||||
|
||||
/*
|
||||
* The orientation indicator is just a half-circle cut-out, positioned on the side of the DIP package closest to
|
||||
* the first pin.
|
||||
*/
|
||||
const auto orientationIndicatorRect = QRectF(
|
||||
-(this->orientationIndicatorDiameter / 2),
|
||||
(bodyHeight / 2) - (this->orientationIndicatorDiameter / 2),
|
||||
this->orientationIndicatorDiameter,
|
||||
this->orientationIndicatorDiameter
|
||||
);
|
||||
|
||||
static const auto backgroundColor = QColor(0x37, 0x38, 0x35);
|
||||
auto targetBodyColor = this->getBodyColor();
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
targetBodyColor.setAlpha(this->getDisableAlphaLevel());
|
||||
this->orientationIndicatorDiameter = this->firstPinIndicatorDiameter % 2 == 0 ?
|
||||
this->firstPinIndicatorDiameter + 3
|
||||
: this->firstPinIndicatorDiameter + 2;
|
||||
}
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(targetBodyColor);
|
||||
painter.drawRect(bodyRect);
|
||||
painter.setBrush(backgroundColor);
|
||||
painter.drawEllipse(firstPinIndicatorRect);
|
||||
painter.drawEllipse(orientationIndicatorRect);
|
||||
void BodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void BodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(
|
||||
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
|
||||
true
|
||||
);
|
||||
const auto bodyHeight = this->height();
|
||||
const auto bodyRect = QRectF(
|
||||
0,
|
||||
0,
|
||||
this->width(),
|
||||
bodyHeight
|
||||
);
|
||||
|
||||
// The first pin indicator is just a circle positioned close to the first pin
|
||||
const auto firstPinIndicatorRect = QRectF(
|
||||
6,
|
||||
(bodyHeight - this->firstPinIndicatorDiameter - 6),
|
||||
this->firstPinIndicatorDiameter,
|
||||
this->firstPinIndicatorDiameter
|
||||
);
|
||||
|
||||
/*
|
||||
* The orientation indicator is just a half-circle cut-out, positioned on the side of the DIP package
|
||||
* closest to the first pin.
|
||||
*/
|
||||
const auto orientationIndicatorRect = QRectF(
|
||||
-(this->orientationIndicatorDiameter / 2),
|
||||
(bodyHeight / 2) - (this->orientationIndicatorDiameter / 2),
|
||||
this->orientationIndicatorDiameter,
|
||||
this->orientationIndicatorDiameter
|
||||
);
|
||||
|
||||
static const auto backgroundColor = QColor(0x37, 0x38, 0x35);
|
||||
auto targetBodyColor = this->getBodyColor();
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
targetBodyColor.setAlpha(this->getDisableAlphaLevel());
|
||||
}
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(targetBodyColor);
|
||||
painter.drawRect(bodyRect);
|
||||
painter.setBrush(backgroundColor);
|
||||
painter.drawEllipse(firstPinIndicatorRect);
|
||||
painter.drawEllipse(orientationIndicatorRect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,242 +8,245 @@
|
||||
|
||||
#include "src/Helpers/Paths.hpp"
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Dip;
|
||||
using namespace Bloom::Exceptions;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Dip
|
||||
{
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetVariant;
|
||||
using Bloom::Targets::TargetVariant;
|
||||
|
||||
DualInlinePackageWidget::DualInlinePackageWidget(
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPackageWidget(targetVariant, insightWorker, parent) {
|
||||
auto stylesheetFile = QFile(QString::fromStdString(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/DualInlinePackage.qss"
|
||||
)
|
||||
);
|
||||
stylesheetFile.open(QFile::ReadOnly);
|
||||
this->setStyleSheet(stylesheetFile.readAll());
|
||||
|
||||
this->pinWidgets.reserve(targetVariant.pinDescriptorsByNumber.size());
|
||||
this->layout = new QVBoxLayout();
|
||||
this->layout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->layout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
|
||||
|
||||
this->topPinLayout = new QHBoxLayout();
|
||||
this->topPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->topPinLayout->setDirection(QBoxLayout::Direction::RightToLeft);
|
||||
this->topPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
this->bottomPinLayout = new QHBoxLayout();
|
||||
this->bottomPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->bottomPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
for (const auto& [targetPinNumber, targetPinDescriptor]: targetVariant.pinDescriptorsByNumber) {
|
||||
auto* pinWidget = new PinWidget(targetPinDescriptor, targetVariant, insightWorker, this);
|
||||
this->pinWidgets.push_back(pinWidget);
|
||||
TargetPackageWidget::pinWidgets.push_back(pinWidget);
|
||||
|
||||
if (targetPinNumber <= (targetVariant.pinDescriptorsByNumber.size() / 2)) {
|
||||
this->bottomPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
} else {
|
||||
this->topPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
}
|
||||
}
|
||||
|
||||
this->bodyWidget = new BodyWidget(this, targetVariant.pinDescriptorsByNumber.size());
|
||||
|
||||
this->layout->addLayout(this->topPinLayout);
|
||||
this->layout->addWidget(this->bodyWidget, 0, Qt::AlignmentFlag::AlignVCenter);
|
||||
this->layout->addLayout(this->bottomPinLayout);
|
||||
this->setLayout(this->layout);
|
||||
|
||||
const auto bodyWidgetHeight = this->bodyWidget->height();
|
||||
const auto bodyWidgetWidth = ((PinWidget::MINIMUM_WIDTH + PinWidget::WIDTH_SPACING)
|
||||
* static_cast<int>(this->pinWidgets.size() / 2)) - PinWidget::WIDTH_SPACING + 46;
|
||||
|
||||
this->bodyWidget->setGeometry(
|
||||
0,
|
||||
PinWidget::MAXIMUM_HEIGHT + PinWidget::WIDTH_SPACING,
|
||||
bodyWidgetWidth,
|
||||
bodyWidgetHeight
|
||||
);
|
||||
|
||||
const auto width = bodyWidgetWidth;
|
||||
const auto height = (
|
||||
(
|
||||
PinWidget::MAXIMUM_HEIGHT + PinWidget::WIDTH_SPACING + PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
+ PinWidget::PIN_LABEL_SHORT_LINE_LENGTH + (
|
||||
(PinWidget::LABEL_HEIGHT + PinWidget::PIN_LABEL_SPACING) * 2
|
||||
DualInlinePackageWidget::DualInlinePackageWidget(
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPackageWidget(targetVariant, insightWorker, parent) {
|
||||
auto stylesheetFile = QFile(QString::fromStdString(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/Stylesheets/"
|
||||
"DualInlinePackage.qss"
|
||||
)
|
||||
) * 2) + bodyWidgetHeight;
|
||||
);
|
||||
stylesheetFile.open(QFile::ReadOnly);
|
||||
this->setStyleSheet(stylesheetFile.readAll());
|
||||
|
||||
this->topPinLayout->setGeometry(QRect(0, 0, width, PinWidget::MAXIMUM_HEIGHT));
|
||||
this->bottomPinLayout->setGeometry(
|
||||
QRect(
|
||||
0,
|
||||
(PinWidget::MAXIMUM_HEIGHT + bodyWidgetHeight + (PinWidget::WIDTH_SPACING * 2)),
|
||||
width,
|
||||
PinWidget::MAXIMUM_HEIGHT
|
||||
)
|
||||
);
|
||||
this->topPinLayout->setContentsMargins(23, 0, 23, 0);
|
||||
this->bottomPinLayout->setContentsMargins( 23, 0, 23, 0);
|
||||
this->pinWidgets.reserve(targetVariant.pinDescriptorsByNumber.size());
|
||||
this->layout = new QVBoxLayout();
|
||||
this->layout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->layout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
|
||||
|
||||
this->setFixedSize(width, height);
|
||||
this->topPinLayout = new QHBoxLayout();
|
||||
this->topPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->topPinLayout->setDirection(QBoxLayout::Direction::RightToLeft);
|
||||
this->topPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
this->bottomPinLayout = new QHBoxLayout();
|
||||
this->bottomPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->bottomPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
this->setGeometry(
|
||||
(parent->width() / 2) - (width / 2),
|
||||
(parent->height() / 2) - (height / 2),
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
for (const auto& [targetPinNumber, targetPinDescriptor]: targetVariant.pinDescriptorsByNumber) {
|
||||
auto* pinWidget = new PinWidget(targetPinDescriptor, targetVariant, insightWorker, this);
|
||||
this->pinWidgets.push_back(pinWidget);
|
||||
TargetPackageWidget::pinWidgets.push_back(pinWidget);
|
||||
|
||||
void DualInlinePackageWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void DualInlinePackageWidget::drawWidget(QPainter& painter) {
|
||||
using Targets::TargetPinState;
|
||||
|
||||
static auto pinNameFont = QFont("'Ubuntu', sans-serif");
|
||||
static auto pinDirectionFont = pinNameFont;
|
||||
pinNameFont.setPixelSize(11);
|
||||
pinDirectionFont.setPixelSize(9);
|
||||
|
||||
static const auto lineColor = QColor(0x4F, 0x4F, 0x4F);
|
||||
static const auto pinNameFontColor = QColor(0xA6, 0xA7, 0xAA);
|
||||
static const auto pinDirectionFontColor = QColor(0x8A, 0x8A, 0x8D);
|
||||
static const auto pinChangedFontColor = QColor(0x4D, 0x7B, 0xBA);
|
||||
|
||||
static const auto inDirectionText = QString("IN");
|
||||
static const auto outDirectionText = QString("OUT");
|
||||
|
||||
for (const auto* pinWidget : this->pinWidgets) {
|
||||
const auto pinGeoPosition = pinWidget->pos();
|
||||
const auto& pinState = pinWidget->getPinState();
|
||||
const auto pinStateChanged = pinWidget->hasPinStateChanged();
|
||||
|
||||
painter.setFont(pinNameFont);
|
||||
|
||||
if (pinWidget->position == Position::TOP) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y()
|
||||
));
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
- pinDirectionLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - pinDirectionLabelLineLength
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT * 2),
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
if (targetPinNumber <= (targetVariant.pinDescriptorsByNumber.size() / 2)) {
|
||||
this->bottomPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
} else {
|
||||
this->topPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::BOTTOM) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
this->bodyWidget = new BodyWidget(this, targetVariant.pinDescriptorsByNumber.size());
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT,
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
));
|
||||
this->layout->addLayout(this->topPinLayout);
|
||||
this->layout->addWidget(this->bodyWidget, 0, Qt::AlignmentFlag::AlignVCenter);
|
||||
this->layout->addLayout(this->bottomPinLayout);
|
||||
this->setLayout(this->layout);
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() + + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
const auto bodyWidgetHeight = this->bodyWidget->height();
|
||||
const auto bodyWidgetWidth = ((PinWidget::MINIMUM_WIDTH + PinWidget::WIDTH_SPACING)
|
||||
* static_cast<int>(this->pinWidgets.size() / 2)) - PinWidget::WIDTH_SPACING + 46;
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
this->bodyWidget->setGeometry(
|
||||
0,
|
||||
PinWidget::MAXIMUM_HEIGHT + PinWidget::WIDTH_SPACING,
|
||||
bodyWidgetWidth,
|
||||
bodyWidgetHeight
|
||||
);
|
||||
|
||||
const auto width = bodyWidgetWidth;
|
||||
const auto height = (
|
||||
(
|
||||
PinWidget::MAXIMUM_HEIGHT + PinWidget::WIDTH_SPACING + PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
+ PinWidget::PIN_LABEL_SHORT_LINE_LENGTH + (
|
||||
(PinWidget::LABEL_HEIGHT + PinWidget::PIN_LABEL_SPACING) * 2
|
||||
)
|
||||
) * 2) + bodyWidgetHeight;
|
||||
|
||||
this->topPinLayout->setGeometry(QRect(0, 0, width, PinWidget::MAXIMUM_HEIGHT));
|
||||
this->bottomPinLayout->setGeometry(
|
||||
QRect(
|
||||
0,
|
||||
(PinWidget::MAXIMUM_HEIGHT + bodyWidgetHeight + (PinWidget::WIDTH_SPACING * 2)),
|
||||
width,
|
||||
PinWidget::MAXIMUM_HEIGHT
|
||||
)
|
||||
);
|
||||
this->topPinLayout->setContentsMargins(23, 0, 23, 0);
|
||||
this->bottomPinLayout->setContentsMargins( 23, 0, 23, 0);
|
||||
|
||||
this->setFixedSize(width, height);
|
||||
|
||||
this->setGeometry(
|
||||
(parent->width() / 2) - (width / 2),
|
||||
(parent->height() / 2) - (height / 2),
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
void DualInlinePackageWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void DualInlinePackageWidget::drawWidget(QPainter& painter) {
|
||||
using Targets::TargetPinState;
|
||||
|
||||
static auto pinNameFont = QFont("'Ubuntu', sans-serif");
|
||||
static auto pinDirectionFont = pinNameFont;
|
||||
pinNameFont.setPixelSize(11);
|
||||
pinDirectionFont.setPixelSize(9);
|
||||
|
||||
static const auto lineColor = QColor(0x4F, 0x4F, 0x4F);
|
||||
static const auto pinNameFontColor = QColor(0xA6, 0xA7, 0xAA);
|
||||
static const auto pinDirectionFontColor = QColor(0x8A, 0x8A, 0x8D);
|
||||
static const auto pinChangedFontColor = QColor(0x4D, 0x7B, 0xBA);
|
||||
|
||||
static const auto inDirectionText = QString("IN");
|
||||
static const auto outDirectionText = QString("OUT");
|
||||
|
||||
for (const auto* pinWidget : this->pinWidgets) {
|
||||
const auto pinGeoPosition = pinWidget->pos();
|
||||
const auto& pinState = pinWidget->getPinState();
|
||||
const auto pinStateChanged = pinWidget->hasPinStateChanged();
|
||||
|
||||
painter.setFont(pinNameFont);
|
||||
|
||||
if (pinWidget->position == Position::TOP) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
pinGeoPosition.y() - pinNameLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength
|
||||
pinGeoPosition.y()
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength,
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
- pinDirectionLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - pinDirectionLabelLineLength
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT * 2),
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::BOTTOM) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT,
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
));
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() + + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MINIMUM_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,34 +2,39 @@
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Dip;
|
||||
using namespace Bloom::Targets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Dip
|
||||
{
|
||||
using namespace Bloom::Targets;
|
||||
|
||||
PinBodyWidget::PinBodyWidget(QWidget* parent, Targets::TargetPinDescriptor pinDescriptor)
|
||||
: TargetPinBodyWidget(parent, std::move(pinDescriptor)) {
|
||||
this->setFixedSize(PinBodyWidget::WIDTH, PinBodyWidget::HEIGHT);
|
||||
}
|
||||
|
||||
void PinBodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void PinBodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
auto pinWidth = PinBodyWidget::WIDTH;
|
||||
auto pinHeight = PinBodyWidget::HEIGHT;
|
||||
this->setFixedSize(pinWidth, pinHeight);
|
||||
|
||||
auto pinColor = this->getBodyColor();
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(pinColor);
|
||||
|
||||
painter.drawRect(
|
||||
0,
|
||||
0,
|
||||
pinWidth,
|
||||
pinHeight
|
||||
);
|
||||
PinBodyWidget::PinBodyWidget(QWidget* parent, Targets::TargetPinDescriptor pinDescriptor)
|
||||
: TargetPinBodyWidget(parent, std::move(pinDescriptor)) {
|
||||
this->setFixedSize(PinBodyWidget::WIDTH, PinBodyWidget::HEIGHT);
|
||||
}
|
||||
|
||||
void PinBodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void PinBodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(
|
||||
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
|
||||
true
|
||||
);
|
||||
auto pinWidth = PinBodyWidget::WIDTH;
|
||||
auto pinHeight = PinBodyWidget::HEIGHT;
|
||||
this->setFixedSize(pinWidth, pinHeight);
|
||||
|
||||
auto pinColor = this->getBodyColor();
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(pinColor);
|
||||
|
||||
painter.drawRect(
|
||||
0,
|
||||
0,
|
||||
pinWidth,
|
||||
pinHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,49 @@
|
||||
#include "PinWidget.hpp"
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Dip;
|
||||
using namespace Bloom::Targets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Dip
|
||||
{
|
||||
using namespace Bloom::Targets;
|
||||
|
||||
PinWidget::PinWidget(
|
||||
const TargetPinDescriptor& pinDescriptor,
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPinWidget(pinDescriptor, targetVariant, insightWorker, parent) {
|
||||
this->setFixedSize(PinWidget::MINIMUM_WIDTH, PinWidget::MAXIMUM_HEIGHT);
|
||||
PinWidget::PinWidget(
|
||||
const TargetPinDescriptor& pinDescriptor,
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPinWidget(pinDescriptor, targetVariant, insightWorker, parent) {
|
||||
this->setFixedSize(PinWidget::MINIMUM_WIDTH, PinWidget::MAXIMUM_HEIGHT);
|
||||
|
||||
this->layout = new QVBoxLayout();
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->layout->setSpacing(0);
|
||||
this->layout = new QVBoxLayout();
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->layout->setSpacing(0);
|
||||
|
||||
this->bodyWidget = new PinBodyWidget(this, this->pinDescriptor);
|
||||
this->position = (pinDescriptor.number > (targetVariant.pinDescriptorsByNumber.size() / 2))
|
||||
? Position::TOP : Position::BOTTOM;
|
||||
this->bodyWidget = new PinBodyWidget(this, this->pinDescriptor);
|
||||
this->position = (pinDescriptor.number > (targetVariant.pinDescriptorsByNumber.size() / 2))
|
||||
? Position::TOP : Position::BOTTOM;
|
||||
|
||||
const bool isTopWidget = this->position == Position::TOP;
|
||||
const bool isTopWidget = this->position == Position::TOP;
|
||||
|
||||
this->layout->setAlignment(isTopWidget ? (Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignBottom)
|
||||
: (Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop));
|
||||
this->layout->setAlignment(isTopWidget ? (Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignBottom)
|
||||
: (Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop));
|
||||
|
||||
this->pinNameLabelText = QString::fromStdString(pinDescriptor.name).toUpper();
|
||||
this->pinNameLabelText.truncate(5);
|
||||
this->pinNameLabelText = QString::fromStdString(pinDescriptor.name).toUpper();
|
||||
this->pinNameLabelText.truncate(5);
|
||||
|
||||
this->pinNumberLabel = new QLabel(this);
|
||||
this->pinNumberLabel->setObjectName("target-pin-number");
|
||||
this->pinNumberLabel->setText(QString::number(pinDescriptor.number));
|
||||
this->pinNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
this->pinNumberLabel = new QLabel(this);
|
||||
this->pinNumberLabel->setObjectName("target-pin-number");
|
||||
this->pinNumberLabel->setText(QString::number(pinDescriptor.number));
|
||||
this->pinNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
|
||||
if (isTopWidget) {
|
||||
this->layout->setDirection(QBoxLayout::Direction::BottomToTop);
|
||||
if (isTopWidget) {
|
||||
this->layout->setDirection(QBoxLayout::Direction::BottomToTop);
|
||||
}
|
||||
|
||||
this->layout->addWidget(this->bodyWidget, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
this->layout->insertSpacing(1, PinWidget::PIN_LABEL_SPACING);
|
||||
this->layout->addWidget(this->pinNumberLabel, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
this->pinNumberLabel->setFixedHeight(PinWidget::LABEL_HEIGHT);
|
||||
|
||||
this->setLayout(this->layout);
|
||||
|
||||
connect(this->bodyWidget, &PinBodyWidget::clicked, this, &TargetPinWidget::onWidgetBodyClicked);
|
||||
}
|
||||
|
||||
this->layout->addWidget(this->bodyWidget, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
this->layout->insertSpacing(1, PinWidget::PIN_LABEL_SPACING);
|
||||
this->layout->addWidget(this->pinNumberLabel, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
this->pinNumberLabel->setFixedHeight(PinWidget::LABEL_HEIGHT);
|
||||
|
||||
this->setLayout(this->layout);
|
||||
|
||||
connect(this->bodyWidget, &PinBodyWidget::clicked, this, &TargetPinWidget::onWidgetBodyClicked);
|
||||
}
|
||||
|
||||
@@ -2,47 +2,51 @@
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Qfp;
|
||||
|
||||
void BodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void BodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
|
||||
auto targetBodyColor = this->getBodyColor();
|
||||
auto backgroundColor = QColor("#373835");
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
targetBodyColor.setAlpha(this->getDisableAlphaLevel());
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Qfp
|
||||
{
|
||||
void BodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(targetBodyColor);
|
||||
void BodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(
|
||||
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
|
||||
true
|
||||
);
|
||||
|
||||
const auto containerSize = this->size();
|
||||
const auto targetBodyWidth = containerSize.width() - 8;
|
||||
const auto targetBodyHeight = containerSize.height() - 8;
|
||||
auto targetBodyColor = this->getBodyColor();
|
||||
auto backgroundColor = QColor("#373835");
|
||||
|
||||
auto targetBodyPoint = QPoint(
|
||||
(containerSize.width() / 2) - (targetBodyWidth / 2),
|
||||
(containerSize.height() / 2) - (targetBodyHeight / 2)
|
||||
);
|
||||
if (!this->isEnabled()) {
|
||||
targetBodyColor.setAlpha(this->getDisableAlphaLevel());
|
||||
}
|
||||
|
||||
painter.drawRect(
|
||||
targetBodyPoint.x(),
|
||||
targetBodyPoint.y(),
|
||||
targetBodyWidth,
|
||||
targetBodyHeight
|
||||
);
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(targetBodyColor);
|
||||
|
||||
painter.setBrush(backgroundColor);
|
||||
painter.drawEllipse(QRectF(
|
||||
targetBodyPoint.x() + 13,
|
||||
targetBodyPoint.y() + 13,
|
||||
18,
|
||||
18
|
||||
));
|
||||
const auto containerSize = this->size();
|
||||
const auto targetBodyWidth = containerSize.width() - 8;
|
||||
const auto targetBodyHeight = containerSize.height() - 8;
|
||||
|
||||
auto targetBodyPoint = QPoint(
|
||||
(containerSize.width() / 2) - (targetBodyWidth / 2),
|
||||
(containerSize.height() / 2) - (targetBodyHeight / 2)
|
||||
);
|
||||
|
||||
painter.drawRect(
|
||||
targetBodyPoint.x(),
|
||||
targetBodyPoint.y(),
|
||||
targetBodyWidth,
|
||||
targetBodyHeight
|
||||
);
|
||||
|
||||
painter.setBrush(backgroundColor);
|
||||
painter.drawEllipse(QRectF(
|
||||
targetBodyPoint.x() + 13,
|
||||
targetBodyPoint.y() + 13,
|
||||
18,
|
||||
18
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,39 +3,44 @@
|
||||
#include <QPainter>
|
||||
#include <QEvent>
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Qfp;
|
||||
using namespace Bloom::Targets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Qfp
|
||||
{
|
||||
using namespace Bloom::Targets;
|
||||
|
||||
PinBodyWidget::PinBodyWidget(QWidget* parent, Targets::TargetPinDescriptor pinDescriptor, bool isVertical)
|
||||
: TargetPinBodyWidget(parent, std::move(pinDescriptor)), isVertical(isVertical) {
|
||||
if (isVertical) {
|
||||
this->setFixedSize(PinBodyWidget::WIDTH, PinBodyWidget::HEIGHT);
|
||||
PinBodyWidget::PinBodyWidget(QWidget* parent, Targets::TargetPinDescriptor pinDescriptor, bool isVertical)
|
||||
: TargetPinBodyWidget(parent, std::move(pinDescriptor)), isVertical(isVertical) {
|
||||
if (isVertical) {
|
||||
this->setFixedSize(PinBodyWidget::WIDTH, PinBodyWidget::HEIGHT);
|
||||
|
||||
} else {
|
||||
this->setFixedSize(PinBodyWidget::HEIGHT, PinBodyWidget::WIDTH);
|
||||
} else {
|
||||
this->setFixedSize(PinBodyWidget::HEIGHT, PinBodyWidget::WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
void PinBodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void PinBodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(
|
||||
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
|
||||
true
|
||||
);
|
||||
auto pinWidth = this->isVertical ? PinBodyWidget::WIDTH : PinBodyWidget::HEIGHT;
|
||||
auto pinHeight = this->isVertical ? PinBodyWidget::HEIGHT : PinBodyWidget::WIDTH;
|
||||
this->setFixedSize(pinWidth, pinHeight);
|
||||
|
||||
auto pinColor = this->getBodyColor();
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(pinColor);
|
||||
|
||||
painter.drawRect(
|
||||
0,
|
||||
0,
|
||||
pinWidth,
|
||||
pinHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void PinBodyWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void PinBodyWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
auto pinWidth = this->isVertical ? PinBodyWidget::WIDTH : PinBodyWidget::HEIGHT;
|
||||
auto pinHeight = this->isVertical ? PinBodyWidget::HEIGHT : PinBodyWidget::WIDTH;
|
||||
this->setFixedSize(pinWidth, pinHeight);
|
||||
|
||||
auto pinColor = this->getBodyColor();
|
||||
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
painter.setBrush(pinColor);
|
||||
|
||||
painter.drawRect(
|
||||
0,
|
||||
0,
|
||||
pinWidth,
|
||||
pinHeight
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,95 +7,97 @@
|
||||
#include "PinWidget.hpp"
|
||||
#include "PinBodyWidget.hpp"
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Qfp;
|
||||
using namespace Bloom::Targets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Qfp
|
||||
{
|
||||
using namespace Bloom::Targets;
|
||||
|
||||
PinWidget::PinWidget(
|
||||
const TargetPinDescriptor& pinDescriptor,
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPinWidget(pinDescriptor, targetVariant, insightWorker, parent) {
|
||||
this->layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->layout->setSpacing(0);
|
||||
PinWidget::PinWidget(
|
||||
const TargetPinDescriptor& pinDescriptor,
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPinWidget(pinDescriptor, targetVariant, insightWorker, parent) {
|
||||
this->layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->layout->setSpacing(0);
|
||||
|
||||
auto pinCountPerLayout = (targetVariant.pinDescriptorsByNumber.size() / 4);
|
||||
auto pinCountPerLayout = (targetVariant.pinDescriptorsByNumber.size() / 4);
|
||||
|
||||
if (pinDescriptor.number <= pinCountPerLayout) {
|
||||
this->position = Position::LEFT;
|
||||
if (pinDescriptor.number <= pinCountPerLayout) {
|
||||
this->position = Position::LEFT;
|
||||
|
||||
} else if (pinDescriptor.number > pinCountPerLayout && pinDescriptor.number <= (pinCountPerLayout * 2)) {
|
||||
this->position = Position::BOTTOM;
|
||||
} else if (pinDescriptor.number > pinCountPerLayout && pinDescriptor.number <= (pinCountPerLayout * 2)) {
|
||||
this->position = Position::BOTTOM;
|
||||
|
||||
} else if (pinDescriptor.number > (pinCountPerLayout * 2) && pinDescriptor.number <= (pinCountPerLayout * 3)) {
|
||||
this->position = Position::RIGHT;
|
||||
} else if (pinDescriptor.number > (pinCountPerLayout * 2) && pinDescriptor.number <= (pinCountPerLayout * 3)) {
|
||||
this->position = Position::RIGHT;
|
||||
|
||||
} else if (pinDescriptor.number > (pinCountPerLayout * 3) && pinDescriptor.number <= (pinCountPerLayout * 4)) {
|
||||
this->position = Position::TOP;
|
||||
}
|
||||
} else if (pinDescriptor.number > (pinCountPerLayout * 3) && pinDescriptor.number <= (pinCountPerLayout * 4)) {
|
||||
this->position = Position::TOP;
|
||||
}
|
||||
|
||||
this->bodyWidget = new PinBodyWidget(
|
||||
this,
|
||||
this->pinDescriptor,
|
||||
(this->position == Position::TOP || this->position == Position::BOTTOM)
|
||||
);
|
||||
|
||||
this->pinNameLabelText = QString::fromStdString(pinDescriptor.name).toUpper();
|
||||
this->pinNameLabelText.truncate(5);
|
||||
|
||||
this->pinNumberLabel = new QLabel(this);
|
||||
this->pinNumberLabel->setObjectName("target-pin-number");
|
||||
auto pinNumberText = QString::number(pinDescriptor.number);
|
||||
pinNumberText.truncate(5);
|
||||
this->pinNumberLabel->setText(QString::number(pinDescriptor.number));
|
||||
this->pinNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
|
||||
if (this->position == Position::LEFT) {
|
||||
this->layout->setAlignment((Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignRight));
|
||||
this->layout->setDirection(QBoxLayout::Direction::RightToLeft);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_HORIZONTAL_WIDTH, PinWidget::MAXIMUM_HORIZONTAL_HEIGHT);
|
||||
|
||||
} else if (this->position == Position::BOTTOM) {
|
||||
this->layout->setAlignment(Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop);
|
||||
this->layout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_VERTICAL_WIDTH, PinWidget::MAXIMUM_VERTICAL_HEIGHT);
|
||||
|
||||
} else if (this->position == Position::RIGHT) {
|
||||
this->layout->setAlignment((Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft));
|
||||
this->layout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_HORIZONTAL_WIDTH, PinWidget::MAXIMUM_HORIZONTAL_HEIGHT);
|
||||
|
||||
} else if (this->position == Position::TOP) {
|
||||
this->layout->setAlignment((Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignBottom));
|
||||
this->layout->setDirection(QBoxLayout::Direction::BottomToTop);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_VERTICAL_WIDTH, PinWidget::MAXIMUM_VERTICAL_HEIGHT);
|
||||
}
|
||||
|
||||
this->layout->addWidget(this->bodyWidget);
|
||||
this->layout->addSpacing(3);
|
||||
this->layout->addWidget(this->pinNumberLabel);
|
||||
|
||||
if (this->position == Position::LEFT || this->position == Position::RIGHT) {
|
||||
this->pinNumberLabel->setFixedSize(
|
||||
PinWidget::MAXIMUM_PIN_NUMBER_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2
|
||||
this->bodyWidget = new PinBodyWidget(
|
||||
this,
|
||||
this->pinDescriptor,
|
||||
(this->position == Position::TOP || this->position == Position::BOTTOM)
|
||||
);
|
||||
|
||||
} else if (this->position == Position::TOP || this->position == Position::BOTTOM) {
|
||||
this->pinNumberLabel->setFixedSize(PinBodyWidget::WIDTH, PinWidget::LABEL_HEIGHT - 2);
|
||||
this->pinNameLabelText = QString::fromStdString(pinDescriptor.name).toUpper();
|
||||
this->pinNameLabelText.truncate(5);
|
||||
|
||||
this->pinNumberLabel = new QLabel(this);
|
||||
this->pinNumberLabel->setObjectName("target-pin-number");
|
||||
auto pinNumberText = QString::number(pinDescriptor.number);
|
||||
pinNumberText.truncate(5);
|
||||
this->pinNumberLabel->setText(QString::number(pinDescriptor.number));
|
||||
this->pinNumberLabel->setAlignment(Qt::AlignmentFlag::AlignCenter);
|
||||
|
||||
if (this->position == Position::LEFT) {
|
||||
this->layout->setAlignment((Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignRight));
|
||||
this->layout->setDirection(QBoxLayout::Direction::RightToLeft);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_HORIZONTAL_WIDTH, PinWidget::MAXIMUM_HORIZONTAL_HEIGHT);
|
||||
|
||||
} else if (this->position == Position::BOTTOM) {
|
||||
this->layout->setAlignment(Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignTop);
|
||||
this->layout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_VERTICAL_WIDTH, PinWidget::MAXIMUM_VERTICAL_HEIGHT);
|
||||
|
||||
} else if (this->position == Position::RIGHT) {
|
||||
this->layout->setAlignment((Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft));
|
||||
this->layout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_HORIZONTAL_WIDTH, PinWidget::MAXIMUM_HORIZONTAL_HEIGHT);
|
||||
|
||||
} else if (this->position == Position::TOP) {
|
||||
this->layout->setAlignment((Qt::AlignmentFlag::AlignHCenter | Qt::AlignmentFlag::AlignBottom));
|
||||
this->layout->setDirection(QBoxLayout::Direction::BottomToTop);
|
||||
this->setFixedSize(PinWidget::MAXIMUM_VERTICAL_WIDTH, PinWidget::MAXIMUM_VERTICAL_HEIGHT);
|
||||
}
|
||||
|
||||
this->layout->addWidget(this->bodyWidget);
|
||||
this->layout->addSpacing(3);
|
||||
this->layout->addWidget(this->pinNumberLabel);
|
||||
|
||||
if (this->position == Position::LEFT || this->position == Position::RIGHT) {
|
||||
this->pinNumberLabel->setFixedSize(
|
||||
PinWidget::MAXIMUM_PIN_NUMBER_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2
|
||||
);
|
||||
|
||||
} else if (this->position == Position::TOP || this->position == Position::BOTTOM) {
|
||||
this->pinNumberLabel->setFixedSize(PinBodyWidget::WIDTH, PinWidget::LABEL_HEIGHT - 2);
|
||||
}
|
||||
|
||||
this->layout->addStretch(1);
|
||||
this->setLayout(this->layout);
|
||||
|
||||
connect(this->bodyWidget, &PinBodyWidget::clicked, this, &TargetPinWidget::onWidgetBodyClicked);
|
||||
}
|
||||
|
||||
this->layout->addStretch(1);
|
||||
this->setLayout(this->layout);
|
||||
void PinWidget::updatePinState(const Targets::TargetPinState& pinState) {
|
||||
TargetPinWidget::updatePinState(pinState);
|
||||
|
||||
connect(this->bodyWidget, &PinBodyWidget::clicked, this, &TargetPinWidget::onWidgetBodyClicked);
|
||||
}
|
||||
|
||||
void PinWidget::updatePinState(const Targets::TargetPinState& pinState) {
|
||||
TargetPinWidget::updatePinState(pinState);
|
||||
|
||||
if (this->bodyWidget != nullptr) {
|
||||
this->bodyWidget->setPinState(pinState);
|
||||
if (this->bodyWidget != nullptr) {
|
||||
this->bodyWidget->setPinState(pinState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,403 +11,407 @@
|
||||
#include "PinWidget.hpp"
|
||||
#include "BodyWidget.hpp"
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets::Qfp;
|
||||
using namespace Bloom::Targets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets::Qfp
|
||||
{
|
||||
using namespace Bloom::Targets;
|
||||
|
||||
QuadFlatPackageWidget::QuadFlatPackageWidget(
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPackageWidget(targetVariant, insightWorker, parent) {
|
||||
assert((targetVariant.pinDescriptorsByNumber.size() % 4) == 0);
|
||||
QuadFlatPackageWidget::QuadFlatPackageWidget(
|
||||
const TargetVariant& targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): TargetPackageWidget(targetVariant, insightWorker, parent) {
|
||||
assert((targetVariant.pinDescriptorsByNumber.size() % 4) == 0);
|
||||
|
||||
auto stylesheetFile = QFile(QString::fromStdString(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss"
|
||||
)
|
||||
);
|
||||
stylesheetFile.open(QFile::ReadOnly);
|
||||
this->setStyleSheet(stylesheetFile.readAll());
|
||||
auto stylesheetFile = QFile(QString::fromStdString(
|
||||
Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/Stylesheets/QuadFlatPackage.qss"
|
||||
)
|
||||
);
|
||||
stylesheetFile.open(QFile::ReadOnly);
|
||||
this->setStyleSheet(stylesheetFile.readAll());
|
||||
|
||||
this->pinWidgets.reserve(targetVariant.pinDescriptorsByNumber.size());
|
||||
this->layout = new QVBoxLayout();
|
||||
this->layout->setSpacing(0);
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->pinWidgets.reserve(targetVariant.pinDescriptorsByNumber.size());
|
||||
this->layout = new QVBoxLayout();
|
||||
this->layout->setSpacing(0);
|
||||
this->layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
this->horizontalLayout = new QHBoxLayout();
|
||||
this->horizontalLayout->setSpacing(0);
|
||||
this->horizontalLayout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
this->horizontalLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
this->horizontalLayout = new QHBoxLayout();
|
||||
this->horizontalLayout->setSpacing(0);
|
||||
this->horizontalLayout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
this->horizontalLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
this->topPinLayout = new QHBoxLayout();
|
||||
this->topPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->topPinLayout->setDirection(QBoxLayout::Direction::RightToLeft);
|
||||
this->topPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
this->topPinLayout = new QHBoxLayout();
|
||||
this->topPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->topPinLayout->setDirection(QBoxLayout::Direction::RightToLeft);
|
||||
this->topPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
this->rightPinLayout = new QVBoxLayout();
|
||||
this->rightPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->rightPinLayout->setDirection(QBoxLayout::Direction::BottomToTop);
|
||||
this->rightPinLayout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
|
||||
this->rightPinLayout = new QVBoxLayout();
|
||||
this->rightPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->rightPinLayout->setDirection(QBoxLayout::Direction::BottomToTop);
|
||||
this->rightPinLayout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
|
||||
|
||||
this->bottomPinLayout = new QHBoxLayout();
|
||||
this->bottomPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->bottomPinLayout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
this->bottomPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
this->bottomPinLayout = new QHBoxLayout();
|
||||
this->bottomPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->bottomPinLayout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
this->bottomPinLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
this->leftPinLayout = new QVBoxLayout();
|
||||
this->leftPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->leftPinLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
this->leftPinLayout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
|
||||
this->leftPinLayout = new QVBoxLayout();
|
||||
this->leftPinLayout->setSpacing(PinWidget::WIDTH_SPACING);
|
||||
this->leftPinLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
this->leftPinLayout->setAlignment(Qt::AlignmentFlag::AlignVCenter);
|
||||
|
||||
const auto pinCountPerLayout = static_cast<int>(targetVariant.pinDescriptorsByNumber.size() / 4);
|
||||
for (const auto& [targetPinNumber, targetPinDescriptor]: targetVariant.pinDescriptorsByNumber) {
|
||||
auto* pinWidget = new PinWidget(targetPinDescriptor, targetVariant, insightWorker, this);
|
||||
this->pinWidgets.push_back(pinWidget);
|
||||
TargetPackageWidget::pinWidgets.push_back(pinWidget);
|
||||
const auto pinCountPerLayout = static_cast<int>(targetVariant.pinDescriptorsByNumber.size() / 4);
|
||||
for (const auto& [targetPinNumber, targetPinDescriptor]: targetVariant.pinDescriptorsByNumber) {
|
||||
auto* pinWidget = new PinWidget(targetPinDescriptor, targetVariant, insightWorker, this);
|
||||
this->pinWidgets.push_back(pinWidget);
|
||||
TargetPackageWidget::pinWidgets.push_back(pinWidget);
|
||||
|
||||
if (pinWidget->position == Position::LEFT) {
|
||||
this->leftPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignRight);
|
||||
if (pinWidget->position == Position::LEFT) {
|
||||
this->leftPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignRight);
|
||||
|
||||
} else if (pinWidget->position == Position::BOTTOM) {
|
||||
this->bottomPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignTop);
|
||||
} else if (pinWidget->position == Position::BOTTOM) {
|
||||
this->bottomPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignTop);
|
||||
|
||||
} else if (pinWidget->position == Position::RIGHT) {
|
||||
this->rightPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
} else if (pinWidget->position == Position::RIGHT) {
|
||||
this->rightPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignLeft);
|
||||
|
||||
} else if (pinWidget->position == Position::TOP) {
|
||||
this->topPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignBottom);
|
||||
} else if (pinWidget->position == Position::TOP) {
|
||||
this->topPinLayout->addWidget(pinWidget, 0, Qt::AlignmentFlag::AlignBottom);
|
||||
}
|
||||
}
|
||||
|
||||
this->bodyWidget = new BodyWidget(this);
|
||||
this->layout->addLayout(this->topPinLayout);
|
||||
this->horizontalLayout->addLayout(this->leftPinLayout);
|
||||
this->horizontalLayout->addWidget(this->bodyWidget);
|
||||
this->horizontalLayout->addLayout(this->rightPinLayout);
|
||||
this->layout->addLayout(this->horizontalLayout);
|
||||
this->layout->addLayout(this->bottomPinLayout);
|
||||
this->setLayout(this->layout);
|
||||
|
||||
// Layout sizing, positioning and padding
|
||||
const auto verticalPinWidgetHeight = PinWidget::MAXIMUM_VERTICAL_HEIGHT;
|
||||
const auto verticalPinWidgetWidth = PinWidget::MAXIMUM_VERTICAL_WIDTH;
|
||||
const auto horizontalPinWidgetHeight = PinWidget::MAXIMUM_HORIZONTAL_HEIGHT;
|
||||
const auto horizontalPinWidgetWidth = PinWidget::MAXIMUM_HORIZONTAL_WIDTH;
|
||||
|
||||
/*
|
||||
* Horizontal layouts are the right and left pin layouts - the ones that hold horizontal pin widgets.
|
||||
* The bottom and top layouts are vertical layouts, as they hold the vertical pin widgets.
|
||||
*/
|
||||
const auto horizontalLayoutHeight = ((horizontalPinWidgetHeight + PinWidget::WIDTH_SPACING) * pinCountPerLayout
|
||||
+ PinWidget::PIN_WIDGET_LAYOUT_PADDING - PinWidget::WIDTH_SPACING);
|
||||
|
||||
const auto verticalLayoutWidth = ((verticalPinWidgetWidth + PinWidget::WIDTH_SPACING) * pinCountPerLayout
|
||||
+ PinWidget::PIN_WIDGET_LAYOUT_PADDING - PinWidget::WIDTH_SPACING);
|
||||
|
||||
const auto height = horizontalLayoutHeight + (verticalPinWidgetHeight * 2) + (
|
||||
(
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
+ PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
+ (PinWidget::MAXIMUM_LABEL_HEIGHT * 2)
|
||||
+ (PinWidget::PIN_LABEL_SPACING * 3)
|
||||
) * 2
|
||||
);
|
||||
const auto width = verticalLayoutWidth + (horizontalPinWidgetWidth * 2) + (
|
||||
(
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
+ PinWidget::MAXIMUM_LABEL_WIDTH
|
||||
+ PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH
|
||||
+ (PinWidget::PIN_LABEL_SPACING * 2)
|
||||
) * 2
|
||||
);
|
||||
|
||||
this->topPinLayout->insertSpacing(0, horizontalPinWidgetWidth);
|
||||
this->topPinLayout->addSpacing(horizontalPinWidgetWidth);
|
||||
|
||||
this->bottomPinLayout->insertSpacing(0, horizontalPinWidgetWidth);
|
||||
this->bottomPinLayout->addSpacing(horizontalPinWidgetWidth);
|
||||
|
||||
this->leftPinLayout->setGeometry(QRect(
|
||||
0,
|
||||
verticalPinWidgetHeight,
|
||||
horizontalPinWidgetWidth,
|
||||
horizontalLayoutHeight
|
||||
));
|
||||
|
||||
this->bodyWidget->setFixedSize(verticalLayoutWidth, horizontalLayoutHeight);
|
||||
|
||||
this->rightPinLayout->setGeometry(QRect(
|
||||
horizontalLayoutHeight + horizontalPinWidgetWidth,
|
||||
verticalPinWidgetHeight,
|
||||
horizontalPinWidgetWidth,
|
||||
horizontalLayoutHeight
|
||||
));
|
||||
|
||||
const auto pinWidgetLayoutMargin = PinWidget::PIN_WIDGET_LAYOUT_PADDING / 2;
|
||||
|
||||
this->topPinLayout->setContentsMargins(
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0
|
||||
);
|
||||
|
||||
this->bottomPinLayout->setContentsMargins(
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0
|
||||
);
|
||||
|
||||
this->leftPinLayout->setContentsMargins(
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin
|
||||
);
|
||||
|
||||
this->rightPinLayout->setContentsMargins(
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin
|
||||
);
|
||||
|
||||
this->setFixedSize(width, height);
|
||||
|
||||
// Set the fixed size and center the widget
|
||||
this->setGeometry(
|
||||
(parent->width() / 2) - (width / 2),
|
||||
(parent->height() / 2) - (height / 2),
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
this->bodyWidget = new BodyWidget(this);
|
||||
this->layout->addLayout(this->topPinLayout);
|
||||
this->horizontalLayout->addLayout(this->leftPinLayout);
|
||||
this->horizontalLayout->addWidget(this->bodyWidget);
|
||||
this->horizontalLayout->addLayout(this->rightPinLayout);
|
||||
this->layout->addLayout(this->horizontalLayout);
|
||||
this->layout->addLayout(this->bottomPinLayout);
|
||||
this->setLayout(this->layout);
|
||||
void QuadFlatPackageWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
// Layout sizing, positioning and padding
|
||||
const auto verticalPinWidgetHeight = PinWidget::MAXIMUM_VERTICAL_HEIGHT;
|
||||
const auto verticalPinWidgetWidth = PinWidget::MAXIMUM_VERTICAL_WIDTH;
|
||||
const auto horizontalPinWidgetHeight = PinWidget::MAXIMUM_HORIZONTAL_HEIGHT;
|
||||
const auto horizontalPinWidgetWidth = PinWidget::MAXIMUM_HORIZONTAL_WIDTH;
|
||||
void QuadFlatPackageWidget::drawWidget(QPainter& painter) {
|
||||
static auto pinNameFont = QFont("'Ubuntu', sans-serif");
|
||||
static auto pinDirectionFont = pinNameFont;
|
||||
pinNameFont.setPixelSize(11);
|
||||
pinDirectionFont.setPixelSize(9);
|
||||
|
||||
/*
|
||||
* Horizontal layouts are the right and left pin layouts - the ones that hold horizontal pin widgets.
|
||||
* The bottom and top layouts are vertical layouts, as they hold the vertical pin widgets.
|
||||
*/
|
||||
const auto horizontalLayoutHeight = ((horizontalPinWidgetHeight + PinWidget::WIDTH_SPACING) * pinCountPerLayout
|
||||
+ PinWidget::PIN_WIDGET_LAYOUT_PADDING - PinWidget::WIDTH_SPACING);
|
||||
static const auto lineColor = QColor(0x4F, 0x4F, 0x4F);
|
||||
static const auto pinNameFontColor = QColor(0xA6, 0xA7, 0xAA);
|
||||
static const auto pinDirectionFontColor = QColor(0x8A, 0x8A, 0x8D);
|
||||
static const auto pinChangedFontColor = QColor(0x4D, 0x7B, 0xBA);
|
||||
|
||||
const auto verticalLayoutWidth = ((verticalPinWidgetWidth + PinWidget::WIDTH_SPACING) * pinCountPerLayout
|
||||
+ PinWidget::PIN_WIDGET_LAYOUT_PADDING - PinWidget::WIDTH_SPACING);
|
||||
static const auto inDirectionText = QString("IN");
|
||||
static const auto outDirectionText = QString("OUT");
|
||||
|
||||
const auto height = horizontalLayoutHeight + (verticalPinWidgetHeight * 2) + (
|
||||
(
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
+ PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
+ (PinWidget::MAXIMUM_LABEL_HEIGHT * 2)
|
||||
+ (PinWidget::PIN_LABEL_SPACING * 3)
|
||||
) * 2
|
||||
);
|
||||
const auto width = verticalLayoutWidth + (horizontalPinWidgetWidth * 2) + (
|
||||
(
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
+ PinWidget::MAXIMUM_LABEL_WIDTH
|
||||
+ PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH
|
||||
+ (PinWidget::PIN_LABEL_SPACING * 2)
|
||||
) * 2
|
||||
);
|
||||
for (const auto* pinWidget : this->pinWidgets) {
|
||||
const auto pinGeoPosition = pinWidget->pos();
|
||||
const auto& pinState = pinWidget->getPinState();
|
||||
const auto pinStateChanged = pinWidget->hasPinStateChanged();
|
||||
|
||||
this->topPinLayout->insertSpacing(0, horizontalPinWidgetWidth);
|
||||
this->topPinLayout->addSpacing(horizontalPinWidgetWidth);
|
||||
painter.setFont(pinNameFont);
|
||||
|
||||
this->bottomPinLayout->insertSpacing(0, horizontalPinWidgetWidth);
|
||||
this->bottomPinLayout->addSpacing(horizontalPinWidgetWidth);
|
||||
if (pinWidget->position == Position::LEFT) {
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() - PinWidget::PIN_LABEL_LONG_LINE_LENGTH,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2),
|
||||
pinGeoPosition.x(),
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2)
|
||||
));
|
||||
|
||||
this->leftPinLayout->setGeometry(QRect(
|
||||
0,
|
||||
verticalPinWidgetHeight,
|
||||
horizontalPinWidgetWidth,
|
||||
horizontalLayoutHeight
|
||||
));
|
||||
|
||||
this->bodyWidget->setFixedSize(verticalLayoutWidth, horizontalLayoutHeight);
|
||||
|
||||
this->rightPinLayout->setGeometry(QRect(
|
||||
horizontalLayoutHeight + horizontalPinWidgetWidth,
|
||||
verticalPinWidgetHeight,
|
||||
horizontalPinWidgetWidth,
|
||||
horizontalLayoutHeight
|
||||
));
|
||||
|
||||
const auto pinWidgetLayoutMargin = PinWidget::PIN_WIDGET_LAYOUT_PADDING / 2;
|
||||
|
||||
this->topPinLayout->setContentsMargins(
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0
|
||||
);
|
||||
|
||||
this->bottomPinLayout->setContentsMargins(
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0
|
||||
);
|
||||
|
||||
this->leftPinLayout->setContentsMargins(
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin
|
||||
);
|
||||
|
||||
this->rightPinLayout->setContentsMargins(
|
||||
0,
|
||||
pinWidgetLayoutMargin,
|
||||
0,
|
||||
pinWidgetLayoutMargin
|
||||
);
|
||||
|
||||
this->setFixedSize(width, height);
|
||||
|
||||
// Set the fixed size and center the widget
|
||||
this->setGeometry(
|
||||
(parent->width() / 2) - (width / 2),
|
||||
(parent->height() / 2) - (height / 2),
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
void QuadFlatPackageWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void QuadFlatPackageWidget::drawWidget(QPainter& painter) {
|
||||
static auto pinNameFont = QFont("'Ubuntu', sans-serif");
|
||||
static auto pinDirectionFont = pinNameFont;
|
||||
pinNameFont.setPixelSize(11);
|
||||
pinDirectionFont.setPixelSize(9);
|
||||
|
||||
static const auto lineColor = QColor(0x4F, 0x4F, 0x4F);
|
||||
static const auto pinNameFontColor = QColor(0xA6, 0xA7, 0xAA);
|
||||
static const auto pinDirectionFontColor = QColor(0x8A, 0x8A, 0x8D);
|
||||
static const auto pinChangedFontColor = QColor(0x4D, 0x7B, 0xBA);
|
||||
|
||||
static const auto inDirectionText = QString("IN");
|
||||
static const auto outDirectionText = QString("OUT");
|
||||
|
||||
for (const auto* pinWidget : this->pinWidgets) {
|
||||
const auto pinGeoPosition = pinWidget->pos();
|
||||
const auto& pinState = pinWidget->getPinState();
|
||||
const auto pinStateChanged = pinWidget->hasPinStateChanged();
|
||||
|
||||
painter.setFont(pinNameFont);
|
||||
|
||||
if (pinWidget->position == Position::LEFT) {
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() - PinWidget::PIN_LABEL_LONG_LINE_LENGTH,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2),
|
||||
pinGeoPosition.x(),
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_HORIZONTAL_HEIGHT / 2)
|
||||
));
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() - PinWidget::PIN_LABEL_LONG_LINE_LENGTH - PinWidget::MAXIMUM_LABEL_WIDTH
|
||||
- (PinWidget::PIN_LABEL_SPACING * 2),
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() - PinWidget::PIN_LABEL_LONG_LINE_LENGTH - PinWidget::MAXIMUM_LABEL_WIDTH
|
||||
- (PinWidget::PIN_LABEL_SPACING * 3) - PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
|
||||
pinGeoPosition.x() - PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
- PinWidget::MAXIMUM_LABEL_WIDTH - (PinWidget::PIN_LABEL_SPACING * 2),
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
|
||||
PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::RIGHT) {
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH + PinWidget::PIN_LABEL_LONG_LINE_LENGTH,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
));
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() - PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
- PinWidget::MAXIMUM_LABEL_WIDTH - (PinWidget::PIN_LABEL_SPACING * 3)
|
||||
- PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
|
||||
PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::RIGHT) {
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH
|
||||
+ PinWidget::PIN_LABEL_LONG_LINE_LENGTH + 8,
|
||||
+ PinWidget::PIN_LABEL_LONG_LINE_LENGTH,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
));
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH
|
||||
+ PinWidget::PIN_LABEL_LONG_LINE_LENGTH + PinWidget::MAXIMUM_LABEL_WIDTH
|
||||
+ (PinWidget::PIN_LABEL_SPACING * 3),
|
||||
+ PinWidget::PIN_LABEL_LONG_LINE_LENGTH + 8,
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
|
||||
PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::TOP) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y()
|
||||
));
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
- pinDirectionLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - pinDirectionLabelLineLength
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT * 2),
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::BOTTOM) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT,
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
|
||||
));
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() + + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + PinWidget::MAXIMUM_HORIZONTAL_WIDTH
|
||||
+ PinWidget::PIN_LABEL_LONG_LINE_LENGTH + PinWidget::MAXIMUM_LABEL_WIDTH
|
||||
+ (PinWidget::PIN_LABEL_SPACING * 3),
|
||||
pinGeoPosition.y() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT / 2),
|
||||
PinWidget::MAXIMUM_PIN_DIRECTION_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::TOP) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
pinGeoPosition.y() - pinNameLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength
|
||||
pinGeoPosition.y()
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
- pinDirectionLabelLineLength,
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() - pinNameLabelLineLength - pinDirectionLabelLineLength
|
||||
- (PinWidget::MAXIMUM_LABEL_HEIGHT * 2),
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
}
|
||||
|
||||
} else if (pinWidget->position == Position::BOTTOM) {
|
||||
painter.setPen(lineColor);
|
||||
const auto pinNameLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
);
|
||||
const auto pinDirectionLabelLineLength = (pinWidget->getPinNumber() % 2 == 0 ?
|
||||
PinWidget::PIN_LABEL_SHORT_LINE_LENGTH
|
||||
: PinWidget::PIN_LABEL_LONG_LINE_LENGTH
|
||||
);
|
||||
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT,
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
|
||||
));
|
||||
|
||||
painter.setPen(pinStateChanged ? pinChangedFontColor : pinNameFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() + + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinWidget->pinNameLabelText
|
||||
);
|
||||
|
||||
if (pinState.has_value() && pinState->ioDirection.has_value()) {
|
||||
painter.setFont(pinDirectionFont);
|
||||
|
||||
painter.setPen(lineColor);
|
||||
painter.drawLine(QLine(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT,
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength
|
||||
));
|
||||
|
||||
painter.setPen(pinDirectionFontColor);
|
||||
painter.drawText(
|
||||
QRect(
|
||||
pinGeoPosition.x() + (PinWidget::MAXIMUM_VERTICAL_WIDTH / 2)
|
||||
- (PinWidget::MAXIMUM_LABEL_WIDTH / 2),
|
||||
pinGeoPosition.y() + PinWidget::MAXIMUM_VERTICAL_HEIGHT + pinNameLabelLineLength
|
||||
+ PinWidget::MAXIMUM_LABEL_HEIGHT + pinDirectionLabelLineLength,
|
||||
PinWidget::MAXIMUM_LABEL_WIDTH,
|
||||
PinWidget::MAXIMUM_LABEL_HEIGHT
|
||||
),
|
||||
Qt::AlignCenter,
|
||||
pinState->ioDirection == TargetPinState::IoDirection::INPUT ? inDirectionText : outDirectionText
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,90 +4,90 @@
|
||||
|
||||
#include "src/Insight/InsightWorker/Tasks/RefreshTargetPinStates.hpp"
|
||||
|
||||
using namespace Bloom;
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets
|
||||
{
|
||||
using Bloom::Targets::TargetState;
|
||||
|
||||
using Bloom::Targets::TargetState;
|
||||
TargetPackageWidget::TargetPackageWidget(
|
||||
Targets::TargetVariant targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): QWidget(parent), targetVariant(std::move(targetVariant)), insightWorker(insightWorker) {
|
||||
QObject::connect(
|
||||
&(this->insightWorker),
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&TargetPackageWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
TargetPackageWidget::TargetPackageWidget(
|
||||
Targets::TargetVariant targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): QWidget(parent), targetVariant(std::move(targetVariant)), insightWorker(insightWorker) {
|
||||
QObject::connect(
|
||||
&(this->insightWorker),
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&TargetPackageWidget::onTargetStateChanged
|
||||
);
|
||||
QObject::connect(
|
||||
&(this->insightWorker),
|
||||
&InsightWorker::targetRegistersWritten,
|
||||
this,
|
||||
&TargetPackageWidget::onRegistersWritten
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
&(this->insightWorker),
|
||||
&InsightWorker::targetRegistersWritten,
|
||||
this,
|
||||
&TargetPackageWidget::onRegistersWritten
|
||||
);
|
||||
this->setDisabled(true);
|
||||
}
|
||||
|
||||
this->setDisabled(true);
|
||||
}
|
||||
|
||||
void TargetPackageWidget::refreshPinStates(std::optional<std::function<void(void)>> callback) {
|
||||
auto* refreshTask = new RefreshTargetPinStates(this->targetVariant.id);
|
||||
QObject::connect(
|
||||
refreshTask,
|
||||
&RefreshTargetPinStates::targetPinStatesRetrieved,
|
||||
this,
|
||||
&TargetPackageWidget::updatePinStates
|
||||
);
|
||||
|
||||
if (callback.has_value()) {
|
||||
void TargetPackageWidget::refreshPinStates(std::optional<std::function<void(void)>> callback) {
|
||||
auto* refreshTask = new RefreshTargetPinStates(this->targetVariant.id);
|
||||
QObject::connect(
|
||||
refreshTask,
|
||||
&InsightWorkerTask::completed,
|
||||
&RefreshTargetPinStates::targetPinStatesRetrieved,
|
||||
this,
|
||||
callback.value()
|
||||
&TargetPackageWidget::updatePinStates
|
||||
);
|
||||
|
||||
if (callback.has_value()) {
|
||||
QObject::connect(
|
||||
refreshTask,
|
||||
&InsightWorkerTask::completed,
|
||||
this,
|
||||
callback.value()
|
||||
);
|
||||
}
|
||||
|
||||
this->insightWorker.queueTask(refreshTask);
|
||||
}
|
||||
|
||||
this->insightWorker.queueTask(refreshTask);
|
||||
}
|
||||
void TargetPackageWidget::updatePinStates(const Targets::TargetPinStateMappingType& pinStatesByNumber) {
|
||||
for (auto& pinWidget : this->pinWidgets) {
|
||||
auto pinNumber = pinWidget->getPinNumber();
|
||||
if (pinStatesByNumber.contains(pinNumber)) {
|
||||
pinWidget->updatePinState(pinStatesByNumber.at(pinNumber));
|
||||
}
|
||||
}
|
||||
|
||||
void TargetPackageWidget::updatePinStates(const Targets::TargetPinStateMappingType& pinStatesByNumber) {
|
||||
for (auto& pinWidget : this->pinWidgets) {
|
||||
auto pinNumber = pinWidget->getPinNumber();
|
||||
if (pinStatesByNumber.contains(pinNumber)) {
|
||||
pinWidget->updatePinState(pinStatesByNumber.at(pinNumber));
|
||||
this->update();
|
||||
}
|
||||
|
||||
void TargetPackageWidget::onTargetStateChanged(TargetState newState) {
|
||||
this->targetState = newState;
|
||||
|
||||
if (newState == TargetState::RUNNING) {
|
||||
this->setDisabled(true);
|
||||
|
||||
} else if (newState == TargetState::STOPPED) {
|
||||
this->refreshPinStates([this] {
|
||||
if (this->targetState == TargetState::STOPPED) {
|
||||
this->setDisabled(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
void TargetPackageWidget::onTargetStateChanged(TargetState newState) {
|
||||
this->targetState = newState;
|
||||
|
||||
if (newState == TargetState::RUNNING) {
|
||||
this->setDisabled(true);
|
||||
|
||||
} else if (newState == TargetState::STOPPED) {
|
||||
this->refreshPinStates([this] {
|
||||
if (this->targetState == TargetState::STOPPED) {
|
||||
this->setDisabled(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void TargetPackageWidget::onRegistersWritten(Targets::TargetRegisters targetRegisters) {
|
||||
if (this->targetState != TargetState::STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a PORT register was just updated, refresh pin states.
|
||||
for (const auto& targetRegister : targetRegisters) {
|
||||
if (targetRegister.descriptor.type == Targets::TargetRegisterType::PORT_REGISTER) {
|
||||
this->refreshPinStates();
|
||||
void TargetPackageWidget::onRegistersWritten(Targets::TargetRegisters targetRegisters) {
|
||||
if (this->targetState != TargetState::STOPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a PORT register was just updated, refresh pin states.
|
||||
for (const auto& targetRegister : targetRegisters) {
|
||||
if (targetRegister.descriptor.type == Targets::TargetRegisterType::PORT_REGISTER) {
|
||||
this->refreshPinStates();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,29 +2,29 @@
|
||||
|
||||
#include <QLayout>
|
||||
|
||||
using namespace Bloom;
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets
|
||||
{
|
||||
TargetPackageWidgetContainer::TargetPackageWidgetContainer(QWidget* parent): QWidget(parent) {}
|
||||
|
||||
TargetPackageWidgetContainer::TargetPackageWidgetContainer(QWidget* parent): QWidget(parent) {}
|
||||
void TargetPackageWidgetContainer::setPackageWidget(TargetPackageWidget* packageWidget) {
|
||||
this->packageWidget = packageWidget;
|
||||
|
||||
void TargetPackageWidgetContainer::setPackageWidget(TargetPackageWidget* packageWidget) {
|
||||
this->packageWidget = packageWidget;
|
||||
|
||||
if (packageWidget != nullptr) {
|
||||
this->layout()->addWidget(packageWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void TargetPackageWidgetContainer::resizeEvent(QResizeEvent* event) {
|
||||
if (this->packageWidget == nullptr) {
|
||||
return;
|
||||
if (packageWidget != nullptr) {
|
||||
this->layout()->addWidget(packageWidget);
|
||||
}
|
||||
}
|
||||
|
||||
const auto packageSize = this->packageWidget->size();
|
||||
this->packageWidget->setGeometry(
|
||||
(this->width() / 2) - (packageSize.width() / 2),
|
||||
(this->height() / 2) - (packageSize.height() / 2),
|
||||
packageSize.width(),
|
||||
packageSize.height()
|
||||
);
|
||||
void TargetPackageWidgetContainer::resizeEvent(QResizeEvent* event) {
|
||||
if (this->packageWidget == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto packageSize = this->packageWidget->size();
|
||||
this->packageWidget->setGeometry(
|
||||
(this->width() / 2) - (packageSize.width() / 2),
|
||||
(this->height() / 2) - (packageSize.height() / 2),
|
||||
packageSize.width(),
|
||||
packageSize.height()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,72 +2,74 @@
|
||||
|
||||
#include "TargetPinBodyWidget.hpp"
|
||||
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets;
|
||||
using namespace Bloom::Targets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets
|
||||
{
|
||||
using namespace Bloom::Targets;
|
||||
|
||||
TargetPinBodyWidget::TargetPinBodyWidget(QWidget* parent, Targets::TargetPinDescriptor pinDescriptor)
|
||||
: QWidget(parent), pinDescriptor(std::move(pinDescriptor)) {
|
||||
this->setObjectName("target-pin-body");
|
||||
this->setToolTip(QString::fromStdString(this->pinDescriptor.name).toUpper());
|
||||
}
|
||||
TargetPinBodyWidget::TargetPinBodyWidget(QWidget* parent, Targets::TargetPinDescriptor pinDescriptor)
|
||||
: QWidget(parent), pinDescriptor(std::move(pinDescriptor)) {
|
||||
this->setObjectName("target-pin-body");
|
||||
this->setToolTip(QString::fromStdString(this->pinDescriptor.name).toUpper());
|
||||
}
|
||||
|
||||
QColor TargetPinBodyWidget::getBodyColor() {
|
||||
auto pinColor = this->defaultBodyColor;
|
||||
QColor TargetPinBodyWidget::getBodyColor() {
|
||||
auto pinColor = this->defaultBodyColor;
|
||||
|
||||
if (this->pinDescriptor.type == TargetPinType::VCC) {
|
||||
pinColor = this->vccBodyColor;
|
||||
if (this->pinDescriptor.type == TargetPinType::VCC) {
|
||||
pinColor = this->vccBodyColor;
|
||||
|
||||
} else if (this->pinDescriptor.type == TargetPinType::GND) {
|
||||
pinColor = this->gndBodyColor;
|
||||
} else if (this->pinDescriptor.type == TargetPinType::GND) {
|
||||
pinColor = this->gndBodyColor;
|
||||
|
||||
} else if (this->pinDescriptor.type == TargetPinType::GPIO) {
|
||||
if (this->pinState.has_value()
|
||||
&& this->pinState->ioState.has_value()
|
||||
&& this->pinState->ioDirection.has_value()
|
||||
) {
|
||||
const auto ioDirection = this->pinState->ioDirection.value();
|
||||
const auto ioState = this->pinState->ioState.value();
|
||||
|
||||
if (this->pinState->ioState.value() == TargetPinState::IoState::HIGH) {
|
||||
pinColor = ioDirection == TargetPinState::IoDirection::OUTPUT ?
|
||||
this->outputHighBodyColor : this->inputHighBodyColor;
|
||||
}
|
||||
|
||||
if ((
|
||||
ioDirection == TargetPinState::IoDirection::OUTPUT
|
||||
|| (ioDirection == TargetPinState::IoDirection::INPUT && ioState == TargetPinState::IoState::LOW)
|
||||
) && !this->hoverActive
|
||||
} else if (this->pinDescriptor.type == TargetPinType::GPIO) {
|
||||
if (this->pinState.has_value()
|
||||
&& this->pinState->ioState.has_value()
|
||||
&& this->pinState->ioDirection.has_value()
|
||||
) {
|
||||
pinColor.setAlpha(220);
|
||||
const auto ioDirection = this->pinState->ioDirection.value();
|
||||
const auto ioState = this->pinState->ioState.value();
|
||||
|
||||
if (this->pinState->ioState.value() == TargetPinState::IoState::HIGH) {
|
||||
pinColor = ioDirection == TargetPinState::IoDirection::OUTPUT ?
|
||||
this->outputHighBodyColor : this->inputHighBodyColor;
|
||||
}
|
||||
|
||||
if ((
|
||||
ioDirection == TargetPinState::IoDirection::OUTPUT
|
||||
|| (ioDirection == TargetPinState::IoDirection::INPUT && ioState == TargetPinState::IoState::LOW)
|
||||
) && !this->hoverActive
|
||||
) {
|
||||
pinColor.setAlpha(220);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
pinColor.setAlpha(this->disableAlphaLevel);
|
||||
}
|
||||
|
||||
return pinColor;
|
||||
}
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
pinColor.setAlpha(this->disableAlphaLevel);
|
||||
}
|
||||
|
||||
return pinColor;
|
||||
}
|
||||
|
||||
bool TargetPinBodyWidget::event(QEvent* event) {
|
||||
if (this->pinState.has_value() && this->pinState->ioDirection == TargetPinState::IoDirection::OUTPUT) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Enter: {
|
||||
this->hoverActive = true;
|
||||
this->repaint();
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave: {
|
||||
this->hoverActive = false;
|
||||
this->repaint();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
bool TargetPinBodyWidget::event(QEvent* event) {
|
||||
if (this->pinState.has_value() && this->pinState->ioDirection == TargetPinState::IoDirection::OUTPUT) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Enter: {
|
||||
this->hoverActive = true;
|
||||
this->repaint();
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave: {
|
||||
this->hoverActive = false;
|
||||
this->repaint();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::event(event);
|
||||
return QWidget::event(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,49 +2,51 @@
|
||||
|
||||
#include "src/Insight/InsightWorker/Tasks/SetTargetPinState.hpp"
|
||||
|
||||
using namespace Bloom;
|
||||
using namespace Bloom::Widgets::InsightTargetWidgets;
|
||||
namespace Bloom::Widgets::InsightTargetWidgets
|
||||
{
|
||||
using Bloom::Targets::TargetVariant;
|
||||
using Bloom::Targets::TargetPinDescriptor;
|
||||
using Bloom::Targets::TargetPinType;
|
||||
using Bloom::Targets::TargetPinState;
|
||||
|
||||
using Bloom::Targets::TargetVariant;
|
||||
using Bloom::Targets::TargetPinDescriptor;
|
||||
using Bloom::Targets::TargetPinType;
|
||||
using Bloom::Targets::TargetPinState;
|
||||
|
||||
TargetPinWidget::TargetPinWidget(
|
||||
Targets::TargetPinDescriptor pinDescriptor,
|
||||
Targets::TargetVariant targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): QWidget(parent),
|
||||
insightWorker(insightWorker),
|
||||
targetVariant(std::move(targetVariant)),
|
||||
pinDescriptor(std::move(pinDescriptor)) {
|
||||
if (this->pinDescriptor.type == TargetPinType::UNKNOWN) {
|
||||
this->setDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void TargetPinWidget::onWidgetBodyClicked() {
|
||||
// Currently, we only allow users to toggle the IO state of output pins
|
||||
if (this->pinState.has_value()
|
||||
&& this->pinState.value().ioDirection == TargetPinState::IoDirection::OUTPUT
|
||||
TargetPinWidget::TargetPinWidget(
|
||||
Targets::TargetPinDescriptor pinDescriptor,
|
||||
Targets::TargetVariant targetVariant,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
)
|
||||
: QWidget(parent)
|
||||
, insightWorker(insightWorker)
|
||||
, targetVariant(std::move(targetVariant))
|
||||
, pinDescriptor(std::move(pinDescriptor)
|
||||
) {
|
||||
this->setDisabled(true);
|
||||
if (this->pinDescriptor.type == TargetPinType::UNKNOWN) {
|
||||
this->setDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
auto pinState = this->pinState.value();
|
||||
pinState.ioState = (pinState.ioState == TargetPinState::IoState::HIGH) ?
|
||||
TargetPinState::IoState::LOW : TargetPinState::IoState::HIGH;
|
||||
void TargetPinWidget::onWidgetBodyClicked() {
|
||||
// Currently, we only allow users to toggle the IO state of output pins
|
||||
if (this->pinState.has_value()
|
||||
&& this->pinState.value().ioDirection == TargetPinState::IoDirection::OUTPUT
|
||||
) {
|
||||
this->setDisabled(true);
|
||||
|
||||
auto* setPinStateTask = new SetTargetPinState(this->pinDescriptor, pinState);
|
||||
QObject::connect(setPinStateTask, &InsightWorkerTask::completed, this, [this, pinState] {
|
||||
this->updatePinState(pinState);
|
||||
this->setDisabled(false);
|
||||
});
|
||||
auto pinState = this->pinState.value();
|
||||
pinState.ioState = (pinState.ioState == TargetPinState::IoState::HIGH) ?
|
||||
TargetPinState::IoState::LOW : TargetPinState::IoState::HIGH;
|
||||
|
||||
QObject::connect(setPinStateTask, &InsightWorkerTask::failed, this, [this] {
|
||||
this->setDisabled(false);
|
||||
});
|
||||
auto* setPinStateTask = new SetTargetPinState(this->pinDescriptor, pinState);
|
||||
QObject::connect(setPinStateTask, &InsightWorkerTask::completed, this, [this, pinState] {
|
||||
this->updatePinState(pinState);
|
||||
this->setDisabled(false);
|
||||
});
|
||||
|
||||
this->insightWorker.queueTask(setPinStateTask);
|
||||
QObject::connect(setPinStateTask, &InsightWorkerTask::failed, this, [this] {
|
||||
this->setDisabled(false);
|
||||
});
|
||||
|
||||
this->insightWorker.queueTask(setPinStateTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,29 +3,30 @@
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
TextInput::TextInput(QWidget* parent): QLineEdit(parent) {}
|
||||
|
||||
TextInput::TextInput(QWidget* parent): QLineEdit(parent) {}
|
||||
void TextInput::contextMenuEvent(QContextMenuEvent* event) {
|
||||
if (QMenu* menu = this->createStandardContextMenu()) {
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
void TextInput::contextMenuEvent(QContextMenuEvent* event) {
|
||||
if (QMenu* menu = this->createStandardContextMenu()) {
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
// Remove default icons
|
||||
for (auto& action : menu->actions()) {
|
||||
action->setIcon(QIcon());
|
||||
}
|
||||
|
||||
// Remove default icons
|
||||
for (auto& action : menu->actions()) {
|
||||
action->setIcon(QIcon());
|
||||
menu->popup(event->globalPos());
|
||||
}
|
||||
}
|
||||
|
||||
menu->popup(event->globalPos());
|
||||
void TextInput::focusInEvent(QFocusEvent* event) {
|
||||
QLineEdit::focusInEvent(event);
|
||||
emit this->focusChanged();
|
||||
}
|
||||
|
||||
void TextInput::focusOutEvent(QFocusEvent* event) {
|
||||
QLineEdit::focusOutEvent(event);
|
||||
emit this->focusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::focusInEvent(QFocusEvent* event) {
|
||||
QLineEdit::focusInEvent(event);
|
||||
emit this->focusChanged();
|
||||
}
|
||||
|
||||
void TextInput::focusOutEvent(QFocusEvent* event) {
|
||||
QLineEdit::focusOutEvent(event);
|
||||
emit this->focusChanged();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user