Prepared HexViewerWidget for snapshot diff window

This commit is contained in:
Nav
2023-05-01 14:49:51 +01:00
parent 86a09b1a4a
commit 5e4d917b57
6 changed files with 103 additions and 54 deletions

View File

@@ -58,12 +58,10 @@ namespace Bloom::Widgets
auto uiLoader = UiLoader(this); auto uiLoader = UiLoader(this);
this->container = uiLoader.load(&widgetUiFile, this); this->container = uiLoader.load(&widgetUiFile, this);
this->container->setStyleSheet(stylesheetFile.readAll()); this->setStyleSheet(stylesheetFile.readAll());
this->container->setFixedSize(this->size()); this->container->setFixedSize(this->size());
this->container->setContentsMargins(0, 0, 0, 0); this->container->setContentsMargins(0, 0, 0, 0);
auto* containerLayout = this->container->findChild<QVBoxLayout*>("hex-viewer-layout");
this->toolBar = this->container->findChild<QWidget*>("tool-bar"); this->toolBar = this->container->findChild<QWidget*>("tool-bar");
this->bottomBar = this->container->findChild<QWidget*>("bottom-bar"); this->bottomBar = this->container->findChild<QWidget*>("bottom-bar");
@@ -92,18 +90,6 @@ namespace Bloom::Widgets
this->loadingHexViewerLabel = this->container->findChild<Label*>("loading-hex-viewer-label"); this->loadingHexViewerLabel = this->container->findChild<Label*>("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->setHoveredRowAndColumnHighlightingEnabled(this->settings.highlightHoveredRowAndCol);
this->setFocusedMemoryHighlightingEnabled(this->settings.highlightFocusedMemory); this->setFocusedMemoryHighlightingEnabled(this->settings.highlightFocusedMemory);
this->setAnnotationsEnabled(this->settings.displayAnnotations); this->setAnnotationsEnabled(this->settings.displayAnnotations);
@@ -188,6 +174,20 @@ namespace Bloom::Widgets
} }
void HexViewerWidget::init() { 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<QVBoxLayout*>("hex-viewer-layout");
containerLayout->insertWidget(2, this->byteItemGraphicsView);
QObject::connect( QObject::connect(
this->byteItemGraphicsView, this->byteItemGraphicsView,
&ItemGraphicsView::sceneReady, &ItemGraphicsView::sceneReady,
@@ -265,6 +265,8 @@ namespace Bloom::Widgets
if (this->byteItemGraphicsScene != nullptr) { if (this->byteItemGraphicsScene != nullptr) {
this->byteItemGraphicsScene->rebuildItemHierarchy(); this->byteItemGraphicsScene->rebuildItemHierarchy();
} }
emit this->settingsChanged(this->settings);
} }
void HexViewerWidget::setHoveredRowAndColumnHighlightingEnabled(bool enabled) { void HexViewerWidget::setHoveredRowAndColumnHighlightingEnabled(bool enabled) {
@@ -274,6 +276,8 @@ namespace Bloom::Widgets
if (this->byteItemGraphicsScene != nullptr) { if (this->byteItemGraphicsScene != nullptr) {
this->byteItemGraphicsScene->update(); this->byteItemGraphicsScene->update();
} }
emit this->settingsChanged(this->settings);
} }
void HexViewerWidget::setFocusedMemoryHighlightingEnabled(bool enabled) { void HexViewerWidget::setFocusedMemoryHighlightingEnabled(bool enabled) {
@@ -283,6 +287,8 @@ namespace Bloom::Widgets
if (this->byteItemGraphicsScene != nullptr) { if (this->byteItemGraphicsScene != nullptr) {
this->byteItemGraphicsScene->update(); this->byteItemGraphicsScene->update();
} }
emit this->settingsChanged(this->settings);
} }
void HexViewerWidget::setAnnotationsEnabled(bool enabled) { void HexViewerWidget::setAnnotationsEnabled(bool enabled) {
@@ -292,6 +298,8 @@ namespace Bloom::Widgets
if (this->byteItemGraphicsScene != nullptr) { if (this->byteItemGraphicsScene != nullptr) {
this->byteItemGraphicsScene->adjustSize(); this->byteItemGraphicsScene->adjustSize();
} }
emit this->settingsChanged(this->settings);
} }
void HexViewerWidget::setDisplayAsciiEnabled(bool enabled) { void HexViewerWidget::setDisplayAsciiEnabled(bool enabled) {
@@ -301,6 +309,8 @@ namespace Bloom::Widgets
if (this->byteItemGraphicsScene != nullptr) { if (this->byteItemGraphicsScene != nullptr) {
this->byteItemGraphicsScene->update(); this->byteItemGraphicsScene->update();
} }
emit this->settingsChanged(this->settings);
} }
void HexViewerWidget::onGoToAddressInputChanged() { void HexViewerWidget::onGoToAddressInputChanged() {
@@ -344,7 +354,11 @@ namespace Bloom::Widgets
); );
} }
void HexViewerWidget::onByteSelectionChanged(Targets::TargetMemorySize selectionCount) { void HexViewerWidget::onByteSelectionChanged(
const std::unordered_map<Targets::TargetMemoryAddress, ByteItem*>& selectedByteItemsByAddress
) {
const auto selectionCount = selectedByteItemsByAddress.size();
if (selectionCount == 0) { if (selectionCount == 0) {
this->selectionCountLabel->hide(); this->selectionCountLabel->hide();
return; return;

View File

@@ -37,7 +37,7 @@ namespace Bloom::Widgets
QWidget* parent QWidget* parent
); );
void init(); virtual void init();
void updateValues(); void updateValues();
void refreshRegions(); void refreshRegions();
void setStackPointer(Targets::TargetStackPointer stackPointer); void setStackPointer(Targets::TargetStackPointer stackPointer);
@@ -45,12 +45,9 @@ namespace Bloom::Widgets
signals: signals:
void ready(); void ready();
void settingsChanged(const HexViewerWidgetSettings& settings);
protected: protected:
void resizeEvent(QResizeEvent* event) override;
void showEvent(QShowEvent* event) override;
private:
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor; const Targets::TargetMemoryDescriptor& targetMemoryDescriptor;
const std::optional<Targets::TargetMemoryBuffer>& data; const std::optional<Targets::TargetMemoryBuffer>& data;
@@ -79,6 +76,8 @@ namespace Bloom::Widgets
Targets::TargetState targetState = Targets::TargetState::UNKNOWN; Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
void resizeEvent(QResizeEvent* event) override;
void showEvent(QShowEvent* event) override;
void onTargetStateChanged(Targets::TargetState newState); void onTargetStateChanged(Targets::TargetState newState);
void setStackMemoryGroupingEnabled(bool enabled); void setStackMemoryGroupingEnabled(bool enabled);
void setHoveredRowAndColumnHighlightingEnabled(bool enabled); void setHoveredRowAndColumnHighlightingEnabled(bool enabled);
@@ -87,6 +86,8 @@ namespace Bloom::Widgets
void setDisplayAsciiEnabled(bool enabled); void setDisplayAsciiEnabled(bool enabled);
void onGoToAddressInputChanged(); void onGoToAddressInputChanged();
void onHoveredAddress(const std::optional<Targets::TargetMemoryAddress>& address); void onHoveredAddress(const std::optional<Targets::TargetMemoryAddress>& address);
void onByteSelectionChanged(Targets::TargetMemorySize selectionCount); void onByteSelectionChanged(
const std::unordered_map<Targets::TargetMemoryAddress, ByteItem*>& selectedByteItemsByAddress
);
}; };
} }

