Removed using namespace directive for class member function definitions in source files
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user