Removed using namespace directive for class member function definitions in source files

This commit is contained in:
Nav
2022-02-05 15:32:08 +00:00
parent 9bbc534973
commit 53a3c815d7
116 changed files with 13113 additions and 12664 deletions

View File

@@ -4,109 +4,115 @@
#include "ByteItem.hpp"
using namespace Bloom::Widgets;
AnnotationItem::AnnotationItem(
std::uint32_t startAddress,
std::size_t size,
QString labelText,
AnnotationItemPosition position
):
QGraphicsItem(nullptr),
startAddress(startAddress),
size(size),
endAddress(static_cast<std::uint32_t>(startAddress + size - 1)),
labelText(std::move(labelText)),
position(position),
width(static_cast<int>((ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) * size - ByteItem::RIGHT_MARGIN)),
height(position == AnnotationItemPosition::TOP ? AnnotationItem::TOP_HEIGHT : AnnotationItem::BOTTOM_HEIGHT
) {
this->setAcceptHoverEvents(true);
this->setToolTip(this->labelText);
}
AnnotationItem::AnnotationItem(
const Targets::TargetMemoryAddressRange& addressRange,
const QString& labelText,
AnnotationItemPosition position
): AnnotationItem(
addressRange.startAddress,
addressRange.endAddress - addressRange.startAddress + 1,
labelText,
position
) {}
AnnotationItem::AnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion, AnnotationItemPosition position)
: AnnotationItem(
focusedMemoryRegion.addressRange,
focusedMemoryRegion.name,
position
) {}
void AnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
auto lineColor = this->getLineColor();
auto labelFontColor = this->getLabelFontColor();
auto font = painter->font();
font.setPixelSize(this->getLabelFontSize());
painter->setFont(font);
const auto isEnabled = this->isEnabled();
lineColor.setAlpha(isEnabled ? 255 : 100);
labelFontColor.setAlpha(isEnabled ? 255 : 100);
const auto fontMetrics = painter->fontMetrics();
auto labelSize = fontMetrics.size(Qt::TextSingleLine, this->labelText);
if (labelSize.width() > this->width) {
labelSize.setWidth(this->width);
this->labelText = fontMetrics.elidedText(this->labelText, Qt::TextElideMode::ElideRight, this->width);
namespace Bloom::Widgets
{
AnnotationItem::AnnotationItem(
std::uint32_t startAddress,
std::size_t size,
QString labelText,
AnnotationItemPosition position
):
QGraphicsItem(nullptr),
startAddress(startAddress),
size(size),
endAddress(static_cast<std::uint32_t>(startAddress + size - 1)),
labelText(std::move(labelText)),
position(position),
width(static_cast<int>((ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) * size - ByteItem::RIGHT_MARGIN)),
height(position == AnnotationItemPosition::TOP ? AnnotationItem::TOP_HEIGHT : AnnotationItem::BOTTOM_HEIGHT
) {
this->setAcceptHoverEvents(true);
this->setToolTip(this->labelText);
}
constexpr auto verticalLineLength = 5;
const auto verticalLineYStart = this->position == AnnotationItemPosition::BOTTOM ? 0 : AnnotationItem::TOP_HEIGHT;
const auto verticalLineYEnd = this->position == AnnotationItemPosition::BOTTOM ?
verticalLineLength : AnnotationItem::TOP_HEIGHT - verticalLineLength;
AnnotationItem::AnnotationItem(
const Targets::TargetMemoryAddressRange& addressRange,
const QString& labelText,
AnnotationItemPosition position
): AnnotationItem(
addressRange.startAddress,
addressRange.endAddress - addressRange.startAddress + 1,
labelText,
position
) {}
const auto labelRect = QRect(
(this->width - labelSize.width()) / 2,
verticalLineYEnd - (this->position == AnnotationItemPosition::BOTTOM ? -6: labelSize.height() + 6),
labelSize.width(),
labelSize.height()
);
AnnotationItem::AnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion, AnnotationItemPosition position)
: AnnotationItem(
focusedMemoryRegion.addressRange,
focusedMemoryRegion.name,
position
) {}
painter->setPen(lineColor);
void AnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
auto lineColor = this->getLineColor();
auto labelFontColor = this->getLabelFontColor();
if (this->size > 1) {
painter->drawLine(QLine(
ByteItem::WIDTH / 2,
verticalLineYStart,
ByteItem::WIDTH / 2,
verticalLineYEnd
));
auto font = painter->font();
font.setPixelSize(this->getLabelFontSize());
painter->setFont(font);
const auto isEnabled = this->isEnabled();
lineColor.setAlpha(isEnabled ? 255 : 100);
labelFontColor.setAlpha(isEnabled ? 255 : 100);
const auto fontMetrics = painter->fontMetrics();
auto labelSize = fontMetrics.size(Qt::TextSingleLine, this->labelText);
if (labelSize.width() > this->width) {
labelSize.setWidth(this->width);
this->labelText = fontMetrics.elidedText(
this->labelText,
Qt::TextElideMode::ElideRight,
this->width
);
}
constexpr auto verticalLineLength = 5;
const auto verticalLineYStart = this->position == AnnotationItemPosition::BOTTOM ? 0
: AnnotationItem::TOP_HEIGHT;
const auto verticalLineYEnd = this->position == AnnotationItemPosition::BOTTOM ?
verticalLineLength : AnnotationItem::TOP_HEIGHT - verticalLineLength;
const auto labelRect = QRect(
(this->width - labelSize.width()) / 2,
verticalLineYEnd - (this->position == AnnotationItemPosition::BOTTOM ? -6: labelSize.height() + 6),
labelSize.width(),
labelSize.height()
);
painter->setPen(lineColor);
if (this->size > 1) {
painter->drawLine(QLine(
ByteItem::WIDTH / 2,
verticalLineYStart,
ByteItem::WIDTH / 2,
verticalLineYEnd
));
painter->drawLine(QLine(
this->width - (ByteItem::WIDTH / 2),
verticalLineYStart,
this->width - (ByteItem::WIDTH / 2),
verticalLineYEnd
));
painter->drawLine(QLine(
ByteItem::WIDTH / 2,
verticalLineYEnd,
(ByteItem::WIDTH / 2) + (this->width - ByteItem::WIDTH),
verticalLineYEnd
));
}
painter->drawLine(QLine(
this->width - (ByteItem::WIDTH / 2),
verticalLineYStart,
this->width - (ByteItem::WIDTH / 2),
verticalLineYEnd
));
painter->drawLine(QLine(
ByteItem::WIDTH / 2,
this->width / 2,
verticalLineYEnd,
(ByteItem::WIDTH / 2) + (this->width - ByteItem::WIDTH),
verticalLineYEnd
this->width / 2,
(this->position == AnnotationItemPosition::BOTTOM ? verticalLineYEnd + 4 : verticalLineYEnd - 4)
));
painter->setPen(labelFontColor);
painter->drawText(labelRect, Qt::AlignCenter, this->labelText);
}
painter->drawLine(QLine(
this->width / 2,
verticalLineYEnd,
this->width / 2,
(this->position == AnnotationItemPosition::BOTTOM ? verticalLineYEnd + 4 : verticalLineYEnd - 4)
));
painter->setPen(labelFontColor);
painter->drawText(labelRect, Qt::AlignCenter, this->labelText);
}

View File

