Replaced stack memory highlighting with grouping, to group stack memory and present annotations
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -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<QPixmap> standardPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> selectedPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> groupedPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> stackMemoryPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> standardAsciiPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> selectedAsciiPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> groupedAsciiPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> stackMemoryAsciiPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> hoveredPrimaryPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> hoveredSecondaryPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> hoveredPrimaryAsciiPixmapsByValue = {};
|
||||
static inline std::vector<QPixmap> hoveredSecondaryAsciiPixmapsByValue = {};
|
||||
static inline std::optional<QPixmap> missingDataPixmap = {};
|
||||
|
||||
static void generatePixmapCaches();
|
||||
|
||||
@@ -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<HexViewerItem*> flattenedItems() const;
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace Bloom::Widgets
|
||||
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
|
||||
this->bottomBar = this->container->findChild<QWidget*>("bottom-bar");
|
||||
|
||||
this->highlightStackMemoryButton = this->toolBar->findChild<SvgToolButton*>(
|
||||
"highlight-stack-memory-btn"
|
||||
this->groupStackMemoryButton = this->toolBar->findChild<SvgToolButton*>(
|
||||
"group-stack-memory-btn"
|
||||
);
|
||||
this->highlightHoveredRowAndColumnButton = this->toolBar->findChild<SvgToolButton*>(
|
||||
"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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Bloom::Widgets
|
||||
{
|
||||
struct HexViewerWidgetSettings
|
||||
{
|
||||
bool highlightStackMemory = true;
|
||||
bool groupStackMemory = true;
|
||||
bool highlightFocusedMemory = true;
|
||||
bool highlightHoveredRowAndCol = true;
|
||||
bool displayAsciiValues = false;
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
#include "StackMemoryGroupItem.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <QColor>
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
StackMemoryGroupItem::StackMemoryGroupItem(
|
||||
Targets::TargetStackPointer stackPointer,
|
||||
const HexViewerSharedState& hexViewerState,
|
||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::unordered_map<Targets::TargetMemoryAddress, ByteItem>& 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<ByteItem*>(item);
|
||||
|
||||
if (byteItem != nullptr) {
|
||||
byteItem->stackMemory = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* groupItem = dynamic_cast<GroupItem*>(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<float>(stackSize) / static_cast<float>(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<int>(heightOffset - 5);
|
||||
const auto verticalLineYEnd = static_cast<int>(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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
#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<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
std::unordered_map<Targets::TargetMemoryAddress, ByteItem>& 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<FocusedRegionGroupItem> focusedRegionGroupItems;
|
||||
};
|
||||
}
|
||||
@@ -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<std::int64_t>(this->hexViewerState.memoryDescriptor.addressRange.endAddress)
|
||||
- static_cast<std::int64_t>(*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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
|
||||
#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<FocusedRegionGroupItem> focusedRegionGroupItems;
|
||||
std::optional<StackMemoryGroupItem> stackMemoryGroupItem;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SvgToolButton" name="highlight-stack-memory-btn">
|
||||
<widget class="SvgToolButton" name="group-stack-memory-btn">
|
||||
<!--
|
||||
This button is hidden by default. Only to be displayed for the RAM inspection pane.
|
||||
-->
|
||||
@@ -60,7 +60,7 @@
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Images/highlight-stack-memory-disabled.svg</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Highlight Stack Memory</string>
|
||||
<string>Group Stack Memory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
Reference in New Issue
Block a user