diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp index 6f445687..b531621f 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp @@ -58,12 +58,10 @@ namespace Bloom::Widgets auto uiLoader = UiLoader(this); this->container = uiLoader.load(&widgetUiFile, this); - this->container->setStyleSheet(stylesheetFile.readAll()); + this->setStyleSheet(stylesheetFile.readAll()); this->container->setFixedSize(this->size()); this->container->setContentsMargins(0, 0, 0, 0); - auto* containerLayout = this->container->findChild("hex-viewer-layout"); - this->toolBar = this->container->findChild("tool-bar"); this->bottomBar = this->container->findChild("bottom-bar"); @@ -92,18 +90,6 @@ namespace Bloom::Widgets this->loadingHexViewerLabel = this->container->findChild("loading-hex-viewer-label"); - this->byteItemGraphicsView = new ItemGraphicsView( - this->targetMemoryDescriptor, - this->data, - this->focusedMemoryRegions, - this->excludedMemoryRegions, - this->settings, - this->container - ); - - this->byteItemGraphicsView->hide(); - containerLayout->insertWidget(2, this->byteItemGraphicsView); - this->setHoveredRowAndColumnHighlightingEnabled(this->settings.highlightHoveredRowAndCol); this->setFocusedMemoryHighlightingEnabled(this->settings.highlightFocusedMemory); this->setAnnotationsEnabled(this->settings.displayAnnotations); @@ -188,6 +174,20 @@ namespace Bloom::Widgets } void HexViewerWidget::init() { + this->byteItemGraphicsView = new ItemGraphicsView( + this->targetMemoryDescriptor, + this->data, + this->focusedMemoryRegions, + this->excludedMemoryRegions, + this->settings, + this->container + ); + + this->byteItemGraphicsView->hide(); + + auto* containerLayout = this->container->findChild("hex-viewer-layout"); + containerLayout->insertWidget(2, this->byteItemGraphicsView); + QObject::connect( this->byteItemGraphicsView, &ItemGraphicsView::sceneReady, @@ -265,6 +265,8 @@ namespace Bloom::Widgets if (this->byteItemGraphicsScene != nullptr) { this->byteItemGraphicsScene->rebuildItemHierarchy(); } + + emit this->settingsChanged(this->settings); } void HexViewerWidget::setHoveredRowAndColumnHighlightingEnabled(bool enabled) { @@ -274,6 +276,8 @@ namespace Bloom::Widgets if (this->byteItemGraphicsScene != nullptr) { this->byteItemGraphicsScene->update(); } + + emit this->settingsChanged(this->settings); } void HexViewerWidget::setFocusedMemoryHighlightingEnabled(bool enabled) { @@ -283,6 +287,8 @@ namespace Bloom::Widgets if (this->byteItemGraphicsScene != nullptr) { this->byteItemGraphicsScene->update(); } + + emit this->settingsChanged(this->settings); } void HexViewerWidget::setAnnotationsEnabled(bool enabled) { @@ -292,6 +298,8 @@ namespace Bloom::Widgets if (this->byteItemGraphicsScene != nullptr) { this->byteItemGraphicsScene->adjustSize(); } + + emit this->settingsChanged(this->settings); } void HexViewerWidget::setDisplayAsciiEnabled(bool enabled) { @@ -301,6 +309,8 @@ namespace Bloom::Widgets if (this->byteItemGraphicsScene != nullptr) { this->byteItemGraphicsScene->update(); } + + emit this->settingsChanged(this->settings); } void HexViewerWidget::onGoToAddressInputChanged() { @@ -344,7 +354,11 @@ namespace Bloom::Widgets ); } - void HexViewerWidget::onByteSelectionChanged(Targets::TargetMemorySize selectionCount) { + void HexViewerWidget::onByteSelectionChanged( + const std::unordered_map& selectedByteItemsByAddress + ) { + const auto selectionCount = selectedByteItemsByAddress.size(); + if (selectionCount == 0) { this->selectionCountLabel->hide(); return; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp index dbed5544..6b6ea3b3 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp @@ -37,7 +37,7 @@ namespace Bloom::Widgets QWidget* parent ); - void init(); + virtual void init(); void updateValues(); void refreshRegions(); void setStackPointer(Targets::TargetStackPointer stackPointer); @@ -45,12 +45,9 @@ namespace Bloom::Widgets signals: void ready(); + void settingsChanged(const HexViewerWidgetSettings& settings); protected: - void resizeEvent(QResizeEvent* event) override; - void showEvent(QShowEvent* event) override; - - private: const Targets::TargetMemoryDescriptor& targetMemoryDescriptor; const std::optional& data; @@ -79,6 +76,8 @@ namespace Bloom::Widgets Targets::TargetState targetState = Targets::TargetState::UNKNOWN; + void resizeEvent(QResizeEvent* event) override; + void showEvent(QShowEvent* event) override; void onTargetStateChanged(Targets::TargetState newState); void setStackMemoryGroupingEnabled(bool enabled); void setHoveredRowAndColumnHighlightingEnabled(bool enabled); @@ -87,6 +86,8 @@ namespace Bloom::Widgets void setDisplayAsciiEnabled(bool enabled); void onGoToAddressInputChanged(); void onHoveredAddress(const std::optional& address); - void onByteSelectionChanged(Targets::TargetMemorySize selectionCount); + void onByteSelectionChanged( + const std::unordered_map& selectedByteItemsByAddress + ); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp index 0a07cec3..347c4cb2 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp @@ -214,9 +214,12 @@ namespace Bloom::Widgets } void ItemGraphicsScene::selectByteItems(const std::set& addresses) { + this->selectedByteItemsByAddress.clear(); + for (auto& [address, byteItem] : this->topLevelGroup->byteItemsByAddress) { if (addresses.contains(address)) { byteItem.selected = true; + this->selectedByteItemsByAddress.insert(std::pair(byteItem.startAddress, &byteItem)); } else if (byteItem.selected) { byteItem.selected = false; @@ -224,6 +227,7 @@ namespace Bloom::Widgets } this->update(); + emit this->selectionChanged(this->selectedByteItemsByAddress); } void ItemGraphicsScene::rebuildItemHierarchy() { @@ -311,8 +315,7 @@ namespace Bloom::Widgets } void ItemGraphicsScene::allocateGraphicsItems() { - const auto* view = this->views().first(); - const auto verticalScrollBarValue = view->verticalScrollBar()->value(); + const auto verticalScrollBarValue = this->getScrollbarValue(); constexpr auto bufferPointSize = 2; const auto gridPointIndex = static_castgridPoints)::size_type>(std::max( @@ -472,10 +475,12 @@ namespace Bloom::Widgets this->toggleByteItemSelection(byteItem); } + emit this->selectionChanged(this->selectedByteItemsByAddress); return; } this->toggleByteItemSelection(*byteItem); + emit this->selectionChanged(this->selectedByteItemsByAddress); break; } } @@ -529,7 +534,7 @@ namespace Bloom::Widgets this->selectByteItem(*byteItem); } } - emit this->selectionChanged(static_cast(this->selectedByteItemsByAddress.size())); + emit this->selectionChanged(this->selectedByteItemsByAddress); } for (const auto& item : hoveredItems) { @@ -577,6 +582,7 @@ namespace Bloom::Widgets void ItemGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { if (event->scenePos().x() <= ByteAddressContainer::WIDTH) { auto* menu = new QMenu(this->parent); + menu->setLayoutDirection(Qt::LayoutDirection::LeftToRight); menu->setObjectName("byte-item-address-container-context-menu"); auto* addressTypeMenu = new QMenu("Address Type", menu); @@ -591,6 +597,7 @@ namespace Bloom::Widgets const auto itemsSelected = !this->selectedByteItemsByAddress.empty(); auto* menu = new QMenu(this->parent); + menu->setLayoutDirection(Qt::LayoutDirection::LeftToRight); menu->addAction(this->selectAllByteItemsAction); menu->addAction(this->deselectByteItemsAction); menu->addSeparator(); @@ -672,6 +679,10 @@ namespace Bloom::Widgets } } + int ItemGraphicsScene::getScrollbarValue() { + return this->views().first()->verticalScrollBar()->value(); + } + void ItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) { this->targetState = newState; } @@ -693,7 +704,7 @@ namespace Bloom::Widgets this->hoverRectX->setPos(0, byteItemScenePos.y()); this->hoverRectY->setPos( byteItemScenePos.x(), - std::max(this->views().first()->verticalScrollBar()->value() - ByteItem::HEIGHT, 0) + std::max(this->getScrollbarValue() - ByteItem::HEIGHT, 0) ); this->hoverRectX->setVisible(true); @@ -747,12 +758,10 @@ namespace Bloom::Widgets void ItemGraphicsScene::toggleByteItemSelection(ByteItem& byteItem) { if (byteItem.selected) { this->deselectByteItem(byteItem); - emit this->selectionChanged(static_cast(this->selectedByteItemsByAddress.size())); return; } this->selectByteItem(byteItem); - emit this->selectionChanged(static_cast(this->selectedByteItemsByAddress.size())); } void ItemGraphicsScene::clearByteItemSelection() { @@ -762,7 +771,7 @@ namespace Bloom::Widgets this->selectedByteItemsByAddress.clear(); this->update(); - emit this->selectionChanged(0); + emit this->selectionChanged(this->selectedByteItemsByAddress); } void ItemGraphicsScene::selectAllByteItems() { @@ -772,7 +781,7 @@ namespace Bloom::Widgets } this->update(); - emit this->selectionChanged(static_cast(this->selectedByteItemsByAddress.size())); + emit this->selectionChanged(this->selectedByteItemsByAddress); } void ItemGraphicsScene::setAddressType(AddressType type) { diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp index b84d59e0..0eaf5f36 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp @@ -66,18 +66,9 @@ namespace Bloom::Widgets signals: void ready(); void hoveredAddress(const std::optional& address); - void selectionChanged(Targets::TargetMemorySize selectionCount); + void selectionChanged(const std::unordered_map& selectedByteItemsByAddress); protected: - bool event(QEvent* event) override; - void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* mouseEvent) override; - void mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) override; - void mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) override; - void mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent) override; - void keyPressEvent(QKeyEvent* keyEvent) override; - void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override; - - private: static constexpr auto GRID_SIZE = 100; bool enabled = true; @@ -146,7 +137,15 @@ namespace Bloom::Widgets return std::max(this->parent->viewport()->width(), 200) - 2; } + bool event(QEvent* event) override; + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* mouseEvent) override; + void mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent) override; + void keyPressEvent(QKeyEvent* keyEvent) override; + void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override; void refreshItemPositionIndices(); + int getScrollbarValue(); void onTargetStateChanged(Targets::TargetState newState); void onByteItemEnter(ByteItem& byteItem); void onByteItemLeave(); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.cpp index 8a1e208a..6ab0310f 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.cpp @@ -1,5 +1,7 @@ #include "ItemGraphicsView.hpp" +#include + #include "ByteItem.hpp" namespace Bloom::Widgets @@ -15,6 +17,11 @@ namespace Bloom::Widgets QWidget* parent ) : QGraphicsView(parent) + , targetMemoryDescriptor(targetMemoryDescriptor) + , data(data) + , focusedMemoryRegions(focusedMemoryRegions) + , excludedMemoryRegions(excludedMemoryRegions) + , settings(settings) { this->setObjectName("graphics-view"); this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); @@ -27,20 +34,23 @@ namespace Bloom::Widgets this->setCacheMode(QGraphicsView::CacheModeFlag::CacheNone); this->setFocusPolicy(Qt::StrongFocus); + this->verticalScrollBar()->setSingleStep((ByteItem::HEIGHT + (ByteItem::BOTTOM_MARGIN / 2))); + this->setViewportMargins(-1, 0, -2, 0); + this->setFrameShape(QFrame::NoFrame); + } + + void ItemGraphicsView::initScene() { this->scene = new ItemGraphicsScene( - targetMemoryDescriptor, - data, - focusedMemoryRegions, - excludedMemoryRegions, - settings, + this->targetMemoryDescriptor, + this->data, + this->focusedMemoryRegions, + this->excludedMemoryRegions, + this->settings, this ); this->setScene(this->scene); - this->verticalScrollBar()->setSingleStep((ByteItem::HEIGHT + (ByteItem::BOTTOM_MARGIN / 2))); - } - void ItemGraphicsView::initScene() { QObject::connect( this->scene, &ItemGraphicsScene::ready, @@ -55,12 +65,16 @@ namespace Bloom::Widgets } void ItemGraphicsView::scrollToByteItemAtAddress(Targets::TargetMemoryAddress address) { + if (this->scene == nullptr) { + return; + } + this->centerOn(this->scene->getByteItemPositionByAddress(address)); } bool ItemGraphicsView::event(QEvent* event) { const auto eventType = event->type(); - if (eventType == QEvent::Type::EnabledChange) { + if (this->scene != nullptr && eventType == QEvent::Type::EnabledChange) { this->scene->setEnabled(this->isEnabled()); } @@ -70,11 +84,18 @@ namespace Bloom::Widgets void ItemGraphicsView::resizeEvent(QResizeEvent* event) { QGraphicsView::resizeEvent(event); + if (this->scene == nullptr) { + return; + } + this->scene->adjustSize(); } void ItemGraphicsView::scrollContentsBy(int dx, int dy) { - this->scene->allocateGraphicsItems(); + if (this->scene != nullptr) { + this->scene->allocateGraphicsItems(); + } + return QGraphicsView::scrollContentsBy(dx, dy); } } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.hpp index aab009ac..d0a4ca08 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.hpp @@ -26,7 +26,7 @@ namespace Bloom::Widgets QWidget* parent ); - void initScene(); + virtual void initScene(); [[nodiscard]] ItemGraphicsScene* getScene() const { return this->scene; @@ -38,11 +38,16 @@ namespace Bloom::Widgets void sceneReady(); protected: + const Targets::TargetMemoryDescriptor& targetMemoryDescriptor; + const std::optional& data; + const std::vector& focusedMemoryRegions; + const std::vector& excludedMemoryRegions; + HexViewerWidgetSettings& settings; + + ItemGraphicsScene* scene = nullptr; + bool event(QEvent* event) override; void resizeEvent(QResizeEvent* event) override; void scrollContentsBy(int dx, int dy) override; - - private: - ItemGraphicsScene* scene = nullptr; }; }