Refactored hex viewer widget to use QGraphicsView items as opposed to widgets, for byte items in the hex viewer.
This requirement became apparent when testing the initial approach with large memory sizes - the GUI became unresponsive due to the number of widgets being constructed. This was along side other performance issues that arose from the large number of widgets
This commit is contained in:
@@ -177,8 +177,9 @@ add_executable(Bloom
|
||||
# Target memory inspection pane
|
||||
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/TargetMemoryInspectionPane.cpp
|
||||
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.cpp
|
||||
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidgetContainer.cpp
|
||||
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteWidget.cpp
|
||||
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemContainerGraphicsView.cpp
|
||||
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItemGraphicsScene.cpp
|
||||
src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ByteItem.cpp
|
||||
)
|
||||
|
||||
set_target_properties(Bloom PROPERTIES OUTPUT_NAME bloom)
|
||||
|
||||
@@ -179,6 +179,7 @@ QScrollBar:vertical {
|
||||
QScrollBar:handle:vertical {
|
||||
border: none;
|
||||
background-color: rgba(69, 69, 66, 0.6);
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
QScrollBar:handle:vertical:hover {
|
||||
@@ -379,26 +380,29 @@ QScrollBar::sub-line:vertical {
|
||||
}
|
||||
|
||||
#hex-viewer-container QScrollArea,
|
||||
#hex-viewer-container #byte-widget-scroll-area-container {
|
||||
#hex-viewer-container #graphics-view-container,
|
||||
#hex-viewer-container #graphics-view-container #graphics-view {
|
||||
background-color: #323330;
|
||||
border: none;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#hex-viewer-container #graphics-view-container {
|
||||
background-color: #50504b;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#hex-viewer-container #byte-widget-scroll-area-container #address-container {
|
||||
#hex-viewer-container #graphics-view-container #address-container {
|
||||
background-color: #353633;
|
||||
border-right: 1px solid #41423f;
|
||||
}
|
||||
|
||||
#hex-viewer-container #byte-widget-scroll-area-container #address-container QLabel {
|
||||
#hex-viewer-container #graphics-view-container #address-container QLabel {
|
||||
background-color: transparent;
|
||||
font-size: 12px;
|
||||
color: rgba(175, 177, 179, 0.72);
|
||||
}
|
||||
|
||||
#hex-viewer-container #byte-widget-scroll-area-container #address-container QLabel:disabled {
|
||||
#hex-viewer-container #graphics-view-container #address-container QLabel:disabled {
|
||||
color: rgba(175, 177, 179, 0.3);
|
||||
}
|
||||
|
||||
#hex-viewer-container #byte {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <QGraphicsItem>
|
||||
#include <cstdint>
|
||||
#include <QEvent>
|
||||
#include <QGraphicsScene>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class ByteAddressContainer: public QGraphicsItem
|
||||
{
|
||||
public:
|
||||
static constexpr int WIDTH = 85;
|
||||
|
||||
static constexpr int RIGHT_MARGIN = 5;
|
||||
static constexpr int BOTTOM_MARGIN = 5;
|
||||
|
||||
std::size_t byteIndex;
|
||||
unsigned char value = 0x00;
|
||||
std::uint32_t address = 0x00;
|
||||
QString addressHex;
|
||||
QString relativeAddressHex;
|
||||
bool valueInitialised = false;
|
||||
|
||||
std::size_t currentRowIndex = 0;
|
||||
std::size_t currentColumnIndex = 0;
|
||||
|
||||
ByteAddressContainer();
|
||||
|
||||
[[nodiscard]] QRectF boundingRect() const override {
|
||||
return QRectF(
|
||||
0,
|
||||
0,
|
||||
ByteAddressContainer::WIDTH,
|
||||
this->scene()->height()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "ByteItem.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
ByteItem::ByteItem(
|
||||
std::size_t byteIndex,
|
||||
std::uint32_t address,
|
||||
std::optional<ByteItem*>& hoveredByteItem
|
||||
): QGraphicsItem(nullptr), byteIndex(byteIndex), address(address), hoveredByteItem(hoveredByteItem) {
|
||||
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->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 = true;
|
||||
}
|
||||
|
||||
void ByteItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
|
||||
painter->setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
painter->setPen(Qt::PenStyle::NoPen);
|
||||
|
||||
static const auto widgetRect = this->boundingRect();
|
||||
|
||||
if (this->hoveredByteItem.has_value()) {
|
||||
const auto hoveredWidget = this->hoveredByteItem.value();
|
||||
|
||||
if (hoveredWidget->currentColumnIndex == this->currentColumnIndex
|
||||
|| hoveredWidget->currentRowIndex == this->currentRowIndex
|
||||
){
|
||||
painter->setBrush(QColor(0x8E, 0x8B, 0x83, hoveredWidget == this ? 70 : 30));
|
||||
painter->drawRect(widgetRect);
|
||||
}
|
||||
}
|
||||
|
||||
auto textColor = QColor(this->valueChanged ? "#547fba" : "#afb1b3");
|
||||
|
||||
if (this->valueInitialised) {
|
||||
if (!this->isEnabled()) {
|
||||
textColor.setAlpha(100);
|
||||
}
|
||||
|
||||
painter->setPen(textColor);
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, this->hexValue);
|
||||
|
||||
} else {
|
||||
textColor.setAlpha(100);
|
||||
painter->setPen(textColor);
|
||||
|
||||
static const auto placeholderString = QString("??");
|
||||
painter->drawText(widgetRect, Qt::AlignCenter, placeholderString);
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,15 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <QEvent>
|
||||
#include <QGraphicsItem>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class ByteWidget: public ClickableWidget
|
||||
class ByteItem: public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static constexpr int WIDTH = 25;
|
||||
static constexpr int HEIGHT = 20;
|
||||
@@ -29,35 +28,34 @@ namespace Bloom::Widgets
|
||||
std::size_t currentRowIndex = 0;
|
||||
std::size_t currentColumnIndex = 0;
|
||||
|
||||
ByteWidget(
|
||||
ByteItem(
|
||||
std::size_t byteNumber,
|
||||
std::uint32_t address,
|
||||
std::optional<ByteWidget*>& hoveredByteWidget,
|
||||
QWidget* parent
|
||||
std::optional<ByteItem*>& hoveredByteItem
|
||||
);
|
||||
void setValue(unsigned char value);
|
||||
|
||||
public slots:
|
||||
void setSelected(bool selected);
|
||||
[[nodiscard]] QRectF boundingRect() const override {
|
||||
return QRectF(
|
||||
0,
|
||||
0,
|
||||
ByteItem::WIDTH,
|
||||
ByteItem::HEIGHT
|
||||
);
|
||||
}
|
||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
|
||||
|
||||
signals:
|
||||
void selected(Bloom::Widgets::ByteWidget*);
|
||||
void enter(Bloom::Widgets::ByteWidget*);
|
||||
void leave(Bloom::Widgets::ByteWidget*);
|
||||
|
||||
protected:
|
||||
virtual void postSetSelected(bool selected) {};
|
||||
bool event(QEvent* event) override;
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void drawWidget(QPainter& painter);
|
||||
void selected(Bloom::Widgets::ByteItem*);
|
||||
void enter(Bloom::Widgets::ByteItem*);
|
||||
void leave(Bloom::Widgets::ByteItem*);
|
||||
|
||||
private:
|
||||
bool hoverActive = false;
|
||||
bool valueChanged = false;
|
||||
|
||||
QString hexValue;
|
||||
std::optional<QString> asciiValue;
|
||||
|
||||
std::optional<ByteWidget*>& hoveredByteWidget;
|
||||
std::optional<ByteItem*>& hoveredByteItem;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "ByteItemContainerGraphicsView.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QTableWidget>
|
||||
#include <QScrollBar>
|
||||
#include <QPainter>
|
||||
#include <cmath>
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
ByteItemContainerGraphicsView::ByteItemContainerGraphicsView(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QLabel* hoveredAddressLabel,
|
||||
QWidget* parent
|
||||
): QGraphicsView(parent) {
|
||||
this->setObjectName("graphics-view");
|
||||
this->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
|
||||
this->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
||||
this->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
|
||||
this->scene = new ByteItemGraphicsScene(
|
||||
targetMemoryDescriptor,
|
||||
insightWorker,
|
||||
hoveredAddressLabel,
|
||||
this
|
||||
);
|
||||
|
||||
this->setScene(this->scene);
|
||||
}
|
||||
|
||||
void ByteItemContainerGraphicsView::resizeEvent(QResizeEvent* event) {
|
||||
Logger::warning("Resizing");
|
||||
this->scene->adjustByteWidgets();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QEvent>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
#include "src/Targets/TargetState.hpp"
|
||||
|
||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||
|
||||
#include "ByteItemGraphicsScene.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class ByteItemContainerGraphicsView: public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ByteItemContainerGraphicsView(
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QLabel* hoveredAddressLabel,
|
||||
QWidget* parent
|
||||
);
|
||||
|
||||
[[nodiscard]] ByteItemGraphicsScene* getScene() const {
|
||||
return this->scene;
|
||||
}
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
private:
|
||||
ByteItemGraphicsScene* scene = nullptr;
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ByteWidgetContainer.hpp"
|
||||
#include "ByteItemGraphicsScene.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QTableWidget>
|
||||
@@ -6,30 +6,24 @@
|
||||
#include <QPainter>
|
||||
#include <cmath>
|
||||
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
ByteWidgetContainer::ByteWidgetContainer(
|
||||
ByteItemGraphicsScene::ByteItemGraphicsScene(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QLabel* hoveredAddressLabel,
|
||||
QWidget* parent
|
||||
): QWidget(parent),
|
||||
): QGraphicsScene(parent),
|
||||
targetMemoryDescriptor(targetMemoryDescriptor),
|
||||
insightWorker(insightWorker),
|
||||
hoveredAddressLabel(hoveredAddressLabel),
|
||||
parent(parent) {
|
||||
this->setObjectName("byte-widget-container");
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Ignored);
|
||||
|
||||
this->setContentsMargins(
|
||||
10,
|
||||
10,
|
||||
10,
|
||||
10
|
||||
);
|
||||
|
||||
/*
|
||||
* Construct ByteWidget objects
|
||||
@@ -38,49 +32,45 @@ parent(parent) {
|
||||
*/
|
||||
const auto memorySize = this->targetMemoryDescriptor.size();
|
||||
const auto startAddress = this->targetMemoryDescriptor.addressRange.startAddress;
|
||||
Logger::error("Constructing bytes begin");
|
||||
for (std::size_t i = 0; i < memorySize; i++) {
|
||||
const auto address = static_cast<std::uint32_t>(startAddress + i);
|
||||
|
||||
auto byteWidget = new ByteWidget(i, address, this->hoveredByteWidget, this);
|
||||
auto byteWidget = new ByteItem(i, address, this->hoveredByteWidget);
|
||||
this->byteWidgetsByAddress.insert(std::pair(
|
||||
address,
|
||||
byteWidget
|
||||
));
|
||||
|
||||
QObject::connect(byteWidget, &ByteWidget::enter, this, &ByteWidgetContainer::onByteWidgetEnter);
|
||||
QObject::connect(byteWidget, &ByteWidget::leave, this, &ByteWidgetContainer::onByteWidgetLeave);
|
||||
this->addItem(byteWidget);
|
||||
}
|
||||
Logger::error("Constructing bytes end");
|
||||
this->adjustByteWidgets();
|
||||
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&ByteWidgetContainer::onTargetStateChanged
|
||||
&ByteItemGraphicsScene::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
void ByteItemGraphicsScene::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
for (auto& [address, byteWidget] : this->byteWidgetsByAddress) {
|
||||
byteWidget->setValue(buffer.at(byteWidget->byteIndex));
|
||||
byteWidget->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::resizeEvent(QResizeEvent* event) {
|
||||
this->adjustByteWidgets();
|
||||
}
|
||||
void ByteItemGraphicsScene::adjustByteWidgets() {
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByRowIndex;
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByColumnIndex;
|
||||
|
||||
void ByteWidgetContainer::adjustByteWidgets() {
|
||||
std::map<std::size_t, std::vector<ByteWidget*>> byteWidgetsByRowIndex;
|
||||
std::map<std::size_t, std::vector<ByteWidget*>> byteWidgetsByColumnIndex;
|
||||
const auto margins = QMargins(10, 10, 10, 10);
|
||||
const auto width = std::max(600, static_cast<int>(this->parent->width()));
|
||||
|
||||
const auto margins = this->contentsMargins();
|
||||
const auto width = this->width();
|
||||
|
||||
constexpr auto byteWidgetWidth = ByteWidget::WIDTH + ByteWidget::RIGHT_MARGIN;
|
||||
constexpr auto byteWidgetHeight = ByteWidget::HEIGHT + ByteWidget::BOTTOM_MARGIN;
|
||||
constexpr auto byteWidgetWidth = ByteItem::WIDTH + ByteItem::RIGHT_MARGIN;
|
||||
constexpr auto byteWidgetHeight = ByteItem::HEIGHT + ByteItem::BOTTOM_MARGIN;
|
||||
const auto rowCapacity = static_cast<std::size_t>(
|
||||
std::floor((width - margins.left() - margins.right()) / byteWidgetWidth)
|
||||
);
|
||||
@@ -97,12 +87,10 @@ void ByteWidgetContainer::adjustByteWidgets() {
|
||||
- (std::floor(byteWidget->byteIndex / rowCapacity) * static_cast<double>(rowCapacity))
|
||||
);
|
||||
|
||||
byteWidget->setGeometry(QRect(
|
||||
byteWidget->setPos(
|
||||
static_cast<int>(columnIndex * byteWidgetWidth + static_cast<std::size_t>(margins.left())),
|
||||
static_cast<int>(rowIndex * byteWidgetHeight + static_cast<std::size_t>(margins.top())),
|
||||
ByteWidget::WIDTH,
|
||||
ByteWidget::HEIGHT
|
||||
));
|
||||
static_cast<int>(rowIndex * byteWidgetHeight + static_cast<std::size_t>(margins.top()))
|
||||
);
|
||||
|
||||
byteWidget->currentRowIndex = static_cast<std::size_t>(rowIndex);
|
||||
byteWidget->currentColumnIndex = static_cast<std::size_t>(columnIndex);
|
||||
@@ -114,8 +102,9 @@ void ByteWidgetContainer::adjustByteWidgets() {
|
||||
}
|
||||
|
||||
const auto minHeight = (rowCount * byteWidgetHeight) + margins.top() + margins.bottom();
|
||||
this->setMinimumHeight(minHeight);
|
||||
this->parent->setMinimumHeight(minHeight);
|
||||
// this->setMinimumHeight(minHeight);
|
||||
this->setSceneRect(0, 0, width, minHeight);
|
||||
// this->parent->setMinimumHeight(minHeight);
|
||||
|
||||
this->byteWidgetsByRowIndex = std::move(byteWidgetsByRowIndex);
|
||||
this->byteWidgetsByColumnIndex = std::move(byteWidgetsByColumnIndex);
|
||||
@@ -123,12 +112,22 @@ void ByteWidgetContainer::adjustByteWidgets() {
|
||||
emit this->byteWidgetsAdjusted();
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::onTargetStateChanged(Targets::TargetState newState) {
|
||||
void ByteItemGraphicsScene::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::onByteWidgetEnter(ByteWidget* widget) {
|
||||
void ByteItemGraphicsScene::onByteWidgetEnter(ByteItem* widget) {
|
||||
if (this->hoveredByteWidget.has_value()) {
|
||||
if (this->hoveredByteWidget.value() == widget) {
|
||||
// This byte item is already marked as hovered
|
||||
return;
|
||||
|
||||
} else {
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
}
|
||||
|
||||
this->hoveredByteWidget = widget;
|
||||
|
||||
this->hoveredAddressLabel->setText(
|
||||
@@ -146,18 +145,33 @@ void ByteWidgetContainer::onByteWidgetEnter(ByteWidget* widget) {
|
||||
}
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::onByteWidgetLeave(ByteWidget* widget) {
|
||||
void ByteItemGraphicsScene::onByteWidgetLeave() {
|
||||
const auto byteItem = this->hoveredByteWidget.value();
|
||||
this->hoveredByteWidget = std::nullopt;
|
||||
|
||||
this->hoveredAddressLabel->setText("Relative Address (Absolute Address):");
|
||||
|
||||
if (!this->byteWidgetsByRowIndex.empty()) {
|
||||
for (auto& byteWidget : this->byteWidgetsByColumnIndex.at(widget->currentColumnIndex)) {
|
||||
for (auto& byteWidget : this->byteWidgetsByColumnIndex.at(byteItem->currentColumnIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto& byteWidget : this->byteWidgetsByRowIndex.at(widget->currentRowIndex)) {
|
||||
for (auto& byteWidget : this->byteWidgetsByRowIndex.at(byteItem->currentRowIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ByteItemGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
|
||||
auto hoveredItems = this->items(mouseEvent->scenePos());
|
||||
if (!hoveredItems.empty()) {
|
||||
auto hoveredByteWidget = dynamic_cast<ByteItem*>(hoveredItems.at(0));
|
||||
|
||||
if (hoveredByteWidget != nullptr) {
|
||||
this->onByteWidgetEnter(hoveredByteWidget);
|
||||
}
|
||||
|
||||
} else if (this->hoveredByteWidget.has_value()) {
|
||||
this->onByteWidgetLeave();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
@@ -8,7 +9,7 @@
|
||||
#include <vector>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QEvent>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
@@ -16,22 +17,22 @@
|
||||
|
||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||
|
||||
#include "ByteWidget.hpp"
|
||||
#include "ByteItem.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class ByteWidgetContainer: public QWidget
|
||||
class ByteItemGraphicsScene: public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
std::optional<ByteWidget*> hoveredByteWidget;
|
||||
std::optional<ByteItem*> hoveredByteWidget;
|
||||
|
||||
std::map<std::uint32_t, ByteWidget*> byteWidgetsByAddress;
|
||||
std::map<std::size_t, std::vector<ByteWidget*>> byteWidgetsByRowIndex;
|
||||
std::map<std::size_t, std::vector<ByteWidget*>> byteWidgetsByColumnIndex;
|
||||
std::map<std::uint32_t, ByteItem*> byteWidgetsByAddress;
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByRowIndex;
|
||||
std::map<std::size_t, std::vector<ByteItem*>> byteWidgetsByColumnIndex;
|
||||
|
||||
ByteWidgetContainer(
|
||||
ByteItemGraphicsScene(
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QLabel* hoveredAddressLabel,
|
||||
@@ -40,11 +41,13 @@ namespace Bloom::Widgets
|
||||
|
||||
void updateValues(const Targets::TargetMemoryBuffer& buffer);
|
||||
|
||||
void adjustByteWidgets();
|
||||
|
||||
signals:
|
||||
void byteWidgetsAdjusted();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
|
||||
|
||||
private:
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor;
|
||||
@@ -54,11 +57,9 @@ namespace Bloom::Widgets
|
||||
QWidget* parent = nullptr;
|
||||
QLabel* hoveredAddressLabel = nullptr;
|
||||
|
||||
void adjustByteWidgets();
|
||||
|
||||
private slots:
|
||||
void onTargetStateChanged(Targets::TargetState newState);
|
||||
void onByteWidgetEnter(Bloom::Widgets::ByteWidget* widget);
|
||||
void onByteWidgetLeave(Bloom::Widgets::ByteWidget* widget);
|
||||
void onByteWidgetEnter(Bloom::Widgets::ByteItem* widget);
|
||||
void onByteWidgetLeave();
|
||||
};
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
#include "ByteWidget.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyle>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
|
||||
ByteWidget::ByteWidget(
|
||||
std::size_t byteIndex,
|
||||
std::uint32_t address,
|
||||
std::optional<ByteWidget*>& hoveredByteWidget,
|
||||
QWidget* parent
|
||||
): ClickableWidget(parent), byteIndex(byteIndex), address(address), hoveredByteWidget(hoveredByteWidget) {
|
||||
this->setObjectName("byte");
|
||||
auto onClick = [this] {
|
||||
this->setSelected(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();
|
||||
|
||||
QObject::connect(this, &ClickableWidget::clicked, this, onClick);
|
||||
QObject::connect(this, &ClickableWidget::rightClicked, this, onClick);
|
||||
|
||||
this->setSelected(false);
|
||||
}
|
||||
|
||||
void ByteWidget::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 = true;
|
||||
}
|
||||
|
||||
void ByteWidget::setSelected(bool selected) {
|
||||
this->setProperty("selected", selected);
|
||||
this->style()->unpolish(this);
|
||||
this->style()->polish(this);
|
||||
|
||||
if (selected) {
|
||||
emit this->selected(this);
|
||||
}
|
||||
|
||||
this->postSetSelected(selected);
|
||||
}
|
||||
|
||||
bool ByteWidget::event(QEvent* event) {
|
||||
if (this->isEnabled()) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Enter: {
|
||||
this->hoverActive = true;
|
||||
emit this->enter(this);
|
||||
this->update();
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave: {
|
||||
this->hoverActive = false;
|
||||
emit this->leave(this);
|
||||
this->update();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
void ByteWidget::paintEvent(QPaintEvent* event) {
|
||||
auto painter = QPainter(this);
|
||||
this->drawWidget(painter);
|
||||
}
|
||||
|
||||
void ByteWidget::drawWidget(QPainter& painter) {
|
||||
painter.setRenderHints(QPainter::RenderHint::Antialiasing | QPainter::RenderHint::SmoothPixmapTransform, true);
|
||||
painter.setPen(Qt::PenStyle::NoPen);
|
||||
|
||||
static const auto widgetRect = QRect(0, 0, ByteWidget::WIDTH, ByteWidget::HEIGHT);
|
||||
|
||||
if (this->hoveredByteWidget.has_value()
|
||||
&& (
|
||||
this->hoveredByteWidget.value()->currentColumnIndex == this->currentColumnIndex
|
||||
|| this->hoveredByteWidget.value()->currentRowIndex == this->currentRowIndex
|
||||
)
|
||||
) {
|
||||
painter.setBrush(QColor(0x8E, 0x8B, 0x83, this->hoverActive ? 70 : 30));
|
||||
painter.drawRect(widgetRect);
|
||||
}
|
||||
|
||||
auto textColor = QColor(this->valueChanged ? "#547fba" : "#afb1b3");
|
||||
|
||||
if (this->valueInitialised) {
|
||||
|
||||
if (!this->isEnabled()) {
|
||||
textColor.setAlpha(100);
|
||||
}
|
||||
|
||||
painter.setPen(textColor);
|
||||
painter.drawText(widgetRect, Qt::AlignCenter, this->hexValue);
|
||||
|
||||
} else {
|
||||
textColor.setAlpha(100);
|
||||
painter.setPen(textColor);
|
||||
|
||||
static const auto placeholderString = QString("??");
|
||||
painter.drawText(widgetRect, Qt::AlignCenter, placeholderString);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "HexViewerWidget.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QTableWidget>
|
||||
#include <QScrollBar>
|
||||
#include <QScrollArea>
|
||||
#include <QPainter>
|
||||
@@ -11,6 +10,7 @@
|
||||
|
||||
#include "src/Helpers/Paths.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
@@ -53,35 +53,19 @@ HexViewerWidget::HexViewerWidget(
|
||||
|
||||
this->hoveredAddressLabel = this->bottomBar->findChild<QLabel*>("byte-address-label");
|
||||
|
||||
this->byteWidgetScrollArea = this->container->findChild<QScrollArea*>("byte-widget-scroll-area");
|
||||
auto byteWidgetScrollAreaWidgetContainer = this->byteWidgetScrollArea->findChild<QWidget*>(
|
||||
"byte-widget-scroll-area-container"
|
||||
auto byteItemGraphicsViewContainer = this->container->findChild<QWidget*>("graphics-view-container");
|
||||
auto byteItemGraphicsViewLayout = byteItemGraphicsViewContainer->findChild<QVBoxLayout*>(
|
||||
"byte-item-container-layout"
|
||||
);
|
||||
auto byteWidgetScrollAreaHorizontalLayout = byteWidgetScrollAreaWidgetContainer->findChild<QHBoxLayout*>(
|
||||
"byte-widget-scroll-area-horizontal-layout"
|
||||
);
|
||||
|
||||
this->byteWidgetContainer = new ByteWidgetContainer(
|
||||
this->byteItemGraphicsView = new ByteItemContainerGraphicsView(
|
||||
targetMemoryDescriptor,
|
||||
insightWorker,
|
||||
this->hoveredAddressLabel,
|
||||
byteWidgetScrollAreaHorizontalLayout->parentWidget()
|
||||
byteItemGraphicsViewContainer
|
||||
);
|
||||
this->byteItemGraphicsScene = this->byteItemGraphicsView->getScene();
|
||||
byteItemGraphicsViewLayout->insertWidget(0, this->byteItemGraphicsView);
|
||||
|
||||
byteWidgetScrollAreaHorizontalLayout->addWidget(this->byteWidgetContainer);
|
||||
|
||||
this->byteWidgetAddressContainer = byteWidgetScrollAreaWidgetContainer->findChild<QWidget*>(
|
||||
"address-container"
|
||||
);
|
||||
this->byteWidgetAddressLayout = this->byteWidgetAddressContainer->findChild<QVBoxLayout*>();
|
||||
this->byteWidgetAddressLayout->setContentsMargins(5, 10, 0, 5);
|
||||
|
||||
QObject::connect(
|
||||
this->byteWidgetContainer,
|
||||
&ByteWidgetContainer::byteWidgetsAdjusted,
|
||||
this,
|
||||
&HexViewerWidget::onByteWidgetsAdjusted
|
||||
);
|
||||
QObject::connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
@@ -93,7 +77,7 @@ HexViewerWidget::HexViewerWidget(
|
||||
}
|
||||
|
||||
void HexViewerWidget::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
this->byteWidgetContainer->updateValues(buffer);
|
||||
this->byteItemGraphicsScene->updateValues(buffer);
|
||||
}
|
||||
|
||||
void HexViewerWidget::resizeEvent(QResizeEvent* event) {
|
||||
@@ -109,36 +93,36 @@ void HexViewerWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
}
|
||||
|
||||
void HexViewerWidget::onByteWidgetsAdjusted() {
|
||||
const auto& byteWidgetsByRowIndex = this->byteWidgetContainer->byteWidgetsByRowIndex;
|
||||
|
||||
int layoutItemMaxIndex = this->byteWidgetAddressLayout->count() - 1;
|
||||
for (const auto& mappingPair : byteWidgetsByRowIndex) {
|
||||
const auto rowIndex = static_cast<int>(mappingPair.first);
|
||||
const auto& byteWidgets = mappingPair.second;
|
||||
|
||||
if (byteWidgets.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QLabel* labelWidget;
|
||||
if (rowIndex > layoutItemMaxIndex) {
|
||||
labelWidget = new QLabel(this->byteWidgetAddressContainer);
|
||||
labelWidget->setFixedSize(75, 20);
|
||||
labelWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
|
||||
this->byteWidgetAddressLayout->addWidget(labelWidget);
|
||||
layoutItemMaxIndex++;
|
||||
|
||||
} else {
|
||||
labelWidget = qobject_cast<QLabel*>(this->byteWidgetAddressLayout->itemAt(rowIndex)->widget());
|
||||
}
|
||||
|
||||
labelWidget->setText(byteWidgets.front()->relativeAddressHex);
|
||||
}
|
||||
|
||||
const auto rowCount = static_cast<int>(byteWidgetsByRowIndex.size());
|
||||
QLayoutItem* labelItem;
|
||||
while ((labelItem = this->byteWidgetAddressLayout->takeAt(rowCount)) != nullptr) {
|
||||
labelItem->widget()->deleteLater();
|
||||
}
|
||||
// const auto& byteWidgetsByRowIndex = this->byteWidgetContainer->byteWidgetsByRowIndex;
|
||||
//
|
||||
// int layoutItemMaxIndex = this->byteWidgetAddressLayout->count() - 1;
|
||||
// for (const auto& mappingPair : byteWidgetsByRowIndex) {
|
||||
// const auto rowIndex = static_cast<int>(mappingPair.first);
|
||||
// const auto& byteWidgets = mappingPair.second;
|
||||
//
|
||||
// if (byteWidgets.empty()) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// QLabel* labelWidget;
|
||||
// if (rowIndex > layoutItemMaxIndex) {
|
||||
// labelWidget = new QLabel(this->byteWidgetAddressContainer);
|
||||
// labelWidget->setFixedSize(75, 20);
|
||||
// labelWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
//
|
||||
// this->byteWidgetAddressLayout->addWidget(labelWidget);
|
||||
// layoutItemMaxIndex++;
|
||||
//
|
||||
// } else {
|
||||
// labelWidget = qobject_cast<QLabel*>(this->byteWidgetAddressLayout->itemAt(rowIndex)->widget());
|
||||
// }
|
||||
//
|
||||
// labelWidget->setText(byteWidgets.front()->relativeAddressHex);
|
||||
// }
|
||||
//
|
||||
// const auto rowCount = static_cast<int>(byteWidgetsByRowIndex.size());
|
||||
// QLayoutItem* labelItem;
|
||||
// while ((labelItem = this->byteWidgetAddressLayout->takeAt(rowCount)) != nullptr) {
|
||||
// labelItem->widget()->deleteLater();
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
#include <QGraphicsView>
|
||||
#include <QVBoxLayout>
|
||||
#include <set>
|
||||
#include <map>
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||
|
||||
#include "ByteWidgetContainer.hpp"
|
||||
#include "ByteItemContainerGraphicsView.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
@@ -46,7 +46,8 @@ namespace Bloom::Widgets
|
||||
QWidget* toolBar = nullptr;
|
||||
QWidget* bottomBar = nullptr;
|
||||
|
||||
ByteWidgetContainer* byteWidgetContainer = nullptr;
|
||||
ByteItemContainerGraphicsView* byteItemGraphicsView = nullptr;
|
||||
ByteItemGraphicsScene* byteItemGraphicsScene = nullptr;
|
||||
QWidget* byteWidgetScrollArea = nullptr;
|
||||
QWidget* byteWidgetAddressContainer = nullptr;
|
||||
QVBoxLayout* byteWidgetAddressLayout = nullptr;
|
||||
|
||||
@@ -53,55 +53,17 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ExpandingHeightScrollAreaWidget" name="byte-widget-scroll-area">
|
||||
<property name="widgetResizable"><bool>true</bool></property>
|
||||
<property name="verticalScrollBarPolicy"><enum>Qt::ScrollBarAsNeeded</enum></property>
|
||||
<property name="sizeAdjustPolicy"><enum>QAbstractScrollArea::AdjustToContents</enum></property>
|
||||
<!-- <property name="horizontalScrollBarPolicy"><enum>Qt::ScrollBarAlwaysOff</enum></property>-->
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||
</property>
|
||||
|
||||
<widget class="QWidget" name="byte-widget-scroll-area-container">
|
||||
<widget class="QWidget" name="graphics-view-container">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Ignored"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="byte-widget-scroll-area-vertical-layout">
|
||||
<layout class="QVBoxLayout" name="byte-item-container-layout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="byte-widget-scroll-area-horizontal-layout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="address-container">
|
||||
<property name="minimumWidth">
|
||||
<number>85</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Ignored"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="vertical-spacer">
|
||||
<property name="orientation">
|
||||
@@ -111,7 +73,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="bottom-bar">
|
||||
|
||||
Reference in New Issue
Block a user