diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp index 46b44862..4a246067 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp @@ -28,10 +28,12 @@ namespace Bloom::Widgets std::size_t byteIndex; Targets::TargetMemoryAddress address = 0x00; - QString addressHex; QString relativeAddressHex; + unsigned char value = 0x00; + QString hexValue; + std::size_t currentRowIndex = 0; std::size_t currentColumnIndex = 0; @@ -62,12 +64,9 @@ namespace Bloom::Widgets void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; private: - unsigned char value = 0x00; bool valueInitialised = false; const HexViewerWidgetSettings& settings; - - QString hexValue; std::optional asciiValue; ByteItem** hoveredByteItem; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp index 72f4fa4d..b1f49dbe 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp @@ -2,6 +2,9 @@ #include #include +#include +#include +#include #include "src/Insight/InsightWorker/InsightWorker.hpp" #include "src/Insight/InsightSignals.hpp" @@ -62,6 +65,53 @@ namespace Bloom::Widgets this->setAddressType(AddressType::ABSOLUTE); } ); + + QObject::connect( + this->selectAllByteItemsAction, + &QAction::triggered, + this, + &ByteItemGraphicsScene::selectAllByteItems + ); + + QObject::connect( + this->deselectByteItemsAction, + &QAction::triggered, + this, + &ByteItemGraphicsScene::clearByteItemSelection + ); + + QObject::connect( + this->copyAbsoluteAddressAction, + &QAction::triggered, + this, + [this] { + this->copyAddressesToClipboard(AddressType::ABSOLUTE); + } + ); + + QObject::connect( + this->copyRelativeAddressAction, + &QAction::triggered, + this, + [this] { + this->copyAddressesToClipboard(AddressType::RELATIVE); + } + ); + + QObject::connect( + this->copyHexValuesAction, + &QAction::triggered, + this, + &ByteItemGraphicsScene::copyHexValuesToClipboard + ); + + QObject::connect( + this->copyDecimalValuesAction, + &QAction::triggered, + this, + &ByteItemGraphicsScene::copyDecimalValuesToClipboard + ); + this->setSceneRect(0, 0, this->getSceneWidth(), 0); } @@ -433,6 +483,26 @@ namespace Bloom::Widgets menu->exec(event->screenPos()); return; } + + const auto itemsSelected = !this->selectedByteItemsByAddress.empty(); + + auto* menu = new QMenu(this->parent); + menu->addAction(this->selectAllByteItemsAction); + menu->addAction(this->deselectByteItemsAction); + menu->addSeparator(); + + auto* copyMenu = new QMenu("Copy Selected", menu); + copyMenu->addAction(this->copyAbsoluteAddressAction); + copyMenu->addAction(this->copyRelativeAddressAction); + copyMenu->addSeparator(); + copyMenu->addAction(this->copyHexValuesAction); + copyMenu->addAction(this->copyDecimalValuesAction); + + copyMenu->setEnabled(itemsSelected); + this->deselectByteItemsAction->setEnabled(itemsSelected); + + menu->addMenu(copyMenu); + menu->exec(event->screenPos()); } void ByteItemGraphicsScene::updateAnnotationValues(const Targets::TargetMemoryBuffer& buffer) { @@ -715,4 +785,46 @@ namespace Bloom::Widgets this->byteAddressContainer->invalidateChildItemCaches(); } + + void ByteItemGraphicsScene::copyAddressesToClipboard(AddressType type) { + if (this->selectedByteItemsByAddress.empty()) { + return; + } + + auto data = QString(); + + for (const auto& [address, byteItem] : this->selectedByteItemsByAddress) { + data.append((type == AddressType::ABSOLUTE ? byteItem->addressHex : byteItem->relativeAddressHex) + "\n"); + } + + QApplication::clipboard()->setText(std::move(data)); + } + + void ByteItemGraphicsScene::copyHexValuesToClipboard() { + if (this->selectedByteItemsByAddress.empty()) { + return; + } + + auto data = QString(); + + for (const auto& [address, byteItem] : this->selectedByteItemsByAddress) { + data.append("0x" + byteItem->hexValue + "\n"); + } + + QApplication::clipboard()->setText(std::move(data)); + } + + void ByteItemGraphicsScene::copyDecimalValuesToClipboard() { + if (this->selectedByteItemsByAddress.empty()) { + return; + } + + auto data = QString(); + + for (const auto& [address, byteItem] : this->selectedByteItemsByAddress) { + data.append(QString::number(byteItem->value, 10) + "\n"); + } + + QApplication::clipboard()->setText(std::move(data)); + } } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.hpp index 42a7ec99..6698b8d1 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.hpp @@ -110,6 +110,13 @@ namespace Bloom::Widgets QGraphicsRectItem* rubberBandRectItem = nullptr; std::optional rubberBandInitPoint = std::nullopt; + // Context menu actions + QAction* selectAllByteItemsAction = new QAction("Select All", this); + QAction* deselectByteItemsAction = new QAction("Deselect All", this); + QAction* copyAbsoluteAddressAction = new QAction("Copy Absolute Addresses", this); + QAction* copyRelativeAddressAction = new QAction("Copy Relative Addresses", this); + QAction* copyHexValuesAction = new QAction("Copy Hexadecimal Values", this); + QAction* copyDecimalValuesAction = new QAction("Copy Decimal Values", this); // Address label container context menu actions QAction* displayRelativeAddressAction = new QAction("Relative", this); @@ -140,5 +147,8 @@ namespace Bloom::Widgets void clearByteItemSelection(); void selectAllByteItems(); void setAddressType(AddressType type); + void copyAddressesToClipboard(AddressType type); + void copyHexValuesToClipboard(); + void copyDecimalValuesToClipboard(); }; }