Implemented rubber-band selection rectangle in memory inspection hex viewer

This commit is contained in:
Nav
2022-09-03 20:36:38 +01:00
parent 4da3a84c06
commit 798f6913a4
4 changed files with 171 additions and 3 deletions

View File

@@ -94,6 +94,7 @@ namespace Bloom::Widgets
* color variant, so that we don't have to make copies or call QColor::setAlpha() for each ByteItem.
*/
static const auto highlightedBackgroundColor = QColor(0x3C, 0x59, 0x5C, 255);
static const auto selectedBackgroundColor = QColor(0x3C, 0x59, 0x5C, 255);
static const auto focusedRegionBackgroundColor = QColor(0x44, 0x44, 0x41, 255);
static const auto stackMemoryBackgroundColor = QColor(0x67, 0x57, 0x20, 210);
@@ -104,6 +105,13 @@ namespace Bloom::Widgets
100
);
static const auto disabledSelectedBackgroundColor = QColor(
selectedBackgroundColor.red(),
selectedBackgroundColor.green(),
selectedBackgroundColor.blue(),
100
);
static const auto disabledFocusedRegionBackgroundColor = QColor(
focusedRegionBackgroundColor.red(),
focusedRegionBackgroundColor.green(),
@@ -133,6 +141,10 @@ namespace Bloom::Widgets
return &(highlightedBackgroundColor);
}
if (this->selected) {
return &(selectedBackgroundColor);
}
const auto* hoveredByteItem = *(this->hoveredByteItem);
const auto hovered = hoveredByteItem == this;
const auto hoveredNeighbour =
@@ -169,6 +181,10 @@ namespace Bloom::Widgets
return &(disabledHighlightedBackgroundColor);
}
if (this->selected) {
return &(disabledSelectedBackgroundColor);
}
if (
this->settings.highlightStackMemory
&& this->currentStackPointer.has_value()

View File

@@ -34,6 +34,7 @@ namespace Bloom::Widgets
std::size_t currentColumnIndex = 0;
bool highlighted = false;
bool selected = false;
const FocusedMemoryRegion* focusedMemoryRegion = nullptr;
const ExcludedMemoryRegion* excludedMemoryRegion = nullptr;

View File

@@ -248,14 +248,109 @@ namespace Bloom::Widgets
return QGraphicsScene::event(event);
}
void ByteItemGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) {
static const auto rubberBandRectBackgroundColor = QColor(0x3C, 0x59, 0x5C, 0x82);
static const auto rubberBandRectBorderColor = QColor(0x3C, 0x59, 0x5C, 255);
const auto mousePosition = mouseEvent->buttonDownScenePos(Qt::MouseButton::LeftButton);
if (mousePosition.x() <= this->byteAddressContainer->boundingRect().width()) {
return;
}
this->clearSelectionRectItem();
this->rubberBandInitPoint = std::move(mousePosition);
this->rubberBandRectItem = new QGraphicsRectItem(
this->rubberBandInitPoint->x(),
this->rubberBandInitPoint->y(),
1,
1
);
this->rubberBandRectItem->setBrush(rubberBandRectBackgroundColor);
this->rubberBandRectItem->setPen(rubberBandRectBorderColor);
this->addItem(this->rubberBandRectItem);
const auto modifiers = mouseEvent->modifiers();
if ((modifiers & (Qt::ControlModifier | Qt::ShiftModifier)) == 0) {
this->clearByteItemSelection();
}
auto clickedItems = this->items(mousePosition);
if (!clickedItems.empty()) {
auto* clickedByteItem = dynamic_cast<ByteItem*>(clickedItems.last());
if (clickedByteItem != nullptr) {
if ((modifiers & Qt::ShiftModifier) != 0) {
for (
auto i = clickedByteItem->address;
i >= this->targetMemoryDescriptor.addressRange.startAddress;
--i
) {
auto* byteItem = this->byteItemsByAddress.at(i);
if (byteItem->selected) {
break;
}
this->toggleByteItemSelection(byteItem);
}
return;
}
this->toggleByteItemSelection(clickedByteItem);
}
}
}
void ByteItemGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
auto hoveredItems = this->items(mouseEvent->scenePos());
const auto mousePosition = mouseEvent->scenePos();
auto hoveredItems = this->items(mousePosition);
if (this->rubberBandRectItem != nullptr && this->rubberBandInitPoint.has_value()) {
const auto oldRect = this->rubberBandRectItem->rect();
this->rubberBandRectItem->setRect(
qMin(mousePosition.x(), this->rubberBandInitPoint->x()),
qMin(mousePosition.y(), this->rubberBandInitPoint->y()),
qAbs(mousePosition.x() - this->rubberBandInitPoint->x()),
qAbs(mousePosition.y() - this->rubberBandInitPoint->y())
);
if ((mouseEvent->modifiers() & Qt::ControlModifier) == 0) {
this->clearByteItemSelection();
} else {
const auto oldItems = this->items(oldRect, Qt::IntersectsItemShape);
for (auto* item : oldItems) {
auto* byteItem = dynamic_cast<ByteItem*>(item);
if (byteItem != nullptr && byteItem->selected) {
this->deselectByteItem(byteItem);
}
}
}
const auto items = this->items(this->rubberBandRectItem->rect(), Qt::IntersectsItemShape);
for (auto* item : items) {
auto* byteItem = dynamic_cast<ByteItem*>(item);
if (byteItem != nullptr && !byteItem->selected) {
this->selectByteItem(byteItem);
}
}
}
ByteItem* hoveredByteItem = nullptr;
AnnotationItem* hoveredAnnotationItem = nullptr;
if (!hoveredItems.empty()) {
hoveredByteItem = dynamic_cast<ByteItem*>(hoveredItems.at(0));
hoveredAnnotationItem = dynamic_cast<AnnotationItem*>(hoveredItems.at(0));
hoveredByteItem = dynamic_cast<ByteItem*>(hoveredItems.last());
hoveredAnnotationItem = dynamic_cast<AnnotationItem*>(hoveredItems.last());
}
if (hoveredByteItem != nullptr) {
@@ -277,6 +372,10 @@ namespace Bloom::Widgets
}
}
void ByteItemGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent) {
this->clearSelectionRectItem();
}
void ByteItemGraphicsScene::updateAnnotationValues(const Targets::TargetMemoryBuffer& buffer) {
const auto memoryStartAddress = this->targetMemoryDescriptor.addressRange.startAddress;
for (auto* valueAnnotationItem : this->valueAnnotationItems) {
@@ -504,4 +603,43 @@ namespace Bloom::Widgets
this->byteItemsByAddress.at(byteItemAddress)->update();
}
}
void ByteItemGraphicsScene::clearSelectionRectItem() {
if (this->rubberBandRectItem != nullptr) {
this->removeItem(this->rubberBandRectItem);
delete this->rubberBandRectItem;
this->rubberBandRectItem = nullptr;
}
}
void ByteItemGraphicsScene::selectByteItem(ByteItem* byteItem) {
byteItem->selected = true;
this->selectedByteItems.insert(byteItem);
byteItem->update();
}
void ByteItemGraphicsScene::deselectByteItem(ByteItem* byteItem) {
byteItem->selected = false;
this->selectedByteItems.erase(byteItem);
byteItem->update();
}
void ByteItemGraphicsScene::toggleByteItemSelection(ByteItem* byteItem) {
if (byteItem->selected) {
this->deselectByteItem(byteItem);
return;
}
this->selectByteItem(byteItem);
}
void ByteItemGraphicsScene::clearByteItemSelection() {
for (auto* byteItem : this->selectedByteItems) {
byteItem->selected = false;
byteItem->update();
}
this->selectedByteItems.clear();
}
}

