diff --git a/src/Insight/CMakeLists.txt b/src/Insight/CMakeLists.txt index c000e4ba..33131fb6 100755 --- a/src/Insight/CMakeLists.txt +++ b/src/Insight/CMakeLists.txt @@ -81,6 +81,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/GroupItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/FocusedRegionGroupItem.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressContainer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteAddressItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemoryRegion.cpp diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp index 8b2a950a..e744e1ec 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp @@ -43,6 +43,14 @@ namespace Bloom::Widgets return; } + if (this->stackMemory && hexViewerState->settings.groupStackMemory) { + painter->drawPixmap( + boundingRect, + ByteItem::stackMemoryAsciiPixmapsByValue[value] + ); + return; + } + if (this->grouped && hexViewerState->settings.highlightFocusedMemory) { painter->drawPixmap( boundingRect, @@ -71,6 +79,14 @@ namespace Bloom::Widgets return; } + if (this->stackMemory && hexViewerState->settings.groupStackMemory) { + painter->drawPixmap( + boundingRect, + ByteItem::stackMemoryPixmapsByValue[value] + ); + return; + } + if (this->grouped && hexViewerState->settings.highlightFocusedMemory) { painter->drawPixmap( boundingRect, @@ -105,6 +121,8 @@ namespace Bloom::Widgets static constexpr auto selectedBackgroundColor = QColor(0x3C, 0x59, 0x5C, 255); static constexpr auto groupedBackgroundColor = QColor(0x44, 0x44, 0x41, 255); static constexpr auto stackMemoryBackgroundColor = QColor(0x44, 0x44, 0x41, 200); + static constexpr auto stackMemoryBarColor = QColor(0x67, 0x57, 0x20, 255); + static const auto hoveredStackMemoryBackgroundColor = QColor( stackMemoryBackgroundColor.red(), stackMemoryBackgroundColor.green(), @@ -112,12 +130,11 @@ namespace Bloom::Widgets 255 ); - static const auto hoveredBackgroundColor = QColor(0x8E, 0x8B, 0x83, 70); - static const auto hoveredSecondaryBackgroundColor = QColor(0x8E, 0x8B, 0x83, 30); + static constexpr auto hoveredBackgroundColor = QColor(0x8E, 0x8B, 0x83, 70); - static const auto standardFontColor = QColor(0xAF, 0xB1, 0xB3); - static const auto fadedFontColor = QColor(0xAF, 0xB1, 0xB3, 100); - static const auto asciiFontColor = QColor(0xA7, 0x77, 0x26); + static constexpr auto standardFontColor = QColor(0xAF, 0xB1, 0xB3); + static constexpr auto fadedFontColor = QColor(0xAF, 0xB1, 0xB3, 100); + static constexpr auto asciiFontColor = QColor(0xA7, 0x77, 0x26); const auto byteItemRect = QRect(0, 0, ByteItem::WIDTH, ByteItem::HEIGHT); const auto byteItemSize = byteItemRect.size(); @@ -137,15 +154,19 @@ namespace Bloom::Widgets auto stackMemoryTemplatePixmap = QPixmap(byteItemSize); stackMemoryTemplatePixmap.fill(stackMemoryBackgroundColor); + { + auto painter = QPainter(&stackMemoryTemplatePixmap); + painter.setBrush(stackMemoryBarColor); + painter.setPen(Qt::PenStyle::NoPen); + painter.drawRect(0, byteItemSize.height() - 3, byteItemSize.width(), 3); + } + auto hoveredStackMemoryTemplatePixmap = QPixmap(byteItemSize); hoveredStackMemoryTemplatePixmap.fill(hoveredStackMemoryBackgroundColor); auto hoveredPrimaryTemplatePixmap = QPixmap(byteItemSize); hoveredPrimaryTemplatePixmap.fill(hoveredBackgroundColor); - auto hoveredSecondaryTemplatePixmap = QPixmap(byteItemSize); - hoveredSecondaryTemplatePixmap.fill(hoveredSecondaryBackgroundColor); - static auto font = QFont("'Ubuntu', sans-serif", 8); for (std::uint16_t value = 0x00; value <= 0xFF; ++value) { @@ -184,6 +205,16 @@ namespace Bloom::Widgets ByteItem::groupedPixmapsByValue.emplace_back(std::move(groupedPixmap)); } + { + auto stackMemoryPixmap = stackMemoryTemplatePixmap; + auto painter = QPainter(&stackMemoryPixmap); + painter.setFont(font); + painter.setPen(standardFontColor); + painter.drawText(byteItemRect, Qt::AlignCenter, hexValue); + + ByteItem::stackMemoryPixmapsByValue.emplace_back(std::move(stackMemoryPixmap)); + } + { auto hoveredPrimaryPixmap = hoveredPrimaryTemplatePixmap; auto painter = QPainter(&hoveredPrimaryPixmap); @@ -194,16 +225,6 @@ namespace Bloom::Widgets ByteItem::hoveredPrimaryPixmapsByValue.emplace_back(std::move(hoveredPrimaryPixmap)); } - { - auto hoveredSecondaryPixmap = hoveredSecondaryTemplatePixmap; - auto painter = QPainter(&hoveredSecondaryPixmap); - painter.setFont(font); - painter.setPen(standardFontColor); - painter.drawText(byteItemRect, Qt::AlignCenter, hexValue); - - ByteItem::hoveredSecondaryPixmapsByValue.emplace_back(std::move(hoveredSecondaryPixmap)); - } - { auto standardAsciiPixmap = standardTemplatePixmap; auto painter = QPainter(&standardAsciiPixmap); @@ -234,6 +255,16 @@ namespace Bloom::Widgets ByteItem::groupedAsciiPixmapsByValue.emplace_back(std::move(groupedAsciiPixmap)); } + { + auto stackMemoryAsciiPixmap = stackMemoryTemplatePixmap; + auto painter = QPainter(&stackMemoryAsciiPixmap); + painter.setFont(font); + painter.setPen(asciiValue.has_value() ? asciiFontColor : fadedFontColor); + painter.drawText(byteItemRect, Qt::AlignCenter, asciiValue.value_or(hexValue)); + + ByteItem::stackMemoryAsciiPixmapsByValue.emplace_back(std::move(stackMemoryAsciiPixmap)); + } + { auto hoveredPrimaryAsciiPixmap = hoveredPrimaryTemplatePixmap; auto painter = QPainter(&hoveredPrimaryAsciiPixmap); @@ -243,16 +274,6 @@ namespace Bloom::Widgets ByteItem::hoveredPrimaryAsciiPixmapsByValue.emplace_back(std::move(hoveredPrimaryAsciiPixmap)); } - - { - auto hoveredSecondaryAsciiPixmap = hoveredSecondaryTemplatePixmap; - auto painter = QPainter(&hoveredSecondaryAsciiPixmap); - painter.setFont(font); - painter.setPen(asciiValue.has_value() ? asciiFontColor : fadedFontColor); - painter.drawText(byteItemRect, Qt::AlignCenter, asciiValue.value_or(hexValue)); - - ByteItem::hoveredSecondaryAsciiPixmapsByValue.emplace_back(std::move(hoveredSecondaryAsciiPixmap)); - } } { diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp index 47235320..3adc27da 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.hpp @@ -23,6 +23,7 @@ namespace Bloom::Widgets bool selected = false; bool excluded = false; bool grouped = false; + bool stackMemory = false; explicit ByteItem(Targets::TargetMemoryAddress address); @@ -43,13 +44,13 @@ namespace Bloom::Widgets static inline std::vector standardPixmapsByValue = {}; static inline std::vector selectedPixmapsByValue = {}; static inline std::vector groupedPixmapsByValue = {}; + static inline std::vector stackMemoryPixmapsByValue = {}; static inline std::vector standardAsciiPixmapsByValue = {}; static inline std::vector selectedAsciiPixmapsByValue = {}; static inline std::vector groupedAsciiPixmapsByValue = {}; + static inline std::vector stackMemoryAsciiPixmapsByValue = {}; static inline std::vector hoveredPrimaryPixmapsByValue = {}; - static inline std::vector hoveredSecondaryPixmapsByValue = {}; static inline std::vector hoveredPrimaryAsciiPixmapsByValue = {}; - static inline std::vector hoveredSecondaryAsciiPixmapsByValue = {}; static inline std::optional missingDataPixmap = {}; static void generatePixmapCaches(); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/GroupItem.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/GroupItem.hpp index c45eca96..24c937e7 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/GroupItem.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/GroupItem.hpp @@ -24,7 +24,7 @@ namespace Bloom::Widgets return this->groupSize; } - void adjustItemPositions(const int maximumWidth, const HexViewerSharedState* hexViewerState); + virtual void adjustItemPositions(const int maximumWidth, const HexViewerSharedState* hexViewerState); [[nodiscard]] std::vector flattenedItems() const; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp index 3cfa764a..671061d9 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp @@ -54,8 +54,8 @@ namespace Bloom::Widgets this->toolBar = this->container->findChild("tool-bar"); this->bottomBar = this->container->findChild("bottom-bar"); - this->highlightStackMemoryButton = this->toolBar->findChild( - "highlight-stack-memory-btn" + this->groupStackMemoryButton = this->toolBar->findChild( + "group-stack-memory-btn" ); this->highlightHoveredRowAndColumnButton = this->toolBar->findChild( "highlight-hovered-rows-columns-btn" @@ -97,21 +97,21 @@ namespace Bloom::Widgets this->setDisplayAsciiEnabled(this->settings.displayAsciiValues); if (this->targetMemoryDescriptor.type == Targets::TargetMemoryType::RAM) { - this->highlightStackMemoryButton->show(); - this->setStackMemoryHighlightingEnabled(this->settings.highlightStackMemory); + this->groupStackMemoryButton->show(); + this->setStackMemoryGroupingEnabled(this->settings.groupStackMemory); QObject::connect( - this->highlightStackMemoryButton, + this->groupStackMemoryButton, &QToolButton::clicked, this, [this] { - this->setStackMemoryHighlightingEnabled(!this->settings.highlightStackMemory); + this->setStackMemoryGroupingEnabled(!this->settings.groupStackMemory); } ); } else { - this->highlightStackMemoryButton->hide(); - this->setStackMemoryHighlightingEnabled(false); + this->groupStackMemoryButton->hide(); + this->setStackMemoryGroupingEnabled(false); } QObject::connect( @@ -225,9 +225,9 @@ namespace Bloom::Widgets this->targetState = newState; } - void HexViewerWidget::setStackMemoryHighlightingEnabled(bool enabled) { - this->highlightStackMemoryButton->setChecked(enabled); - this->settings.highlightStackMemory = enabled; + void HexViewerWidget::setStackMemoryGroupingEnabled(bool enabled) { + this->groupStackMemoryButton->setChecked(enabled); + this->settings.groupStackMemory = enabled; if (this->byteItemGraphicsScene != nullptr) { this->byteItemGraphicsScene->rebuildItemHierarchy(); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp index 9a29be85..abaa5f26 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp @@ -65,7 +65,7 @@ namespace Bloom::Widgets ItemGraphicsScene* byteItemGraphicsScene = nullptr; Label* hoveredAddressLabel = nullptr; - SvgToolButton* highlightStackMemoryButton = nullptr; + SvgToolButton* groupStackMemoryButton = nullptr; SvgToolButton* highlightFocusedMemoryButton = nullptr; SvgToolButton* highlightHoveredRowAndColumnButton = nullptr; SvgToolButton* displayAnnotationsButton = nullptr; @@ -76,7 +76,7 @@ namespace Bloom::Widgets Targets::TargetState targetState = Targets::TargetState::UNKNOWN; void onTargetStateChanged(Targets::TargetState newState); - void setStackMemoryHighlightingEnabled(bool enabled); + void setStackMemoryGroupingEnabled(bool enabled); void setHoveredRowAndColumnHighlightingEnabled(bool enabled); void setFocusedMemoryHighlightingEnabled(bool enabled); void setAnnotationsEnabled(bool enabled); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidgetSettings.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidgetSettings.hpp index 20d8aa2a..44fb456f 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidgetSettings.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidgetSettings.hpp @@ -6,7 +6,7 @@ namespace Bloom::Widgets { struct HexViewerWidgetSettings { - bool highlightStackMemory = true; + bool groupStackMemory = true; bool highlightFocusedMemory = true; bool highlightHoveredRowAndCol = true; bool displayAsciiValues = false; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.cpp new file mode 100644 index 00000000..1e7ab32f --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.cpp @@ -0,0 +1,244 @@ +#include "StackMemoryGroupItem.hpp" + +#include +#include + +namespace Bloom::Widgets +{ + StackMemoryGroupItem::StackMemoryGroupItem( + Targets::TargetStackPointer stackPointer, + const HexViewerSharedState& hexViewerState, + const std::vector& focusedMemoryRegions, + std::unordered_map& byteItemsByAddress, + HexViewerItem* parent + ) + : GroupItem(stackPointer + 1, parent) + , stackPointer(stackPointer) + , hexViewerState(hexViewerState) + { + const auto startAddress = this->startAddress; + const auto endAddress = this->hexViewerState.memoryDescriptor.addressRange.endAddress; + + // Sanity check + assert(byteItemsByAddress.contains(startAddress) && byteItemsByAddress.contains(endAddress)); + + for (const auto& focusedRegion : focusedMemoryRegions) { + if ( + focusedRegion.addressRange.startAddress < startAddress + || focusedRegion.addressRange.endAddress > endAddress + ) { + /* + * This focused region is outside of stack memory, so we don't need to handle it here. + * + * This will also catch the regions that intersect with stack memory but are not completely contained + * within the stack. There's no clear way to present these regions, so we ignore them, for now. + */ + continue; + } + + this->focusedRegionGroupItems.emplace_back(focusedRegion, byteItemsByAddress, this); + items.emplace_back(&(this->focusedRegionGroupItems.back())); + } + + for (auto address = startAddress; address <= endAddress; ++address) { + auto& byteItem = byteItemsByAddress.at(address); + + byteItem.stackMemory = true; + + if (byteItem.parent == nullptr || byteItem.parent == this->parent) { + byteItem.parent = this; + this->items.push_back(&byteItem); + } + } + + this->sortItems(); + } + + StackMemoryGroupItem::~StackMemoryGroupItem() { + const auto updateChildItems = [] (const decltype(this->items)& items, const auto& updateChildItems) -> void { + for (auto& item : items) { + auto* byteItem = dynamic_cast(item); + + if (byteItem != nullptr) { + byteItem->stackMemory = false; + continue; + } + + auto* groupItem = dynamic_cast(item); + + if (groupItem != nullptr) { + updateChildItems(groupItem->items, updateChildItems); + } + } + }; + + updateChildItems(this->items, updateChildItems); + } + + void StackMemoryGroupItem::adjustItemPositions( + const int maximumWidth, + const HexViewerSharedState* hexViewerState + ) { + GroupItem::adjustItemPositions(maximumWidth, hexViewerState); + this->groupSize.setWidth(maximumWidth); + } + + void StackMemoryGroupItem::refreshValues() { + for (auto& focusedRegionItem : this->focusedRegionGroupItems) { + focusedRegionItem.refreshValue(this->hexViewerState); + } + } + + void StackMemoryGroupItem::paint( + QPainter* painter, + const HexViewerSharedState* hexViewerState, + const QGraphicsItem* graphicsItem + ) const { + painter->setRenderHints(QPainter::RenderHint::Antialiasing, false); + + if (!graphicsItem->isEnabled()) { + painter->setOpacity(0.5); + } + + const auto headingText = QString("Stack Memory"); + + const auto stackSize = hexViewerState->memoryDescriptor.addressRange.endAddress - this->startAddress + 1; + const auto& memoryCapacity = hexViewerState->memoryDescriptor.size(); + + const auto stackSizeHeadingText = QString("Stack size:"); + const auto stackSizeValueText = QString::number(stackSize) + " byte(s) (" + + QString::number(static_cast(stackSize) / static_cast(memoryCapacity / 100), 'f' , 1) + + "% of memory capacity)"; + + const auto stackPointerHeadingText = QString("Stack pointer:"); + const auto stackPointerValueText = "0x" + QString::number( + this->stackPointer, + 16 + ).rightJustified(8, '0').toUpper(); + + static constexpr auto lineColor = QColor(0x4F, 0x4F, 0x4F); + static constexpr auto headingLabelFontColor = QColor(0x6F, 0x6F, 0x6F); + static constexpr auto valueLabelFontColor = QColor(0x94, 0x6F, 0x30, 230); + + static auto headingLabelFont = QFont("'Ubuntu', sans-serif"); + headingLabelFont.setPixelSize(13); + + static auto valueFont = QFont("'Ubuntu', sans-serif"); + valueFont.setPixelSize(13); + valueFont.setItalic(true); + + painter->setFont(headingLabelFont); + + const auto groupWidth = this->groupSize.width(); + const auto fontMetrics = painter->fontMetrics(); + + auto headingLabelSize = fontMetrics.size(Qt::TextSingleLine, headingText); + + auto stackSizeHeadingLabelSize = fontMetrics.size(Qt::TextSingleLine, stackSizeHeadingText); + auto stackSizeLabelSize = fontMetrics.size(Qt::TextSingleLine, stackSizeValueText); + + auto stackPointerHeadingLabelSize = fontMetrics.size(Qt::TextSingleLine, stackPointerHeadingText); + auto stackPointerLabelSize = fontMetrics.size(Qt::TextSingleLine, stackPointerValueText); + + static constexpr auto labelLineHeight = 4; + static constexpr auto labelBottomMargin = 10; + static constexpr auto labelRightMargin = 3; + + const auto heightOffset = headingLabelSize.height() + stackSizeHeadingLabelSize.height() + + stackPointerHeadingLabelSize.height() + (labelBottomMargin * 3) + 15; + + const auto verticalLineYStart = static_cast(heightOffset - 5); + const auto verticalLineYEnd = static_cast(heightOffset); + + const auto lineStartX = ByteItem::WIDTH / 2; + const auto lineEndX = groupWidth - + (ByteItem::WIDTH / 2); + + const auto labelRect = QRect( + (groupWidth - headingLabelSize.width()) / 2, + verticalLineYStart - stackPointerHeadingLabelSize.height() - stackSizeHeadingLabelSize.height() + - headingLabelSize.height() - labelLineHeight - (labelBottomMargin * 2) - 3, + headingLabelSize.width(), + headingLabelSize.height() + ); + + const auto stackPointerHeadingLabelRect = QRect( + labelRect.left() + (labelRect.width() / 2) - ( + (stackPointerHeadingLabelSize.width() + stackPointerLabelSize.width()) / 2 + ), + labelRect.bottom() + labelBottomMargin, + stackPointerHeadingLabelSize.width(), + stackPointerHeadingLabelSize.height() + ); + + const auto stackPointerValueLabelRect = QRect( + stackPointerHeadingLabelRect.right() + labelRightMargin, + labelRect.bottom() + labelBottomMargin, + stackPointerLabelSize.width(), + stackPointerLabelSize.height() + ); + + const auto stackSizeHeadingLabelRect = QRect( + labelRect.left() + (labelRect.width() / 2) - ( + (stackSizeHeadingLabelSize.width() + stackSizeLabelSize.width()) / 2 + ), + stackPointerHeadingLabelRect.bottom() + labelBottomMargin, + stackSizeHeadingLabelSize.width(), + stackSizeHeadingLabelSize.height() + ); + + const auto stackSizeValueLabelRect = QRect( + stackSizeHeadingLabelRect.right() + labelRightMargin, + stackPointerHeadingLabelRect.bottom() + labelBottomMargin, + stackSizeLabelSize.width(), + stackSizeLabelSize.height() + ); + + painter->setPen(lineColor); + + painter->drawLine(QLine( + lineStartX, + verticalLineYStart, + lineStartX, + verticalLineYEnd + )); + + painter->drawLine(QLine( + lineEndX, + verticalLineYStart, + lineEndX, + verticalLineYEnd + )); + + painter->drawLine(QLine( + lineStartX, + verticalLineYStart, + lineEndX, + verticalLineYStart + )); + + painter->drawLine(QLine( + groupWidth / 2, + verticalLineYStart - labelLineHeight, + groupWidth / 2, + verticalLineYStart + )); + + painter->setPen(headingLabelFontColor); + + painter->drawText(labelRect, Qt::AlignCenter, headingText); + painter->drawText(stackSizeHeadingLabelRect, Qt::AlignCenter, stackSizeHeadingText); + painter->drawText(stackPointerHeadingLabelRect, Qt::AlignCenter, stackPointerHeadingText); + + painter->setFont(valueFont); + painter->setPen(valueLabelFontColor); + painter->drawText(stackSizeValueLabelRect, Qt::AlignCenter, stackSizeValueText); + painter->drawText(stackPointerValueLabelRect, Qt::AlignCenter, stackPointerValueText); + } + + QMargins StackMemoryGroupItem::groupMargins( + const HexViewerSharedState* hexViewerState, + const int maximumWidth + ) const { + return QMargins(0, 100, 0, 20); + } +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.hpp new file mode 100644 index 00000000..f1c44de0 --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/StackMemoryGroupItem.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include "GroupItem.hpp" +#include "ByteItem.hpp" +#include "FocusedRegionGroupItem.hpp" + +#include "src/Targets/TargetMemory.hpp" +#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/FocusedMemoryRegion.hpp" + +namespace Bloom::Widgets +{ + class StackMemoryGroupItem: public GroupItem + { + public: + StackMemoryGroupItem( + Targets::TargetStackPointer stackPointer, + const HexViewerSharedState& hexViewerState, + const std::vector& focusedMemoryRegions, + std::unordered_map& byteItemsByAddress, + HexViewerItem* parent + ); + + ~StackMemoryGroupItem(); + + void adjustItemPositions(const int maximumWidth, const HexViewerSharedState* hexViewerState) override; + + void refreshValues(); + + void paint( + QPainter* painter, + const HexViewerSharedState* hexViewerState, + const QGraphicsItem* graphicsItem + ) const override; + + protected: + QMargins groupMargins(const HexViewerSharedState* hexViewerState, const int maximumWidth) const override; + + bool positionOnNewLine(const int maximumWidth) override { + return true; + } + + private: + Targets::TargetStackPointer stackPointer; + const HexViewerSharedState& hexViewerState; + + std::list focusedRegionGroupItems; + }; +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.cpp index dd27f3fc..f200a669 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.cpp @@ -22,12 +22,47 @@ namespace Bloom::Widgets void TopLevelGroupItem::rebuildItemHierarchy() { this->items.clear(); this->focusedRegionGroupItems.clear(); + this->stackMemoryGroupItem.reset(); + + const auto& currentStackPointer = this->hexViewerState.currentStackPointer; + const auto stackGroupingRequired = currentStackPointer.has_value() + && this->hexViewerState.settings.groupStackMemory + && ( + static_cast(this->hexViewerState.memoryDescriptor.addressRange.endAddress) + - static_cast(*currentStackPointer + 1) + ) > 0; for (const auto& focusedRegion : this->focusedMemoryRegions) { + if ( + stackGroupingRequired + && ( + focusedRegion.addressRange.startAddress > *currentStackPointer + 1 + || focusedRegion.addressRange.endAddress > *currentStackPointer + 1 + ) + ) { + /* + * This focused region contains stack memory - the StackMemoryGroupItem will create and manage the + * corresponding FocusedMemoryRegionGroupItem for it. + */ + continue; + } + this->focusedRegionGroupItems.emplace_back(focusedRegion, this->byteItemsByAddress, this); items.emplace_back(&(this->focusedRegionGroupItems.back())); } + if (stackGroupingRequired) { + this->stackMemoryGroupItem.emplace( + *(currentStackPointer), + this->hexViewerState, + this->focusedMemoryRegions, + this->byteItemsByAddress, + this + ); + + items.emplace_back(&*(this->stackMemoryGroupItem)); + } + for (auto& [address, byteItem] : this->byteItemsByAddress) { if (byteItem.parent != nullptr && byteItem.parent != this) { // This ByteItem is managed by another group @@ -46,5 +81,9 @@ namespace Bloom::Widgets for (auto& focusedRegionItem : this->focusedRegionGroupItems) { focusedRegionItem.refreshValue(this->hexViewerState); } + + if (this->stackMemoryGroupItem.has_value()) { + this->stackMemoryGroupItem->refreshValues(); + } } } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.hpp index b3d6ba54..8ba9fc71 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/TopLevelGroupItem.hpp @@ -3,9 +3,11 @@ #include #include #include +#include #include "GroupItem.hpp" #include "FocusedRegionGroupItem.hpp" +#include "StackMemoryGroupItem.hpp" #include "ByteItem.hpp" #include "src/Targets/TargetMemory.hpp" @@ -41,5 +43,6 @@ namespace Bloom::Widgets const HexViewerSharedState& hexViewerState; std::list focusedRegionGroupItems; + std::optional stackMemoryGroupItem; }; } 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 eeea898c..eaa43bd3 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui @@ -42,7 +42,7 @@ - + @@ -60,7 +60,7 @@ :/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Images/highlight-stack-memory-disabled.svg - Highlight Stack Memory + Group Stack Memory diff --git a/src/ProjectSettings.cpp b/src/ProjectSettings.cpp index 3e05fc36..e810eb55 100644 --- a/src/ProjectSettings.cpp +++ b/src/ProjectSettings.cpp @@ -166,9 +166,9 @@ namespace Bloom auto& hexViewerSettings = inspectionPaneSettings.hexViewerWidgetSettings; const auto hexViewerSettingsObj = jsonObject.find("hexViewerSettings")->toObject(); - if (hexViewerSettingsObj.contains("highlightStackMemory")) { - hexViewerSettings.highlightStackMemory = - hexViewerSettingsObj.value("highlightStackMemory").toBool(); + if (hexViewerSettingsObj.contains("groupStackMemory")) { + hexViewerSettings.groupStackMemory = + hexViewerSettingsObj.value("groupStackMemory").toBool(); } if (hexViewerSettingsObj.contains("highlightFocusedMemory")) { @@ -284,7 +284,7 @@ namespace Bloom const auto& hexViewerSettings = inspectionPaneSettings.hexViewerWidgetSettings; settingsObj.insert("hexViewerSettings", QJsonObject({ - {"highlightStackMemory", hexViewerSettings.highlightStackMemory}, + {"groupStackMemory", hexViewerSettings.groupStackMemory}, {"highlightFocusedMemory", hexViewerSettings.highlightFocusedMemory}, {"highlightHoveredRowAndCol", hexViewerSettings.highlightHoveredRowAndCol}, {"displayAsciiValues", hexViewerSettings.displayAsciiValues},