@@ -1,71 +1,72 @@
#include "ByteAddressContainer.hpp"
using namespace Bloom::Widgets;
namespace Bloom::Widgets
{
void ByteAddressContainer::adjustAddressLabels(
const std::map<std::size_t, std::vector<ByteItem*>>& byteItemsByRowIndex
) {
static const auto margins = QMargins(0, 10, 0, 0);
void ByteAddressContainer::adjustAddressLabels(
const std::map<std::size_t, std::vector<ByteItem*>>& byteItemsByRowIndex
) {
static const auto margins = QMargins(0, 10, 0, 0);
const auto newRowCount = byteItemsByRowIndex.size();
const auto layoutItemMaxIndex = static_cast<int>(this->addressItemsByRowIndex.size() - 1);
const auto newRowCount = byteItemsByRowIndex.size();
const auto layoutItemMaxIndex = static_cast<int>(this->addressItemsByRowIndex.size() - 1);
for (const auto& mappingPair : byteItemsByRowIndex) {
const auto rowIndex = static_cast<std::size_t>(mappingPair.first);
const auto& byteItems = mappingPair.second;
for (const auto& mappingPair : byteItemsByRowIndex) {
const auto rowIndex = static_cast<std::size_t>(mappingPair.first);
const auto& byteItems = mappingPair.second;
if (byteItems.empty()) {
continue;
}
if (byteItems.empty()) {
continue;
ByteAddressItem* addressLabel = nullptr;
if (static_cast<int>(rowIndex) > layoutItemMaxIndex) {
addressLabel = new ByteAddressItem(this);
this->addressItemsByRowIndex.insert(std::pair(rowIndex, addressLabel));
} else {
addressLabel = this->addressItemsByRowIndex.at(rowIndex);
}
const auto& firstByteItem = byteItems.front();
addressLabel->setAddressHex(firstByteItem->relativeAddressHex);
addressLabel->setPos(
0,
firstByteItem->pos().y()
);
}
ByteAddressItem* addressLabel = nullptr;
if (static_cast<int>(rowIndex) > layoutItemMaxIndex) {
addressLabel = new ByteAddressItem(this);
this->addressItemsByRowIndex.insert(std::pair(rowIndex, addressLabel));
// Delete any address items we no longer need
const auto addressItemCount = this->addressItemsByRowIndex.size();
} else {
addressLabel = this->addressItemsByRowIndex.at(rowIndex);
if (newRowCount > 0 && newRowCount < addressItemCount) {
for (auto i = (addressItemCount - 1); i >= newRowCount; i--) {
delete this->addressItemsByRowIndex.at(i);
this->addressItemsByRowIndex.erase(i);
}
}
const auto& firstByteItem = byteItems.front();
addressLabel->setAddressHex(firstByteItem->relativeAddressHex);
addressLabel->setPos(
this->update();
}
void ByteAddressContainer::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
static const auto backgroundColor = QColor(0x35, 0x36, 0x33);
static const auto borderColor = QColor(0x41, 0x42, 0x3F);
painter->setPen(Qt::PenStyle::NoPen);
painter->setBrush(backgroundColor);
painter->drawRect(
0,
firstByteItem->pos().y()
0,
ByteAddressContainer::WIDTH,
static_cast<int>(this->boundingRect().height())
);
painter->setPen(borderColor);
painter->drawLine(
ByteAddressContainer::WIDTH - 1,
0,
ByteAddressContainer::WIDTH - 1,
static_cast<int>(this->boundingRect().height())
);
}
// Delete any address items we no longer need
const auto addressItemCount = this->addressItemsByRowIndex.size();
if (newRowCount > 0 && newRowCount < addressItemCount) {
for (auto i = (addressItemCount - 1); i >= newRowCount; i--) {
delete this->addressItemsByRowIndex.at(i);
this->addressItemsByRowIndex.erase(i);
}
}
this->update();
}
void ByteAddressContainer::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
static const auto backgroundColor = QColor(0x35, 0x36, 0x33);
static const auto borderColor = QColor(0x41, 0x42, 0x3F);
painter->setPen(Qt::PenStyle::NoPen);
painter->setBrush(backgroundColor);
painter->drawRect(
0,
0,
ByteAddressContainer::WIDTH,
static_cast<int>(this->boundingRect().height())
);
painter->setPen(borderColor);
painter->drawLine(
ByteAddressContainer::WIDTH - 1,
0,
ByteAddressContainer::WIDTH - 1,
static_cast<int>(this->boundingRect().height())
);
}

View File

@@ -1,28 +1,31 @@
#include "ByteAddressItem.hpp"
#include <QPainter>
#include <QStyle>
using namespace Bloom::Widgets;
namespace Bloom::Widgets
{
void ByteAddressItem::setAddressHex(const QString& addressHex) {
this->setCacheMode(
QGraphicsItem::CacheMode::ItemCoordinateCache,
QSize(ByteAddressItem::WIDTH, ByteAddressItem::HEIGHT)
);
this->addressHex = addressHex;
}
void ByteAddressItem::setAddressHex(const QString& addressHex) {
this->setCacheMode(
QGraphicsItem::CacheMode::ItemCoordinateCache,
QSize(ByteAddressItem::WIDTH, ByteAddressItem::HEIGHT)
);
this->addressHex = addressHex;
}
void ByteAddressItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
static const auto widgetRect = this->boundingRect();
static auto fontColor = QColor(0x8F, 0x91, 0x92);
static auto font = QFont("'Ubuntu', sans-serif");
font.setPixelSize(12);
fontColor.setAlpha(!this->isEnabled() ? 100 : 255);
painter->setFont(font);
painter->setPen(fontColor);
painter->drawText(widgetRect, Qt::AlignCenter, this->addressHex);
void ByteAddressItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
painter->setRenderHints(
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
true
);
static const auto widgetRect = this->boundingRect();
static auto fontColor = QColor(0x8F, 0x91, 0x92);
static auto font = QFont("'Ubuntu', sans-serif");
font.setPixelSize(12);
fontColor.setAlpha(!this->isEnabled() ? 100 : 255);
painter->setFont(font);
painter->setPen(fontColor);
painter->drawText(widgetRect, Qt::AlignCenter, this->addressHex);
}
}

View File

@@ -1,166 +1,175 @@
#include "ByteItem.hpp"
#include <QPainter>
#include <QStyle>
using namespace Bloom::Widgets;
ByteItem::ByteItem(
std::size_t byteIndex,
std::uint32_t address,
std::optional<std::uint32_t>& currentStackPointer,
std::optional<ByteItem*>& hoveredByteItem,
std::optional<AnnotationItem*>& hoveredAnnotationItem,
std::set<std::uint32_t>& highlightedAddresses,
const HexViewerWidgetSettings& settings
):
QGraphicsItem(nullptr),
byteIndex(byteIndex),
address(address),
currentStackPointer(currentStackPointer),
hoveredByteItem(hoveredByteItem),
hoveredAnnotationItem(hoveredAnnotationItem),
highlightedAddresses(highlightedAddresses),
settings(settings)
namespace Bloom::Widgets
{
this->setCacheMode(
QGraphicsItem::CacheMode::ItemCoordinateCache,
QSize(ByteItem::WIDTH, ByteItem::HEIGHT)
);
this->setAcceptHoverEvents(true);
ByteItem::ByteItem(
std::size_t byteIndex,
std::uint32_t address,
std::optional<std::uint32_t>& currentStackPointer,
std::optional<ByteItem*>& hoveredByteItem,
std::optional<AnnotationItem*>& hoveredAnnotationItem,
std::set<std::uint32_t>& highlightedAddresses,
const HexViewerWidgetSettings& settings
)
: QGraphicsItem(nullptr)
, byteIndex(byteIndex)
, address(address)
, currentStackPointer(currentStackPointer)
, hoveredByteItem(hoveredByteItem)
, hoveredAnnotationItem(hoveredAnnotationItem)
, highlightedAddresses(highlightedAddresses)
, settings(settings)
{
this->setCacheMode(
QGraphicsItem::CacheMode::ItemCoordinateCache,
QSize(ByteItem::WIDTH, ByteItem::HEIGHT)
);
this->setAcceptHoverEvents(true);
this->addressHex = "0x" + QString::number(this->address, 16).rightJustified(8, '0').toUpper();
this->relativeAddressHex = "0x" + QString::number(this->byteIndex, 16).rightJustified(8, '0').toUpper();
this->addressHex = "0x" + QString::number(this->address, 16).rightJustified(
8,
'0'
).toUpper();
this->relativeAddressHex = "0x" + QString::number(this->byteIndex, 16).rightJustified(
8,
'0'
).toUpper();
this->setSelected(false);
}
void ByteItem::setValue(unsigned char value) {
this->valueChanged = this->valueInitialised && this->value != value;
this->value = value;
this->hexValue = QString::number(this->value, 16).rightJustified(2, '0').toUpper();
this->asciiValue = (this->value >= 32 && this->value <= 126)
? std::optional("'" + QString(QChar(this->value)) + "'") : std::nullopt;
this->valueInitialised = this->excludedMemoryRegion == nullptr;
this->update();
}
void ByteItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
painter->setPen(Qt::PenStyle::NoPen);
// TODO: This code could do with some tidying. It's getting quite messy.
static const auto widgetRect = this->boundingRect();
static const auto standardTextColor = QColor(0xAF, 0xB1, 0xB3);
static const auto valueChangedTextColor = QColor(0x54, 0x7F, 0xBA);
static auto font = QFont("'Ubuntu', sans-serif");
static const auto highlightedBackgroundColor = QColor(0x3C, 0x59, 0x5C, 255);
static const auto focusedRegionBackgroundColor = QColor(0x44, 0x44, 0x41, 255);
static const auto stackMemoryBackgroundColor = QColor(0x67, 0x57, 0x20, 210);
static const auto hoveredBackgroundColor = QColor(0x8E, 0x8B, 0x83, 70);
static const auto hoveredNeighbourBackgroundColor = QColor(0x8E, 0x8B, 0x83, 30);
static const auto hoveredAnnotationBackgroundColor = QColor(0x8E, 0x8B, 0x83, 50);
const auto isEnabled = this->isEnabled();
const auto highlightingEnabled = !this->highlightedAddresses.empty();
const auto highlightedByte = highlightingEnabled && this->highlightedAddresses.contains(this->address);
auto textColor = standardTextColor;
auto asciiTextColor = QColor(0xA7, 0x77, 0x26);
auto backgroundColor = std::optional<QColor>();
font.setPixelSize(11);
painter->setFont(font);
if (highlightedByte) {
backgroundColor = highlightedBackgroundColor;
asciiTextColor = standardTextColor;
} else if (this->settings.highlightStackMemory && this->currentStackPointer.has_value()
&& this->address > this->currentStackPointer
) {
// This byte is within the stack memory
backgroundColor = stackMemoryBackgroundColor;
asciiTextColor = standardTextColor;
} else if (this->settings.highlightFocusedMemory && this->focusedMemoryRegion != nullptr) {
// This byte is within a focused region
backgroundColor = focusedRegionBackgroundColor;
this->setSelected(false);
}
const auto* hoveredByteItem = this->hoveredByteItem.value_or(nullptr);
const auto* hoveredAnnotationItem = this->hoveredAnnotationItem.value_or(nullptr);
if (hoveredByteItem != nullptr) {
if (hoveredByteItem == this) {
if (backgroundColor.has_value()) {
backgroundColor->setAlpha(255);
void ByteItem::setValue(unsigned char value) {
this->valueChanged = this->valueInitialised && this->value != value;
} else {
backgroundColor = hoveredBackgroundColor;
}
this->value = value;
this->hexValue = QString::number(this->value, 16).rightJustified(2, '0').toUpper();
this->asciiValue = (this->value >= 32 && this->value <= 126)
? std::optional("'" + QString(QChar(this->value)) + "'") : std::nullopt;
} else if (this->settings.highlightHoveredRowAndCol
&& (
hoveredByteItem->currentColumnIndex == this->currentColumnIndex
|| hoveredByteItem->currentRowIndex == this->currentRowIndex
)
this->valueInitialised = this->excludedMemoryRegion == nullptr;
this->update();
}
void ByteItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
painter->setRenderHints(
QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform,
true
);
painter->setPen(Qt::PenStyle::NoPen);
// TODO: This code could do with some tidying. It's getting quite messy.
static const auto widgetRect = this->boundingRect();
static const auto standardTextColor = QColor(0xAF, 0xB1, 0xB3);
static const auto valueChangedTextColor = QColor(0x54, 0x7F, 0xBA);
static auto font = QFont("'Ubuntu', sans-serif");
static const auto highlightedBackgroundColor = QColor(0x3C, 0x59, 0x5C, 255);
static const auto focusedRegionBackgroundColor = QColor(0x44, 0x44, 0x41, 255);
static const auto stackMemoryBackgroundColor = QColor(0x67, 0x57, 0x20, 210);
static const auto hoveredBackgroundColor = QColor(0x8E, 0x8B, 0x83, 70);
static const auto hoveredNeighbourBackgroundColor = QColor(0x8E, 0x8B, 0x83, 30);
static const auto hoveredAnnotationBackgroundColor = QColor(0x8E, 0x8B, 0x83, 50);
const auto isEnabled = this->isEnabled();
const auto highlightingEnabled = !this->highlightedAddresses.empty();
const auto highlightedByte = highlightingEnabled && this->highlightedAddresses.contains(this->address);
auto textColor = standardTextColor;
auto asciiTextColor = QColor(0xA7, 0x77, 0x26);
auto backgroundColor = std::optional<QColor>();
font.setPixelSize(11);
painter->setFont(font);
if (highlightedByte) {
backgroundColor = highlightedBackgroundColor;
asciiTextColor = standardTextColor;
} else if (this->settings.highlightStackMemory && this->currentStackPointer.has_value()
&& this->address > this->currentStackPointer
) {
if (backgroundColor.has_value()) {
backgroundColor->setAlpha(220);
// This byte is within the stack memory
backgroundColor = stackMemoryBackgroundColor;
asciiTextColor = standardTextColor;
} else if (this->settings.highlightFocusedMemory && this->focusedMemoryRegion != nullptr) {
// This byte is within a focused region
backgroundColor = focusedRegionBackgroundColor;
}
const auto* hoveredByteItem = this->hoveredByteItem.value_or(nullptr);
const auto* hoveredAnnotationItem = this->hoveredAnnotationItem.value_or(nullptr);
if (hoveredByteItem != nullptr) {
if (hoveredByteItem == this) {
if (backgroundColor.has_value()) {
backgroundColor->setAlpha(255);
} else {
backgroundColor = hoveredBackgroundColor;
}
} else if (this->settings.highlightHoveredRowAndCol
&& (
hoveredByteItem->currentColumnIndex == this->currentColumnIndex
|| hoveredByteItem->currentRowIndex == this->currentRowIndex
)
) {
if (backgroundColor.has_value()) {
backgroundColor->setAlpha(220);
} else {
backgroundColor = hoveredNeighbourBackgroundColor;
}
}
} else if (
!this->settings.highlightFocusedMemory
&& hoveredAnnotationItem != nullptr
&& this->address >= hoveredAnnotationItem->startAddress
&& this->address <= hoveredAnnotationItem->endAddress
) {
backgroundColor = hoveredAnnotationBackgroundColor;
}
if (backgroundColor.has_value()) {
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
backgroundColor->setAlpha(100);
}
painter->setBrush(backgroundColor.value());
painter->drawRect(widgetRect);
}
if (this->valueInitialised && this->excludedMemoryRegion == nullptr) {
if (this->settings.displayAsciiValues && this->asciiValue.has_value()) {
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
asciiTextColor.setAlpha(100);
}
painter->setPen(asciiTextColor);
painter->drawText(widgetRect, Qt::AlignCenter, this->asciiValue.value());
} else {
backgroundColor = hoveredNeighbourBackgroundColor;
if (!isEnabled || (highlightingEnabled && !highlightedByte) || this->settings.displayAsciiValues) {
textColor.setAlpha(100);
}
painter->setPen(textColor);
painter->drawText(widgetRect, Qt::AlignCenter, this->hexValue);
return;
}
}
} else if (
!this->settings.highlightFocusedMemory
&& hoveredAnnotationItem != nullptr
&& this->address >= hoveredAnnotationItem->startAddress
&& this->address <= hoveredAnnotationItem->endAddress
) {
backgroundColor = hoveredAnnotationBackgroundColor;
}
if (backgroundColor.has_value()) {
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
backgroundColor->setAlpha(100);
}
painter->setBrush(backgroundColor.value());
painter->drawRect(widgetRect);
}
if (this->valueInitialised && this->excludedMemoryRegion == nullptr) {
if (this->settings.displayAsciiValues && this->asciiValue.has_value()) {
if (!isEnabled || (highlightingEnabled && !highlightedByte)) {
asciiTextColor.setAlpha(100);
}
painter->setPen(asciiTextColor);
painter->drawText(widgetRect, Qt::AlignCenter, this->asciiValue.value());
} else {
if (!isEnabled || (highlightingEnabled && !highlightedByte) || this->settings.displayAsciiValues) {
textColor.setAlpha(100);
}
textColor.setAlpha(100);
painter->setPen(textColor);
painter->drawText(widgetRect, Qt::AlignCenter, this->hexValue);
return;
static const auto placeholderString = QString("??");
painter->drawText(widgetRect, Qt::AlignCenter, placeholderString);
}
} else {
textColor.setAlpha(100);
painter->setPen(textColor);
static const auto placeholderString = QString("??");
painter->drawText(widgetRect, Qt::AlignCenter, placeholderString);
}
}

View File

@@ -1,53 +1,54 @@
#include "ByteItemContainerGraphicsView.hpp"
using namespace Bloom::Widgets;
namespace Bloom::Widgets
{
using Bloom::Targets::TargetMemoryDescriptor;
using Bloom::Targets::TargetMemoryDescriptor;
ByteItemContainerGraphicsView::ByteItemContainerGraphicsView(
const TargetMemoryDescriptor& targetMemoryDescriptor,
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
InsightWorker& insightWorker,
const HexViewerWidgetSettings& settings,
QLabel* hoveredAddressLabel,
QWidget* parent
): QGraphicsView(parent) {
this->setObjectName("graphics-view");
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
this->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
ByteItemContainerGraphicsView::ByteItemContainerGraphicsView(
const TargetMemoryDescriptor& targetMemoryDescriptor,
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
InsightWorker& insightWorker,
const HexViewerWidgetSettings& settings,
QLabel* hoveredAddressLabel,
QWidget* parent
): QGraphicsView(parent) {
this->setObjectName("graphics-view");
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
this->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
this->scene = new ByteItemGraphicsScene(
targetMemoryDescriptor,
focusedMemoryRegions,
excludedMemoryRegions,
insightWorker,
settings,
hoveredAddressLabel,
this
);
this->scene = new ByteItemGraphicsScene(
targetMemoryDescriptor,
focusedMemoryRegions,
excludedMemoryRegions,
insightWorker,
settings,
hoveredAddressLabel,
this
);
this->setScene(this->scene);
this->setScene(this->scene);
}
void ByteItemContainerGraphicsView::scrollToByteItemAtAddress(std::uint32_t address) {
this->centerOn(this->scene->getByteItemPositionByAddress(address));
}
bool ByteItemContainerGraphicsView::event(QEvent* event) {
const auto eventType = event->type();
if (eventType == QEvent::Type::EnabledChange) {
this->scene->setEnabled(this->isEnabled());
}
return QGraphicsView::event(event);
}
void ByteItemContainerGraphicsView::scrollToByteItemAtAddress(std::uint32_t address) {
this->centerOn(this->scene->getByteItemPositionByAddress(address));
}
void ByteItemContainerGraphicsView::resizeEvent(QResizeEvent* event) {
QGraphicsView::resizeEvent(event);
this->scene->adjustSize();
bool ByteItemContainerGraphicsView::event(QEvent* event) {
const auto eventType = event->type();
if (eventType == QEvent::Type::EnabledChange) {
this->scene->setEnabled(this->isEnabled());
}
return QGraphicsView::event(event);
}
void ByteItemContainerGraphicsView::resizeEvent(QResizeEvent* event) {
QGraphicsView::resizeEvent(event);
this->scene->adjustSize();
}
}

View File

@@ -2,494 +2,497 @@
#include <cmath>
using namespace Bloom::Widgets;
using Bloom::Targets::TargetMemoryDescriptor;
ByteItemGraphicsScene::ByteItemGraphicsScene(
const TargetMemoryDescriptor& targetMemoryDescriptor,
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
InsightWorker& insightWorker,
const HexViewerWidgetSettings& settings,
QLabel* hoveredAddressLabel,
QGraphicsView* parent
):
QGraphicsScene(parent),
targetMemoryDescriptor(targetMemoryDescriptor),
focusedMemoryRegions(focusedMemoryRegions),
excludedMemoryRegions(excludedMemoryRegions),
insightWorker(insightWorker),
settings(settings),
hoveredAddressLabel(hoveredAddressLabel),
parent(parent)
namespace Bloom::Widgets
{
this->setObjectName("byte-widget-container");
using Bloom::Targets::TargetMemoryDescriptor;
this->byteAddressContainer = new ByteAddressContainer();
this->addItem(this->byteAddressContainer);
ByteItemGraphicsScene::ByteItemGraphicsScene(
const TargetMemoryDescriptor& targetMemoryDescriptor,
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
InsightWorker& insightWorker,
const HexViewerWidgetSettings& settings,
QLabel* hoveredAddressLabel,
QGraphicsView* parent
)
: QGraphicsScene(parent)
, targetMemoryDescriptor(targetMemoryDescriptor)
, focusedMemoryRegions(focusedMemoryRegions)
, excludedMemoryRegions(excludedMemoryRegions)
, insightWorker(insightWorker)
, settings(settings)
, hoveredAddressLabel(hoveredAddressLabel)
, parent(parent)
{
this->setObjectName("byte-widget-container");
// Construct ByteWidget objects
const auto memorySize = this->targetMemoryDescriptor.size();
const auto startAddress = this->targetMemoryDescriptor.addressRange.startAddress;
for (std::uint32_t i = 0; i < memorySize; i++) {
const auto address = startAddress + i;
this->byteAddressContainer = new ByteAddressContainer();
this->addItem(this->byteAddressContainer);
auto* byteWidget = new ByteItem(
i,
address,
this->currentStackPointer,
this->hoveredByteWidget,
this->hoveredAnnotationItem,
this->highlightedAddresses,
settings
// Construct ByteWidget objects
const auto memorySize = this->targetMemoryDescriptor.size();
const auto startAddress = this->targetMemoryDescriptor.addressRange.startAddress;
for (std::uint32_t i = 0; i < memorySize; i++) {
const auto address = startAddress + i;
auto* byteWidget = new ByteItem(
i,
address,
this->currentStackPointer,
this->hoveredByteWidget,
this->hoveredAnnotationItem,
this->highlightedAddresses,
settings
);
this->byteItemsByAddress.insert(std::pair(
address,
byteWidget
));
this->addItem(byteWidget);
}
QObject::connect(
&insightWorker,
&InsightWorker::targetStateUpdated,
this,
&ByteItemGraphicsScene::onTargetStateChanged
);
this->byteItemsByAddress.insert(std::pair(
address,
byteWidget
));
this->addItem(byteWidget);
this->refreshRegions();
this->adjustSize();
}
QObject::connect(
&insightWorker,
&InsightWorker::targetStateUpdated,
this,
&ByteItemGraphicsScene::onTargetStateChanged
);
void ByteItemGraphicsScene::updateValues(const Targets::TargetMemoryBuffer& buffer) {
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
byteWidget->setValue(buffer.at(byteWidget->byteIndex));
}
this->refreshRegions();
this->adjustSize();
}
void ByteItemGraphicsScene::updateValues(const Targets::TargetMemoryBuffer& buffer) {
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
byteWidget->setValue(buffer.at(byteWidget->byteIndex));
this->updateAnnotationValues(buffer);
this->lastValueBuffer = buffer;
}
this->updateAnnotationValues(buffer);
this->lastValueBuffer = buffer;
}
void ByteItemGraphicsScene::updateStackPointer(std::uint32_t stackPointer) {
this->currentStackPointer = stackPointer;
this->invalidateChildItemCaches();
}
void ByteItemGraphicsScene::updateStackPointer(std::uint32_t stackPointer) {
this->currentStackPointer = stackPointer;
this->invalidateChildItemCaches();
}
void ByteItemGraphicsScene::setHighlightedAddresses(const std::set<std::uint32_t>& highlightedAddresses) {
this->highlightedAddresses = highlightedAddresses;
this->invalidateChildItemCaches();
}
void ByteItemGraphicsScene::setHighlightedAddresses(const std::set<std::uint32_t>& highlightedAddresses) {
this->highlightedAddresses = highlightedAddresses;
this->invalidateChildItemCaches();
}
void ByteItemGraphicsScene::refreshRegions() {
for (auto& [byteAddress, byteWidget] : this->byteItemsByAddress) {
byteWidget->focusedMemoryRegion = nullptr;
byteWidget->excludedMemoryRegion = nullptr;
void ByteItemGraphicsScene::refreshRegions() {
for (auto& [byteAddress, byteWidget] : this->byteItemsByAddress) {
byteWidget->focusedMemoryRegion = nullptr;
byteWidget->excludedMemoryRegion = nullptr;
for (const auto& focusedRegion : this->focusedMemoryRegions) {
if (byteAddress >= focusedRegion.addressRange.startAddress
&& byteAddress <= focusedRegion.addressRange.endAddress
) {
byteWidget->focusedMemoryRegion = &focusedRegion;
break;
}
}
for (const auto& excludedRegion : this->excludedMemoryRegions) {
if (byteAddress >= excludedRegion.addressRange.startAddress
&& byteAddress <= excludedRegion.addressRange.endAddress
) {
byteWidget->excludedMemoryRegion = &excludedRegion;
break;
}
}
byteWidget->update();
}
// Refresh annotation items
this->hoveredAnnotationItem = std::nullopt;
for (auto* annotationItem : this->annotationItems) {
this->removeItem(annotationItem);
delete annotationItem;
}
this->annotationItems.clear();
this->valueAnnotationItems.clear();
for (const auto& focusedRegion : this->focusedMemoryRegions) {
if (byteAddress >= focusedRegion.addressRange.startAddress
&& byteAddress <= focusedRegion.addressRange.endAddress
) {
byteWidget->focusedMemoryRegion = &focusedRegion;
break;
auto* annotationItem = new AnnotationItem(focusedRegion, AnnotationItemPosition::BOTTOM);
annotationItem->setEnabled(this->enabled);
this->addItem(annotationItem);
this->annotationItems.emplace_back(annotationItem);
if (focusedRegion.dataType != MemoryRegionDataType::UNKNOWN) {
auto* valueAnnotationItem = new ValueAnnotationItem(focusedRegion);
valueAnnotationItem->setEnabled(this->enabled);
this->addItem(valueAnnotationItem);
this->annotationItems.emplace_back(valueAnnotationItem);
this->valueAnnotationItems.emplace_back(valueAnnotationItem);
}
}
for (const auto& excludedRegion : this->excludedMemoryRegions) {
if (byteAddress >= excludedRegion.addressRange.startAddress
&& byteAddress <= excludedRegion.addressRange.endAddress
) {
byteWidget->excludedMemoryRegion = &excludedRegion;
break;
if (this->targetState == Targets::TargetState::STOPPED && this->enabled && !this->lastValueBuffer.empty()) {
this->updateAnnotationValues(this->lastValueBuffer);
}
this->adjustSize(true);
}
void ByteItemGraphicsScene::adjustSize(bool forced) {
const auto width = this->getSceneWidth();
const auto columnCount = static_cast<std::size_t>(
std::floor(
(width - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH
+ ByteItem::RIGHT_MARGIN) / (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
)
);
const auto rowCount = static_cast<int>(
std::ceil(static_cast<double>(this->byteItemsByAddress.size()) / static_cast<double>(columnCount))
);
// Don't bother recalculating the byte & annotation positions if the number of rows & columns haven't changed.
if (this->byteItemsByAddress.empty()
|| (
!forced
&& rowCount == this->byteItemsByRowIndex.size()
&& columnCount == this->byteItemsByColumnIndex.size()
)
) {
this->setSceneRect(
0,
0,
width,
std::max(static_cast<int>(this->sceneRect().height()), this->parent->viewport()->height())
);
return;
}
if (!this->byteItemsByAddress.empty()) {
this->adjustByteItemPositions();
if (this->settings.displayAnnotations) {
this->adjustAnnotationItemPositions();
}
const auto* lastByteItem = (--this->byteItemsByAddress.end())->second;
const auto sceneHeight = static_cast<int>(
lastByteItem->pos().y() + ByteItem::HEIGHT + AnnotationItem::BOTTOM_HEIGHT + this->margins.bottom()
);
this->setSceneRect(
0,
0,
width,
std::max(sceneHeight, this->parent->height())
);
}
byteWidget->update();
this->update();
}
// Refresh annotation items
this->hoveredAnnotationItem = std::nullopt;
for (auto* annotationItem : this->annotationItems) {
this->removeItem(annotationItem);
delete annotationItem;
}
void ByteItemGraphicsScene::setEnabled(bool enabled) {
if (this->enabled != enabled) {
this->enabled = enabled;
this->annotationItems.clear();
this->valueAnnotationItems.clear();
for (auto& [byteAddress, byteItem] : this->byteItemsByAddress) {
byteItem->setEnabled(this->enabled);
}
for (const auto& focusedRegion : this->focusedMemoryRegions) {
auto* annotationItem = new AnnotationItem(focusedRegion, AnnotationItemPosition::BOTTOM);
annotationItem->setEnabled(this->enabled);
this->addItem(annotationItem);
this->annotationItems.emplace_back(annotationItem);
for (auto* annotationItem : this->annotationItems) {
annotationItem->setEnabled(this->enabled);
}
if (focusedRegion.dataType != MemoryRegionDataType::UNKNOWN) {
auto* valueAnnotationItem = new ValueAnnotationItem(focusedRegion);
valueAnnotationItem->setEnabled(this->enabled);
this->addItem(valueAnnotationItem);
this->annotationItems.emplace_back(valueAnnotationItem);
this->valueAnnotationItems.emplace_back(valueAnnotationItem);
this->byteAddressContainer->setEnabled(enabled);
this->byteAddressContainer->update();
this->update();
}
}
if (this->targetState == Targets::TargetState::STOPPED && this->enabled && !this->lastValueBuffer.empty()) {
this->updateAnnotationValues(this->lastValueBuffer);
}
this->adjustSize(true);
}
void ByteItemGraphicsScene::adjustSize(bool forced) {
const auto width = this->getSceneWidth();
const auto columnCount = static_cast<std::size_t>(
std::floor(
(width - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH + ByteItem::RIGHT_MARGIN)
/ (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
)
);
const auto rowCount = static_cast<int>(
std::ceil(static_cast<double>(this->byteItemsByAddress.size()) / static_cast<double>(columnCount))
);
// Don't bother recalculating the byte item & annotation positions if the number of rows & columns have not changed.
if (this->byteItemsByAddress.empty()
|| (
!forced
&& rowCount == this->byteItemsByRowIndex.size()
&& columnCount == this->byteItemsByColumnIndex.size()
)
) {
this->setSceneRect(
0,
0,
width,
std::max(static_cast<int>(this->sceneRect().height()), this->parent->viewport()->height())
);
return;
}
if (!this->byteItemsByAddress.empty()) {
this->adjustByteItemPositions();
if (this->settings.displayAnnotations) {
this->adjustAnnotationItemPositions();
}
const auto* lastByteItem = (--this->byteItemsByAddress.end())->second;
const auto sceneHeight = static_cast<int>(
lastByteItem->pos().y() + ByteItem::HEIGHT + AnnotationItem::BOTTOM_HEIGHT + this->margins.bottom()
);
this->setSceneRect(
0,
0,
width,
std::max(sceneHeight, this->parent->height())
);
}
this->update();
}
void ByteItemGraphicsScene::setEnabled(bool enabled) {
if (this->enabled != enabled) {
this->enabled = enabled;
for (auto& [byteAddress, byteItem] : this->byteItemsByAddress) {
byteItem->setEnabled(this->enabled);
void ByteItemGraphicsScene::invalidateChildItemCaches() {
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
byteWidget->update();
}
for (auto* annotationItem : this->annotationItems) {
annotationItem->setEnabled(this->enabled);
annotationItem->update();
}
}
QPointF ByteItemGraphicsScene::getByteItemPositionByAddress(std::uint32_t address) {
if (this->byteItemsByAddress.contains(address)) {
return this->byteItemsByAddress.at(address)->pos();
}
this->byteAddressContainer->setEnabled(enabled);
this->byteAddressContainer->update();
this->update();
}
}
void ByteItemGraphicsScene::invalidateChildItemCaches() {
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
byteWidget->update();
return QPointF();
}
for (auto* annotationItem : this->annotationItems) {
annotationItem->update();
}
}
QPointF ByteItemGraphicsScene::getByteItemPositionByAddress(std::uint32_t address) {
if (this->byteItemsByAddress.contains(address)) {
return this->byteItemsByAddress.at(address)->pos();
}
return QPointF();
}
bool ByteItemGraphicsScene::event(QEvent* event) {
if (event->type() == QEvent::Type::GraphicsSceneLeave && this->hoveredByteWidget.has_value()) {
this->onByteWidgetLeave();
}
return QGraphicsScene::event(event);
}
void ByteItemGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
auto hoveredItems = this->items(mouseEvent->scenePos());
ByteItem* hoveredByteItem = nullptr;
AnnotationItem* hoveredAnnotationItem = nullptr;
if (!hoveredItems.empty()) {
hoveredByteItem = dynamic_cast<ByteItem*>(hoveredItems.at(0));
hoveredAnnotationItem = dynamic_cast<AnnotationItem*>(hoveredItems.at(0));
}
if (hoveredByteItem != nullptr) {
this->onByteWidgetEnter(hoveredByteItem);
return;
}
if (this->hoveredByteWidget.has_value()) {
this->onByteWidgetLeave();
}
if (hoveredAnnotationItem != nullptr) {
this->onAnnotationItemEnter(hoveredAnnotationItem);
return;
}
if (this->hoveredAnnotationItem.has_value()) {
this->onAnnotationItemLeave();
}
}
void ByteItemGraphicsScene::updateAnnotationValues(const Targets::TargetMemoryBuffer& buffer) {
const auto memoryStartAddress = this->targetMemoryDescriptor.addressRange.startAddress;
for (auto* valueAnnotationItem : this->valueAnnotationItems) {
if (valueAnnotationItem->size > buffer.size()) {
continue;
bool ByteItemGraphicsScene::event(QEvent* event) {
if (event->type() == QEvent::Type::GraphicsSceneLeave && this->hoveredByteWidget.has_value()) {
this->onByteWidgetLeave();
}
const auto relativeStartAddress = valueAnnotationItem->startAddress - memoryStartAddress;
const auto relativeEndAddress = valueAnnotationItem->endAddress - memoryStartAddress;
valueAnnotationItem->setValue(Targets::TargetMemoryBuffer(
buffer.begin() + relativeStartAddress,
buffer.begin() + relativeEndAddress + 1
));
return QGraphicsScene::event(event);
}
}
void ByteItemGraphicsScene::adjustByteItemPositions() {
const auto columnCount = static_cast<std::size_t>(
std::floor(
(this->getSceneWidth() - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH + ByteItem::RIGHT_MARGIN)
/ (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
)
);
void ByteItemGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
auto hoveredItems = this->items(mouseEvent->scenePos());
ByteItem* hoveredByteItem = nullptr;
AnnotationItem* hoveredAnnotationItem = nullptr;
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByRowIndex;
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByColumnIndex;
if (!hoveredItems.empty()) {
hoveredByteItem = dynamic_cast<ByteItem*>(hoveredItems.at(0));
hoveredAnnotationItem = dynamic_cast<AnnotationItem*>(hoveredItems.at(0));
}
auto rowIndicesWithTopAnnotations = std::set<std::size_t>();
auto rowIndicesWithBottomAnnotations = std::set<std::size_t>();
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
if (hoveredByteItem != nullptr) {
this->onByteWidgetEnter(hoveredByteItem);
return;
}
for (auto* annotationItem : this->annotationItems) {
const auto firstByteRowIndex = static_cast<std::size_t>(
std::ceil(static_cast<double>((annotationItem->startAddress - memoryAddressRange.startAddress) + 1)
/ static_cast<double>(columnCount)) - 1
if (this->hoveredByteWidget.has_value()) {
this->onByteWidgetLeave();
}
if (hoveredAnnotationItem != nullptr) {
this->onAnnotationItemEnter(hoveredAnnotationItem);
return;
}
if (this->hoveredAnnotationItem.has_value()) {
this->onAnnotationItemLeave();
}
}
void ByteItemGraphicsScene::updateAnnotationValues(const Targets::TargetMemoryBuffer& buffer) {
const auto memoryStartAddress = this->targetMemoryDescriptor.addressRange.startAddress;
for (auto* valueAnnotationItem : this->valueAnnotationItems) {
if (valueAnnotationItem->size > buffer.size()) {
continue;
}
const auto relativeStartAddress = valueAnnotationItem->startAddress - memoryStartAddress;
const auto relativeEndAddress = valueAnnotationItem->endAddress - memoryStartAddress;
valueAnnotationItem->setValue(Targets::TargetMemoryBuffer(
buffer.begin() + relativeStartAddress,
buffer.begin() + relativeEndAddress + 1
));
}
}
void ByteItemGraphicsScene::adjustByteItemPositions() {
const auto columnCount = static_cast<std::size_t>(
std::floor(
(this->getSceneWidth() - this->margins.left() - this->margins.right() - ByteAddressContainer::WIDTH
+ ByteItem::RIGHT_MARGIN) / (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN)
)
);
const auto lastByteRowIndex = static_cast<std::size_t>(
std::ceil(static_cast<double>((annotationItem->endAddress - memoryAddressRange.startAddress) + 1)
/ static_cast<double>(columnCount)) - 1
);
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByRowIndex;
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByColumnIndex;
// We only display annotations that span a single row.
if (this->settings.displayAnnotations && firstByteRowIndex == lastByteRowIndex) {
annotationItem->show();
auto rowIndicesWithTopAnnotations = std::set<std::size_t>();
auto rowIndicesWithBottomAnnotations = std::set<std::size_t>();
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
for (auto* annotationItem : this->annotationItems) {
const auto firstByteRowIndex = static_cast<std::size_t>(
std::ceil(static_cast<double>((annotationItem->startAddress - memoryAddressRange.startAddress) + 1)
/ static_cast<double>(columnCount)) - 1
);
const auto lastByteRowIndex = static_cast<std::size_t>(
std::ceil(static_cast<double>((annotationItem->endAddress - memoryAddressRange.startAddress) + 1)
/ static_cast<double>(columnCount)) - 1
);
// We only display annotations that span a single row.
if (this->settings.displayAnnotations && firstByteRowIndex == lastByteRowIndex) {
annotationItem->show();
if (annotationItem->position == AnnotationItemPosition::TOP) {
rowIndicesWithTopAnnotations.insert(firstByteRowIndex);
} else if (annotationItem->position == AnnotationItemPosition::BOTTOM) {
rowIndicesWithBottomAnnotations.insert(firstByteRowIndex);
}
} else {
annotationItem->hide();
}
}
constexpr auto annotationTopHeight = AnnotationItem::TOP_HEIGHT;
constexpr auto annotationBottomHeight = AnnotationItem::BOTTOM_HEIGHT;
std::size_t lastRowIndex = 0;
int rowYPosition = margins.top();
auto currentRowAnnotatedTop = false;
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
const auto rowIndex = static_cast<std::size_t>(
std::ceil(static_cast<double>(byteWidget->byteIndex + 1) / static_cast<double>(columnCount)) - 1
);
const auto columnIndex = static_cast<std::size_t>(
static_cast<double>(byteWidget->byteIndex)
- (std::floor(byteWidget->byteIndex / columnCount) * static_cast<double>(columnCount))
);
if (rowIndex != lastRowIndex) {
rowYPosition += ByteItem::HEIGHT + ByteItem::BOTTOM_MARGIN;
currentRowAnnotatedTop = false;
if (rowIndicesWithBottomAnnotations.contains(lastRowIndex)) {
rowYPosition += annotationBottomHeight;
}
}
if (!currentRowAnnotatedTop && rowIndicesWithTopAnnotations.contains(rowIndex)) {
rowYPosition += annotationTopHeight;
currentRowAnnotatedTop = true;
}
byteWidget->setPos(
static_cast<int>(
columnIndex * (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) + this->margins.left()
+ ByteAddressContainer::WIDTH
),
rowYPosition
);
byteWidget->currentRowIndex = rowIndex;
byteWidget->currentColumnIndex = columnIndex;
byteWidgetsByRowIndex[byteWidget->currentRowIndex].emplace_back(byteWidget);
byteWidgetsByColumnIndex[byteWidget->currentColumnIndex].emplace_back(byteWidget);
lastRowIndex = rowIndex;
}
this->byteItemsByRowIndex = std::move(byteWidgetsByRowIndex);
this->byteItemsByColumnIndex = std::move(byteWidgetsByColumnIndex);
this->byteAddressContainer->adjustAddressLabels(this->byteItemsByRowIndex);
}
void ByteItemGraphicsScene::adjustAnnotationItemPositions() {
if (this->byteItemsByAddress.empty() || !this->settings.displayAnnotations) {
return;
}
for (auto* annotationItem : this->annotationItems) {
if (!this->byteItemsByAddress.contains(annotationItem->startAddress)) {
annotationItem->hide();
continue;
}
const auto firstByteItemPosition = this->byteItemsByAddress.at(annotationItem->startAddress)->pos();
if (annotationItem->position == AnnotationItemPosition::TOP) {
rowIndicesWithTopAnnotations.insert(firstByteRowIndex);
annotationItem->setPos(
firstByteItemPosition.x(),
firstByteItemPosition.y() - AnnotationItem::TOP_HEIGHT - 1
);
} else if (annotationItem->position == AnnotationItemPosition::BOTTOM) {
rowIndicesWithBottomAnnotations.insert(firstByteRowIndex);
annotationItem->setPos(
firstByteItemPosition.x(),
firstByteItemPosition.y() + ByteItem::HEIGHT
);
}
}
}
void ByteItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) {
using Targets::TargetState;
this->targetState = newState;
}
void ByteItemGraphicsScene::onByteWidgetEnter(ByteItem* widget) {
if (this->hoveredByteWidget.has_value()) {
if (this->hoveredByteWidget.value() == widget) {
// This byte item is already marked as hovered
return;
}
this->onByteWidgetLeave();
}
this->hoveredByteWidget = widget;
this->hoveredAddressLabel->setText(
"Relative Address (Absolute Address): " + widget->relativeAddressHex + " (" + widget->addressHex + ")"
);
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
for (auto& byteWidget : this->byteItemsByColumnIndex.at(widget->currentColumnIndex)) {
byteWidget->update();
}
for (auto& byteWidget : this->byteItemsByRowIndex.at(widget->currentRowIndex)) {
byteWidget->update();
}
} else {
annotationItem->hide();
widget->update();
}
}
constexpr auto annotationTopHeight = AnnotationItem::TOP_HEIGHT;
constexpr auto annotationBottomHeight = AnnotationItem::BOTTOM_HEIGHT;
void ByteItemGraphicsScene::onByteWidgetLeave() {
auto* byteItem = this->hoveredByteWidget.value();
this->hoveredByteWidget = std::nullopt;
std::size_t lastRowIndex = 0;
int rowYPosition = margins.top();
auto currentRowAnnotatedTop = false;
this->hoveredAddressLabel->setText("Relative Address (Absolute Address):");
for (auto& [address, byteWidget] : this->byteItemsByAddress) {
const auto rowIndex = static_cast<std::size_t>(
std::ceil(static_cast<double>(byteWidget->byteIndex + 1) / static_cast<double>(columnCount)) - 1
);
const auto columnIndex = static_cast<std::size_t>(
static_cast<double>(byteWidget->byteIndex)
- (std::floor(byteWidget->byteIndex / columnCount) * static_cast<double>(columnCount))
);
if (rowIndex != lastRowIndex) {
rowYPosition += ByteItem::HEIGHT + ByteItem::BOTTOM_MARGIN;
currentRowAnnotatedTop = false;
if (rowIndicesWithBottomAnnotations.contains(lastRowIndex)) {
rowYPosition += annotationBottomHeight;
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
for (auto& byteWidget : this->byteItemsByColumnIndex.at(byteItem->currentColumnIndex)) {
byteWidget->update();
}
for (auto& byteWidget : this->byteItemsByRowIndex.at(byteItem->currentRowIndex)) {
byteWidget->update();
}
} else {
byteItem->update();
}
if (!currentRowAnnotatedTop && rowIndicesWithTopAnnotations.contains(rowIndex)) {
rowYPosition += annotationTopHeight;
currentRowAnnotatedTop = true;
}
byteWidget->setPos(
static_cast<int>(
columnIndex * (ByteItem::WIDTH + ByteItem::RIGHT_MARGIN) + this->margins.left() + ByteAddressContainer::WIDTH),
rowYPosition
);
byteWidget->currentRowIndex = rowIndex;
byteWidget->currentColumnIndex = columnIndex;
byteWidgetsByRowIndex[byteWidget->currentRowIndex].emplace_back(byteWidget);
byteWidgetsByColumnIndex[byteWidget->currentColumnIndex].emplace_back(byteWidget);
lastRowIndex = rowIndex;
}
this->byteItemsByRowIndex = std::move(byteWidgetsByRowIndex);
this->byteItemsByColumnIndex = std::move(byteWidgetsByColumnIndex);
void ByteItemGraphicsScene::onAnnotationItemEnter(AnnotationItem* annotationItem) {
if (this->hoveredAnnotationItem.has_value()) {
if (this->hoveredAnnotationItem.value() == annotationItem) {
return;
}
this->byteAddressContainer->adjustAddressLabels(this->byteItemsByRowIndex);
}
void ByteItemGraphicsScene::adjustAnnotationItemPositions() {
if (this->byteItemsByAddress.empty() || !this->settings.displayAnnotations) {
return;
}
for (auto* annotationItem : this->annotationItems) {
if (!this->byteItemsByAddress.contains(annotationItem->startAddress)) {
annotationItem->hide();
continue;
this->onAnnotationItemLeave();
}
const auto firstByteItemPosition = this->byteItemsByAddress.at(annotationItem->startAddress)->pos();
this->hoveredAnnotationItem = annotationItem;
if (annotationItem->position == AnnotationItemPosition::TOP) {
annotationItem->setPos(
firstByteItemPosition.x(),
firstByteItemPosition.y() - AnnotationItem::TOP_HEIGHT - 1
);
for (
auto byteItemAddress = annotationItem->startAddress;
byteItemAddress <= annotationItem->endAddress;
byteItemAddress++
) {
this->byteItemsByAddress.at(byteItemAddress)->update();
}
}
} else if (annotationItem->position == AnnotationItemPosition::BOTTOM) {
annotationItem->setPos(
firstByteItemPosition.x(),
firstByteItemPosition.y() + ByteItem::HEIGHT
);
void ByteItemGraphicsScene::onAnnotationItemLeave() {
auto* annotationItem = this->hoveredAnnotationItem.value();
this->hoveredAnnotationItem = std::nullopt;
for (
auto byteItemAddress = annotationItem->startAddress;
byteItemAddress <= annotationItem->endAddress;
byteItemAddress++
) {
this->byteItemsByAddress.at(byteItemAddress)->update();
}
}
}
void ByteItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) {
using Targets::TargetState;
this->targetState = newState;
}
void ByteItemGraphicsScene::onByteWidgetEnter(ByteItem* widget) {
if (this->hoveredByteWidget.has_value()) {
if (this->hoveredByteWidget.value() == widget) {
// This byte item is already marked as hovered
return;
}
this->onByteWidgetLeave();
}
this->hoveredByteWidget = widget;
this->hoveredAddressLabel->setText(
"Relative Address (Absolute Address): " + widget->relativeAddressHex + " (" + widget->addressHex + ")"
);
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
for (auto& byteWidget : this->byteItemsByColumnIndex.at(widget->currentColumnIndex)) {
byteWidget->update();
}
for (auto& byteWidget : this->byteItemsByRowIndex.at(widget->currentRowIndex)) {
byteWidget->update();
}
} else {
widget->update();
}
}
void ByteItemGraphicsScene::onByteWidgetLeave() {
auto* byteItem = this->hoveredByteWidget.value();
this->hoveredByteWidget = std::nullopt;
this->hoveredAddressLabel->setText("Relative Address (Absolute Address):");
if (this->settings.highlightHoveredRowAndCol && !this->byteItemsByRowIndex.empty()) {
for (auto& byteWidget : this->byteItemsByColumnIndex.at(byteItem->currentColumnIndex)) {
byteWidget->update();
}
for (auto& byteWidget : this->byteItemsByRowIndex.at(byteItem->currentRowIndex)) {
byteWidget->update();
}
} else {
byteItem->update();
}
}
void ByteItemGraphicsScene::onAnnotationItemEnter(AnnotationItem* annotationItem) {
if (this->hoveredAnnotationItem.has_value()) {
if (this->hoveredAnnotationItem.value() == annotationItem) {
return;
}
this->onAnnotationItemLeave();
}
this->hoveredAnnotationItem = annotationItem;
for (
auto byteItemAddress = annotationItem->startAddress;
byteItemAddress <= annotationItem->endAddress;
byteItemAddress++
) {
this->byteItemsByAddress.at(byteItemAddress)->update();
}
}
void ByteItemGraphicsScene::onAnnotationItemLeave() {
auto* annotationItem = this->hoveredAnnotationItem.value();
this->hoveredAnnotationItem = std::nullopt;
for (
auto byteItemAddress = annotationItem->startAddress;
byteItemAddress <= annotationItem->endAddress;
byteItemAddress++
) {
this->byteItemsByAddress.at(byteItemAddress)->update();
}
}

View File

@@ -5,240 +5,244 @@
#include "src/Helpers/Paths.hpp"
#include "src/Exceptions/Exception.hpp"
using namespace Bloom::Widgets;
using namespace Bloom::Exceptions;
using Bloom::Targets::TargetMemoryDescriptor;
HexViewerWidget::HexViewerWidget(
const TargetMemoryDescriptor& targetMemoryDescriptor,
HexViewerWidgetSettings& settings,
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
InsightWorker& insightWorker,
QWidget* parent
):
QWidget(parent),
targetMemoryDescriptor(targetMemoryDescriptor),
settings(settings),
focusedMemoryRegions(focusedMemoryRegions),
excludedMemoryRegions(excludedMemoryRegions),
insightWorker(insightWorker)
namespace Bloom::Widgets
{
this->setObjectName("hex-viewer-widget");
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
using namespace Bloom::Exceptions;
auto widgetUiFile = QFile(
QString::fromStdString(Paths::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget"
+ "/UiFiles/HexViewerWidget.ui"
)
);
using Bloom::Targets::TargetMemoryDescriptor;
if (!widgetUiFile.open(QFile::ReadOnly)) {
throw Exception("Failed to open HexViewerWidget UI file");
}
HexViewerWidget::HexViewerWidget(
const TargetMemoryDescriptor& targetMemoryDescriptor,
HexViewerWidgetSettings& settings,
std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
InsightWorker& insightWorker,
QWidget* parent
)
: QWidget(parent)
, targetMemoryDescriptor(targetMemoryDescriptor)
, settings(settings)
, focusedMemoryRegions(focusedMemoryRegions)
, excludedMemoryRegions(excludedMemoryRegions)
, insightWorker(insightWorker)
{
this->setObjectName("hex-viewer-widget");
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
auto uiLoader = UiLoader(this);
this->container = uiLoader.load(&widgetUiFile, this);
this->container->setFixedSize(this->size());
this->container->setContentsMargins(0, 0, 0, 0);
auto widgetUiFile = QFile(
QString::fromStdString(Paths::compiledResourcesPath()
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget"
+ "/UiFiles/HexViewerWidget.ui"
)
);
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
this->bottomBar = this->container->findChild<QWidget*>("bottom-bar");
if (!widgetUiFile.open(QFile::ReadOnly)) {
throw Exception("Failed to open HexViewerWidget UI file");
}
this->refreshButton = this->toolBar->findChild<SvgToolButton*>("refresh-memory-btn");
this->highlightStackMemoryButton = this->toolBar->findChild<SvgToolButton*>("highlight-stack-memory-btn");
this->highlightHoveredRowAndColumnButton = this->toolBar->findChild<SvgToolButton*>(
"highlight-hovered-rows-columns-btn"
);
this->highlightFocusedMemoryButton = this->container->findChild<SvgToolButton*>(
"highlight-focused-memory-btn"
);
this->displayAnnotationsButton = this->container->findChild<SvgToolButton*>("display-annotations-btn");
this->displayAsciiButton = this->container->findChild<SvgToolButton*>("display-ascii-btn");
auto uiLoader = UiLoader(this);
this->container = uiLoader.load(&widgetUiFile, this);
this->container->setFixedSize(this->size());
this->container->setContentsMargins(0, 0, 0, 0);
this->goToAddressInput = this->container->findChild<TextInput*>("go-to-address-input");
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
this->bottomBar = this->container->findChild<QWidget*>("bottom-bar");
this->toolBar->setContentsMargins(0, 0, 0, 0);
this->toolBar->layout()->setContentsMargins(5, 0, 5, 1);
this->refreshButton = this->toolBar->findChild<SvgToolButton*>("refresh-memory-btn");
this->highlightStackMemoryButton = this->toolBar->findChild<SvgToolButton*>(
"highlight-stack-memory-btn"
);
this->highlightHoveredRowAndColumnButton = this->toolBar->findChild<SvgToolButton*>(
"highlight-hovered-rows-columns-btn"
);
this->highlightFocusedMemoryButton = this->container->findChild<SvgToolButton*>(
"highlight-focused-memory-btn"
);
this->displayAnnotationsButton = this->container->findChild<SvgToolButton*>("display-annotations-btn");
this->displayAsciiButton = this->container->findChild<SvgToolButton*>("display-ascii-btn");
this->bottomBar->setContentsMargins(0, 0, 0, 0);
this->bottomBar->layout()->setContentsMargins(5, 0, 5, 0);
this->goToAddressInput = this->container->findChild<TextInput*>("go-to-address-input");
this->hoveredAddressLabel = this->bottomBar->findChild<QLabel*>("byte-address-label");
this->toolBar->setContentsMargins(0, 0, 0, 0);
this->toolBar->layout()->setContentsMargins(5, 0, 5, 1);
this->byteItemGraphicsViewContainer = this->container->findChild<QWidget*>("graphics-view-container");
this->byteItemGraphicsView = new ByteItemContainerGraphicsView(
this->targetMemoryDescriptor,
this->focusedMemoryRegions,
this->excludedMemoryRegions,
this->insightWorker,
this->settings,
this->hoveredAddressLabel,
this->byteItemGraphicsViewContainer
);
this->byteItemGraphicsScene = this->byteItemGraphicsView->getScene();
this->bottomBar->setContentsMargins(0, 0, 0, 0);
this->bottomBar->layout()->setContentsMargins(5, 0, 5, 0);
this->setHoveredRowAndColumnHighlightingEnabled(this->settings.highlightHoveredRowAndCol);
this->setFocusedMemoryHighlightingEnabled(this->settings.highlightFocusedMemory);
this->setAnnotationsEnabled(this->settings.displayAnnotations);
this->setDisplayAsciiEnabled(this->settings.displayAsciiValues);
this->hoveredAddressLabel = this->bottomBar->findChild<QLabel*>("byte-address-label");
if (this->targetMemoryDescriptor.type == Targets::TargetMemoryType::RAM) {
this->highlightStackMemoryButton->show();
this->setStackMemoryHighlightingEnabled(this->settings.highlightStackMemory);
this->byteItemGraphicsViewContainer = this->container->findChild<QWidget*>("graphics-view-container");
this->byteItemGraphicsView = new ByteItemContainerGraphicsView(
this->targetMemoryDescriptor,
this->focusedMemoryRegions,
this->excludedMemoryRegions,
this->insightWorker,
this->settings,
this->hoveredAddressLabel,
this->byteItemGraphicsViewContainer
);
this->byteItemGraphicsScene = this->byteItemGraphicsView->getScene();
this->setHoveredRowAndColumnHighlightingEnabled(this->settings.highlightHoveredRowAndCol);
this->setFocusedMemoryHighlightingEnabled(this->settings.highlightFocusedMemory);
this->setAnnotationsEnabled(this->settings.displayAnnotations);
this->setDisplayAsciiEnabled(this->settings.displayAsciiValues);
if (this->targetMemoryDescriptor.type == Targets::TargetMemoryType::RAM) {
this->highlightStackMemoryButton->show();
this->setStackMemoryHighlightingEnabled(this->settings.highlightStackMemory);
QObject::connect(
this->highlightStackMemoryButton,
&QToolButton::clicked,
this,
[this] {
this->setStackMemoryHighlightingEnabled(!this->settings.highlightStackMemory);
}
);
} else {
this->highlightStackMemoryButton->hide();
this->setStackMemoryHighlightingEnabled(false);
}
QObject::connect(
this->highlightStackMemoryButton,
this->highlightHoveredRowAndColumnButton,
&QToolButton::clicked,
this,
[this] {
this->setStackMemoryHighlightingEnabled(!this->settings.highlightStackMemory);
this->setHoveredRowAndColumnHighlightingEnabled(!this->settings.highlightHoveredRowAndCol);
}
);
} else {
this->highlightStackMemoryButton->hide();
this->setStackMemoryHighlightingEnabled(false);
QObject::connect(
this->highlightFocusedMemoryButton,
&QToolButton::clicked,
this,
[this] {
this->setFocusedMemoryHighlightingEnabled(!this->settings.highlightFocusedMemory);
}
);
QObject::connect(
this->displayAnnotationsButton,
&QToolButton::clicked,
this,
[this] {
this->setAnnotationsEnabled(!this->settings.displayAnnotations);
}
);
QObject::connect(
this->displayAsciiButton,
&QToolButton::clicked,
this,
[this] {
this->setDisplayAsciiEnabled(!this->settings.displayAsciiValues);
}
);
QObject::connect(
this->goToAddressInput,
&QLineEdit::textEdited,
this,
&HexViewerWidget::onGoToAddressInputChanged
);
QObject::connect(
this->goToAddressInput,
&TextInput::focusChanged,
this,
&HexViewerWidget::onGoToAddressInputChanged
);
QObject::connect(
&insightWorker,
&InsightWorker::targetStateUpdated,
this,
&HexViewerWidget::onTargetStateChanged
);
this->show();
}
QObject::connect(
this->highlightHoveredRowAndColumnButton,
&QToolButton::clicked,
this,
[this] {
this->setHoveredRowAndColumnHighlightingEnabled(!this->settings.highlightHoveredRowAndCol);
}
);
QObject::connect(
this->highlightFocusedMemoryButton,
&QToolButton::clicked,
this,
[this] {
this->setFocusedMemoryHighlightingEnabled(!this->settings.highlightFocusedMemory);
}
);
QObject::connect(
this->displayAnnotationsButton,
&QToolButton::clicked,
this,
[this] {
this->setAnnotationsEnabled(!this->settings.displayAnnotations);
}
);
QObject::connect(
this->displayAsciiButton,
&QToolButton::clicked,
this,
[this] {
this->setDisplayAsciiEnabled(!this->settings.displayAsciiValues);
}
);
QObject::connect(
this->goToAddressInput,
&QLineEdit::textEdited,
this,
&HexViewerWidget::onGoToAddressInputChanged
);
QObject::connect(
this->goToAddressInput,
&TextInput::focusChanged,
this,
&HexViewerWidget::onGoToAddressInputChanged
);
QObject::connect(
&insightWorker,
&InsightWorker::targetStateUpdated,
this,
&HexViewerWidget::onTargetStateChanged
);
this->show();
}
void HexViewerWidget::updateValues(const Targets::TargetMemoryBuffer& buffer) {
this->byteItemGraphicsScene->updateValues(buffer);
}
void HexViewerWidget::refreshRegions() {
this->byteItemGraphicsScene->refreshRegions();
}
void HexViewerWidget::setStackPointer(std::uint32_t stackPointer) {
this->byteItemGraphicsScene->updateStackPointer(stackPointer);
}
void HexViewerWidget::resizeEvent(QResizeEvent* event) {
this->container->setFixedSize(
this->width(),
this->height()
);
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
}
void HexViewerWidget::showEvent(QShowEvent* event) {
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
}
void HexViewerWidget::onTargetStateChanged(Targets::TargetState newState) {
using Targets::TargetState;
this->targetState = newState;
}
void HexViewerWidget::setStackMemoryHighlightingEnabled(bool enabled) {
this->highlightStackMemoryButton->setChecked(enabled);
this->settings.highlightStackMemory = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::setHoveredRowAndColumnHighlightingEnabled(bool enabled) {
this->highlightHoveredRowAndColumnButton->setChecked(enabled);
this->settings.highlightHoveredRowAndCol = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::setFocusedMemoryHighlightingEnabled(bool enabled) {
this->highlightFocusedMemoryButton->setChecked(enabled);
this->settings.highlightFocusedMemory = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::setAnnotationsEnabled(bool enabled) {
this->displayAnnotationsButton->setChecked(enabled);
this->settings.displayAnnotations = enabled;
this->byteItemGraphicsScene->adjustSize(true);
}
void HexViewerWidget::setDisplayAsciiEnabled(bool enabled) {
this->displayAsciiButton->setChecked(enabled);
this->settings.displayAsciiValues = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::onGoToAddressInputChanged() {
auto addressConversionOk = false;
const auto address = this->goToAddressInput->text().toUInt(&addressConversionOk, 16);
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
if (addressConversionOk && memoryAddressRange.contains(address) && this->goToAddressInput->hasFocus()) {
this->byteItemGraphicsScene->setHighlightedAddresses({address});
this->byteItemGraphicsView->scrollToByteItemAtAddress(address);
return;
void HexViewerWidget::updateValues(const Targets::TargetMemoryBuffer& buffer) {
this->byteItemGraphicsScene->updateValues(buffer);
}
this->byteItemGraphicsScene->setHighlightedAddresses({});
void HexViewerWidget::refreshRegions() {
this->byteItemGraphicsScene->refreshRegions();
}
void HexViewerWidget::setStackPointer(std::uint32_t stackPointer) {
this->byteItemGraphicsScene->updateStackPointer(stackPointer);
}
void HexViewerWidget::resizeEvent(QResizeEvent* event) {
this->container->setFixedSize(
this->width(),
this->height()
);
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
}
void HexViewerWidget::showEvent(QShowEvent* event) {
this->byteItemGraphicsView->setFixedSize(this->byteItemGraphicsViewContainer->size());
}
void HexViewerWidget::onTargetStateChanged(Targets::TargetState newState) {
using Targets::TargetState;
this->targetState = newState;
}
void HexViewerWidget::setStackMemoryHighlightingEnabled(bool enabled) {
this->highlightStackMemoryButton->setChecked(enabled);
this->settings.highlightStackMemory = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::setHoveredRowAndColumnHighlightingEnabled(bool enabled) {
this->highlightHoveredRowAndColumnButton->setChecked(enabled);
this->settings.highlightHoveredRowAndCol = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::setFocusedMemoryHighlightingEnabled(bool enabled) {
this->highlightFocusedMemoryButton->setChecked(enabled);
this->settings.highlightFocusedMemory = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::setAnnotationsEnabled(bool enabled) {
this->displayAnnotationsButton->setChecked(enabled);
this->settings.displayAnnotations = enabled;
this->byteItemGraphicsScene->adjustSize(true);
}
void HexViewerWidget::setDisplayAsciiEnabled(bool enabled) {
this->displayAsciiButton->setChecked(enabled);
this->settings.displayAsciiValues = enabled;
this->byteItemGraphicsScene->invalidateChildItemCaches();
}
void HexViewerWidget::onGoToAddressInputChanged() {
auto addressConversionOk = false;
const auto address = this->goToAddressInput->text().toUInt(&addressConversionOk, 16);
const auto& memoryAddressRange = this->targetMemoryDescriptor.addressRange;
if (addressConversionOk && memoryAddressRange.contains(address) && this->goToAddressInput->hasFocus()) {
this->byteItemGraphicsScene->setHighlightedAddresses({address});
this->byteItemGraphicsView->scrollToByteItemAtAddress(address);
return;
}
this->byteItemGraphicsScene->setHighlightedAddresses({});
}
}

View File

@@ -2,68 +2,46 @@
#include <algorithm>
using namespace Bloom::Widgets;
ValueAnnotationItem::ValueAnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion)
: AnnotationItem(focusedMemoryRegion, AnnotationItemPosition::TOP)
, focusedMemoryRegion(focusedMemoryRegion)
, endianness(focusedMemoryRegion.endianness)
namespace Bloom::Widgets
{
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
}
void ValueAnnotationItem::setValue(const Targets::TargetMemoryBuffer& value) {
this->value = value;
if (this->endianness == Targets::TargetMemoryEndianness::LITTLE) {
std::reverse(this->value.begin(), this->value.end());
}
this->refreshLabelText();
this->setToolTip(this->labelText);
}
void ValueAnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
auto font = painter->font();
font.setItalic(true);
painter->setFont(font);
AnnotationItem::paint(painter, option, widget);
}
void ValueAnnotationItem::refreshLabelText() {
this->update();
if (this->value.empty()) {
ValueAnnotationItem::ValueAnnotationItem(const FocusedMemoryRegion& focusedMemoryRegion)
: AnnotationItem(focusedMemoryRegion, AnnotationItemPosition::TOP)
, focusedMemoryRegion(focusedMemoryRegion)
, endianness(focusedMemoryRegion.endianness)
{
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
return;
}
switch (this->focusedMemoryRegion.dataType) {
case MemoryRegionDataType::UNSIGNED_INTEGER: {
std::uint64_t integerValue = 0;
for (const auto& byte : this->value) {
integerValue = (integerValue << 8) | byte;
}
void ValueAnnotationItem::setValue(const Targets::TargetMemoryBuffer& value) {
this->value = value;
this->labelText = QString::number(integerValue);
break;
if (this->endianness == Targets::TargetMemoryEndianness::LITTLE) {
std::reverse(this->value.begin(), this->value.end());
}
case MemoryRegionDataType::SIGNED_INTEGER: {
const auto valueSize = this->value.size();
if (valueSize == 1) {
this->labelText = QString::number(static_cast<int8_t>(this->value[0]));
break;
}
this->refreshLabelText();
this->setToolTip(this->labelText);
}
if (valueSize == 2) {
this->labelText = QString::number(static_cast<int16_t>((this->value[0] << 8) | this->value[1]));
break;
}
void ValueAnnotationItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
auto font = painter->font();
font.setItalic(true);
painter->setFont(font);
if (valueSize <= 4) {
std::int32_t integerValue = 0;
AnnotationItem::paint(painter, option, widget);
}
void ValueAnnotationItem::refreshLabelText() {
this->update();
if (this->value.empty()) {
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
return;
}
switch (this->focusedMemoryRegion.dataType) {
case MemoryRegionDataType::UNSIGNED_INTEGER: {
std::uint64_t integerValue = 0;
for (const auto& byte : this->value) {
integerValue = (integerValue << 8) | byte;
}
@@ -71,42 +49,65 @@ void ValueAnnotationItem::refreshLabelText() {
this->labelText = QString::number(integerValue);
break;
}
case MemoryRegionDataType::SIGNED_INTEGER: {
const auto valueSize = this->value.size();
std::int64_t integerValue = 0;
for (const auto& byte : this->value) {
integerValue = (integerValue << 8) | byte;
if (valueSize == 1) {
this->labelText = QString::number(static_cast<int8_t>(this->value[0]));
break;
}
if (valueSize == 2) {
this->labelText = QString::number(static_cast<int16_t>((this->value[0] << 8) | this->value[1]));
break;
}
if (valueSize <= 4) {
std::int32_t integerValue = 0;
for (const auto& byte : this->value) {
integerValue = (integerValue << 8) | byte;
}
this->labelText = QString::number(integerValue);
break;
}
std::int64_t integerValue = 0;
for (const auto& byte : this->value) {
integerValue = (integerValue << 8) | byte;
}
this->labelText = QString::number(integerValue);
break;
}
case MemoryRegionDataType::ASCII_STRING: {
// Replace non-ASCII chars with '?'
auto asciiData = this->value;
this->labelText = QString::number(integerValue);
break;
}
case MemoryRegionDataType::ASCII_STRING: {
// Replace non-ASCII chars with '?'
auto asciiData = this->value;
std::replace_if(
asciiData.begin(),
asciiData.end(),
[] (unsigned char value) {
/*
* We only care about non-control characters (with the exception of the white space character) in
* the standard ASCII range.
*/
constexpr auto asciiRangeStart = 32;
constexpr auto asciiRangeEnd = 126;
return value < asciiRangeStart || value > asciiRangeEnd;
},
'?'
);
std::replace_if(
asciiData.begin(),
asciiData.end(),
[] (unsigned char value) {
/*
* We only care about non-control characters (with the exception of the white space character) in
* the standard ASCII range.
*/
constexpr auto asciiRangeStart = 32;
constexpr auto asciiRangeEnd = 126;
return value < asciiRangeStart || value > asciiRangeEnd;
},
'?'
);
this->labelText = "'" + QString::fromLatin1(
reinterpret_cast<const char*>(asciiData.data()),
static_cast<qsizetype>(asciiData.size())
) + "'";
break;
}
default: {
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
this->labelText = "'" + QString::fromLatin1(
reinterpret_cast<const char*>(asciiData.data()),
static_cast<qsizetype>(asciiData.size())
) + "'";
break;
}
default: {
this->labelText = QString(ValueAnnotationItem::DEFAULT_LABEL_TEXT);
}
}
}
}