From e2c4dcb97fa56c0dd6aec7b452370e3280531f8c Mon Sep 17 00:00:00 2001 From: Nav Date: Sun, 24 Oct 2021 20:40:53 +0100 Subject: [PATCH] Refactored hex viewer widget to use QGraphicsView items as opposed to widgets, for byte items in the hex viewer. This requirement became apparent when testing the initial approach with large memory sizes - the GUI became unresponsive due to the number of widgets being constructed. This was along side other performance issues that arose from the large number of widgets --- CMakeLists.txt | 5 +- .../Stylesheets/InsightWindow.qss | 20 +-- .../HexViewerWidget/ByteAddressContainer.hpp | 46 +++++++ .../HexViewerWidget/ByteItem.cpp | 68 +++++++++++ .../{ByteWidget.hpp => ByteItem.hpp} | 36 +++--- .../ByteItemContainerGraphicsView.cpp | 41 +++++++ .../ByteItemContainerGraphicsView.hpp | 47 ++++++++ ...ontainer.cpp => ByteItemGraphicsScene.cpp} | 96 ++++++++------- ...ontainer.hpp => ByteItemGraphicsScene.hpp} | 27 +++-- .../HexViewerWidget/ByteWidget.cpp | 114 ------------------ .../HexViewerWidget/HexViewerWidget.cpp | 98 +++++++-------- .../HexViewerWidget/HexViewerWidget.hpp | 7 +- .../UiFiles/HexViewerWidget.ui | 71 +++-------- 13 files changed, 364 insertions(+), 312 deletions(-) create mode 100644 src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressContainer.hpp create mode 100644 src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp rename src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/{ByteWidget.hpp => ByteItem.hpp} (58%) create mode 100644 src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.cpp create mode 100644 src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.hpp rename src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/{ByteWidgetContainer.cpp => ByteItemGraphicsScene.cpp} (63%) rename src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/{ByteWidgetContainer.hpp => ByteItemGraphicsScene.hpp} (64%) delete mode 100644 src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b4d607e..b4b2e040 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,8 +177,9 @@ add_executable(Bloom # Target memory inspection pane src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/TargetMemoryInspectionPane.cpp src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp - src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.cpp - src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.cpp + src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.cpp + src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp + src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp ) set_target_properties(Bloom PROPERTIES OUTPUT_NAME bloom) diff --git a/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss b/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss index 090d8cc8..4407677d 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss +++ b/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss @@ -179,6 +179,7 @@ QScrollBar:vertical { QScrollBar:handle:vertical { border: none; background-color: rgba(69, 69, 66, 0.6); + min-height: 30px; } QScrollBar:handle:vertical:hover { @@ -379,26 +380,29 @@ QScrollBar::sub-line:vertical { } #hex-viewer-container QScrollArea, -#hex-viewer-container #byte-widget-scroll-area-container { +#hex-viewer-container #graphics-view-container, +#hex-viewer-container #graphics-view-container #graphics-view { background-color: #323330; border: none; + font-size: 11px; +} + +#hex-viewer-container #graphics-view-container { + background-color: #50504b; + border: none; } -#hex-viewer-container #byte-widget-scroll-area-container #address-container { +#hex-viewer-container #graphics-view-container #address-container { background-color: #353633; border-right: 1px solid #41423f; } -#hex-viewer-container #byte-widget-scroll-area-container #address-container QLabel { +#hex-viewer-container #graphics-view-container #address-container QLabel { background-color: transparent; font-size: 12px; color: rgba(175, 177, 179, 0.72); } -#hex-viewer-container #byte-widget-scroll-area-container #address-container QLabel:disabled { +#hex-viewer-container #graphics-view-container #address-container QLabel:disabled { color: rgba(175, 177, 179, 0.3); } - -#hex-viewer-container #byte { - font-size: 11px; -} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressContainer.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressContainer.hpp new file mode 100644 index 00000000..269880fa --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressContainer.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp" + +namespace Bloom::Widgets +{ + class ByteAddressContainer: public QGraphicsItem + { + public: + static constexpr int WIDTH = 85; + + static constexpr int RIGHT_MARGIN = 5; + static constexpr int BOTTOM_MARGIN = 5; + + std::size_t byteIndex; + unsigned char value = 0x00; + std::uint32_t address = 0x00; + QString addressHex; + QString relativeAddressHex; + bool valueInitialised = false; + + std::size_t currentRowIndex = 0; + std::size_t currentColumnIndex = 0; + + ByteAddressContainer(); + + [[nodiscard]] QRectF boundingRect() const override { + return QRectF( + 0, + 0, + ByteAddressContainer::WIDTH, + this->scene()->height() + ); + } + + + private: + + }; +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp new file mode 100644 index 00000000..e754cd8e --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp @@ -0,0 +1,68 @@ +#include "ByteItem.hpp" + +#include +#include + +#include "src/Logger/Logger.hpp" + +using namespace Bloom::Widgets; + +ByteItem::ByteItem( + std::size_t byteIndex, + std::uint32_t address, + std::optional& hoveredByteItem +): QGraphicsItem(nullptr), byteIndex(byteIndex), address(address), hoveredByteItem(hoveredByteItem) { + 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->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 = true; +} + +void ByteItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { + painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true); + painter->setPen(Qt::PenStyle::NoPen); + + static const auto widgetRect = this->boundingRect(); + + if (this->hoveredByteItem.has_value()) { + const auto hoveredWidget = this->hoveredByteItem.value(); + + if (hoveredWidget->currentColumnIndex == this->currentColumnIndex + || hoveredWidget->currentRowIndex == this->currentRowIndex + ){ + painter->setBrush(QColor(0x8E, 0x8B, 0x83, hoveredWidget == this ? 70 : 30)); + painter->drawRect(widgetRect); + } + } + + auto textColor = QColor(this->valueChanged ? "#547fba" : "#afb1b3"); + + if (this->valueInitialised) { + if (!this->isEnabled()) { + textColor.setAlpha(100); + } + + painter->setPen(textColor); + painter->drawText(widgetRect, Qt::AlignCenter, this->hexValue); + + } else { + textColor.setAlpha(100); + painter->setPen(textColor); + + static const auto placeholderString = QString("??"); + painter->drawText(widgetRect, Qt::AlignCenter, placeholderString); + } +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp similarity index 58% rename from src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.hpp rename to src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp index 586dc7de..90581a20 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp @@ -2,16 +2,15 @@ #include #include +#include #include #include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp" namespace Bloom::Widgets { - class ByteWidget: public ClickableWidget + class ByteItem: public QGraphicsItem { - Q_OBJECT - public: static constexpr int WIDTH = 25; static constexpr int HEIGHT = 20; @@ -29,35 +28,34 @@ namespace Bloom::Widgets std::size_t currentRowIndex = 0; std::size_t currentColumnIndex = 0; - ByteWidget( + ByteItem( std::size_t byteNumber, std::uint32_t address, - std::optional& hoveredByteWidget, - QWidget* parent + std::optional& hoveredByteItem ); void setValue(unsigned char value); - public slots: - void setSelected(bool selected); + [[nodiscard]] QRectF boundingRect() const override { + return QRectF( + 0, + 0, + ByteItem::WIDTH, + ByteItem::HEIGHT + ); + } + void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; signals: - void selected(Bloom::Widgets::ByteWidget*); - void enter(Bloom::Widgets::ByteWidget*); - void leave(Bloom::Widgets::ByteWidget*); - - protected: - virtual void postSetSelected(bool selected) {}; - bool event(QEvent* event) override; - void paintEvent(QPaintEvent* event) override; - void drawWidget(QPainter& painter); + void selected(Bloom::Widgets::ByteItem*); + void enter(Bloom::Widgets::ByteItem*); + void leave(Bloom::Widgets::ByteItem*); private: - bool hoverActive = false; bool valueChanged = false; QString hexValue; std::optional asciiValue; - std::optional& hoveredByteWidget; + std::optional& hoveredByteItem; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.cpp new file mode 100644 index 00000000..3786def4 --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.cpp @@ -0,0 +1,41 @@ +#include "ByteItemContainerGraphicsView.hpp" + +#include +#include +#include +#include +#include + +#include "src/Logger/Logger.hpp" + +using namespace Bloom::Widgets; +using namespace Bloom::Exceptions; + +using Bloom::Targets::TargetMemoryDescriptor; + +ByteItemContainerGraphicsView::ByteItemContainerGraphicsView( + const TargetMemoryDescriptor& targetMemoryDescriptor, + InsightWorker& insightWorker, + QLabel* hoveredAddressLabel, + QWidget* parent +): QGraphicsView(parent) { + this->setObjectName("graphics-view"); + this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); + this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded); + this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff); + this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + this->scene = new ByteItemGraphicsScene( + targetMemoryDescriptor, + insightWorker, + hoveredAddressLabel, + this + ); + + this->setScene(this->scene); +} + +void ByteItemContainerGraphicsView::resizeEvent(QResizeEvent* event) { + Logger::warning("Resizing"); + this->scene->adjustByteWidgets(); +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.hpp new file mode 100644 index 00000000..c573714f --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/Targets/TargetMemory.hpp" +#include "src/Targets/TargetState.hpp" + +#include "src/Insight/InsightWorker/InsightWorker.hpp" + +#include "ByteItemGraphicsScene.hpp" + +namespace Bloom::Widgets +{ + class ByteItemContainerGraphicsView: public QGraphicsView + { + Q_OBJECT + + public: + ByteItemContainerGraphicsView( + const Targets::TargetMemoryDescriptor& targetMemoryDescriptor, + InsightWorker& insightWorker, + QLabel* hoveredAddressLabel, + QWidget* parent + ); + + [[nodiscard]] ByteItemGraphicsScene* getScene() const { + return this->scene; + } + + protected: + void resizeEvent(QResizeEvent* event) override; + + private: + ByteItemGraphicsScene* scene = nullptr; + }; +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp similarity index 63% rename from src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.cpp rename to src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp index 850b2305..ae0315cf 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp @@ -1,4 +1,4 @@ -#include "ByteWidgetContainer.hpp" +#include "ByteItemGraphicsScene.hpp" #include #include @@ -6,30 +6,24 @@ #include #include +#include "src/Logger/Logger.hpp" + using namespace Bloom::Widgets; using namespace Bloom::Exceptions; using Bloom::Targets::TargetMemoryDescriptor; -ByteWidgetContainer::ByteWidgetContainer( +ByteItemGraphicsScene::ByteItemGraphicsScene( const TargetMemoryDescriptor& targetMemoryDescriptor, InsightWorker& insightWorker, QLabel* hoveredAddressLabel, QWidget* parent -): QWidget(parent), +): QGraphicsScene(parent), targetMemoryDescriptor(targetMemoryDescriptor), insightWorker(insightWorker), hoveredAddressLabel(hoveredAddressLabel), parent(parent) { this->setObjectName("byte-widget-container"); - this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Ignored); - - this->setContentsMargins( - 10, - 10, - 10, - 10 - ); /* * Construct ByteWidget objects @@ -38,49 +32,45 @@ parent(parent) { */ const auto memorySize = this->targetMemoryDescriptor.size(); const auto startAddress = this->targetMemoryDescriptor.addressRange.startAddress; + Logger::error("Constructing bytes begin"); for (std::size_t i = 0; i < memorySize; i++) { const auto address = static_cast(startAddress + i); - auto byteWidget = new ByteWidget(i, address, this->hoveredByteWidget, this); + auto byteWidget = new ByteItem(i, address, this->hoveredByteWidget); this->byteWidgetsByAddress.insert(std::pair( address, byteWidget )); - QObject::connect(byteWidget, &ByteWidget::enter, this, &ByteWidgetContainer::onByteWidgetEnter); - QObject::connect(byteWidget, &ByteWidget::leave, this, &ByteWidgetContainer::onByteWidgetLeave); + this->addItem(byteWidget); } + Logger::error("Constructing bytes end"); + this->adjustByteWidgets(); QObject::connect( &insightWorker, &InsightWorker::targetStateUpdated, this, - &ByteWidgetContainer::onTargetStateChanged + &ByteItemGraphicsScene::onTargetStateChanged ); - - this->show(); } -void ByteWidgetContainer::updateValues(const Targets::TargetMemoryBuffer& buffer) { +void ByteItemGraphicsScene::updateValues(const Targets::TargetMemoryBuffer& buffer) { for (auto& [address, byteWidget] : this->byteWidgetsByAddress) { byteWidget->setValue(buffer.at(byteWidget->byteIndex)); byteWidget->update(); } } -void ByteWidgetContainer::resizeEvent(QResizeEvent* event) { - this->adjustByteWidgets(); -} +void ByteItemGraphicsScene::adjustByteWidgets() { + std::map> byteWidgetsByRowIndex; + std::map> byteWidgetsByColumnIndex; -void ByteWidgetContainer::adjustByteWidgets() { - std::map> byteWidgetsByRowIndex; - std::map> byteWidgetsByColumnIndex; + const auto margins = QMargins(10, 10, 10, 10); + const auto width = std::max(600, static_cast(this->parent->width())); - const auto margins = this->contentsMargins(); - const auto width = this->width(); - - constexpr auto byteWidgetWidth = ByteWidget::WIDTH + ByteWidget::RIGHT_MARGIN; - constexpr auto byteWidgetHeight = ByteWidget::HEIGHT + ByteWidget::BOTTOM_MARGIN; + constexpr auto byteWidgetWidth = ByteItem::WIDTH + ByteItem::RIGHT_MARGIN; + constexpr auto byteWidgetHeight = ByteItem::HEIGHT + ByteItem::BOTTOM_MARGIN; const auto rowCapacity = static_cast( std::floor((width - margins.left() - margins.right()) / byteWidgetWidth) ); @@ -97,12 +87,10 @@ void ByteWidgetContainer::adjustByteWidgets() { - (std::floor(byteWidget->byteIndex / rowCapacity) * static_cast(rowCapacity)) ); - byteWidget->setGeometry(QRect( + byteWidget->setPos( static_cast(columnIndex * byteWidgetWidth + static_cast(margins.left())), - static_cast(rowIndex * byteWidgetHeight + static_cast(margins.top())), - ByteWidget::WIDTH, - ByteWidget::HEIGHT - )); + static_cast(rowIndex * byteWidgetHeight + static_cast(margins.top())) + ); byteWidget->currentRowIndex = static_cast(rowIndex); byteWidget->currentColumnIndex = static_cast(columnIndex); @@ -114,8 +102,9 @@ void ByteWidgetContainer::adjustByteWidgets() { } const auto minHeight = (rowCount * byteWidgetHeight) + margins.top() + margins.bottom(); - this->setMinimumHeight(minHeight); - this->parent->setMinimumHeight(minHeight); +// this->setMinimumHeight(minHeight); + this->setSceneRect(0, 0, width, minHeight); +// this->parent->setMinimumHeight(minHeight); this->byteWidgetsByRowIndex = std::move(byteWidgetsByRowIndex); this->byteWidgetsByColumnIndex = std::move(byteWidgetsByColumnIndex); @@ -123,12 +112,22 @@ void ByteWidgetContainer::adjustByteWidgets() { emit this->byteWidgetsAdjusted(); } -void ByteWidgetContainer::onTargetStateChanged(Targets::TargetState newState) { +void ByteItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) { using Targets::TargetState; this->targetState = newState; } -void ByteWidgetContainer::onByteWidgetEnter(ByteWidget* widget) { +void ByteItemGraphicsScene::onByteWidgetEnter(ByteItem* widget) { + if (this->hoveredByteWidget.has_value()) { + if (this->hoveredByteWidget.value() == widget) { + // This byte item is already marked as hovered + return; + + } else { + this->onByteWidgetLeave(); + } + } + this->hoveredByteWidget = widget; this->hoveredAddressLabel->setText( @@ -146,18 +145,33 @@ void ByteWidgetContainer::onByteWidgetEnter(ByteWidget* widget) { } } -void ByteWidgetContainer::onByteWidgetLeave(ByteWidget* widget) { +void ByteItemGraphicsScene::onByteWidgetLeave() { + const auto byteItem = this->hoveredByteWidget.value(); this->hoveredByteWidget = std::nullopt; this->hoveredAddressLabel->setText("Relative Address (Absolute Address):"); if (!this->byteWidgetsByRowIndex.empty()) { - for (auto& byteWidget : this->byteWidgetsByColumnIndex.at(widget->currentColumnIndex)) { + for (auto& byteWidget : this->byteWidgetsByColumnIndex.at(byteItem->currentColumnIndex)) { byteWidget->update(); } - for (auto& byteWidget : this->byteWidgetsByRowIndex.at(widget->currentRowIndex)) { + for (auto& byteWidget : this->byteWidgetsByRowIndex.at(byteItem->currentRowIndex)) { byteWidget->update(); } } } + +void ByteItemGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) { + auto hoveredItems = this->items(mouseEvent->scenePos()); + if (!hoveredItems.empty()) { + auto hoveredByteWidget = dynamic_cast(hoveredItems.at(0)); + + if (hoveredByteWidget != nullptr) { + this->onByteWidgetEnter(hoveredByteWidget); + } + + } else if (this->hoveredByteWidget.has_value()) { + this->onByteWidgetLeave(); + } +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.hpp similarity index 64% rename from src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.hpp rename to src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.hpp index 8a005b8b..2f6fd4a5 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -8,7 +9,7 @@ #include #include #include -#include +#include #include #include "src/Targets/TargetMemory.hpp" @@ -16,22 +17,22 @@ #include "src/Insight/InsightWorker/InsightWorker.hpp" -#include "ByteWidget.hpp" +#include "ByteItem.hpp" namespace Bloom::Widgets { - class ByteWidgetContainer: public QWidget + class ByteItemGraphicsScene: public QGraphicsScene { Q_OBJECT public: - std::optional hoveredByteWidget; + std::optional hoveredByteWidget; - std::map byteWidgetsByAddress; - std::map> byteWidgetsByRowIndex; - std::map> byteWidgetsByColumnIndex; + std::map byteWidgetsByAddress; + std::map> byteWidgetsByRowIndex; + std::map> byteWidgetsByColumnIndex; - ByteWidgetContainer( + ByteItemGraphicsScene( const Targets::TargetMemoryDescriptor& targetMemoryDescriptor, InsightWorker& insightWorker, QLabel* hoveredAddressLabel, @@ -40,11 +41,13 @@ namespace Bloom::Widgets void updateValues(const Targets::TargetMemoryBuffer& buffer); + void adjustByteWidgets(); + signals: void byteWidgetsAdjusted(); protected: - void resizeEvent(QResizeEvent* event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) override; private: const Targets::TargetMemoryDescriptor& targetMemoryDescriptor; @@ -54,11 +57,9 @@ namespace Bloom::Widgets QWidget* parent = nullptr; QLabel* hoveredAddressLabel = nullptr; - void adjustByteWidgets(); - private slots: void onTargetStateChanged(Targets::TargetState newState); - void onByteWidgetEnter(Bloom::Widgets::ByteWidget* widget); - void onByteWidgetLeave(Bloom::Widgets::ByteWidget* widget); + void onByteWidgetEnter(Bloom::Widgets::ByteItem* widget); + void onByteWidgetLeave(); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.cpp deleted file mode 100644 index a5b60773..00000000 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "ByteWidget.hpp" - -#include -#include - -using namespace Bloom::Widgets; - -ByteWidget::ByteWidget( - std::size_t byteIndex, - std::uint32_t address, - std::optional& hoveredByteWidget, - QWidget* parent -): ClickableWidget(parent), byteIndex(byteIndex), address(address), hoveredByteWidget(hoveredByteWidget) { - this->setObjectName("byte"); - auto onClick = [this] { - this->setSelected(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(); - - QObject::connect(this, &ClickableWidget::clicked, this, onClick); - QObject::connect(this, &ClickableWidget::rightClicked, this, onClick); - - this->setSelected(false); -} - -void ByteWidget::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 = true; -} - -void ByteWidget::setSelected(bool selected) { - this->setProperty("selected", selected); - this->style()->unpolish(this); - this->style()->polish(this); - - if (selected) { - emit this->selected(this); - } - - this->postSetSelected(selected); -} - -bool ByteWidget::event(QEvent* event) { - if (this->isEnabled()) { - switch (event->type()) { - case QEvent::Enter: { - this->hoverActive = true; - emit this->enter(this); - this->update(); - break; - } - case QEvent::Leave: { - this->hoverActive = false; - emit this->leave(this); - this->update(); - break; - } - default: { - break; - } - } - } - - return QWidget::event(event); -} - -void ByteWidget::paintEvent(QPaintEvent* event) { - auto painter = QPainter(this); - this->drawWidget(painter); -} - -void ByteWidget::drawWidget(QPainter& painter) { - painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true); - painter.setPen(Qt::PenStyle::NoPen); - - static const auto widgetRect = QRect(0, 0, ByteWidget::WIDTH, ByteWidget::HEIGHT); - - if (this->hoveredByteWidget.has_value() - && ( - this->hoveredByteWidget.value()->currentColumnIndex == this->currentColumnIndex - || this->hoveredByteWidget.value()->currentRowIndex == this->currentRowIndex - ) - ) { - painter.setBrush(QColor(0x8E, 0x8B, 0x83, this->hoverActive ? 70 : 30)); - painter.drawRect(widgetRect); - } - - auto textColor = QColor(this->valueChanged ? "#547fba" : "#afb1b3"); - - if (this->valueInitialised) { - - if (!this->isEnabled()) { - textColor.setAlpha(100); - } - - painter.setPen(textColor); - painter.drawText(widgetRect, Qt::AlignCenter, this->hexValue); - - } else { - textColor.setAlpha(100); - painter.setPen(textColor); - - static const auto placeholderString = QString("??"); - painter.drawText(widgetRect, Qt::AlignCenter, placeholderString); - } -} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp index 3c76fd12..625050a9 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp @@ -1,7 +1,6 @@ #include "HexViewerWidget.hpp" #include -#include #include #include #include @@ -11,6 +10,7 @@ #include "src/Helpers/Paths.hpp" #include "src/Exceptions/Exception.hpp" +#include "src/Logger/Logger.hpp" using namespace Bloom::Widgets; using namespace Bloom::Exceptions; @@ -53,35 +53,19 @@ HexViewerWidget::HexViewerWidget( this->hoveredAddressLabel = this->bottomBar->findChild("byte-address-label"); - this->byteWidgetScrollArea = this->container->findChild("byte-widget-scroll-area"); - auto byteWidgetScrollAreaWidgetContainer = this->byteWidgetScrollArea->findChild( - "byte-widget-scroll-area-container" + auto byteItemGraphicsViewContainer = this->container->findChild("graphics-view-container"); + auto byteItemGraphicsViewLayout = byteItemGraphicsViewContainer->findChild( + "byte-item-container-layout" ); - auto byteWidgetScrollAreaHorizontalLayout = byteWidgetScrollAreaWidgetContainer->findChild( - "byte-widget-scroll-area-horizontal-layout" - ); - - this->byteWidgetContainer = new ByteWidgetContainer( + this->byteItemGraphicsView = new ByteItemContainerGraphicsView( targetMemoryDescriptor, insightWorker, this->hoveredAddressLabel, - byteWidgetScrollAreaHorizontalLayout->parentWidget() + byteItemGraphicsViewContainer ); + this->byteItemGraphicsScene = this->byteItemGraphicsView->getScene(); + byteItemGraphicsViewLayout->insertWidget(0, this->byteItemGraphicsView); - byteWidgetScrollAreaHorizontalLayout->addWidget(this->byteWidgetContainer); - - this->byteWidgetAddressContainer = byteWidgetScrollAreaWidgetContainer->findChild( - "address-container" - ); - this->byteWidgetAddressLayout = this->byteWidgetAddressContainer->findChild(); - this->byteWidgetAddressLayout->setContentsMargins(5, 10, 0, 5); - - QObject::connect( - this->byteWidgetContainer, - &ByteWidgetContainer::byteWidgetsAdjusted, - this, - &HexViewerWidget::onByteWidgetsAdjusted - ); QObject::connect( &insightWorker, &InsightWorker::targetStateUpdated, @@ -93,7 +77,7 @@ HexViewerWidget::HexViewerWidget( } void HexViewerWidget::updateValues(const Targets::TargetMemoryBuffer& buffer) { - this->byteWidgetContainer->updateValues(buffer); + this->byteItemGraphicsScene->updateValues(buffer); } void HexViewerWidget::resizeEvent(QResizeEvent* event) { @@ -109,36 +93,36 @@ void HexViewerWidget::onTargetStateChanged(Targets::TargetState newState) { } void HexViewerWidget::onByteWidgetsAdjusted() { - const auto& byteWidgetsByRowIndex = this->byteWidgetContainer->byteWidgetsByRowIndex; - - int layoutItemMaxIndex = this->byteWidgetAddressLayout->count() - 1; - for (const auto& mappingPair : byteWidgetsByRowIndex) { - const auto rowIndex = static_cast(mappingPair.first); - const auto& byteWidgets = mappingPair.second; - - if (byteWidgets.empty()) { - continue; - } - - QLabel* labelWidget; - if (rowIndex > layoutItemMaxIndex) { - labelWidget = new QLabel(this->byteWidgetAddressContainer); - labelWidget->setFixedSize(75, 20); - labelWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - - this->byteWidgetAddressLayout->addWidget(labelWidget); - layoutItemMaxIndex++; - - } else { - labelWidget = qobject_cast(this->byteWidgetAddressLayout->itemAt(rowIndex)->widget()); - } - - labelWidget->setText(byteWidgets.front()->relativeAddressHex); - } - - const auto rowCount = static_cast(byteWidgetsByRowIndex.size()); - QLayoutItem* labelItem; - while ((labelItem = this->byteWidgetAddressLayout->takeAt(rowCount)) != nullptr) { - labelItem->widget()->deleteLater(); - } +// const auto& byteWidgetsByRowIndex = this->byteWidgetContainer->byteWidgetsByRowIndex; +// +// int layoutItemMaxIndex = this->byteWidgetAddressLayout->count() - 1; +// for (const auto& mappingPair : byteWidgetsByRowIndex) { +// const auto rowIndex = static_cast(mappingPair.first); +// const auto& byteWidgets = mappingPair.second; +// +// if (byteWidgets.empty()) { +// continue; +// } +// +// QLabel* labelWidget; +// if (rowIndex > layoutItemMaxIndex) { +// labelWidget = new QLabel(this->byteWidgetAddressContainer); +// labelWidget->setFixedSize(75, 20); +// labelWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); +// +// this->byteWidgetAddressLayout->addWidget(labelWidget); +// layoutItemMaxIndex++; +// +// } else { +// labelWidget = qobject_cast(this->byteWidgetAddressLayout->itemAt(rowIndex)->widget()); +// } +// +// labelWidget->setText(byteWidgets.front()->relativeAddressHex); +// } +// +// const auto rowCount = static_cast(byteWidgetsByRowIndex.size()); +// QLayoutItem* labelItem; +// while ((labelItem = this->byteWidgetAddressLayout->takeAt(rowCount)) != nullptr) { +// labelItem->widget()->deleteLater(); +// } } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp index fb7182fb..cf899d59 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include @@ -16,7 +16,7 @@ #include "src/Insight/InsightWorker/InsightWorker.hpp" -#include "ByteWidgetContainer.hpp" +#include "ByteItemContainerGraphicsView.hpp" namespace Bloom::Widgets { @@ -46,7 +46,8 @@ namespace Bloom::Widgets QWidget* toolBar = nullptr; QWidget* bottomBar = nullptr; - ByteWidgetContainer* byteWidgetContainer = nullptr; + ByteItemContainerGraphicsView* byteItemGraphicsView = nullptr; + ByteItemGraphicsScene* byteItemGraphicsScene = nullptr; QWidget* byteWidgetScrollArea = nullptr; QWidget* byteWidgetAddressContainer = nullptr; QVBoxLayout* byteWidgetAddressLayout = nullptr; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui index f486387e..63edb637 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui @@ -53,64 +53,25 @@ - - true - Qt::ScrollBarAsNeeded - QAbstractScrollArea::AdjustToContents - + - + - - - - + + + 0 - - - 0 - - - 0 - - - - - 0 - - - 0 - - - - - 85 - - - - - - - 5 - - - 0 - - - - - - - - - - - Qt::Vertical - - - - - + + 0 + + + + + Qt::Vertical + + + +