New target memory inspection pane and hex viewer widget
This commit is contained in:
@@ -27,6 +27,7 @@ using Bloom::Targets::TargetPinState;
|
||||
using Bloom::Targets::TargetVariant;
|
||||
using Bloom::Targets::TargetPackage;
|
||||
using Bloom::Targets::TargetPinDescriptor;
|
||||
using Bloom::Targets::TargetMemoryType;
|
||||
|
||||
InsightWindow::InsightWindow(InsightWorker& insightWorker): QMainWindow(nullptr), insightWorker(insightWorker) {
|
||||
this->setObjectName("main-window");
|
||||
@@ -239,10 +240,12 @@ void InsightWindow::toggleTargetRegistersPane() {
|
||||
|
||||
void InsightWindow::toggleRamInspectionPane() {
|
||||
if (this->bottomPanel->isVisible()) {
|
||||
this->ramInspectionPane->deactivate();
|
||||
this->bottomPanel->hide();
|
||||
this->ramInspectionButton->setChecked(false);
|
||||
|
||||
} else {
|
||||
this->ramInspectionPane->activate();
|
||||
this->bottomPanel->show();
|
||||
this->ramInspectionButton->setChecked(true);
|
||||
}
|
||||
@@ -486,13 +489,26 @@ void InsightWindow::activate() {
|
||||
auto leftPanelLayout = this->leftPanel->layout();
|
||||
this->targetRegistersSidePane = new TargetRegistersPaneWidget(
|
||||
this->targetDescriptor,
|
||||
insightWorker,
|
||||
this->insightWorker,
|
||||
this->leftPanel
|
||||
);
|
||||
leftPanelLayout->addWidget(this->targetRegistersSidePane);
|
||||
this->targetRegistersButton->setChecked(false);
|
||||
this->targetRegistersButton->setDisabled(false);
|
||||
|
||||
auto bottomPanelLayout = this->bottomPanel->layout();
|
||||
if (this->targetDescriptor.memoryDescriptorsByType.contains(TargetMemoryType::RAM)) {
|
||||
auto& ramDescriptor = this->targetDescriptor.memoryDescriptorsByType.at(TargetMemoryType::RAM);
|
||||
this->ramInspectionPane = new TargetMemoryInspectionPane(
|
||||
ramDescriptor,
|
||||
this->insightWorker,
|
||||
this->bottomPanel
|
||||
);
|
||||
bottomPanelLayout->addWidget(this->ramInspectionPane);
|
||||
this->ramInspectionButton->setChecked(false);
|
||||
this->ramInspectionButton->setDisabled(false);
|
||||
}
|
||||
|
||||
this->toggleUi(this->targetState != TargetState::STOPPED);
|
||||
this->activated = true;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp"
|
||||
#include "Widgets/TargetWidgets/TargetPackageWidget.hpp"
|
||||
#include "Widgets/TargetRegistersPane/TargetRegistersPaneWidget.hpp"
|
||||
#include "Widgets/TargetMemoryInspectionPane/TargetMemoryInspectionPane.hpp"
|
||||
#include "AboutWindow.hpp"
|
||||
|
||||
namespace Bloom
|
||||
@@ -91,6 +92,7 @@ namespace Bloom
|
||||
|
||||
QWidget* bottomMenuBar = nullptr;
|
||||
Widgets::PanelWidget* bottomPanel = nullptr;
|
||||
Widgets::TargetMemoryInspectionPane* ramInspectionPane = nullptr;
|
||||
QToolButton* ramInspectionButton = nullptr;
|
||||
|
||||
QWidget* footer = nullptr;
|
||||
|
||||
@@ -299,19 +299,30 @@ QScrollBar::sub-line:vertical {
|
||||
border-top: 1px solid #2F2F2D;
|
||||
}
|
||||
|
||||
#bottom-menu-bar #ram-inspection-btn {
|
||||
#bottom-menu-bar #ram-inspection-btn,
|
||||
#bottom-menu-bar #eeprom-inspection-btn {
|
||||
position: relative;
|
||||
border: none;
|
||||
min-width: 90px;
|
||||
min-height: 22px;
|
||||
}
|
||||
|
||||
#bottom-menu-bar #ram-inspection-btn #ram-inspection-btn-icon {
|
||||
margin-left: 9px;
|
||||
#bottom-menu-bar #ram-inspection-btn {
|
||||
min-width: 71px;
|
||||
}
|
||||
|
||||
#bottom-menu-bar #ram-inspection-btn #ram-inspection-btn-label {
|
||||
margin-left: 2px;
|
||||
#bottom-menu-bar #eeprom-inspection-btn {
|
||||
min-width: 97px;
|
||||
}
|
||||
|
||||
#bottom-menu-bar #ram-inspection-btn #ram-inspection-btn-icon,
|
||||
#bottom-menu-bar #eeprom-inspection-btn #eeprom-inspection-btn-icon {
|
||||
margin-left: 7px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
#bottom-menu-bar #ram-inspection-btn #ram-inspection-btn-label,
|
||||
#bottom-menu-bar #eeprom-inspection-btn #eeprom-inspection-btn-label {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
#bottom-menu-bar QToolButton:hover,
|
||||
@@ -324,3 +335,57 @@ QScrollBar::sub-line:vertical {
|
||||
border-top: 1px solid #2F2F2D;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Target Memory Inspection Pane */
|
||||
#target-memory-inspection-pane #title-bar {
|
||||
background-color: #383F43;
|
||||
border-bottom: 1px solid #2F2F2D;
|
||||
}
|
||||
|
||||
#target-memory-inspection-pane #title {
|
||||
color: #afb1b3;
|
||||
}
|
||||
|
||||
#hex-viewer-container #tool-bar,
|
||||
#hex-viewer-container #search-bar {
|
||||
border-bottom: 1px solid #2F2F2D;
|
||||
}
|
||||
|
||||
#hex-viewer-container #tool-bar QToolButton {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
qproperty-buttonWidth: 24;
|
||||
qproperty-buttonHeight: 20;
|
||||
}
|
||||
|
||||
#hex-viewer-container #tool-bar QToolButton:hover {
|
||||
background-color: #454541;
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#hex-viewer-container QScrollArea,
|
||||
#hex-viewer-container #byte-widget-scroll-area-container {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#hex-viewer-container #byte-widget-scroll-area-container #address-container {
|
||||
background-color: transparent;
|
||||
border-right: 1px solid #2F2F2D;
|
||||
}
|
||||
|
||||
#hex-viewer-container #byte-widget-scroll-area-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 {
|
||||
color: rgba(175, 177, 179, 0.3);
|
||||
}
|
||||
|
||||
#hex-viewer-container #byte {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
@@ -252,11 +252,8 @@
|
||||
<property name="panelType">
|
||||
<enum>PanelWidgetType::BOTTOM</enum>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="minimumResize">
|
||||
<number>200</number>
|
||||
<number>300</number>
|
||||
</property>
|
||||
<property name="handleSize">
|
||||
<number>10</number>
|
||||
@@ -275,14 +272,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<item alignment="Qt::AlignBottom">
|
||||
<widget class="QWidget" name="bottom-menu-bar">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
@@ -323,20 +320,71 @@
|
||||
<number>22</number>
|
||||
</property>
|
||||
<property name="containerWidth">
|
||||
<number>15</number>
|
||||
<number>22</number>
|
||||
</property>
|
||||
<property name="svgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/target-registers.svg</string>
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-icon.svg</string>
|
||||
</property>
|
||||
<property name="disabledSvgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/target-registers-disabled.svg</string>
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-icon-disabled.svg</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignLeft">
|
||||
<widget class="QLabel" name="ram-inspection-btn-label">
|
||||
<property name="text">
|
||||
<string>Memory</string>
|
||||
<string>RAM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignLeft">
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="eeprom-inspection-btn">
|
||||
<property name="toolTip">
|
||||
<string>Inspect EEPROM</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="disabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignLeft">
|
||||
<widget class="SvgWidget" name="eeprom-inspection-btn-icon">
|
||||
<property name="containerHeight">
|
||||
<number>22</number>
|
||||
</property>
|
||||
<property name="containerWidth">
|
||||
<number>22</number>
|
||||
</property>
|
||||
<property name="svgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-icon.svg</string>
|
||||
</property>
|
||||
<property name="disabledSvgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-icon-disabled.svg</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignLeft">
|
||||
<widget class="QLabel" name="eeprom-inspection-btn-label">
|
||||
<property name="text">
|
||||
<string>EEPROM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#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();
|
||||
|
||||
this->connect(this, &ClickableWidget::clicked, this, onClick);
|
||||
this->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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <QEvent>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class ByteWidget: public ClickableWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static constexpr int WIDTH = 25;
|
||||
static constexpr int HEIGHT = 20;
|
||||
|
||||
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;
|
||||
|
||||
ByteWidget(
|
||||
std::size_t byteNumber,
|
||||
std::uint32_t address,
|
||||
std::optional<ByteWidget*>& hoveredByteWidget,
|
||||
QWidget* parent
|
||||
);
|
||||
void setValue(unsigned char value);
|
||||
|
||||
public slots:
|
||||
void setSelected(bool selected);
|
||||
|
||||
signals:
|
||||
void selected(ByteWidget*);
|
||||
void enter(ByteWidget*);
|
||||
void leave(ByteWidget*);
|
||||
|
||||
protected:
|
||||
virtual void postSetSelected(bool selected) {};
|
||||
bool event(QEvent* event) override;
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void drawWidget(QPainter& painter);
|
||||
|
||||
private:
|
||||
bool hoverActive = false;
|
||||
bool valueChanged = false;
|
||||
|
||||
QString hexValue;
|
||||
std::optional<QString> asciiValue;
|
||||
|
||||
std::optional<ByteWidget*>& hoveredByteWidget;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
#include "ByteWidgetContainer.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QTableWidget>
|
||||
#include <QScrollBar>
|
||||
#include <QPainter>
|
||||
#include <cmath>
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
|
||||
ByteWidgetContainer::ByteWidgetContainer(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): QWidget(parent), targetMemoryDescriptor(targetMemoryDescriptor), insightWorker(insightWorker), parent(parent) {
|
||||
this->setObjectName("byte-widget-container");
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Ignored);
|
||||
|
||||
this->setContentsMargins(
|
||||
10,
|
||||
10,
|
||||
10,
|
||||
10
|
||||
);
|
||||
|
||||
/*
|
||||
* Construct ByteWidget objects
|
||||
*
|
||||
* No need to position them here - the subsequent call to resizeEvent() will do that.
|
||||
*/
|
||||
const auto memorySize = this->targetMemoryDescriptor.size();
|
||||
const auto startAddress = this->targetMemoryDescriptor.addressRange.startAddress;
|
||||
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);
|
||||
this->byteWidgetsByAddress.insert(std::pair(
|
||||
address,
|
||||
byteWidget
|
||||
));
|
||||
|
||||
this->connect(byteWidget, &ByteWidget::enter, this, &ByteWidgetContainer::onByteWidgetEnter);
|
||||
this->connect(byteWidget, &ByteWidget::leave, this, &ByteWidgetContainer::onByteWidgetLeave);
|
||||
}
|
||||
|
||||
this->connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&ByteWidgetContainer::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::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 ByteWidgetContainer::adjustByteWidgets() {
|
||||
std::map<std::size_t, std::vector<ByteWidget*>> byteWidgetsByRowIndex;
|
||||
std::map<std::size_t, std::vector<ByteWidget*>> byteWidgetsByColumnIndex;
|
||||
|
||||
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;
|
||||
const auto rowCapacity = static_cast<std::size_t>(
|
||||
std::floor((width - margins.left() - margins.right()) / byteWidgetWidth)
|
||||
);
|
||||
const auto rowCount = static_cast<int>(
|
||||
std::ceil(static_cast<double>(this->byteWidgetsByAddress.size()) / static_cast<double>(rowCapacity))
|
||||
);
|
||||
|
||||
for (auto& [address, byteWidget] : this->byteWidgetsByAddress) {
|
||||
const auto rowIndex = static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(byteWidget->byteIndex + 1) / static_cast<double>(rowCapacity)) - 1
|
||||
);
|
||||
const auto columnIndex = static_cast<std::size_t>(
|
||||
static_cast<double>(byteWidget->byteIndex)
|
||||
- (std::floor(byteWidget->byteIndex / rowCapacity) * static_cast<double>(rowCapacity))
|
||||
);
|
||||
|
||||
byteWidget->setGeometry(QRect(
|
||||
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
|
||||
));
|
||||
|
||||
byteWidget->currentRowIndex = static_cast<std::size_t>(rowIndex);
|
||||
byteWidget->currentColumnIndex = static_cast<std::size_t>(columnIndex);
|
||||
|
||||
byteWidgetsByRowIndex[byteWidget->currentRowIndex].emplace_back(byteWidget);
|
||||
byteWidgetsByColumnIndex[byteWidget->currentColumnIndex].emplace_back(byteWidget);
|
||||
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
const auto minHeight = (rowCount * byteWidgetHeight) + margins.top() + margins.bottom();
|
||||
this->setMinimumHeight(minHeight);
|
||||
this->parent->setMinimumHeight(minHeight);
|
||||
|
||||
this->byteWidgetsByRowIndex.swap(byteWidgetsByRowIndex);
|
||||
this->byteWidgetsByColumnIndex.swap(byteWidgetsByColumnIndex);
|
||||
|
||||
emit this->byteWidgetsAdjusted();
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::onByteWidgetEnter(ByteWidget* widget) {
|
||||
this->hoveredByteWidget = widget;
|
||||
|
||||
if (!this->byteWidgetsByRowIndex.empty()) {
|
||||
for (auto& byteWidget : this->byteWidgetsByColumnIndex.at(widget->currentColumnIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto& byteWidget : this->byteWidgetsByRowIndex.at(widget->currentRowIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ByteWidgetContainer::onByteWidgetLeave(ByteWidget* widget) {
|
||||
this->hoveredByteWidget = std::nullopt;
|
||||
|
||||
if (!this->byteWidgetsByRowIndex.empty()) {
|
||||
for (auto& byteWidget : this->byteWidgetsByColumnIndex.at(widget->currentColumnIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
|
||||
for (auto& byteWidget : this->byteWidgetsByRowIndex.at(widget->currentRowIndex)) {
|
||||
byteWidget->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QEvent>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
#include "src/Targets/TargetState.hpp"
|
||||
|
||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||
|
||||
#include "ByteWidget.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class ByteWidgetContainer: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
std::optional<ByteWidget*> 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;
|
||||
|
||||
ByteWidgetContainer(
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
);
|
||||
|
||||
void updateValues(const Targets::TargetMemoryBuffer& buffer);
|
||||
|
||||
signals:
|
||||
void byteWidgetsAdjusted();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
private:
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor;
|
||||
InsightWorker& insightWorker;
|
||||
|
||||
QWidget* parent = nullptr;
|
||||
|
||||
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
|
||||
|
||||
void adjustByteWidgets();
|
||||
|
||||
private slots:
|
||||
void onTargetStateChanged(Targets::TargetState newState);
|
||||
void onByteWidgetEnter(ByteWidget* widget);
|
||||
void onByteWidgetLeave(ByteWidget* widget);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
#include "HexViewerWidget.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QTableWidget>
|
||||
#include <QScrollBar>
|
||||
#include <QScrollArea>
|
||||
#include <QPainter>
|
||||
#include <cmath>
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
||||
|
||||
#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,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
): QWidget(parent), targetMemoryDescriptor(targetMemoryDescriptor), insightWorker(insightWorker) {
|
||||
this->setObjectName("hex-viewer-widget");
|
||||
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
||||
|
||||
auto widgetUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget"
|
||||
+ "/UiFiles/HexViewerWidget.ui"
|
||||
)
|
||||
);
|
||||
|
||||
if (!widgetUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open HexViewerWidget UI file");
|
||||
}
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&widgetUiFile, this);
|
||||
this->container->setFixedSize(this->size());
|
||||
this->container->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
this->toolBar = this->container->findChild<QWidget*>("tool-bar");
|
||||
this->refreshButton = this->container->findChild<QToolButton*>("refresh-memory-btn");
|
||||
|
||||
this->toolBar->setContentsMargins(0, 0, 0, 0);
|
||||
this->toolBar->layout()->setContentsMargins(5, 0, 5, 0);
|
||||
|
||||
this->byteWidgetScrollArea = this->container->findChild<QScrollArea*>("byte-widget-scroll-area");
|
||||
auto byteWidgetScrollAreaWidgetContainer = this->byteWidgetScrollArea->findChild<QWidget*>(
|
||||
"byte-widget-scroll-area-container"
|
||||
);
|
||||
auto byteWidgetScrollAreaHorizontalLayout = byteWidgetScrollAreaWidgetContainer->findChild<QHBoxLayout*>(
|
||||
"byte-widget-scroll-area-horizontal-layout"
|
||||
);
|
||||
|
||||
this->byteWidgetContainer = new ByteWidgetContainer(
|
||||
targetMemoryDescriptor,
|
||||
insightWorker,
|
||||
byteWidgetScrollAreaHorizontalLayout->parentWidget()
|
||||
);
|
||||
|
||||
byteWidgetScrollAreaHorizontalLayout->addWidget(this->byteWidgetContainer);
|
||||
|
||||
this->byteWidgetAddressContainer = byteWidgetScrollAreaWidgetContainer->findChild<QWidget*>(
|
||||
"address-container"
|
||||
);
|
||||
this->byteWidgetAddressLayout = this->byteWidgetAddressContainer->findChild<QVBoxLayout*>();
|
||||
this->byteWidgetAddressLayout->setContentsMargins(5, 10, 0, 5);
|
||||
|
||||
this->connect(
|
||||
this->byteWidgetContainer,
|
||||
&ByteWidgetContainer::byteWidgetsAdjusted,
|
||||
this,
|
||||
&HexViewerWidget::onByteWidgetsAdjusted
|
||||
);
|
||||
this->connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&HexViewerWidget::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->show();
|
||||
}
|
||||
|
||||
void HexViewerWidget::updateValues(const Targets::TargetMemoryBuffer& buffer) {
|
||||
this->byteWidgetContainer->updateValues(buffer);
|
||||
}
|
||||
|
||||
void HexViewerWidget::resizeEvent(QResizeEvent* event) {
|
||||
this->container->setFixedSize(
|
||||
this->width(),
|
||||
this->height()
|
||||
);
|
||||
}
|
||||
|
||||
void HexViewerWidget::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QEvent>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
#include "src/Targets/TargetState.hpp"
|
||||
|
||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||
|
||||
#include "ByteWidgetContainer.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class HexViewerWidget: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QToolButton* refreshButton = nullptr;
|
||||
|
||||
HexViewerWidget(
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
QWidget* parent
|
||||
);
|
||||
|
||||
void updateValues(const Targets::TargetMemoryBuffer& buffer);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
private:
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor;
|
||||
InsightWorker& insightWorker;
|
||||
|
||||
QWidget* container = nullptr;
|
||||
QWidget* toolBar = nullptr;
|
||||
|
||||
ByteWidgetContainer* byteWidgetContainer = nullptr;
|
||||
QWidget* byteWidgetScrollArea = nullptr;
|
||||
QWidget* byteWidgetAddressContainer = nullptr;
|
||||
QVBoxLayout* byteWidgetAddressLayout = nullptr;
|
||||
|
||||
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
|
||||
|
||||
private slots:
|
||||
void onTargetStateChanged(Targets::TargetState newState);
|
||||
void onByteWidgetsAdjusted();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<widget class="QWidget" name="hex-viewer-container">
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||
</property>
|
||||
<item alignment="Qt::AlignTop">
|
||||
<widget class="QWidget" name="tool-bar">
|
||||
<property name="minimumHeight">
|
||||
<number>27</number>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>27</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="SvgToolButton" name="refresh-memory-btn">
|
||||
<property name="svgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Images/refresh.svg</string>
|
||||
</property>
|
||||
<property name="disabledSvgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Images/refresh-disabled.svg</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Refresh Memory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignTop">
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</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">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Ignored"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="byte-widget-scroll-area-vertical-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>80</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">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<!-- <item>-->
|
||||
<!-- <spacer name="vertical-spacer">-->
|
||||
<!-- <property name="orientation">-->
|
||||
<!-- <enum>Qt::Vertical</enum>-->
|
||||
<!-- </property>-->
|
||||
<!-- </spacer>-->
|
||||
<!-- </item>-->
|
||||
</layout>
|
||||
</widget>
|
||||
</ui>
|
||||
@@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="20"
|
||||
height="15"
|
||||
viewBox="0 0 5.2916667 3.96875"
|
||||
version="1.1"
|
||||
id="svg974"
|
||||
sodipodi:docname="memory-inspection-icon.svg"
|
||||
inkscape:version="1.0.1 (1.0.1+r75)">
|
||||
<defs
|
||||
id="defs968" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#343532"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.9899495"
|
||||
inkscape:cx="-326.26819"
|
||||
inkscape:cy="-242.5437"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:window-width="3440"
|
||||
inkscape:window-height="1353"
|
||||
inkscape:window-x="2560"
|
||||
inkscape:window-y="34"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true" />
|
||||
<metadata
|
||||
id="metadata971">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Body"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.142636"
|
||||
id="rect1537"
|
||||
width="3.175"
|
||||
height="1.3229166"
|
||||
x="1.0583333"
|
||||
y="1.3229167" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Pins">
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0411755"
|
||||
id="rect1537-3"
|
||||
width="0.52916664"
|
||||
height="0.66145831"
|
||||
x="2.3812499"
|
||||
y="0.39687499" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0411754"
|
||||
id="rect1537-3-6"
|
||||
width="0.52916664"
|
||||
height="0.66145831"
|
||||
x="1.5875001"
|
||||
y="0.39687499" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0411754"
|
||||
id="rect1537-3-7"
|
||||
width="0.52916664"
|
||||
height="0.66145831"
|
||||
x="3.175"
|
||||
y="0.39687499" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0411754"
|
||||
id="rect1537-3-5"
|
||||
width="0.52916664"
|
||||
height="0.66145831"
|
||||
x="2.3812499"
|
||||
y="2.9104166" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0411754"
|
||||
id="rect1537-3-5-6"
|
||||
width="0.52916664"
|
||||
height="0.66145831"
|
||||
x="3.175"
|
||||
y="2.9104166" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0411754"
|
||||
id="rect1537-3-5-2"
|
||||
width="0.52916664"
|
||||
height="0.66145831"
|
||||
x="1.5875"
|
||||
y="2.9104166" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="20"
|
||||
height="16"
|
||||
viewBox="0 0 5.2916667 4.2333333"
|
||||
version="1.1"
|
||||
id="svg974"
|
||||
sodipodi:docname="memory-inspection-icon.svg"
|
||||
inkscape:version="1.0.1 (1.0.1+r75)">
|
||||
<defs
|
||||
id="defs968" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#343532"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="25.611036"
|
||||
inkscape:cy="3.7785754"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer2"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:window-width="3440"
|
||||
inkscape:window-height="1353"
|
||||
inkscape:window-x="2560"
|
||||
inkscape:window-y="34"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true" />
|
||||
<metadata
|
||||
id="metadata971">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Body"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Pins">
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368285"
|
||||
id="rect1537-3"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="1.5874999"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-6"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="0.79374987"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-7"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="2.3812499"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="1.5875001"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-6"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="2.3812501"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-2"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="0.79374987"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-9"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="1.5875003"
|
||||
y="2.6458333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-6-1"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="2.3812501"
|
||||
y="2.6458333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-2-2"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="0.79374987"
|
||||
y="2.6458333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-70"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="3.175"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-7-9"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="3.9687502"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-3"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="3.1750002"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-6-6"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="3.9687502"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-9-0"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="3.1750004"
|
||||
y="2.6458335" />
|
||||
<rect
|
||||
style="fill:#c4c4c4;fill-opacity:0.545098;stroke-width:0.0368284"
|
||||
id="rect1537-3-5-6-1-6"
|
||||
width="0.52916664"
|
||||
height="0.5291667"
|
||||
x="3.9687502"
|
||||
y="2.6458335" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,155 @@
|
||||
#include "TargetMemoryInspectionPane.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
#include <set>
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
||||
|
||||
#include "src/Insight/InsightWorker/Tasks/ReadTargetMemory.hpp"
|
||||
|
||||
#include "src/Helpers/Paths.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
using namespace Bloom::Widgets;
|
||||
using namespace Bloom::Exceptions;
|
||||
|
||||
using Bloom::Targets::TargetMemoryDescriptor;
|
||||
using Bloom::Targets::TargetMemoryType;
|
||||
|
||||
TargetMemoryInspectionPane::TargetMemoryInspectionPane(
|
||||
const TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
PanelWidget* parent
|
||||
): QWidget(parent), parent(parent), targetMemoryDescriptor(targetMemoryDescriptor), insightWorker(insightWorker) {
|
||||
this->setObjectName("target-memory-inspection-pane");
|
||||
|
||||
auto memoryInspectionPaneUiFile = QFile(
|
||||
QString::fromStdString(Paths::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/UiFiles/TargetMemoryInspectionPane.ui"
|
||||
)
|
||||
);
|
||||
|
||||
if (!memoryInspectionPaneUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open MemoryInspectionPane UI file");
|
||||
}
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
this->container = uiLoader.load(&memoryInspectionPaneUiFile, this);
|
||||
this->container->setFixedSize(parent->width(), parent->maximumHeight());
|
||||
|
||||
this->titleBar = this->container->findChild<QWidget*>("title-bar");
|
||||
|
||||
this->titleBar->layout()->setContentsMargins(7, 0, 7, 0);
|
||||
auto titleLabel = this->titleBar->findChild<QLabel*>("title");
|
||||
titleLabel->setText("Internal RAM");
|
||||
|
||||
auto subContainerLayout = this->container->findChild<QHBoxLayout*>("sub-container-layout");
|
||||
this->hexViewerWidget = new HexViewerWidget(this->targetMemoryDescriptor, this->insightWorker, this);
|
||||
this->hexViewerWidget->setDisabled(true);
|
||||
|
||||
subContainerLayout->addWidget(this->hexViewerWidget);
|
||||
|
||||
this->connect(
|
||||
&insightWorker,
|
||||
&InsightWorker::targetStateUpdated,
|
||||
this,
|
||||
&TargetMemoryInspectionPane::onTargetStateChanged
|
||||
);
|
||||
|
||||
this->connect(
|
||||
this->hexViewerWidget->refreshButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->refreshMemoryValues();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::refreshMemoryValues(std::optional<std::function<void(void)>> callback) {
|
||||
this->hexViewerWidget->refreshButton->setDisabled(true);
|
||||
|
||||
auto readMemoryTask = new ReadTargetMemory(
|
||||
this->targetMemoryDescriptor.type,
|
||||
this->targetMemoryDescriptor.addressRange.startAddress,
|
||||
this->targetMemoryDescriptor.size()
|
||||
);
|
||||
|
||||
this->connect(
|
||||
readMemoryTask,
|
||||
&ReadTargetMemory::targetMemoryRead,
|
||||
this,
|
||||
&TargetMemoryInspectionPane::onMemoryRead
|
||||
);
|
||||
|
||||
this->connect(
|
||||
readMemoryTask,
|
||||
&InsightWorkerTask::completed,
|
||||
this,
|
||||
[this] {
|
||||
this->hexViewerWidget->refreshButton->setDisabled(false);
|
||||
}
|
||||
);
|
||||
|
||||
if (callback.has_value()) {
|
||||
this->connect(
|
||||
readMemoryTask,
|
||||
&InsightWorkerTask::completed,
|
||||
this,
|
||||
callback.value()
|
||||
);
|
||||
}
|
||||
|
||||
this->insightWorker.queueTask(readMemoryTask);
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::activate() {
|
||||
this->show();
|
||||
this->activated = true;
|
||||
this->postActivate();
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::deactivate() {
|
||||
this->hide();
|
||||
this->activated = false;
|
||||
this->postDeactivate();
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::resizeEvent(QResizeEvent* event) {
|
||||
const auto parentSize = this->parent->size();
|
||||
const auto width = parentSize.width() - 1;
|
||||
this->container->setFixedSize(width, parentSize.height());
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::postActivate() {
|
||||
if (this->targetState == Targets::TargetState::STOPPED) {
|
||||
this->refreshMemoryValues();
|
||||
}
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::postDeactivate() {
|
||||
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::onTargetStateChanged(Targets::TargetState newState) {
|
||||
using Targets::TargetState;
|
||||
this->targetState = newState;
|
||||
|
||||
if (this->activated) {
|
||||
if (newState == TargetState::STOPPED) {
|
||||
this->refreshMemoryValues([this] {
|
||||
this->hexViewerWidget->setDisabled(false);
|
||||
});
|
||||
|
||||
} else {
|
||||
this->hexViewerWidget->setDisabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TargetMemoryInspectionPane::onMemoryRead(const Targets::TargetMemoryBuffer& buffer) {
|
||||
this->hexViewerWidget->updateValues(buffer);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QScrollArea>
|
||||
#include <set>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QEvent>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp"
|
||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||
|
||||
#include "HexViewerWidget/HexViewerWidget.hpp"
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
#include "src/Targets/TargetState.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class TargetMemoryInspectionPane: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
bool activated = false;
|
||||
|
||||
TargetMemoryInspectionPane(
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
InsightWorker& insightWorker,
|
||||
PanelWidget *parent
|
||||
);
|
||||
|
||||
void refreshMemoryValues(std::optional<std::function<void(void)>> callback = std::nullopt);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
virtual void postActivate();
|
||||
virtual void postDeactivate();
|
||||
|
||||
private:
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor;
|
||||
InsightWorker& insightWorker;
|
||||
|
||||
PanelWidget* parent = nullptr;
|
||||
QWidget* container = nullptr;
|
||||
|
||||
QWidget* titleBar = nullptr;
|
||||
HexViewerWidget* hexViewerWidget = nullptr;
|
||||
|
||||
Targets::TargetState targetState = Targets::TargetState::UNKNOWN;
|
||||
|
||||
private slots:
|
||||
void onTargetStateChanged(Targets::TargetState newState);
|
||||
void onMemoryRead(const Targets::TargetMemoryBuffer& buffer);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<widget class="QWidget" name="container">
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignTop">
|
||||
<widget class="QWidget" name="title-bar">
|
||||
<property name="minimumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="title"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="sub-container-layout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
||||
</layout>
|
||||
</item>
|
||||
<!-- <item alignment="Qt::AlignTop">-->
|
||||
<!-- <spacer name="vertical-spacer">-->
|
||||
<!-- <property name="orientation">-->
|
||||
<!-- <enum>Qt::Vertical</enum>-->
|
||||
<!-- </property>-->
|
||||
<!-- </spacer>-->
|
||||
<!-- </item>-->
|
||||
</layout>
|
||||
</widget>
|
||||
</ui>
|
||||
@@ -23,6 +23,8 @@
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/UiFiles/TargetRegisterInspectorWindow.ui">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/UiFiles/TargetRegisterInspectorWindow.ui</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/UiFiles/RegisterHistoryWidget.ui">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/UiFiles/RegisterHistoryWidget.ui</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/UiFiles/ErrorDialogue.ui">./Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/UiFiles/ErrorDialogue.ui</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/UiFiles/TargetMemoryInspectionPane.ui">./Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/UiFiles/TargetMemoryInspectionPane.ui</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui">./Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui</file>
|
||||
|
||||
<!-- QT UI stylesheets for Insight -->
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss">./Insight/UserInterfaces/InsightWindow/Stylesheets/InsightWindow.qss</file>
|
||||
@@ -47,5 +49,7 @@
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/search-registers.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/Images/search-registers.svg</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Images/icon.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/Images/icon.svg</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/Images/icon.svg">./Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/Images/icon.svg</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-icon.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-icon.svg</file>
|
||||
<file alias="/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-disabled-icon.svg">./Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/Images/memory-inspection-disabled-icon.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
Reference in New Issue
Block a user