View File

@@ -214,9 +214,12 @@ namespace Bloom::Widgets
} }
void ItemGraphicsScene::selectByteItems(const std::set<std::uint32_t>& addresses) { void ItemGraphicsScene::selectByteItems(const std::set<std::uint32_t>& addresses) {
this->selectedByteItemsByAddress.clear();
for (auto& [address, byteItem] : this->topLevelGroup->byteItemsByAddress) { for (auto& [address, byteItem] : this->topLevelGroup->byteItemsByAddress) {
if (addresses.contains(address)) { if (addresses.contains(address)) {
byteItem.selected = true; byteItem.selected = true;
this->selectedByteItemsByAddress.insert(std::pair(byteItem.startAddress, &byteItem));
} else if (byteItem.selected) { } else if (byteItem.selected) {
byteItem.selected = false; byteItem.selected = false;
@@ -224,6 +227,7 @@ namespace Bloom::Widgets
} }
this->update(); this->update();
emit this->selectionChanged(this->selectedByteItemsByAddress);
} }
void ItemGraphicsScene::rebuildItemHierarchy() { void ItemGraphicsScene::rebuildItemHierarchy() {
@@ -311,8 +315,7 @@ namespace Bloom::Widgets
} }
void ItemGraphicsScene::allocateGraphicsItems() { void ItemGraphicsScene::allocateGraphicsItems() {
const auto* view = this->views().first(); const auto verticalScrollBarValue = this->getScrollbarValue();
const auto verticalScrollBarValue = view->verticalScrollBar()->value();
constexpr auto bufferPointSize = 2; constexpr auto bufferPointSize = 2;
const auto gridPointIndex = static_cast<decltype(this->gridPoints)::size_type>(std::max( const auto gridPointIndex = static_cast<decltype(this->gridPoints)::size_type>(std::max(
@@ -472,10 +475,12 @@ namespace Bloom::Widgets
this->toggleByteItemSelection(byteItem); this->toggleByteItemSelection(byteItem);
} }
emit this->selectionChanged(this->selectedByteItemsByAddress);
return; return;
} }
this->toggleByteItemSelection(*byteItem); this->toggleByteItemSelection(*byteItem);
emit this->selectionChanged(this->selectedByteItemsByAddress);
break; break;
} }
} }
@@ -529,7 +534,7 @@ namespace Bloom::Widgets
this->selectByteItem(*byteItem); this->selectByteItem(*byteItem);
} }
} }
emit this->selectionChanged(static_cast<Targets::TargetMemorySize>(this->selectedByteItemsByAddress.size())); emit this->selectionChanged(this->selectedByteItemsByAddress);
} }
for (const auto& item : hoveredItems) { for (const auto& item : hoveredItems) {
@@ -577,6 +582,7 @@ namespace Bloom::Widgets
void ItemGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { void ItemGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) {
if (event->scenePos().x() <= ByteAddressContainer::WIDTH) { if (event->scenePos().x() <= ByteAddressContainer::WIDTH) {
auto* menu = new QMenu(this->parent); auto* menu = new QMenu(this->parent);
menu->setLayoutDirection(Qt::LayoutDirection::LeftToRight);
menu->setObjectName("byte-item-address-container-context-menu"); menu->setObjectName("byte-item-address-container-context-menu");
auto* addressTypeMenu = new QMenu("Address Type", menu); auto* addressTypeMenu = new QMenu("Address Type", menu);
@@ -591,6 +597,7 @@ namespace Bloom::Widgets
const auto itemsSelected = !this->selectedByteItemsByAddress.empty(); const auto itemsSelected = !this->selectedByteItemsByAddress.empty();
auto* menu = new QMenu(this->parent); auto* menu = new QMenu(this->parent);
menu->setLayoutDirection(Qt::LayoutDirection::LeftToRight);
menu->addAction(this->selectAllByteItemsAction); menu->addAction(this->selectAllByteItemsAction);
menu->addAction(this->deselectByteItemsAction); menu->addAction(this->deselectByteItemsAction);
menu->addSeparator(); menu->addSeparator();
@@ -672,6 +679,10 @@ namespace Bloom::Widgets
} }
} }
int ItemGraphicsScene::getScrollbarValue() {
return this->views().first()->verticalScrollBar()->value();
}
void ItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) { void ItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) {
this->targetState = newState; this->targetState = newState;
} }
@@ -693,7 +704,7 @@ namespace Bloom::Widgets
this->hoverRectX->setPos(0, byteItemScenePos.y()); this->hoverRectX->setPos(0, byteItemScenePos.y());
this->hoverRectY->setPos( this->hoverRectY->setPos(
byteItemScenePos.x(), byteItemScenePos.x(),
std::max(this->views().first()->verticalScrollBar()->value() - ByteItem::HEIGHT, 0) std::max(this->getScrollbarValue() - ByteItem::HEIGHT, 0)
); );
this->hoverRectX->setVisible(true); this->hoverRectX->setVisible(true);
@@ -747,12 +758,10 @@ namespace Bloom::Widgets
void ItemGraphicsScene::toggleByteItemSelection(ByteItem& byteItem) { void ItemGraphicsScene::toggleByteItemSelection(ByteItem& byteItem) {
if (byteItem.selected) { if (byteItem.selected) {
this->deselectByteItem(byteItem); this->deselectByteItem(byteItem);
emit this->selectionChanged(static_cast<Targets::TargetMemorySize>(this->selectedByteItemsByAddress.size()));
return; return;
} }
this->selectByteItem(byteItem); this->selectByteItem(byteItem);
emit this->selectionChanged(static_cast<Targets::TargetMemorySize>(this->selectedByteItemsByAddress.size()));
} }
void ItemGraphicsScene::clearByteItemSelection() { void ItemGraphicsScene::clearByteItemSelection() {
@@ -762,7 +771,7 @@ namespace Bloom::Widgets
this->selectedByteItemsByAddress.clear(); this->selectedByteItemsByAddress.clear();
this->update(); this->update();
emit this->selectionChanged(0); emit this->selectionChanged(this->selectedByteItemsByAddress);
} }
void ItemGraphicsScene::selectAllByteItems() { void ItemGraphicsScene::selectAllByteItems() {
@@ -772,7 +781,7 @@ namespace Bloom::Widgets
} }
this->update(); this->update();
emit this->selectionChanged(static_cast<Targets::TargetMemorySize>(this->selectedByteItemsByAddress.size())); emit this->selectionChanged(this->selectedByteItemsByAddress);
} }
void ItemGraphicsScene::setAddressType(AddressType type) { void ItemGraphicsScene::setAddressType(AddressType type) {

View File

@@ -66,18 +66,9 @@ namespace Bloom::Widgets
signals: signals:
void ready(); void ready();
void hoveredAddress(const std::optional<Targets::TargetMemoryAddress>& address); void hoveredAddress(const std::optional<Targets::TargetMemoryAddress>& address);
void selectionChanged(Targets::TargetMemorySize selectionCount); void selectionChanged(const std::unordered_map<Targets::TargetMemoryAddress, ByteItem*>& selectedByteItemsByAddress);
protected: 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; static constexpr auto GRID_SIZE = 100;
bool enabled = true; bool enabled = true;
@@ -146,7 +137,15 @@ namespace Bloom::Widgets
return std::max(this->parent->viewport()->width(), 200) - 2; 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(); void refreshItemPositionIndices();
int getScrollbarValue();
void onTargetStateChanged(Targets::TargetState newState); void onTargetStateChanged(Targets::TargetState newState);
void onByteItemEnter(ByteItem& byteItem); void onByteItemEnter(ByteItem& byteItem);
void onByteItemLeave(); void onByteItemLeave();

View File

@@ -1,5 +1,7 @@
#include "ItemGraphicsView.hpp" #include "ItemGraphicsView.hpp"
#include <QLayout>
#include "ByteItem.hpp" #include "ByteItem.hpp"
namespace Bloom::Widgets namespace Bloom::Widgets
@@ -15,6 +17,11 @@ namespace Bloom::Widgets
QWidget* parent QWidget* parent
) )
: QGraphicsView(parent) : QGraphicsView(parent)
, targetMemoryDescriptor(targetMemoryDescriptor)
, data(data)
, focusedMemoryRegions(focusedMemoryRegions)
, excludedMemoryRegions(excludedMemoryRegions)
, settings(settings)
{ {
this->setObjectName("graphics-view"); this->setObjectName("graphics-view");
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
@@ -27,20 +34,23 @@ namespace Bloom::Widgets
this->setCacheMode(QGraphicsView::CacheModeFlag::CacheNone); this->setCacheMode(QGraphicsView::CacheModeFlag::CacheNone);
this->setFocusPolicy(Qt::StrongFocus); 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( this->scene = new ItemGraphicsScene(
targetMemoryDescriptor, this->targetMemoryDescriptor,
data, this->data,
focusedMemoryRegions, this->focusedMemoryRegions,
excludedMemoryRegions, this->excludedMemoryRegions,
settings, this->settings,
this this
); );
this->setScene(this->scene); this->setScene(this->scene);
this->verticalScrollBar()->setSingleStep((ByteItem::HEIGHT + (ByteItem::BOTTOM_MARGIN / 2)));
}
void ItemGraphicsView::initScene() {
QObject::connect( QObject::connect(
this->scene, this->scene,
&ItemGraphicsScene::ready, &ItemGraphicsScene::ready,
@@ -55,12 +65,16 @@ namespace Bloom::Widgets
} }
void ItemGraphicsView::scrollToByteItemAtAddress(Targets::TargetMemoryAddress address) { void ItemGraphicsView::scrollToByteItemAtAddress(Targets::TargetMemoryAddress address) {
if (this->scene == nullptr) {
return;
}
this->centerOn(this->scene->getByteItemPositionByAddress(address)); this->centerOn(this->scene->getByteItemPositionByAddress(address));
} }
bool ItemGraphicsView::event(QEvent* event) { bool ItemGraphicsView::event(QEvent* event) {
const auto eventType = event->type(); const auto eventType = event->type();
if (eventType == QEvent::Type::EnabledChange) { if (this->scene != nullptr && eventType == QEvent::Type::EnabledChange) {
this->scene->setEnabled(this->isEnabled()); this->scene->setEnabled(this->isEnabled());
} }
@@ -70,11 +84,18 @@ namespace Bloom::Widgets
void ItemGraphicsView::resizeEvent(QResizeEvent* event) { void ItemGraphicsView::resizeEvent(QResizeEvent* event) {
QGraphicsView::resizeEvent(event); QGraphicsView::resizeEvent(event);
if (this->scene == nullptr) {
return;
}
this->scene->adjustSize(); this->scene->adjustSize();
} }
void ItemGraphicsView::scrollContentsBy(int dx, int dy) { void ItemGraphicsView::scrollContentsBy(int dx, int dy) {
if (this->scene != nullptr) {
this->scene->allocateGraphicsItems(); this->scene->allocateGraphicsItems();
}
return QGraphicsView::scrollContentsBy(dx, dy); return QGraphicsView::scrollContentsBy(dx, dy);
} }
} }

View File

@@ -26,7 +26,7 @@ namespace Bloom::Widgets
QWidget* parent QWidget* parent
); );
void initScene(); virtual void initScene();
[[nodiscard]] ItemGraphicsScene* getScene() const { [[nodiscard]] ItemGraphicsScene* getScene() const {
return this->scene; return this->scene;
@@ -38,11 +38,16 @@ namespace Bloom::Widgets
void sceneReady(); void sceneReady();
protected: protected:
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor;
const std::optional<Targets::TargetMemoryBuffer>& data;
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions;
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions;
HexViewerWidgetSettings& settings;
ItemGraphicsScene* scene = nullptr;
bool event(QEvent* event) override; bool event(QEvent* event) override;
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;
void scrollContentsBy(int dx, int dy) override; void scrollContentsBy(int dx, int dy) override;
private:
ItemGraphicsScene* scene = nullptr;
}; };
} }