Initial work for the SnapshotDiff window
This commit is contained in:
@@ -109,6 +109,10 @@ target_sources(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/CreateSnapshotWindow/CreateSnapshotWindow.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/SnapshotViewer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/MemoryRegionItem.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiff.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialHexViewerWidget.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsView.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/DifferentialHexViewerWidget/DifferentialItemGraphicsScene.cpp
|
||||
|
||||
# Memory region manager window
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemoryRegionManager/MemoryRegionManagerWindow.cpp
|
||||
@@ -182,18 +186,29 @@ qt_add_resources(
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Images/display-annotations-disabled.svg"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Images/ascii-view.svg"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Images/ascii-view-disabled.svg"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/Images/new-snapshot-icon.svg"
|
||||
|
||||
# Hex viewer widget
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/UiFiles/HexViewerWidget.ui"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/Stylesheets/HexViewerWidget.qss"
|
||||
|
||||
# Memory snapshots
|
||||
# Memory snapshot manager
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/UiFiles/SnapshotManager.ui"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/CreateSnapshotWindow/UiFiles/CreateSnapshotWindow.ui"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/Images/new-snapshot-icon.svg"
|
||||
|
||||
# Memory snapshot viewer
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/UiFiles/SnapshotViewer.ui"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotViewer/Stylesheets/SnapshotViewer.qss"
|
||||
|
||||
# Memory snapshot diff
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/UiFiles/SnapshotDiff.ui"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Stylesheets/SnapshotDiff.qss"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-settings.svg"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-scroll.svg"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-hover.svg"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-selection.svg"
|
||||
|
||||
|
||||
# Memory region manager window
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemoryRegionManager/UiFiles/MemoryRegionManagerWindow.ui"
|
||||
"./UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemoryRegionManager/Stylesheets/MemoryRegionManagerWindow.qss"
|
||||
|
||||
@@ -87,6 +87,22 @@ namespace Bloom::Widgets
|
||||
void ListScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) {
|
||||
const auto button = mouseEvent->button();
|
||||
|
||||
const auto mousePosition = mouseEvent->buttonDownScenePos(button);
|
||||
|
||||
const auto items = this->items(mousePosition);
|
||||
if (items.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* clickedListItem = dynamic_cast<ListItem*>(items.first());
|
||||
if (clickedListItem == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clickedListItem->selected && button == Qt::MouseButton::RightButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto selectedItemCount = this->selectedItems.size();
|
||||
if (selectedItemCount > 0) {
|
||||
const auto ctrlModifierEnabled = (mouseEvent->modifiers() & Qt::ControlModifier) != 0;
|
||||
@@ -109,18 +125,6 @@ namespace Bloom::Widgets
|
||||
}
|
||||
}
|
||||
|
||||
const auto mousePosition = mouseEvent->buttonDownScenePos(button);
|
||||
|
||||
const auto items = this->items(mousePosition);
|
||||
if (items.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* clickedListItem = dynamic_cast<ListItem*>(items.first());
|
||||
if (clickedListItem == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->selectionLimit > 0) {
|
||||
this->selectedItems.push_back(clickedListItem);
|
||||
clickedListItem->selected = true;
|
||||
@@ -148,6 +152,14 @@ namespace Bloom::Widgets
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clickedListItem->selected) {
|
||||
/*
|
||||
* Sometimes, QT won't trigger a press event when the user double clicks. This usually happens when the
|
||||
* first click closes a context menu.
|
||||
*/
|
||||
this->mousePressEvent(mouseEvent);
|
||||
}
|
||||
|
||||
emit this->itemDoubleClicked(clickedListItem);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
struct DifferentialHexViewerSharedState
|
||||
{
|
||||
bool syncingSettings = false;
|
||||
bool syncingScroll = false;
|
||||
bool syncingHover = false;
|
||||
bool syncingSelection = false;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
#include "DifferentialHexViewerWidget.hpp"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <cassert>
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
DifferentialHexViewerWidget::DifferentialHexViewerWidget(
|
||||
DifferentialHexViewerWidgetType type,
|
||||
DifferentialHexViewerSharedState& state,
|
||||
const SnapshotDiffSettings& snapshotDiffSettings,
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& data,
|
||||
HexViewerWidgetSettings& settings,
|
||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
QWidget* parent
|
||||
)
|
||||
: HexViewerWidget(
|
||||
targetMemoryDescriptor,
|
||||
data,
|
||||
settings,
|
||||
focusedMemoryRegions,
|
||||
excludedMemoryRegions,
|
||||
parent
|
||||
)
|
||||
, type(type)
|
||||
, state(state)
|
||||
, snapshotDiffSettings(snapshotDiffSettings)
|
||||
{}
|
||||
|
||||
void DifferentialHexViewerWidget::init() {
|
||||
this->differentialView = new DifferentialItemGraphicsView(
|
||||
this->state,
|
||||
this->snapshotDiffSettings,
|
||||
this->targetMemoryDescriptor,
|
||||
this->data,
|
||||
this->focusedMemoryRegions,
|
||||
this->excludedMemoryRegions,
|
||||
this->settings,
|
||||
this->container
|
||||
);
|
||||
|
||||
if (this->type == DifferentialHexViewerWidgetType::PRIMARY) {
|
||||
this->differentialView->setLayoutDirection(Qt::LayoutDirection::RightToLeft);
|
||||
}
|
||||
|
||||
this->byteItemGraphicsView = this->differentialView;
|
||||
this->byteItemGraphicsView->hide();
|
||||
|
||||
auto* containerLayout = this->container->findChild<QVBoxLayout*>("hex-viewer-layout");
|
||||
containerLayout->insertWidget(2, this->byteItemGraphicsView);
|
||||
|
||||
QObject::connect(
|
||||
this->byteItemGraphicsView,
|
||||
&ItemGraphicsView::sceneReady,
|
||||
this,
|
||||
[this] {
|
||||
this->differentialScene = dynamic_cast<DifferentialItemGraphicsScene*>(
|
||||
this->byteItemGraphicsView->getScene()
|
||||
);
|
||||
this->byteItemGraphicsScene = this->differentialScene;
|
||||
|
||||
QObject::connect(
|
||||
this->byteItemGraphicsScene,
|
||||
&ItemGraphicsScene::hoveredAddress,
|
||||
this,
|
||||
&DifferentialHexViewerWidget::onHoveredAddress
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->byteItemGraphicsScene,
|
||||
&ItemGraphicsScene::selectionChanged,
|
||||
this,
|
||||
&DifferentialHexViewerWidget::onByteSelectionChanged
|
||||
);
|
||||
|
||||
this->loadingHexViewerLabel->hide();
|
||||
this->byteItemGraphicsView->show();
|
||||
|
||||
emit this->ready();
|
||||
}
|
||||
);
|
||||
|
||||
this->byteItemGraphicsView->initScene();
|
||||
}
|
||||
|
||||
void DifferentialHexViewerWidget::setOther(DifferentialHexViewerWidget* other) {
|
||||
assert(other->byteItemGraphicsView != nullptr);
|
||||
assert(other->byteItemGraphicsScene != nullptr);
|
||||
|
||||
this->other = other;
|
||||
this->differentialView->setOther(this->other->differentialView);
|
||||
|
||||
QObject::connect(
|
||||
this->other,
|
||||
&HexViewerWidget::settingsChanged,
|
||||
this,
|
||||
&DifferentialHexViewerWidget::onOtherSettingsChanged
|
||||
);
|
||||
}
|
||||
|
||||
void DifferentialHexViewerWidget::onOtherSettingsChanged(const HexViewerWidgetSettings& settings) {
|
||||
if (!this->snapshotDiffSettings.syncHexViewerSettings || this->state.syncingSettings) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->state.syncingSettings = true;
|
||||
|
||||
this->setStackMemoryGroupingEnabled(settings.groupStackMemory);
|
||||
this->setFocusedMemoryHighlightingEnabled(settings.highlightFocusedMemory);
|
||||
this->setHoveredRowAndColumnHighlightingEnabled(settings.highlightHoveredRowAndCol);
|
||||
this->setDisplayAsciiEnabled(settings.displayAsciiValues);
|
||||
this->setAnnotationsEnabled(settings.displayAnnotations);
|
||||
|
||||
this->state.syncingSettings = false;
|
||||
|
||||
this->differentialView->update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/HexViewerWidget.hpp"
|
||||
|
||||
#include "DifferentialHexViewerWidgetType.hpp"
|
||||
#include "DifferentialHexViewerSharedState.hpp"
|
||||
#include "DifferentialItemGraphicsView.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiffSettings.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class DifferentialHexViewerWidget final: public HexViewerWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DifferentialHexViewerWidget(
|
||||
DifferentialHexViewerWidgetType type,
|
||||
DifferentialHexViewerSharedState& state,
|
||||
const SnapshotDiffSettings& snapshotDiffSettings,
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& data,
|
||||
HexViewerWidgetSettings& settings,
|
||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
QWidget* parent
|
||||
);
|
||||
|
||||
void init() override;
|
||||
|
||||
void setOther(DifferentialHexViewerWidget* other);
|
||||
|
||||
private:
|
||||
DifferentialHexViewerWidgetType type;
|
||||
DifferentialHexViewerSharedState& state;
|
||||
|
||||
const SnapshotDiffSettings& snapshotDiffSettings;
|
||||
DifferentialItemGraphicsView* differentialView = nullptr;
|
||||
DifferentialItemGraphicsScene* differentialScene = nullptr;
|
||||
|
||||
DifferentialHexViewerWidget* other = nullptr;
|
||||
|
||||
void onOtherSettingsChanged(const HexViewerWidgetSettings& settings);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
enum class DifferentialHexViewerWidgetType: std::uint8_t
|
||||
{
|
||||
PRIMARY,
|
||||
SECONDARY,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
#include "DifferentialItemGraphicsScene.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
DifferentialItemGraphicsScene::DifferentialItemGraphicsScene(
|
||||
DifferentialHexViewerSharedState& state,
|
||||
const SnapshotDiffSettings& snapshotDiffSettings,
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& data,
|
||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
HexViewerWidgetSettings& settings,
|
||||
QGraphicsView* parent
|
||||
)
|
||||
: ItemGraphicsScene(
|
||||
targetMemoryDescriptor,
|
||||
data,
|
||||
focusedMemoryRegions,
|
||||
excludedMemoryRegions,
|
||||
settings,
|
||||
parent
|
||||
)
|
||||
, diffHexViewerState(state)
|
||||
, snapshotDiffSettings(snapshotDiffSettings)
|
||||
{}
|
||||
|
||||
void DifferentialItemGraphicsScene::setOther(DifferentialItemGraphicsScene* other) {
|
||||
this->other = other;
|
||||
|
||||
QObject::connect(
|
||||
this->other,
|
||||
&DifferentialItemGraphicsScene::hoveredAddress,
|
||||
this,
|
||||
&DifferentialItemGraphicsScene::onOtherHoveredAddress
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->other,
|
||||
&DifferentialItemGraphicsScene::selectionChanged,
|
||||
this,
|
||||
&DifferentialItemGraphicsScene::onOtherSelectionChanged
|
||||
);
|
||||
}
|
||||
|
||||
ByteItem* DifferentialItemGraphicsScene::byteItemAtViewportVerticalCenter() {
|
||||
const auto scrollBarValue = this->getScrollbarValue();
|
||||
|
||||
const auto midPosition = static_cast<qreal>(
|
||||
scrollBarValue
|
||||
);
|
||||
|
||||
const auto gridPointIndex = static_cast<decltype(this->gridPoints)::size_type>(
|
||||
std::min(
|
||||
static_cast<int>(
|
||||
std::floor(static_cast<float>(midPosition) / static_cast<float>(ItemGraphicsScene::GRID_SIZE)) + 1
|
||||
),
|
||||
static_cast<int>(this->gridPoints.size() - 1)
|
||||
)
|
||||
);
|
||||
|
||||
return static_cast<ByteItem*>(*(this->gridPoints[gridPointIndex]));
|
||||
}
|
||||
|
||||
void DifferentialItemGraphicsScene::onOtherHoveredAddress(
|
||||
const std::optional<Targets::TargetMemoryAddress>& address
|
||||
) {
|
||||
if (!this->snapshotDiffSettings.syncHexViewerHover || this->diffHexViewerState.syncingHover) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!address.has_value()) {
|
||||
if (this->state.hoveredByteItem != nullptr) {
|
||||
this->onByteItemLeave();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto& byteItem = this->topLevelGroup->byteItemsByAddress.find(*address)->second;
|
||||
const auto itemPosition = byteItem.position().y();
|
||||
const auto scrollbarValue = this->getScrollbarValue();
|
||||
|
||||
if (
|
||||
byteItem.allocatedGraphicsItem == nullptr
|
||||
|| itemPosition < scrollbarValue
|
||||
|| itemPosition > (scrollbarValue + this->views().first()->viewport()->height())
|
||||
) {
|
||||
// The item isn't visible
|
||||
return;
|
||||
}
|
||||
|
||||
this->diffHexViewerState.syncingHover = true;
|
||||
this->onByteItemEnter(byteItem);
|
||||
this->diffHexViewerState.syncingHover = false;
|
||||
}
|
||||
|
||||
void DifferentialItemGraphicsScene::onOtherSelectionChanged(
|
||||
const std::unordered_map<Targets::TargetMemoryAddress, ByteItem*>& selectedByteItemsByAddress
|
||||
) {
|
||||
if (!this->snapshotDiffSettings.syncHexViewerSelection || this->diffHexViewerState.syncingSelection) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->diffHexViewerState.syncingSelection = true;
|
||||
this->clearByteItemSelection();
|
||||
|
||||
for (const auto& [address, otherByteItem] : selectedByteItemsByAddress) {
|
||||
auto& byteItem = this->topLevelGroup->byteItemsByAddress.at(address);
|
||||
byteItem.selected = true;
|
||||
this->selectedByteItemsByAddress.insert(std::pair(byteItem.startAddress, &byteItem));
|
||||
}
|
||||
|
||||
emit this->selectionChanged(this->selectedByteItemsByAddress);
|
||||
this->diffHexViewerState.syncingSelection = false;
|
||||
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsScene.hpp"
|
||||
|
||||
#include "DifferentialHexViewerSharedState.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiffSettings.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class DifferentialItemGraphicsScene final: public ItemGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DifferentialItemGraphicsScene(
|
||||
DifferentialHexViewerSharedState& state,
|
||||
const SnapshotDiffSettings& snapshotDiffSettings,
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& data,
|
||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
HexViewerWidgetSettings& settings,
|
||||
QGraphicsView* parent
|
||||
);
|
||||
|
||||
void setOther(DifferentialItemGraphicsScene* other);
|
||||
ByteItem* byteItemAtViewportVerticalCenter();
|
||||
|
||||
protected:
|
||||
DifferentialHexViewerSharedState& diffHexViewerState;
|
||||
const SnapshotDiffSettings& snapshotDiffSettings;
|
||||
DifferentialItemGraphicsScene* other = nullptr;
|
||||
|
||||
void onOtherHoveredAddress(const std::optional<Targets::TargetMemoryAddress>& address);
|
||||
void onOtherSelectionChanged(
|
||||
const std::unordered_map<Targets::TargetMemoryAddress, ByteItem*>& selectedByteItemsByAddress
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "DifferentialItemGraphicsView.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
DifferentialItemGraphicsView::DifferentialItemGraphicsView(
|
||||
DifferentialHexViewerSharedState& state,
|
||||
const SnapshotDiffSettings& snapshotDiffSettings,
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& data,
|
||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
HexViewerWidgetSettings& settings,
|
||||
QWidget* parent
|
||||
)
|
||||
: ItemGraphicsView(
|
||||
targetMemoryDescriptor,
|
||||
data,
|
||||
focusedMemoryRegions,
|
||||
excludedMemoryRegions,
|
||||
settings,
|
||||
parent
|
||||
)
|
||||
, state(state)
|
||||
, snapshotDiffSettings(snapshotDiffSettings)
|
||||
{}
|
||||
|
||||
void DifferentialItemGraphicsView::initScene() {
|
||||
this->differentialScene = new DifferentialItemGraphicsScene(
|
||||
this->state,
|
||||
this->snapshotDiffSettings,
|
||||
this->targetMemoryDescriptor,
|
||||
this->data,
|
||||
this->focusedMemoryRegions,
|
||||
this->excludedMemoryRegions,
|
||||
this->settings,
|
||||
this
|
||||
);
|
||||
|
||||
this->scene = this->differentialScene;
|
||||
this->setScene(this->scene);
|
||||
|
||||
QObject::connect(
|
||||
this->scene,
|
||||
&ItemGraphicsScene::ready,
|
||||
this,
|
||||
[this] {
|
||||
this->scene->setEnabled(this->isEnabled());
|
||||
emit this->sceneReady();
|
||||
}
|
||||
);
|
||||
|
||||
this->scene->init();
|
||||
}
|
||||
|
||||
void DifferentialItemGraphicsView::setOther(DifferentialItemGraphicsView* other) {
|
||||
this->other = other;
|
||||
this->differentialScene->setOther(this->other->differentialScene);
|
||||
}
|
||||
|
||||
void DifferentialItemGraphicsView::alignScroll(
|
||||
Targets::TargetMemoryAddress otherByteItemAddress,
|
||||
int otherByteItemYOffset
|
||||
) {
|
||||
const auto byteItemPosition = this->differentialScene->getByteItemPositionByAddress(otherByteItemAddress);
|
||||
this->verticalScrollBar()->setValue(
|
||||
std::max(static_cast<int>(byteItemPosition.y() - otherByteItemYOffset), 0)
|
||||
);
|
||||
}
|
||||
|
||||
void DifferentialItemGraphicsView::scrollContentsBy(int dx, int dy) {
|
||||
ItemGraphicsView::scrollContentsBy(dx, dy);
|
||||
|
||||
if (!this->snapshotDiffSettings.syncHexViewerScroll || this->state.syncingScroll) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* byteItem = this->differentialScene->byteItemAtViewportVerticalCenter();
|
||||
|
||||
this->state.syncingScroll = true;
|
||||
this->other->alignScroll(byteItem->startAddress, byteItem->position().y() - this->verticalScrollBar()->value());
|
||||
this->state.syncingScroll = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ItemGraphicsView.hpp"
|
||||
|
||||
#include "DifferentialHexViewerSharedState.hpp"
|
||||
#include "DifferentialItemGraphicsScene.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/SnapshotDiffSettings.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class DifferentialItemGraphicsView final: public ItemGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DifferentialItemGraphicsView(
|
||||
DifferentialHexViewerSharedState& state,
|
||||
const SnapshotDiffSettings& snapshotDiffSettings,
|
||||
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor,
|
||||
const std::optional<Targets::TargetMemoryBuffer>& data,
|
||||
const std::vector<FocusedMemoryRegion>& focusedMemoryRegions,
|
||||
const std::vector<ExcludedMemoryRegion>& excludedMemoryRegions,
|
||||
HexViewerWidgetSettings& settings,
|
||||
QWidget* parent
|
||||
);
|
||||
|
||||
void initScene() override;
|
||||
|
||||
void setOther(DifferentialItemGraphicsView* other);
|
||||
void alignScroll(Targets::TargetMemoryAddress otherByteItemAddress, int otherByteItemYOffset);
|
||||
|
||||
protected:
|
||||
DifferentialHexViewerSharedState& state;
|
||||
const SnapshotDiffSettings& snapshotDiffSettings;
|
||||
|
||||
DifferentialItemGraphicsScene* differentialScene = nullptr;
|
||||
DifferentialItemGraphicsView* other = nullptr;
|
||||
|
||||
void scrollContentsBy(int dx, int dy) override;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="27"
|
||||
height="22"
|
||||
viewBox="0 0 7.1437502 5.8208333"
|
||||
version="1.1"
|
||||
id="svg974"
|
||||
sodipodi:docname="sync-hex-viewer-hover.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs968" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#343532"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="22.455047"
|
||||
inkscape:cx="13.604959"
|
||||
inkscape:cy="2.137604"
|
||||
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"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<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" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Main"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-0"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.5291664"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875001"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.6458333"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-0-3"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.5291664"
|
||||
y="1.8520832" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-7-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875001"
|
||||
y="1.8520832" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.6458333"
|
||||
y="1.8520832" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-8"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.5291664"
|
||||
y="3.96875" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875001"
|
||||
y="3.96875" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.645833"
|
||||
y="3.96875" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-3"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041671"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041671"
|
||||
y="1.8520832" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041667"
|
||||
y="3.96875" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-5"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7624998"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7-3"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7624998"
|
||||
y="1.8520833" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-5"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7624998"
|
||||
y="3.9687502" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-3-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208337"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7-6-2"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208337"
|
||||
y="1.8520833" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:0.204609;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-7-9"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208332"
|
||||
y="3.9687502" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.30862"
|
||||
id="rect858"
|
||||
width="3.4395833"
|
||||
height="0.26458335"
|
||||
x="1.8520834"
|
||||
y="1.0583333" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148256"
|
||||
id="rect858-3"
|
||||
width="0.26458335"
|
||||
height="0.79374999"
|
||||
x="1.8520834"
|
||||
y="1.0583333" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148256"
|
||||
id="rect858-3-6"
|
||||
width="0.26458335"
|
||||
height="0.79374999"
|
||||
x="5.0270829"
|
||||
y="1.0583334" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
@@ -0,0 +1,195 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="29"
|
||||
height="22"
|
||||
viewBox="0 0 7.6729169 5.8208333"
|
||||
version="1.1"
|
||||
id="svg974"
|
||||
sodipodi:docname="sync-hex-viewer-scroll.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs968" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#343532"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.6634687"
|
||||
inkscape:cx="9.9762183"
|
||||
inkscape:cy="-0.70628094"
|
||||
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"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<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" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Main"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-0"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="1.8520836"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.9104171"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.9687505"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-0-3"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="1.8520836"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-7-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.9104171"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.9687505"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0781248"
|
||||
id="rect1537-3-6-3-6-5"
|
||||
width="0.5291667"
|
||||
height="2.3812501"
|
||||
x="6.0854168"
|
||||
y="2.1166668" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0781248"
|
||||
id="rect1537-3-6-3-6-5-2"
|
||||
width="0.5291667"
|
||||
height="2.3812501"
|
||||
x="1.0583335"
|
||||
y="2.1166666" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-8"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="1.8520836"
|
||||
y="3.9687502" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.9104171"
|
||||
y="3.9687502" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.9687502"
|
||||
y="3.9687502" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-9"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.0270839"
|
||||
y="2.9104168" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7-1"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.0270839"
|
||||
y="1.8520832" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-2"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.0270834"
|
||||
y="3.9687502" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.444769"
|
||||
id="rect858"
|
||||
width="7.1437502"
|
||||
height="0.26458335"
|
||||
x="0.26458329"
|
||||
y="1.0583333" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.256788"
|
||||
id="rect858-3"
|
||||
width="0.26458335"
|
||||
height="2.3812501"
|
||||
x="0.26458329"
|
||||
y="1.0583333" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.256788"
|
||||
id="rect858-3-6"
|
||||
width="0.26458335"
|
||||
height="2.3812501"
|
||||
x="7.1437497"
|
||||
y="1.0583334" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148257"
|
||||
id="rect858-3-6-7"
|
||||
width="0.79374999"
|
||||
height="0.26458335"
|
||||
x="6.6145835"
|
||||
y="3.1750002" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148257"
|
||||
id="rect858-3-6-7-5"
|
||||
width="0.79374999"
|
||||
height="0.26458335"
|
||||
x="0.26458329"
|
||||
y="3.175" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
@@ -0,0 +1,209 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="27"
|
||||
height="22"
|
||||
viewBox="0 0 7.1437502 5.8208333"
|
||||
version="1.1"
|
||||
id="svg974"
|
||||
sodipodi:docname="sync-hex-viewer-selection.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs968" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#343532"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="31.72939"
|
||||
inkscape:cx="3.0098278"
|
||||
inkscape:cy="6.2717877"
|
||||
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"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<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" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Main"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-0"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.52916634"
|
||||
y="2.1166666" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875001"
|
||||
y="2.1166666" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.6458333"
|
||||
y="2.1166666" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-0-3"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.52916634"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-7-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875001"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.6458333"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-8"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.52916634"
|
||||
y="3.175" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875001"
|
||||
y="3.175" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.645833"
|
||||
y="3.175" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-3"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041671"
|
||||
y="2.1166666" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041671"
|
||||
y="1.058333" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041667"
|
||||
y="3.175" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-5"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7624998"
|
||||
y="2.1166668" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7-3"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7624998"
|
||||
y="1.0583332" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-5"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7624998"
|
||||
y="3.1750002" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-3-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208337"
|
||||
y="2.1166668" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-7-6-2"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208337"
|
||||
y="1.0583332" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-7-9"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208332"
|
||||
y="3.1750002" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.30862"
|
||||
id="rect858"
|
||||
width="3.4395833"
|
||||
height="0.26458335"
|
||||
x="2.3812501"
|
||||
y="4.4979167" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148256"
|
||||
id="rect858-3"
|
||||
width="0.26458335"
|
||||
height="0.79374999"
|
||||
x="2.3812501"
|
||||
y="3.96875" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148256"
|
||||
id="rect858-3-3"
|
||||
width="0.26458335"
|
||||
height="0.79374999"
|
||||
x="5.5562491"
|
||||
y="3.9687505" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="27"
|
||||
height="21"
|
||||
viewBox="0 0 7.1437502 5.5562499"
|
||||
version="1.1"
|
||||
id="svg974"
|
||||
sodipodi:docname="sync-hex-viewer-settings.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs968" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#343532"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="13.972733"
|
||||
inkscape:cx="8.6955075"
|
||||
inkscape:cy="8.5165876"
|
||||
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"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<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" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Main"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="fill:#316065;fill-opacity:1;stroke-width:0.0863703"
|
||||
id="rect1537-3-6"
|
||||
width="2.9104166"
|
||||
height="0.5291667"
|
||||
x="0.52916664"
|
||||
y="1.8520831" />
|
||||
<rect
|
||||
style="display:inline;fill:#316065;fill-opacity:1;stroke-width:0.0863703"
|
||||
id="rect1537-3-6-3"
|
||||
width="2.9104166"
|
||||
height="0.5291667"
|
||||
x="3.7041667"
|
||||
y="1.8520832" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-0"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.52916664"
|
||||
y="2.6458337" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-7"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875003"
|
||||
y="2.6458337" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.6458335"
|
||||
y="2.6458337" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-3-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041667"
|
||||
y="2.6458337" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-8"
|
||||
width="0.79374999"
|
||||
height="0.79374993"
|
||||
x="0.52916664"
|
||||
y="3.7041669" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-7-8"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="1.5875003"
|
||||
y="3.7041669" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="2.6458333"
|
||||
y="3.7041669" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-3-3"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="3.7041667"
|
||||
y="3.7041669" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-8-5"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7625003"
|
||||
y="2.6458337" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-3-6-3"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208337"
|
||||
y="2.6458337" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-4-4-5"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="4.7625003"
|
||||
y="3.7041669" />
|
||||
<rect
|
||||
style="display:inline;fill:#838382;fill-opacity:1;stroke-width:0.0552426"
|
||||
id="rect1537-3-6-3-3-6"
|
||||
width="0.79374999"
|
||||
height="0.79374999"
|
||||
x="5.8208337"
|
||||
y="3.7041669" />
|
||||
<rect
|
||||
style="fill:#6c6c6c;fill-opacity:1;stroke-width:0.331511"
|
||||
id="rect858"
|
||||
width="3.96875"
|
||||
height="0.26458335"
|
||||
x="1.5875"
|
||||
y="1.0583333" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148256"
|
||||
id="rect858-3"
|
||||
width="0.26458335"
|
||||
height="0.79374999"
|
||||
x="1.5875"
|
||||
y="1.0583333" />
|
||||
<rect
|
||||
style="display:inline;fill:#6c6c6c;fill-opacity:1;stroke-width:0.148256"
|
||||
id="rect858-3-6"
|
||||
width="0.26458335"
|
||||
height="0.79374999"
|
||||
x="5.291667"
|
||||
y="1.0583333" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,241 @@
|
||||
#include "SnapshotDiff.hpp"
|
||||
|
||||
#include <QFile>
|
||||
#include <QVBoxLayout>
|
||||
#include <algorithm>
|
||||
|
||||
#include "src/Insight/InsightWorker/Tasks/WriteTargetMemory.hpp"
|
||||
#include "src/Insight/InsightWorker/InsightWorker.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ConfirmationDialog.hpp"
|
||||
|
||||
#include "src/Services/PathService.hpp"
|
||||
#include "src/Exceptions/Exception.hpp"
|
||||
|
||||
#include "src/Insight/InsightSignals.hpp"
|
||||
#include "src/Logger/Logger.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
using Bloom::Exceptions::Exception;
|
||||
|
||||
SnapshotDiff::SnapshotDiff(
|
||||
MemorySnapshot& snapshotA,
|
||||
MemorySnapshot& snapshotB,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent
|
||||
)
|
||||
: QWidget(parent)
|
||||
, memoryDescriptor(memoryDescriptor)
|
||||
, hexViewerDataA(snapshotA.data)
|
||||
, focusedRegionsA(snapshotA.focusedRegions)
|
||||
, excludedRegionsA(snapshotA.excludedRegions)
|
||||
, stackPointerA(snapshotA.stackPointer)
|
||||
, hexViewerDataB(snapshotB.data)
|
||||
, focusedRegionsB(snapshotB.focusedRegions)
|
||||
, excludedRegionsB(snapshotB.excludedRegions)
|
||||
, stackPointerB(snapshotB.stackPointer)
|
||||
{
|
||||
this->init();
|
||||
|
||||
this->setWindowTitle(
|
||||
"Comparing snapshot \"" + snapshotA.name + "\" with snapshot \"" + snapshotB.name + "\""
|
||||
);
|
||||
|
||||
this->dataAPrimaryLabel->setText(snapshotA.name);
|
||||
this->dataBPrimaryLabel->setText(snapshotB.name);
|
||||
this->dataASecondaryLabel->setText(snapshotA.createdDate.toString("dd/MM/yyyy hh:mm"));
|
||||
this->dataBSecondaryLabel->setText(snapshotB.createdDate.toString("dd/MM/yyyy hh:mm"));
|
||||
}
|
||||
|
||||
void SnapshotDiff::showEvent(QShowEvent* event) {
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
void SnapshotDiff::resizeEvent(QResizeEvent* event) {
|
||||
this->container->setFixedSize(this->size());
|
||||
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void SnapshotDiff::init() {
|
||||
this->setWindowFlag(Qt::Window);
|
||||
this->setObjectName("snapshot-diff");
|
||||
|
||||
auto windowUiFile = QFile(
|
||||
QString::fromStdString(Services::PathService::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/SnapshotManager/SnapshotDiff/UiFiles/SnapshotDiff.ui"
|
||||
)
|
||||
);
|
||||
|
||||
auto stylesheetFile = QFile(
|
||||
QString::fromStdString(Services::PathService::compiledResourcesPath()
|
||||
+ "/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane"
|
||||
+ "/SnapshotManager/SnapshotDiff/Stylesheets/SnapshotDiff.qss"
|
||||
)
|
||||
);
|
||||
|
||||
if (!windowUiFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open SnapshotDiff UI file");
|
||||
}
|
||||
|
||||
if (!stylesheetFile.open(QFile::ReadOnly)) {
|
||||
throw Exception("Failed to open SnapshotDiff stylesheet file");
|
||||
}
|
||||
|
||||
// Set ideal window size
|
||||
this->setFixedSize(1600, 910);
|
||||
this->setMinimumSize(700, 600);
|
||||
this->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
||||
|
||||
auto uiLoader = UiLoader(this);
|
||||
const auto styleSheet = stylesheetFile.readAll();
|
||||
this->container = uiLoader.load(&windowUiFile, this);
|
||||
this->container->setStyleSheet(styleSheet);
|
||||
|
||||
auto* toolBar = this->container->findChild<QWidget*>("tool-bar");
|
||||
|
||||
this->syncHexViewerSettingsButton = toolBar->findChild<SvgToolButton*>("sync-settings-btn");
|
||||
this->syncHexViewerScrollButton = toolBar->findChild<SvgToolButton*>("sync-scroll-btn");
|
||||
this->syncHexViewerHoverButton = toolBar->findChild<SvgToolButton*>("sync-hover-btn");
|
||||
this->syncHexViewerSelectionButton = toolBar->findChild<SvgToolButton*>("sync-selection-btn");
|
||||
|
||||
this->restoreBytesAction = new ContextMenuAction("Restore Selection", std::nullopt, this);
|
||||
|
||||
this->dataAContainer = this->container->findChild<QWidget*>("data-a-container");
|
||||
this->dataBContainer = this->container->findChild<QWidget*>("data-b-container");
|
||||
|
||||
this->dataAPrimaryLabel = this->dataAContainer->findChild<Label*>("primary-label");
|
||||
this->dataASecondaryLabel = this->dataAContainer->findChild<Label*>("secondary-label");
|
||||
this->dataBPrimaryLabel = this->dataBContainer->findChild<Label*>("primary-label");
|
||||
this->dataBSecondaryLabel = this->dataBContainer->findChild<Label*>("secondary-label");
|
||||
|
||||
auto snapshotAContainerLayout = this->dataAContainer->findChild<QVBoxLayout*>();
|
||||
auto snapshotBContainerLayout = this->dataBContainer->findChild<QVBoxLayout*>();
|
||||
|
||||
this->hexViewerWidgetA = new DifferentialHexViewerWidget(
|
||||
DifferentialHexViewerWidgetType::PRIMARY,
|
||||
this->differentialHexViewerSharedState,
|
||||
this->settings,
|
||||
this->memoryDescriptor,
|
||||
this->hexViewerDataA,
|
||||
this->hexViewerWidgetSettingsA,
|
||||
this->focusedRegionsA,
|
||||
this->excludedRegionsA,
|
||||
this
|
||||
);
|
||||
|
||||
this->hexViewerWidgetB = new DifferentialHexViewerWidget(
|
||||
DifferentialHexViewerWidgetType::SECONDARY,
|
||||
this->differentialHexViewerSharedState,
|
||||
this->settings,
|
||||
this->memoryDescriptor,
|
||||
this->hexViewerDataB,
|
||||
this->hexViewerWidgetSettingsB,
|
||||
this->focusedRegionsB,
|
||||
this->excludedRegionsB,
|
||||
this
|
||||
);
|
||||
|
||||
this->hexViewerWidgetA->setObjectName("differential-hex-viewer-widget-a");
|
||||
this->hexViewerWidgetB->setObjectName("differential-hex-viewer-widget-b");
|
||||
|
||||
this->hexViewerWidgetA->setStyleSheet(this->hexViewerWidgetA->styleSheet() + styleSheet);
|
||||
this->hexViewerWidgetB->setStyleSheet(this->hexViewerWidgetB->styleSheet() + styleSheet);
|
||||
|
||||
snapshotAContainerLayout->addWidget(this->hexViewerWidgetA);
|
||||
snapshotBContainerLayout->addWidget(this->hexViewerWidgetB);
|
||||
|
||||
this->bottomBar = this->container->findChild<QWidget*>("bottom-bar");
|
||||
this->bottomBarLayout = this->bottomBar->findChild<QHBoxLayout*>();
|
||||
|
||||
this->setSyncHexViewerSettingsEnabled(this->settings.syncHexViewerSettings);
|
||||
this->setSyncHexViewerScrollEnabled(this->settings.syncHexViewerScroll);
|
||||
this->setSyncHexViewerHoverEnabled(this->settings.syncHexViewerHover);
|
||||
this->setSyncHexViewerSelectionEnabled(this->settings.syncHexViewerSelection);
|
||||
|
||||
QObject::connect(
|
||||
this->syncHexViewerSettingsButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setSyncHexViewerSettingsEnabled(!this->settings.syncHexViewerSettings);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->syncHexViewerScrollButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setSyncHexViewerScrollEnabled(!this->settings.syncHexViewerScroll);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->syncHexViewerHoverButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setSyncHexViewerHoverEnabled(!this->settings.syncHexViewerHover);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->syncHexViewerSelectionButton,
|
||||
&QToolButton::clicked,
|
||||
this,
|
||||
[this] {
|
||||
this->setSyncHexViewerSelectionEnabled(!this->settings.syncHexViewerSelection);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(this->hexViewerWidgetA, &HexViewerWidget::ready, this, &SnapshotDiff::onHexViewerAReady);
|
||||
QObject::connect(this->hexViewerWidgetB, &HexViewerWidget::ready, this, &SnapshotDiff::onHexViewerBReady);
|
||||
|
||||
this->hexViewerWidgetA->init();
|
||||
this->hexViewerWidgetB->init();
|
||||
|
||||
this->move(this->parentWidget()->window()->geometry().center() - this->rect().center());
|
||||
}
|
||||
|
||||
void SnapshotDiff::onHexViewerAReady() {
|
||||
this->hexViewerWidgetB->setOther(this->hexViewerWidgetA);
|
||||
|
||||
// this->hexViewerWidgetA->addExternalContextMenuAction(this->restoreBytesAction);
|
||||
if (this->stackPointerA.has_value()) {
|
||||
this->hexViewerWidgetA->setStackPointer(*(this->stackPointerA));
|
||||
}
|
||||
}
|
||||
|
||||
void SnapshotDiff::onHexViewerBReady() {
|
||||
this->hexViewerWidgetA->setOther(this->hexViewerWidgetB);
|
||||
|
||||
if (this->stackPointerB.has_value()) {
|
||||
this->hexViewerWidgetB->setStackPointer(*(this->stackPointerB));
|
||||
}
|
||||
}
|
||||
|
||||
void SnapshotDiff::setSyncHexViewerSettingsEnabled(bool enabled) {
|
||||
this->settings.syncHexViewerSettings = enabled;
|
||||
this->syncHexViewerSettingsButton->setChecked(this->settings.syncHexViewerSettings);
|
||||
}
|
||||
|
||||
void SnapshotDiff::setSyncHexViewerScrollEnabled(bool enabled) {
|
||||
this->settings.syncHexViewerScroll = enabled;
|
||||
this->syncHexViewerScrollButton->setChecked(this->settings.syncHexViewerScroll);
|
||||
}
|
||||
|
||||
void SnapshotDiff::setSyncHexViewerHoverEnabled(bool enabled) {
|
||||
this->settings.syncHexViewerHover = enabled;
|
||||
this->syncHexViewerHoverButton->setChecked(this->settings.syncHexViewerHover);
|
||||
}
|
||||
|
||||
void SnapshotDiff::setSyncHexViewerSelectionEnabled(bool enabled) {
|
||||
this->settings.syncHexViewerSelection = enabled;
|
||||
this->syncHexViewerSelectionButton->setChecked(this->settings.syncHexViewerSelection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QShowEvent>
|
||||
#include <QResizeEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPlainTextEdit>
|
||||
#include <optional>
|
||||
|
||||
#include "SnapshotDiffSettings.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/Label.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/PushButton.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/ListView/ListView.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TaskProgressIndicator/TaskProgressIndicator.hpp"
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp"
|
||||
#include "DifferentialHexViewerWidget/DifferentialHexViewerWidget.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/HexViewerWidget/ContextMenuAction.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class SnapshotDiff: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SnapshotDiff(
|
||||
MemorySnapshot& snapshotA,
|
||||
MemorySnapshot& snapshotB,
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor,
|
||||
QWidget* parent = nullptr
|
||||
);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
private:
|
||||
SnapshotDiffSettings settings;
|
||||
|
||||
const Targets::TargetMemoryDescriptor& memoryDescriptor;
|
||||
|
||||
QWidget* container = nullptr;
|
||||
|
||||
SvgToolButton* syncHexViewerSettingsButton = nullptr;
|
||||
SvgToolButton* syncHexViewerScrollButton = nullptr;
|
||||
SvgToolButton* syncHexViewerHoverButton = nullptr;
|
||||
SvgToolButton* syncHexViewerSelectionButton = nullptr;
|
||||
|
||||
QWidget* dataAContainer = nullptr;
|
||||
QWidget* dataBContainer = nullptr;
|
||||
|
||||
Label* dataAPrimaryLabel = nullptr;
|
||||
Label* dataBPrimaryLabel = nullptr;
|
||||
|
||||
Label* dataASecondaryLabel = nullptr;
|
||||
Label* dataBSecondaryLabel = nullptr;
|
||||
|
||||
DifferentialHexViewerSharedState differentialHexViewerSharedState;
|
||||
|
||||
std::optional<Targets::TargetMemoryBuffer> hexViewerDataA;
|
||||
std::vector<FocusedMemoryRegion> focusedRegionsA;
|
||||
std::vector<ExcludedMemoryRegion> excludedRegionsA;
|
||||
std::optional<Targets::TargetStackPointer> stackPointerA;
|
||||
DifferentialHexViewerWidget* hexViewerWidgetA = nullptr;
|
||||
HexViewerWidgetSettings hexViewerWidgetSettingsA = HexViewerWidgetSettings();
|
||||
|
||||
std::optional<Targets::TargetMemoryBuffer> hexViewerDataB;
|
||||
std::vector<FocusedMemoryRegion> focusedRegionsB;
|
||||
std::vector<ExcludedMemoryRegion> excludedRegionsB;
|
||||
std::optional<Targets::TargetStackPointer> stackPointerB;
|
||||
DifferentialHexViewerWidget* hexViewerWidgetB = nullptr;
|
||||
HexViewerWidgetSettings hexViewerWidgetSettingsB = HexViewerWidgetSettings();
|
||||
|
||||
ContextMenuAction* restoreBytesAction = nullptr;
|
||||
|
||||
QWidget* bottomBar = nullptr;
|
||||
QHBoxLayout* bottomBarLayout = nullptr;
|
||||
|
||||
void init();
|
||||
|
||||
void onHexViewerAReady();
|
||||
void onHexViewerBReady();
|
||||
|
||||
void setSyncHexViewerSettingsEnabled(bool enabled);
|
||||
void setSyncHexViewerScrollEnabled(bool enabled);
|
||||
void setSyncHexViewerHoverEnabled(bool enabled);
|
||||
void setSyncHexViewerSelectionEnabled(bool enabled);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
struct SnapshotDiffSettings
|
||||
{
|
||||
bool syncHexViewerSettings = true;
|
||||
bool syncHexViewerScroll = true;
|
||||
bool syncHexViewerHover = true;
|
||||
bool syncHexViewerSelection = false;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#snapshot-diff,
|
||||
#snapshot-diff #container {
|
||||
background-color: #373835;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#snapshot-diff #tool-bar {
|
||||
border-bottom: 1px solid #41423f;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
#snapshot-diff #tool-bar #sync-label {
|
||||
color: #8a8a8d;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
#snapshot-diff #tool-bar QToolButton {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
qproperty-buttonWidth: 33;
|
||||
qproperty-buttonHeight: 23;
|
||||
}
|
||||
|
||||
#snapshot-diff #tool-bar QToolButton:hover {
|
||||
background-color: #41413b;
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#snapshot-diff #tool-bar QToolButton:checked {
|
||||
background-color: #43433d;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#snapshot-diff #tool-bar #separator {
|
||||
background-color: transparent;
|
||||
border-right: 1px solid #41423f;
|
||||
padding: 0;
|
||||
min-width: 1px;
|
||||
max-width: 1px;
|
||||
}
|
||||
|
||||
#snapshot-diff #data-details-container {
|
||||
border-bottom: 1px solid #41423f;
|
||||
color: #8a8a8d;
|
||||
}
|
||||
|
||||
#snapshot-diff #data-details-container #primary-label,
|
||||
#snapshot-diff #data-details-container #secondary-label {
|
||||
color: #8a8a8d;
|
||||
}
|
||||
|
||||
#snapshot-diff #snapshot-a-container,
|
||||
#snapshot-diff #snapshot-a-container #data-details-container {
|
||||
border-right: 1px solid #41423f;
|
||||
}
|
||||
|
||||
#snapshot-diff #differential-hex-viewer-widget-a #hex-viewer-container QScrollBar {
|
||||
margin: 0;
|
||||
padding: 1px 3px 0 3px;
|
||||
width: 15px;
|
||||
border-right: 1px solid #41423f;
|
||||
}
|
||||
|
||||
#snapshot-diff #differential-hex-viewer-widget-a #hex-viewer-container #graphics-view {
|
||||
border-right: 1px solid #41423f;
|
||||
}
|
||||
|
||||
#snapshot-diff #bottom-bar {
|
||||
border-top: 1px solid #41423f;
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
<?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>
|
||||
<widget class="QWidget" name="tool-bar">
|
||||
<property name="minimumHeight">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="sizeHint">
|
||||
<size>
|
||||
<width>6</width>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Label" name="sync-label">
|
||||
<property name="text">
|
||||
<string>Synchronisation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="sizeHint">
|
||||
<size>
|
||||
<width>3</width>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SvgToolButton" name="sync-settings-btn">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="svgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-settings.svg</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Sync settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SvgToolButton" name="sync-scroll-btn">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="svgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-scroll.svg</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Sync scrolling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SvgToolButton" name="sync-hover-btn">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="svgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-hover.svg</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Sync hover</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SvgToolButton" name="sync-selection-btn">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="svgFilePath">
|
||||
<string>:/compiled/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/SnapshotManager/SnapshotDiff/Images/sync-hex-viewer-selection.svg</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Sync selection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="separator"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="sub-container">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="sub-layout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="data-a-container">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="data-details-container">
|
||||
<property name="minimumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="sizeHint">
|
||||
<size>
|
||||
<width>6</width>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Label" name="primary-label"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Label" name="secondary-label"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="sizeHint">
|
||||
<size>
|
||||
<width>6</width>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="data-b-container">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QWidget" name="data-details-container">
|
||||
<property name="minimumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="sizeHint">
|
||||
<size>
|
||||
<width>6</width>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Label" name="primary-label"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Label" name="secondary-label"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontal-spacer">
|
||||
<property name="sizeHint">
|
||||
<size>
|
||||
<width>6</width>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="bottom-bar">
|
||||
<property name="minimumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="maximumHeight">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</ui>
|
||||
@@ -100,6 +100,13 @@ namespace Bloom::Widgets
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->snapshotListScene,
|
||||
&ListScene::selectionChanged,
|
||||
this,
|
||||
&SnapshotManager::onSnapshotItemSelectionChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->snapshotListScene,
|
||||
&ListScene::itemDoubleClicked,
|
||||
@@ -125,9 +132,29 @@ namespace Bloom::Widgets
|
||||
&QAction::triggered,
|
||||
this,
|
||||
[this] {
|
||||
if (this->contextMenuSnapshotItem != nullptr) {
|
||||
this->openSnapshotViewer(this->contextMenuSnapshotItem->memorySnapshot.id);
|
||||
if (this->selectedSnapshotItems.size() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->openSnapshotViewer(this->selectedSnapshotItems.front()->memorySnapshot.id);
|
||||
}
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->openSnapshotDiffAction,
|
||||
&QAction::triggered,
|
||||
this,
|
||||
[this] {
|
||||
if (this->selectedSnapshotItems.size() != 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& first = this->selectedSnapshotItems.front()->memorySnapshot;
|
||||
const auto& second = this->selectedSnapshotItems.back()->memorySnapshot;
|
||||
this->openSnapshotDiff(
|
||||
first.createdDate < second.createdDate ? first.id : second.id,
|
||||
first.createdDate < second.createdDate ? second.id : first.id
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -136,9 +163,11 @@ namespace Bloom::Widgets
|
||||
&QAction::triggered,
|
||||
this,
|
||||
[this] {
|
||||
if (this->contextMenuSnapshotItem != nullptr) {
|
||||
this->deleteSnapshot(this->contextMenuSnapshotItem->memorySnapshot.id, true);
|
||||
if (this->selectedSnapshotItems.size() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->deleteSnapshot(this->selectedSnapshotItems.front()->memorySnapshot.id, true);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -147,9 +176,11 @@ namespace Bloom::Widgets
|
||||
&QAction::triggered,
|
||||
this,
|
||||
[this] {
|
||||
if (this->contextMenuSnapshotItem != nullptr) {
|
||||
this->restoreSnapshot(this->contextMenuSnapshotItem->memorySnapshot.id, true);
|
||||
if (this->selectedSnapshotItems.size() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->restoreSnapshot(this->selectedSnapshotItems.front()->memorySnapshot.id, true);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -247,12 +278,17 @@ namespace Bloom::Widgets
|
||||
this->snapshotListScene->addListItem(snapshotItem);
|
||||
}
|
||||
|
||||
void SnapshotManager::onSnapshotItemSelected(MemorySnapshotItem* item) {
|
||||
if (this->selectedItem != nullptr && this->selectedItem != item) {
|
||||
this->selectedItem->setSelected(false);
|
||||
}
|
||||
void SnapshotManager::onSnapshotItemSelectionChanged(const std::list<ListItem*>& selectedItems) {
|
||||
this->selectedSnapshotItems.clear();
|
||||
|
||||
this->selectedItem = item;
|
||||
std::transform(
|
||||
selectedItems.begin(),
|
||||
selectedItems.end(),
|
||||
std::inserter(this->selectedSnapshotItems, this->selectedSnapshotItems.end()),
|
||||
[] (ListItem* item) {
|
||||
return dynamic_cast<MemorySnapshotItem*>(item);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void SnapshotManager::openSnapshotViewer(const QString& snapshotId) {
|
||||
@@ -276,6 +312,34 @@ namespace Bloom::Widgets
|
||||
snapshotViewer->activateWindow();
|
||||
}
|
||||
|
||||
void SnapshotManager::openSnapshotDiff(const QString& snapshotIdA, const QString& snapshotIdB) {
|
||||
const auto diffKey = snapshotIdA + snapshotIdB;
|
||||
auto snapshotDiffIt = this->snapshotDiffs.find(diffKey);
|
||||
|
||||
if (snapshotDiffIt == this->snapshotDiffs.end()) {
|
||||
const auto& snapshotItA = this->snapshotsById.find(snapshotIdA);
|
||||
const auto& snapshotItB = this->snapshotsById.find(snapshotIdB);
|
||||
|
||||
if (snapshotItA == this->snapshotsById.end() || snapshotItB == this->snapshotsById.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
snapshotDiffIt = this->snapshotDiffs.insert(
|
||||
diffKey,
|
||||
new SnapshotDiff(
|
||||
snapshotItA.value(),
|
||||
snapshotItB.value(),
|
||||
this->memoryDescriptor,
|
||||
this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
auto* snapshotDiff = snapshotDiffIt.value();
|
||||
snapshotDiff->show();
|
||||
snapshotDiff->activateWindow();
|
||||
}
|
||||
|
||||
void SnapshotManager::deleteSnapshot(const QString& snapshotId, bool confirmationPromptEnabled) {
|
||||
const auto& snapshotIt = this->snapshotsById.find(snapshotId);
|
||||
|
||||
@@ -460,17 +524,22 @@ namespace Bloom::Widgets
|
||||
return;
|
||||
}
|
||||
|
||||
this->contextMenuSnapshotItem = snapshotItem;
|
||||
|
||||
auto* menu = new QMenu(this);
|
||||
|
||||
menu->addAction(this->openSnapshotViewerAction);
|
||||
menu->addAction(this->deleteSnapshotAction);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
menu->addAction(this->restoreSnapshotAction);
|
||||
|
||||
this->restoreSnapshotAction->setEnabled(this->targetState == Targets::TargetState::STOPPED);
|
||||
this->openSnapshotViewerAction->setEnabled(this->selectedSnapshotItems.size() == 1);
|
||||
this->deleteSnapshotAction->setEnabled(this->selectedSnapshotItems.size() == 1);
|
||||
this->restoreSnapshotAction->setEnabled(
|
||||
this->selectedSnapshotItems.size() == 1 && this->targetState == Targets::TargetState::STOPPED
|
||||
);
|
||||
|
||||
if (this->selectedSnapshotItems.size() == 2) {
|
||||
menu->addAction(this->openSnapshotDiffAction);
|
||||
}
|
||||
|
||||
menu->exec(sourcePosition);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "./CreateSnapshotWindow/CreateSnapshotWindow.hpp"
|
||||
#include "MemorySnapshotItem.hpp"
|
||||
#include "SnapshotViewer/SnapshotViewer.hpp"
|
||||
#include "SnapshotDiff/SnapshotDiff.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
@@ -65,6 +66,7 @@ namespace Bloom::Widgets
|
||||
QMap<QString, MemorySnapshot> snapshotsById;
|
||||
QMap<QString, MemorySnapshotItem*> snapshotItemsById;
|
||||
QMap<QString, SnapshotViewer*> snapshotViewersById;
|
||||
QMap<QString, SnapshotDiff*> snapshotDiffs;
|
||||
|
||||
QWidget* container = nullptr;
|
||||
QWidget* toolBar = nullptr;
|
||||
@@ -75,9 +77,10 @@ namespace Bloom::Widgets
|
||||
ListView* snapshotListView = nullptr;
|
||||
ListScene* snapshotListScene = nullptr;
|
||||
|
||||
MemorySnapshotItem* contextMenuSnapshotItem = nullptr;
|
||||
std::list<MemorySnapshotItem*> selectedSnapshotItems;
|
||||
|
||||
QAction* openSnapshotViewerAction = new QAction("Open", this);
|
||||
QAction* openSnapshotDiffAction = new QAction("Compare Selection", this);
|
||||
QAction* deleteSnapshotAction = new QAction("Delete", this);
|
||||
QAction* restoreSnapshotAction = new QAction("Restore", this);
|
||||
|
||||
@@ -89,8 +92,9 @@ namespace Bloom::Widgets
|
||||
);
|
||||
|
||||
void addSnapshot(MemorySnapshot&& snapshotTmp);
|
||||
void onSnapshotItemSelected(MemorySnapshotItem* item);
|
||||
void onSnapshotItemSelectionChanged(const std::list<ListItem*>& selectedItems);
|
||||
void openSnapshotViewer(const QString& snapshotId);
|
||||
void openSnapshotDiff(const QString& snapshotIdA, const QString& snapshotIdB);
|
||||
void deleteSnapshot(const QString& snapshotId, bool confirmationPromptEnabled);
|
||||
void restoreSnapshot(const QString& snapshotId, bool confirmationPromptEnabled);
|
||||
void onSnapshotItemDoubleClick(MemorySnapshotItem* item);
|
||||
|
||||
Reference in New Issue
Block a user