diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ContextMenuAction.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ContextMenuAction.hpp index ca7c9783..26b09ce7 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ContextMenuAction.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ContextMenuAction.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "src/Targets/TargetMemory.hpp" @@ -28,7 +29,7 @@ namespace Widgets * always be enabled. */ using IsEnabledCallbackType = std::function< - bool(const std::unordered_map&) + bool(const std::set&) >; public: @@ -41,6 +42,6 @@ namespace Widgets ); signals: - void invoked(const std::unordered_map& selectedByteItemsByAddress); + void invoked(const std::set& selectedByteItemAddresses); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerSharedState.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerSharedState.hpp index 24503983..4e4cb2ac 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerSharedState.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerSharedState.hpp @@ -20,6 +20,7 @@ namespace Widgets ByteItem* hoveredByteItem = nullptr; std::optional currentStackPointer; bool highlightingEnabled = false; + std::set highlightedAddressRanges; HexViewerSharedState( const Targets::TargetMemoryDescriptor& memoryDescriptor, diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp index 424230cd..1181d4b6 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp @@ -242,22 +242,17 @@ namespace Widgets this->byteItemGraphicsScene->addExternalContextMenuAction(action); } - void HexViewerWidget::highlightBytes(const std::set& addresses) { - this->byteItemGraphicsScene->highlightByteItems(addresses); - } - - void HexViewerWidget::highlightBytes(const std::set& addressRanges) { - this->byteItemGraphicsScene->highlightByteItems(this->addressRangesToAddresses(addressRanges)); + void HexViewerWidget::highlightByteItemRanges(const std::set& addressRanges) { + this->byteItemGraphicsScene->highlightByteItemRanges(addressRanges); } void HexViewerWidget::clearHighlighting() { - this->highlightBytes(std::set()); + this->byteItemGraphicsScene->clearByteItemHighlighting(); } void HexViewerWidget::selectAndHighlightBytes(const std::set& addressRanges) { - const auto addresses = this->addressRangesToAddresses(addressRanges); - this->byteItemGraphicsScene->highlightByteItems(addresses); - this->byteItemGraphicsScene->selectByteItems(addresses); + this->byteItemGraphicsScene->highlightByteItemRanges(addressRanges); + this->byteItemGraphicsScene->selectByteItemRanges(addressRanges); } void HexViewerWidget::centerOnByte(Targets::TargetMemoryAddress address) { @@ -377,9 +372,9 @@ namespace Widgets } void HexViewerWidget::onByteSelectionChanged( - const std::unordered_map& selectedByteItemsByAddress + const std::set& selectedByteItemAddresses ) { - const auto selectionCount = selectedByteItemsByAddress.size(); + const auto selectionCount = selectedByteItemAddresses.size(); if (selectionCount == 0) { this->selectionCountLabel->hide(); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp index 68f8f7ff..b5ff92a0 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp @@ -42,8 +42,7 @@ namespace Widgets void refreshRegions(); void setStackPointer(Targets::TargetStackPointer stackPointer); void addExternalContextMenuAction(ContextMenuAction* action); - void highlightBytes(const std::set& addresses); - void highlightBytes(const std::set& addressRanges); + void highlightByteItemRanges(const std::set& addressRanges); void clearHighlighting(); void selectAndHighlightBytes(const std::set& addressRanges); void centerOnByte(Targets::TargetMemoryAddress address); @@ -91,9 +90,7 @@ namespace Widgets void setDisplayAsciiEnabled(bool enabled); void onGoToAddressInputChanged(); void onHoveredAddress(const std::optional& address); - void onByteSelectionChanged( - const std::unordered_map& selectedByteItemsByAddress - ); + void onByteSelectionChanged(const std::set& selectedByteItemAddresses); std::set addressRangesToAddresses( const std::set& addressRanges ); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp index 3c460123..f3af375f 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.cpp @@ -215,18 +215,18 @@ namespace Widgets InsightWorker::queueTask(constructHexViewerTopLevelGroupItem); } - void ItemGraphicsScene::updateStackPointer(std::uint32_t stackPointer) { + void ItemGraphicsScene::updateStackPointer(Targets::TargetStackPointer stackPointer) { this->state.currentStackPointer = stackPointer; this->rebuildItemHierarchy(); } - void ItemGraphicsScene::selectByteItems(const std::set& addresses) { - this->selectedByteItemsByAddress.clear(); + void ItemGraphicsScene::selectByteItems(const std::set& addresses) { + this->selectedByteItemAddresses.clear(); for (auto& [address, byteItem] : this->topLevelGroup->byteItemsByAddress) { if (addresses.contains(address)) { byteItem.selected = true; - this->selectedByteItemsByAddress.insert(std::pair(byteItem.startAddress, &byteItem)); + this->selectedByteItemAddresses.insert(byteItem.startAddress); } else if (byteItem.selected) { byteItem.selected = false; @@ -234,16 +234,37 @@ namespace Widgets } this->update(); - emit this->selectionChanged(this->selectedByteItemsByAddress); + emit this->selectionChanged(addresses); } - void ItemGraphicsScene::highlightByteItems(const std::set& addresses) { - for (auto& [address, byteItem] : this->topLevelGroup->byteItemsByAddress) { - byteItem.highlighted = addresses.contains(address); + void ItemGraphicsScene::selectByteItemRanges(const std::set& addressRanges) { + return this->selectByteItems(this->addressRangesToAddresses(addressRanges)); + } + + void ItemGraphicsScene::highlightByteItemRanges(const std::set& addressRanges) { + /* + * Don't bother updating the byte items if addressRanges is empty - updating the this->state.highlightingEnabled + * flag will prevent the highlighting, and the byte items will be updated the next time we actually want to + * highlight something. + * + * Not pretty but it saves a lot of cycles. + */ + if (!addressRanges.empty()) { + const auto addresses = this->addressRangesToAddresses(addressRanges); + for (auto& [address, byteItem] : this->topLevelGroup->byteItemsByAddress) { + byteItem.highlighted = addresses.contains(address); + } } - this->state.highlightingEnabled = !addresses.empty(); + this->state.highlightingEnabled = !addressRanges.empty(); + this->state.highlightedAddressRanges = std::move(addressRanges); this->update(); + + emit this->highlightingChanged(addressRanges); + } + + void ItemGraphicsScene::clearByteItemHighlighting() { + this->highlightByteItemRanges({}); } void ItemGraphicsScene::rebuildItemHierarchy() { @@ -323,7 +344,7 @@ namespace Widgets void ItemGraphicsScene::addExternalContextMenuAction(ContextMenuAction* action) { QObject::connect(action, &QAction::triggered, this, [this, action] () { - emit action->invoked(this->selectedByteItemsByAddress); + emit action->invoked(this->selectedByteItemAddresses); }); this->externalContextMenuActions.push_back(action); @@ -367,8 +388,7 @@ namespace Widgets const auto mousePosition = mouseEvent->buttonDownScenePos(button); if (this->state.highlightingEnabled) { - this->state.highlightingEnabled = false; - this->update(); + this->clearByteItemHighlighting(); } if (mousePosition.x() <= this->byteAddressContainer->boundingRect().width()) { @@ -424,12 +444,12 @@ namespace Widgets this->toggleByteItemSelection(byteItem); } - emit this->selectionChanged(this->selectedByteItemsByAddress); + emit this->selectionChanged(this->selectedByteItemAddresses); return; } this->toggleByteItemSelection(*clickedByteItem); - emit this->selectionChanged(this->selectedByteItemsByAddress); + emit this->selectionChanged(this->selectedByteItemAddresses); } } @@ -463,7 +483,7 @@ namespace Widgets for (auto& byteItem : items) { this->selectByteItem(*byteItem); } - emit this->selectionChanged(this->selectedByteItemsByAddress); + emit this->selectionChanged(this->selectedByteItemAddresses); } auto* hoveredByteItem = this->itemIndex->byteItemAt(mousePosition); @@ -485,7 +505,7 @@ namespace Widgets void ItemGraphicsScene::keyPressEvent(QKeyEvent* keyEvent) { const auto key = keyEvent->key(); - if (key == Qt::Key_Escape && !this->selectedByteItemsByAddress.empty()) { + if (key == Qt::Key_Escape && !this->selectedByteItemAddresses.empty()) { this->clearByteItemSelection(); return; } @@ -514,7 +534,7 @@ namespace Widgets return; } - const auto itemsSelected = !this->selectedByteItemsByAddress.empty(); + const auto itemsSelected = !this->selectedByteItemAddresses.empty(); auto* menu = new QMenu(this->parent); menu->setLayoutDirection(Qt::LayoutDirection::LeftToRight); @@ -548,7 +568,7 @@ namespace Widgets itemsSelected && ( !externalAction->isEnabledCallback.has_value() - || externalAction->isEnabledCallback.value()(this->selectedByteItemsByAddress) + || externalAction->isEnabledCallback.value()(this->selectedByteItemAddresses) ) ); @@ -620,12 +640,12 @@ namespace Widgets void ItemGraphicsScene::selectByteItem(ByteItem& byteItem) { byteItem.selected = true; - this->selectedByteItemsByAddress.insert(std::pair(byteItem.startAddress, &byteItem)); + this->selectedByteItemAddresses.insert(byteItem.startAddress); } void ItemGraphicsScene::deselectByteItem(ByteItem& byteItem) { byteItem.selected = false; - this->selectedByteItemsByAddress.erase(byteItem.startAddress); + this->selectedByteItemAddresses.erase(byteItem.startAddress); } void ItemGraphicsScene::toggleByteItemSelection(ByteItem& byteItem) { @@ -638,23 +658,24 @@ namespace Widgets } void ItemGraphicsScene::clearByteItemSelection() { - for (auto& [address, byteItem] : this->selectedByteItemsByAddress) { - byteItem->selected = false; + for (const auto& address : this->selectedByteItemAddresses) { + auto& byteItem = this->topLevelGroup->byteItemsByAddress.at(address); + byteItem.selected = false; } - this->selectedByteItemsByAddress.clear(); + this->selectedByteItemAddresses.clear(); this->update(); - emit this->selectionChanged(this->selectedByteItemsByAddress); + emit this->selectionChanged(this->selectedByteItemAddresses); } void ItemGraphicsScene::selectAllByteItems() { for (auto& [address, byteItem] : this->topLevelGroup->byteItemsByAddress) { byteItem.selected = true; - this->selectedByteItemsByAddress.insert(std::pair(byteItem.startAddress, &byteItem)); + this->selectedByteItemAddresses.insert(byteItem.startAddress); } this->update(); - emit this->selectionChanged(this->selectedByteItemsByAddress); + emit this->selectionChanged(this->selectedByteItemAddresses); } void ItemGraphicsScene::setAddressType(AddressType type) { @@ -666,34 +687,31 @@ namespace Widgets this->byteAddressContainer->invalidateChildItemCaches(); } - std::map ItemGraphicsScene::sortedByteItemsByAddress() { - auto sortedByteItemsByAddress = std::map(); - std::transform( - this->selectedByteItemsByAddress.begin(), - this->selectedByteItemsByAddress.end(), - std::inserter(sortedByteItemsByAddress, sortedByteItemsByAddress.end()), - [] (const decltype(this->selectedByteItemsByAddress)::value_type& pair) { - return pair; - } - ); + std::set ItemGraphicsScene::excludedAddresses() { + auto output = std::set(); - return sortedByteItemsByAddress; + for (const auto& excludedRegion : this->excludedMemoryRegions) { + const auto regionAddresses = excludedRegion.addressRange.addresses(); + output.insert(regionAddresses.begin(), regionAddresses.end()); + } + + return output; } void ItemGraphicsScene::copyAddressesToClipboard(AddressType type) { - if (this->selectedByteItemsByAddress.empty()) { + if (this->selectedByteItemAddresses.empty()) { return; } auto data = QString(); const auto memoryStartAddress = this->state.memoryDescriptor.addressRange.startAddress; - for (const auto& [address, byteItem] : this->sortedByteItemsByAddress()) { + for (const auto& address : this->selectedByteItemAddresses) { data.append( "0x" + QString::number( type == AddressType::RELATIVE - ? byteItem->startAddress - memoryStartAddress - : byteItem->startAddress, + ? address - memoryStartAddress + : address, 16 ).rightJustified(8, '0').toUpper() + "\n" ); @@ -703,16 +721,17 @@ namespace Widgets } void ItemGraphicsScene::copyHexValuesToClipboard(bool withDelimiters) { - if (this->selectedByteItemsByAddress.empty()) { + if (this->selectedByteItemAddresses.empty()) { return; } + const auto excludedAddresses = this->excludedAddresses(); auto data = QString(); - for (const auto& [address, byteItem] : this->sortedByteItemsByAddress()) { - const unsigned char byteValue = byteItem->excluded + for (const auto& address : this->selectedByteItemAddresses) { + const unsigned char byteValue = excludedAddresses.contains(address) ? 0x00 - : (*this->state.data)[byteItem->startAddress - this->state.memoryDescriptor.addressRange.startAddress]; + : (*this->state.data)[address - this->state.memoryDescriptor.addressRange.startAddress]; data.append( withDelimiters @@ -725,16 +744,17 @@ namespace Widgets } void ItemGraphicsScene::copyDecimalValuesToClipboard() { - if (this->selectedByteItemsByAddress.empty() || !this->state.data.has_value()) { + if (this->selectedByteItemAddresses.empty() || !this->state.data.has_value()) { return; } + const auto excludedAddresses = this->excludedAddresses(); auto data = QString(); - for (const auto& [address, byteItem] : this->sortedByteItemsByAddress()) { - const unsigned char byteValue = byteItem->excluded + for (const auto& address : this->selectedByteItemAddresses) { + const unsigned char byteValue = excludedAddresses.contains(address) ? 0x00 - : (*this->state.data)[byteItem->startAddress - this->state.memoryDescriptor.addressRange.startAddress]; + : (*this->state.data)[address - this->state.memoryDescriptor.addressRange.startAddress]; data.append(QString::number(byteValue, 10) + "\n"); } @@ -742,16 +762,17 @@ namespace Widgets } void ItemGraphicsScene::copyBinaryBitStringToClipboard(bool withDelimiters) { - if (this->selectedByteItemsByAddress.empty()) { + if (this->selectedByteItemAddresses.empty()) { return; } + const auto excludedAddresses = this->excludedAddresses(); auto data = QString(); - for (const auto& [address, byteItem] : this->sortedByteItemsByAddress()) { - const unsigned char byteValue = byteItem->excluded + for (const auto& address : this->selectedByteItemAddresses) { + const unsigned char byteValue = excludedAddresses.contains(address) ? 0x00 - : (*this->state.data)[byteItem->startAddress - this->state.memoryDescriptor.addressRange.startAddress]; + : (*this->state.data)[address - this->state.memoryDescriptor.addressRange.startAddress]; data.append( withDelimiters @@ -764,16 +785,17 @@ namespace Widgets } void ItemGraphicsScene::copyValueMappingToClipboard() { - if (this->selectedByteItemsByAddress.empty() || !this->state.data.has_value()) { + if (this->selectedByteItemAddresses.empty() || !this->state.data.has_value()) { return; } + const auto excludedAddresses = this->excludedAddresses(); auto data = QJsonObject(); - for (const auto& [address, byteItem] : this->sortedByteItemsByAddress()) { - const unsigned char byteValue = byteItem->excluded + for (const auto& address : this->selectedByteItemAddresses) { + const unsigned char byteValue = excludedAddresses.contains(address) ? 0x00 - : (*this->state.data)[byteItem->startAddress - this->state.memoryDescriptor.addressRange.startAddress]; + : (*this->state.data)[address - this->state.memoryDescriptor.addressRange.startAddress]; data.insert( "0x" + QString::number(address, 16).rightJustified(8, '0').toUpper(), @@ -785,17 +807,18 @@ namespace Widgets } void ItemGraphicsScene::copyAsciiValueToClipboard() { - if (this->selectedByteItemsByAddress.empty() || !this->state.data.has_value()) { + if (this->selectedByteItemAddresses.empty() || !this->state.data.has_value()) { return; } + const auto excludedAddresses = this->excludedAddresses(); auto data = QString(); - for (const auto& [address, byteItem] : this->sortedByteItemsByAddress()) { + for (const auto& address : this->selectedByteItemAddresses) { const unsigned char byteValue = - (*this->state.data)[byteItem->startAddress - this->state.memoryDescriptor.addressRange.startAddress]; + (*this->state.data)[address - this->state.memoryDescriptor.addressRange.startAddress]; - if (byteItem->excluded || byteValue < 32 || byteValue > 126) { + if (excludedAddresses.contains(address) || byteValue < 32 || byteValue > 126) { continue; } @@ -804,4 +827,17 @@ namespace Widgets QApplication::clipboard()->setText(std::move(data)); } + + std::set ItemGraphicsScene::addressRangesToAddresses( + const std::set& addressRanges + ) { + auto addresses = std::set(); + + for (const auto& range : addressRanges) { + const auto rangeAddresses = range.addresses(); + addresses.insert(rangeAddresses.begin(), rangeAddresses.end()); + } + + return addresses; + } } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp index 4f6a8ab5..23356222 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp @@ -56,7 +56,9 @@ namespace Widgets void init(); void updateStackPointer(Targets::TargetStackPointer stackPointer); void selectByteItems(const std::set& addresses); - void highlightByteItems(const std::set& addresses); + void selectByteItemRanges(const std::set& addressRanges); + void highlightByteItemRanges(const std::set& addressRanges); + void clearByteItemHighlighting(); void rebuildItemHierarchy(); void adjustSize(); void setEnabled(bool enabled); @@ -67,9 +69,8 @@ namespace Widgets signals: void ready(); void hoveredAddress(const std::optional& address); - void selectionChanged( - const std::unordered_map& selectedByteItemsByAddress - ); + void selectionChanged(const std::set& addresses); + void highlightingChanged(const std::set& addressRanges); protected: bool enabled = true; @@ -91,6 +92,7 @@ namespace Widgets ByteAddressContainer* byteAddressContainer = nullptr; std::unordered_map selectedByteItemsByAddress; + std::set selectedByteItemAddresses; QGraphicsRectItem* rubberBandRectItem = nullptr; std::optional rubberBandInitPoint = std::nullopt; @@ -154,12 +156,15 @@ namespace Widgets void clearByteItemSelection(); void selectAllByteItems(); void setAddressType(AddressType type); - std::map sortedByteItemsByAddress(); + std::set excludedAddresses(); void copyAddressesToClipboard(AddressType type); void copyHexValuesToClipboard(bool withDelimiters); void copyDecimalValuesToClipboard(); void copyBinaryBitStringToClipboard(bool withDelimiters); void copyValueMappingToClipboard(); void copyAsciiValueToClipboard(); + std::set addressRangesToAddresses( + const std::set& addressRanges + ); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.cpp index 00672ee1..2ddd689c 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.cpp @@ -138,3 +138,14 @@ bool MemorySnapshot::isCompatible(const Targets::TargetMemoryDescriptor& memoryD return true; } + +std::set MemorySnapshot::excludedAddresses() const { + auto output = std::set(); + + for (const auto& excludedRegion : this->excludedRegions) { + const auto regionAddresses = excludedRegion.addressRange.addresses(); + output.insert(regionAddresses.begin(), regionAddresses.end()); + } + + return output; +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp index f8a1ca4d..0d4224c2 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp @@ -43,6 +43,7 @@ public: QJsonObject toJson() const; bool isCompatible(const Targets::TargetMemoryDescriptor& memoryDescriptor) const; + std::set excludedAddresses() const; virtual ~MemorySnapshot() = default; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialHexViewerSharedState.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialHexViewerSharedState.hpp index 21099224..bc50aee6 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialHexViewerSharedState.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialHexViewerSharedState.hpp @@ -12,5 +12,6 @@ namespace Widgets bool syncingScroll = false; bool syncingHover = false; bool syncingSelection = false; + bool syncingHighlightedRanges = false; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.cpp index 1a628494..af728f0c 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.cpp @@ -44,6 +44,13 @@ namespace Widgets this, &DifferentialItemGraphicsScene::onOtherSelectionChanged ); + + QObject::connect( + this->other, + &DifferentialItemGraphicsScene::highlightingChanged, + this, + &DifferentialItemGraphicsScene::onOtherHighlightedByteRangesChanged + ); } ByteItem* DifferentialItemGraphicsScene::byteItemAtViewportTop() { @@ -97,23 +104,27 @@ namespace Widgets } void DifferentialItemGraphicsScene::onOtherSelectionChanged( - const std::unordered_map& selectedByteItemsByAddress + const std::set& addresses ) { if (!this->snapshotDiffSettings.syncHexViewerSelection || this->diffHexViewerState.syncingSelection) { return; } this->diffHexViewerState.syncingSelection = true; - this->clearByteItemSelection(); + this->selectByteItems(addresses); + this->diffHexViewerState.syncingSelection = false; + } - for (const auto& [address, otherByteItem] : selectedByteItemsByAddress) { - auto& byteItem = this->topLevelGroup->byteItemsByAddress.at(address); - byteItem.selected = true; - this->selectedByteItemsByAddress.insert(std::pair(byteItem.startAddress, &byteItem)); + void DifferentialItemGraphicsScene::onOtherHighlightedByteRangesChanged( + const std::set& addressRanges + ) { + if (this->diffHexViewerState.syncingHighlightedRanges) { + return; } - emit this->selectionChanged(this->selectedByteItemsByAddress); - this->diffHexViewerState.syncingSelection = false; + this->diffHexViewerState.syncingHighlightedRanges = true; + this->highlightByteItemRanges(addressRanges); + this->diffHexViewerState.syncingHighlightedRanges = false; this->update(); } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.hpp index b0e1c85d..b2306cfe 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.hpp @@ -41,8 +41,7 @@ namespace Widgets QMargins margins() override; void onOtherHoveredAddress(const std::optional& address); - void onOtherSelectionChanged( - const std::unordered_map& selectedByteItemsByAddress - ); + void onOtherSelectionChanged(const std::set& addresses); + void onOtherHighlightedByteRangesChanged(const std::set& addressRanges); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp index db958fd4..149b9904 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp @@ -85,7 +85,7 @@ namespace Widgets this->restoreBytesAction = new ContextMenuAction( "Restore Selection", - [this] (const std::unordered_map&) { + [this] (const std::set&) { return this->memoryDescriptor.access.writeableDuringDebugSession; }, this @@ -95,8 +95,8 @@ namespace Widgets this->restoreBytesAction, &ContextMenuAction::invoked, this, - [this] (const std::unordered_map& selectedByteItemsByAddress) { - this->restoreSelectedBytes(selectedByteItemsByAddress, true); + [this] (const std::set& selectedByteItemAddresses) { + this->restoreSelectedBytes(selectedByteItemAddresses, true); } ); } @@ -446,20 +446,20 @@ namespace Widgets } void SnapshotDiff::restoreSelectedBytes( - const std::unordered_map& selectedByteItemsByAddress, + std::set addresses, bool confirmationPromptEnabled ) { - auto sortedByteItemsByAddress = std::map(); - - for (const auto& pair : selectedByteItemsByAddress) { - if (pair.second->excluded) { - continue; - } - - sortedByteItemsByAddress.insert(pair); + auto excludedAddresses = std::set(); + for (const auto& excludedRegion : this->excludedRegionsA) { + const auto regionAddresses = excludedRegion.addressRange.addresses(); + excludedAddresses.insert(regionAddresses.begin(), regionAddresses.end()); } - if (sortedByteItemsByAddress.empty()) { + std::erase_if(addresses, [excludedAddresses] (const auto& address) { + return excludedAddresses.contains(address); + }); + + if (addresses.empty()) { // The user has only selected bytes that are within an excluded region - nothing to do here return; } @@ -467,8 +467,7 @@ namespace Widgets if (confirmationPromptEnabled) { auto* confirmationDialog = new ConfirmationDialog( "Restore selected bytes", - "This operation will write " + QString::number(sortedByteItemsByAddress.size()) - + " byte(s) to the target's " + "This operation will write " + QString::number(addresses.size()) + " byte(s) to the target's " + EnumToStringMappings::targetMemoryTypes.at(this->memoryDescriptor.type).toUpper() + ".

Are you sure you want to proceed?", "Proceed", @@ -480,8 +479,8 @@ namespace Widgets confirmationDialog, &ConfirmationDialog::confirmed, this, - [this, selectedByteItemsByAddress] { - this->restoreSelectedBytes(selectedByteItemsByAddress, false); + [this, addresses] { + this->restoreSelectedBytes(addresses, false); } ); @@ -491,10 +490,10 @@ namespace Widgets auto writeBlocks = std::vector(); - Targets::TargetMemoryAddress blockStartAddress = sortedByteItemsByAddress.begin()->first; + Targets::TargetMemoryAddress blockStartAddress = *(addresses.begin()); Targets::TargetMemoryAddress blockEndAddress = blockStartAddress; - for (const auto& [address, byteItem] : sortedByteItemsByAddress) { + for (const auto& address : addresses) { if (address > (blockEndAddress + 1)) { // Commit the block const auto dataBeginOffset = blockStartAddress - this->memoryDescriptor.addressRange.startAddress; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp index f48624d7..2ad9d730 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.hpp @@ -128,7 +128,7 @@ namespace Widgets void setSyncHexViewerSelectionEnabled(bool enabled); void restoreSelectedBytes( - const std::unordered_map& selectedByteItemsByAddress, + std::set addresses, bool confirmationPromptEnabled ); }; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.cpp index ce0f7c7f..e7840fbf 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.cpp @@ -126,7 +126,7 @@ namespace Widgets this->restoreBytesAction = new ContextMenuAction( "Restore Selection", - [this] (const std::unordered_map&) { + [this] (const std::set&) { return this->memoryDescriptor.access.writeableDuringDebugSession; }, this @@ -170,8 +170,8 @@ namespace Widgets this->restoreBytesAction, &ContextMenuAction::invoked, this, - [this] (const std::unordered_map& selectedByteItemsByAddress) { - this->restoreSelectedBytes(selectedByteItemsByAddress, true); + [this] (const std::set& selectedByteItemAddresses) { + this->restoreSelectedBytes(selectedByteItemAddresses, true); } ); @@ -197,21 +197,15 @@ namespace Widgets } void SnapshotViewer::restoreSelectedBytes( - const std::unordered_map& selectedByteItemsByAddress, + std::set addresses, bool confirmationPromptEnabled ) { - auto sortedByteItemsByAddress = std::map(); + const auto excludedAddresses = this->snapshot.excludedAddresses(); + std::erase_if(addresses, [excludedAddresses] (const auto& address) { + return excludedAddresses.contains(address); + }); - // Ideally, we'd use std::transform here, but that would require an additional pass to remove excluded bytes - for (const auto& pair : selectedByteItemsByAddress) { - if (pair.second->excluded) { - continue; - } - - sortedByteItemsByAddress.insert(pair); - } - - if (sortedByteItemsByAddress.empty()) { + if (addresses.empty()) { // The user has only selected bytes that are within an excluded region - nothing to do here return; } @@ -219,8 +213,7 @@ namespace Widgets if (confirmationPromptEnabled) { auto* confirmationDialog = new ConfirmationDialog( "Restore selected bytes", - "This operation will write " + QString::number(sortedByteItemsByAddress.size()) - + " byte(s) to the target's " + "This operation will write " + QString::number(addresses.size()) + " byte(s) to the target's " + EnumToStringMappings::targetMemoryTypes.at(this->memoryDescriptor.type).toUpper() + ".

Are you sure you want to proceed?", "Proceed", @@ -232,8 +225,8 @@ namespace Widgets confirmationDialog, &ConfirmationDialog::confirmed, this, - [this, selectedByteItemsByAddress] { - this->restoreSelectedBytes(selectedByteItemsByAddress, false); + [this, addresses] { + this->restoreSelectedBytes(addresses, false); } ); @@ -243,10 +236,10 @@ namespace Widgets auto writeBlocks = std::vector(); - Targets::TargetMemoryAddress blockStartAddress = sortedByteItemsByAddress.begin()->first; + Targets::TargetMemoryAddress blockStartAddress = *(addresses.begin()); Targets::TargetMemoryAddress blockEndAddress = blockStartAddress; - for (const auto& [address, byteItem] : sortedByteItemsByAddress) { + for (const auto& address : addresses) { if (address > (blockEndAddress + 1)) { // Commit the block const auto dataBeginOffset = blockStartAddress - this->memoryDescriptor.addressRange.startAddress; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.hpp index c85d7b8a..6e743e1e 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.hpp @@ -63,7 +63,7 @@ namespace Widgets void onHexViewerReady(); void restoreSelectedBytes( - const std::unordered_map& selectedByteItemsByAddress, + std::set addresses, bool confirmationPromptEnabled ); }; diff --git a/src/Targets/TargetMemory.hpp b/src/Targets/TargetMemory.hpp index c9089ac4..6655183b 100644 --- a/src/Targets/TargetMemory.hpp +++ b/src/Targets/TargetMemory.hpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace Targets @@ -60,6 +61,17 @@ namespace Targets [[nodiscard]] bool contains(const TargetMemoryAddressRange& addressRange) const { return this->startAddress <= addressRange.startAddress && this->endAddress >= addressRange.endAddress; } + + std::set addresses() const { + auto addresses = std::set(); + auto addressesIt = addresses.end(); + + for (auto i = this->startAddress; i <= this->endAddress; ++i) { + addressesIt = addresses.insert(addressesIt, i); + } + + return addresses; + } }; struct TargetMemoryAccess