View File

@@ -14,6 +14,8 @@
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneWheelEvent>
#include <optional>
#include <QGraphicsRectItem>
#include <QPointF>
#include "src/Targets/TargetMemory.hpp"
#include "src/Targets/TargetState.hpp"
@@ -63,7 +65,9 @@ namespace Bloom::Widgets
protected:
bool event(QEvent* event) override;
void mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent) override;
private:
const Targets::TargetMemoryDescriptor& targetMemoryDescriptor;
@@ -97,6 +101,10 @@ namespace Bloom::Widgets
ByteAddressContainer* byteAddressContainer = nullptr;
std::set<ByteItem*> highlightedByteItems;
std::set<ByteItem*> selectedByteItems;
QGraphicsRectItem* rubberBandRectItem = nullptr;
std::optional<QPointF> rubberBandInitPoint = std::nullopt;
int getSceneWidth() {
/*
@@ -116,5 +124,10 @@ namespace Bloom::Widgets
void onByteWidgetLeave();
void onAnnotationItemEnter(Bloom::Widgets::AnnotationItem* annotationItem);
void onAnnotationItemLeave();
void clearSelectionRectItem();
void selectByteItem(ByteItem* byteItem);
void deselectByteItem(ByteItem* byteItem);
void toggleByteItemSelection(ByteItem* byteItem);
void clearByteItemSelection();
};
}