Support external context menu actions in the HexViewerWidget
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
#include "ContextMenuAction.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
ContextMenuAction::ContextMenuAction(
|
||||
const QString& text,
|
||||
std::optional<IsEnabledCallbackType> isEnabledCallback,
|
||||
QWidget* parent
|
||||
)
|
||||
: isEnabledCallback(isEnabledCallback)
|
||||
, QAction(text, parent)
|
||||
{}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAction>
|
||||
#include <QWidget>
|
||||
#include <functional>
|
||||
#include <QString>
|
||||
#include <optional>
|
||||
|
||||
#include "src/Targets/TargetMemory.hpp"
|
||||
#include "ByteItem.hpp"
|
||||
|
||||
namespace Bloom::Widgets
|
||||
{
|
||||
class ContextMenuAction: public QAction
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/*
|
||||
* The ContextMenuAction::isEnabledCallback member is just a callback function that implements any specific
|
||||
* rules which determine if the action should be enabled (in the context menu).
|
||||
*
|
||||
* If the callback returns false, the menu action will be disabled.
|
||||
*
|
||||
* The callback is called just before the context menu is presented to the user, everytime the context menu
|
||||
* is requested.
|
||||
*
|
||||
* If no callback is specified (ContextMenuAction::isEnabledCallback == std::nullopt), the menu action will
|
||||
* always be enabled.
|
||||
*/
|
||||
using IsEnabledCallbackType = std::function<
|
||||
bool(const std::unordered_map<Targets::TargetMemoryAddress, ByteItem*>&)
|
||||
>;
|
||||
|
||||
public:
|
||||
std::optional<IsEnabledCallbackType> isEnabledCallback;
|
||||
|
||||
ContextMenuAction(
|
||||
const QString& text,
|
||||
std::optional<IsEnabledCallbackType> isEnabledCallback,
|
||||
QWidget* parent
|
||||
);
|
||||
|
||||
signals:
|
||||
void invoked(const std::unordered_map<Targets::TargetMemoryAddress, ByteItem*>& selectedByteItemsByAddress);
|
||||
};
|
||||
}
|
||||
@@ -237,6 +237,11 @@ namespace Bloom::Widgets
|
||||
}
|
||||
}
|
||||
|
||||
void HexViewerWidget::addExternalContextMenuAction(ContextMenuAction* action) {
|
||||
assert(this->byteItemGraphicsScene != nullptr);
|
||||
this->byteItemGraphicsScene->addExternalContextMenuAction(action);
|
||||
}
|
||||
|
||||
void HexViewerWidget::resizeEvent(QResizeEvent* event) {
|
||||
this->container->setFixedSize(
|
||||
this->width(),
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "HexViewerWidgetSettings.hpp"
|
||||
#include "ItemGraphicsView.hpp"
|
||||
#include "ContextMenuAction.hpp"
|
||||
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemoryRegion.hpp"
|
||||
#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/FocusedMemoryRegion.hpp"
|
||||
@@ -40,6 +41,7 @@ namespace Bloom::Widgets
|
||||
void updateValues();
|
||||
void refreshRegions();
|
||||
void setStackPointer(Targets::TargetStackPointer stackPointer);
|
||||
void addExternalContextMenuAction(ContextMenuAction* action);
|
||||
|
||||
signals:
|
||||
void ready();
|
||||
|
||||
@@ -321,6 +321,14 @@ namespace Bloom::Widgets
|
||||
this->update();
|
||||
}
|
||||
|
||||
void ItemGraphicsScene::addExternalContextMenuAction(ContextMenuAction* action) {
|
||||
QObject::connect(action, &QAction::triggered, this, [this, action] () {
|
||||
emit action->invoked(this->selectedByteItemsByAddress);
|
||||
});
|
||||
|
||||
this->externalContextMenuActions.push_back(action);
|
||||
}
|
||||
|
||||
bool ItemGraphicsScene::event(QEvent* event) {
|
||||
if (event->type() == QEvent::Type::GraphicsSceneLeave && this->state.hoveredByteItem != nullptr) {
|
||||
this->onByteItemLeave();
|
||||
@@ -549,6 +557,23 @@ namespace Bloom::Widgets
|
||||
this->deselectByteItemsAction->setEnabled(itemsSelected);
|
||||
|
||||
menu->addMenu(copyMenu);
|
||||
|
||||
if (!this->externalContextMenuActions.empty()) {
|
||||
menu->addSeparator();
|
||||
|
||||
for (auto& externalAction : this->externalContextMenuActions) {
|
||||
menu->addAction(externalAction);
|
||||
externalAction->setEnabled(
|
||||
itemsSelected
|
||||
&& (
|
||||
!externalAction->isEnabledCallback.has_value()
|
||||
|| externalAction->isEnabledCallback.value()(this->selectedByteItemsByAddress)
|
||||
)
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
menu->exec(event->screenPos());
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "GroupItem.hpp"
|
||||
#include "ByteItem.hpp"
|
||||
#include "ByteAddressContainer.hpp"
|
||||
#include "ContextMenuAction.hpp"
|
||||
|
||||
#include "HexViewerSharedState.hpp"
|
||||
|
||||
@@ -60,6 +61,7 @@ namespace Bloom::Widgets
|
||||
void refreshValues();
|
||||
QPointF getByteItemPositionByAddress(Targets::TargetMemoryAddress address);
|
||||
void allocateGraphicsItems();
|
||||
void addExternalContextMenuAction(ContextMenuAction* action);
|
||||
|
||||
signals:
|
||||
void ready();
|
||||
@@ -121,6 +123,8 @@ namespace Bloom::Widgets
|
||||
QAction* displayRelativeAddressAction = new QAction("Relative", this);
|
||||
QAction* displayAbsoluteAddressAction = new QAction("Absolute", this);
|
||||
|
||||
std::vector<ContextMenuAction*> externalContextMenuActions;
|
||||
|
||||
int getSceneWidth() {
|
||||
/*
|
||||
* Minus 2 for the QSS margin on the vertical scrollbar (which isn't accounted for during viewport
|
||||
|
||||
Reference in New Issue
Block a user