mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-21 22:23:46 +00:00
Simplify and move Plugin context menu gui code out of core. (#2039)
This commit is contained in:
parent
a1b5a41e56
commit
1ae78655fa
@ -155,7 +155,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
|||||||
|
|
||||||
Plugins()->loadPlugins();
|
Plugins()->loadPlugins();
|
||||||
|
|
||||||
for (auto *plugin : Plugins()->getPlugins()) {
|
for (auto &plugin : Plugins()->getPlugins()) {
|
||||||
plugin->registerDecompilers();
|
plugin->registerDecompilers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,9 +248,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
|||||||
|
|
||||||
CutterApplication::~CutterApplication()
|
CutterApplication::~CutterApplication()
|
||||||
{
|
{
|
||||||
#ifdef CUTTER_ENABLE_PYTHON
|
|
||||||
Plugins()->destroyPlugins();
|
Plugins()->destroyPlugins();
|
||||||
#endif
|
|
||||||
delete mainWindow;
|
delete mainWindow;
|
||||||
#ifdef CUTTER_ENABLE_PYTHON
|
#ifdef CUTTER_ENABLE_PYTHON
|
||||||
Python()->shutdown();
|
Python()->shutdown();
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
<primitive-type name="bool"/>
|
<primitive-type name="bool"/>
|
||||||
|
|
||||||
<object-type name="CutterCore">
|
<object-type name="CutterCore">
|
||||||
<enum-type name="ContextMenuType" />
|
|
||||||
</object-type>
|
</object-type>
|
||||||
<object-type name="Configuration" />
|
<object-type name="Configuration" />
|
||||||
<object-type name="MainWindow" >
|
<object-type name="MainWindow" >
|
||||||
<enum-type name="MenuType" />
|
<enum-type name="MenuType" />
|
||||||
|
<enum-type name="ContextMenuType" />
|
||||||
</object-type>
|
</object-type>
|
||||||
<object-type name="BasicBlockHighlighter" />
|
<object-type name="BasicBlockHighlighter" />
|
||||||
<object-type name="CutterDockWidget" />
|
<object-type name="CutterDockWidget" />
|
||||||
|
@ -209,13 +209,6 @@ void CutterCore::initialize()
|
|||||||
|
|
||||||
// Initialize Async tasks manager
|
// Initialize Async tasks manager
|
||||||
asyncTaskManager = new AsyncTaskManager(this);
|
asyncTaskManager = new AsyncTaskManager(this);
|
||||||
|
|
||||||
// Initialize context menu extensions for plugins
|
|
||||||
disassemblyContextMenuExtensions = new QMenu(tr("Plugins"));
|
|
||||||
disassemblyContextMenuExtensions->menuAction()->setVisible(false);
|
|
||||||
disassemblyContextMenuExtensions->setEnabled(false);
|
|
||||||
addressableContextMenuExtensions = new QMenu(tr("Plugins"));
|
|
||||||
addressableContextMenuExtensions->menuAction()->setVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CutterCore::~CutterCore()
|
CutterCore::~CutterCore()
|
||||||
@ -2301,39 +2294,6 @@ QStringList CutterCore::getAnalPluginNames()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMenu *CutterCore::getContextMenuExtensions(ContextMenuType type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case ContextMenuType::Disassembly:
|
|
||||||
return disassemblyContextMenuExtensions;
|
|
||||||
case ContextMenuType::Addressable:
|
|
||||||
return addressableContextMenuExtensions;
|
|
||||||
default:
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CutterCore::addContextMenuExtensionAction(ContextMenuType type, QAction *action)
|
|
||||||
{
|
|
||||||
QMenu *menu = getContextMenuExtensions(type);
|
|
||||||
if (menu) {
|
|
||||||
// The submenu should be invisible and disabled while it's empty
|
|
||||||
if (menu->isEmpty()) {
|
|
||||||
menu->menuAction()->setVisible(true);
|
|
||||||
menu->setEnabled(true);
|
|
||||||
}
|
|
||||||
menu->addAction(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CutterCore::addContextMenuExtensionSeparator(ContextMenuType type)
|
|
||||||
{
|
|
||||||
QMenu *menu = getContextMenuExtensions(type);
|
|
||||||
if (menu) {
|
|
||||||
menu->addSeparator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList CutterCore::getProjectNames()
|
QStringList CutterCore::getProjectNames()
|
||||||
{
|
{
|
||||||
CORE_LOCK();
|
CORE_LOCK();
|
||||||
|
@ -425,17 +425,6 @@ public:
|
|||||||
QStringList getAsmPluginNames();
|
QStringList getAsmPluginNames();
|
||||||
QStringList getAnalPluginNames();
|
QStringList getAnalPluginNames();
|
||||||
|
|
||||||
/* Context menu plugins */
|
|
||||||
enum class ContextMenuType { Disassembly, Addressable };
|
|
||||||
/**
|
|
||||||
* @brief Fetches the pointer to a context menu extension of type
|
|
||||||
* @param type - the type of the context menu
|
|
||||||
* @return plugins submenu of the selected context menu
|
|
||||||
*/
|
|
||||||
QMenu *getContextMenuExtensions(ContextMenuType type);
|
|
||||||
void addContextMenuExtensionAction(ContextMenuType type, QAction *action);
|
|
||||||
void addContextMenuExtensionSeparator(ContextMenuType type);
|
|
||||||
|
|
||||||
/* Projects */
|
/* Projects */
|
||||||
QStringList getProjectNames();
|
QStringList getProjectNames();
|
||||||
void openProject(const QString &name);
|
void openProject(const QString &name);
|
||||||
@ -649,9 +638,6 @@ private:
|
|||||||
|
|
||||||
QSharedPointer<R2Task> debugTask;
|
QSharedPointer<R2Task> debugTask;
|
||||||
R2TaskDialog *debugTaskDialog;
|
R2TaskDialog *debugTaskDialog;
|
||||||
|
|
||||||
QMenu *disassemblyContextMenuExtensions = nullptr;
|
|
||||||
QMenu *addressableContextMenuExtensions = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RCoreLocked
|
class RCoreLocked
|
||||||
|
@ -132,6 +132,10 @@ void MainWindow::initUI()
|
|||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
// Initialize context menu extensions for plugins
|
||||||
|
disassemblyContextMenuExtensions = new QMenu(tr("Plugins"), this);
|
||||||
|
addressableContextMenuExtensions = new QMenu(tr("Plugins"), this);
|
||||||
|
|
||||||
connect(ui->actionExtraGraph, &QAction::triggered, this, &MainWindow::addExtraGraph);
|
connect(ui->actionExtraGraph, &QAction::triggered, this, &MainWindow::addExtraGraph);
|
||||||
connect(ui->actionExtraDisassembly, &QAction::triggered, this, &MainWindow::addExtraDisassembly);
|
connect(ui->actionExtraDisassembly, &QAction::triggered, this, &MainWindow::addExtraDisassembly);
|
||||||
connect(ui->actionExtraHexdump, &QAction::triggered, this, &MainWindow::addExtraHexdump);
|
connect(ui->actionExtraHexdump, &QAction::triggered, this, &MainWindow::addExtraHexdump);
|
||||||
@ -193,7 +197,7 @@ void MainWindow::initUI()
|
|||||||
initBackForwardMenu();
|
initBackForwardMenu();
|
||||||
|
|
||||||
/* Setup plugins interfaces */
|
/* Setup plugins interfaces */
|
||||||
for (auto plugin : Plugins()->getPlugins()) {
|
for (auto &plugin : Plugins()->getPlugins()) {
|
||||||
plugin->setupInterface(this);
|
plugin->setupInterface(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1660,3 +1664,15 @@ void MainWindow::onZoomReset()
|
|||||||
{
|
{
|
||||||
Config()->setZoomFactor(1.0);
|
Config()->setZoomFactor(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMenu *MainWindow::getContextMenuExtensions(ContextMenuType type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case ContextMenuType::Disassembly:
|
||||||
|
return disassemblyContextMenuExtensions;
|
||||||
|
case ContextMenuType::Addressable:
|
||||||
|
return addressableContextMenuExtensions;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -125,6 +125,15 @@ public:
|
|||||||
void setCurrentMemoryWidget(MemoryDockWidget* memoryWidget);
|
void setCurrentMemoryWidget(MemoryDockWidget* memoryWidget);
|
||||||
MemoryDockWidget* getLastMemoryWidget();
|
MemoryDockWidget* getLastMemoryWidget();
|
||||||
|
|
||||||
|
/* Context menu plugins */
|
||||||
|
enum class ContextMenuType { Disassembly, Addressable };
|
||||||
|
/**
|
||||||
|
* @brief Fetches the pointer to a context menu extension of type
|
||||||
|
* @param type - the type of the context menu
|
||||||
|
* @return plugins submenu of the selected context menu
|
||||||
|
*/
|
||||||
|
QMenu *getContextMenuExtensions(ContextMenuType type);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void finalizeOpen();
|
void finalizeOpen();
|
||||||
|
|
||||||
@ -263,6 +272,9 @@ private:
|
|||||||
QDockWidget *breakpointDock = nullptr;
|
QDockWidget *breakpointDock = nullptr;
|
||||||
QDockWidget *registerRefsDock = nullptr;
|
QDockWidget *registerRefsDock = nullptr;
|
||||||
|
|
||||||
|
QMenu *disassemblyContextMenuExtensions = nullptr;
|
||||||
|
QMenu *addressableContextMenuExtensions = nullptr;
|
||||||
|
|
||||||
void initUI();
|
void initUI();
|
||||||
void initToolBar();
|
void initToolBar();
|
||||||
void initDocks();
|
void initDocks();
|
||||||
|
@ -39,7 +39,7 @@ PluginsOptionsWidget::PluginsOptionsWidget(PreferencesDialog *dialog)
|
|||||||
tr("Author")
|
tr("Author")
|
||||||
});
|
});
|
||||||
|
|
||||||
for (CutterPlugin *plugin : Plugins()->getPlugins()) {
|
for (auto &plugin : Plugins()->getPlugins()) {
|
||||||
auto item = new QTreeWidgetItem();
|
auto item = new QTreeWidgetItem();
|
||||||
item->setText(0, plugin->getName());
|
item->setText(0, plugin->getName());
|
||||||
item->setText(1, plugin->getDescription());
|
item->setText(1, plugin->getDescription());
|
||||||
|
@ -40,8 +40,8 @@ AddressableItemContextMenu::AddressableItemContextMenu(QWidget *parent, MainWind
|
|||||||
addAction(&actionAddcomment);
|
addAction(&actionAddcomment);
|
||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
pluginMenu = Core()->getContextMenuExtensions(CutterCore::ContextMenuType::Addressable);
|
pluginMenu = mainWindow->getContextMenuExtensions(MainWindow::ContextMenuType::Addressable);
|
||||||
addMenu(pluginMenu);
|
pluginMenuAction = addMenu(pluginMenu);
|
||||||
addSeparator();
|
addSeparator();
|
||||||
|
|
||||||
setHasTarget(hasTarget);
|
setHasTarget(hasTarget);
|
||||||
@ -105,6 +105,7 @@ void AddressableItemContextMenu::aboutToShowSlot()
|
|||||||
}
|
}
|
||||||
actionShowInMenu.setMenu(mainWindow->createShowInMenu(this, offset));
|
actionShowInMenu.setMenu(mainWindow->createShowInMenu(this, offset));
|
||||||
|
|
||||||
|
pluginMenuAction->setVisible(!pluginMenu->isEmpty());
|
||||||
for (QAction *pluginAction : pluginMenu->actions()) {
|
for (QAction *pluginAction : pluginMenu->actions()) {
|
||||||
pluginAction->setData(QVariant::fromValue(offset));
|
pluginAction->setData(QVariant::fromValue(offset));
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ private:
|
|||||||
virtual void aboutToShowSlot();
|
virtual void aboutToShowSlot();
|
||||||
|
|
||||||
QMenu *pluginMenu;
|
QMenu *pluginMenu;
|
||||||
|
QAction *pluginMenuAction;
|
||||||
MainWindow *mainWindow;
|
MainWindow *mainWindow;
|
||||||
|
|
||||||
RVA offset;
|
RVA offset;
|
||||||
|
@ -156,8 +156,8 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
|||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
|
|
||||||
pluginMenu = Core()->getContextMenuExtensions(CutterCore::ContextMenuType::Disassembly);
|
pluginMenu = mainWindow->getContextMenuExtensions(MainWindow::ContextMenuType::Disassembly);
|
||||||
addMenu(pluginMenu);
|
pluginActionMenuAction = addMenu(pluginMenu);
|
||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
|
|
||||||
@ -529,6 +529,7 @@ void DisassemblyContextMenu::aboutToShowSlot()
|
|||||||
QString progCounterName = Core()->getRegisterName("PC").toUpper();
|
QString progCounterName = Core()->getRegisterName("PC").toUpper();
|
||||||
actionSetPC.setText("Set " + progCounterName + " here");
|
actionSetPC.setText("Set " + progCounterName + " here");
|
||||||
|
|
||||||
|
pluginActionMenuAction->setVisible(!pluginMenu->isEmpty());
|
||||||
for (QAction *pluginAction : pluginMenu->actions()) {
|
for (QAction *pluginAction : pluginMenu->actions()) {
|
||||||
pluginAction->setData(QVariant::fromValue(offset));
|
pluginAction->setData(QVariant::fromValue(offset));
|
||||||
}
|
}
|
||||||
|
@ -182,6 +182,7 @@ private:
|
|||||||
|
|
||||||
QAction showInSubmenu;
|
QAction showInSubmenu;
|
||||||
QList<QAction*> showTargetMenuActions;
|
QList<QAction*> showTargetMenuActions;
|
||||||
|
QAction *pluginActionMenuAction;
|
||||||
|
|
||||||
// For creating anonymous entries (that are always visible)
|
// For creating anonymous entries (that are always visible)
|
||||||
QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut);
|
QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut);
|
||||||
|
@ -33,7 +33,7 @@ PluginManager::~PluginManager()
|
|||||||
|
|
||||||
void PluginManager::loadPlugins()
|
void PluginManager::loadPlugins()
|
||||||
{
|
{
|
||||||
assert(plugins.isEmpty());
|
assert(plugins.empty());
|
||||||
|
|
||||||
QString userPluginDir = getUserPluginsDirectory();
|
QString userPluginDir = getUserPluginsDirectory();
|
||||||
if (!userPluginDir.isEmpty()) {
|
if (!userPluginDir.isEmpty()) {
|
||||||
@ -51,7 +51,7 @@ void PluginManager::loadPlugins()
|
|||||||
void PluginManager::loadPluginsFromDir(const QDir &pluginsDir, bool writable)
|
void PluginManager::loadPluginsFromDir(const QDir &pluginsDir, bool writable)
|
||||||
{
|
{
|
||||||
qInfo() << "Plugins are loaded from" << pluginsDir.absolutePath();
|
qInfo() << "Plugins are loaded from" << pluginsDir.absolutePath();
|
||||||
int loadedPlugins = plugins.length();
|
int loadedPlugins = plugins.size();
|
||||||
if (!pluginsDir.exists()) {
|
if (!pluginsDir.exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -74,16 +74,19 @@ void PluginManager::loadPluginsFromDir(const QDir &pluginsDir, bool writable)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
loadedPlugins = plugins.length() - loadedPlugins;
|
loadedPlugins = plugins.size() - loadedPlugins;
|
||||||
qInfo() << "Loaded" << loadedPlugins << "plugin(s).";
|
qInfo() << "Loaded" << loadedPlugins << "plugin(s).";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PluginManager::PluginTerminator::operator()(CutterPlugin *plugin) const
|
||||||
|
{
|
||||||
|
plugin->terminate();
|
||||||
|
delete plugin;
|
||||||
|
}
|
||||||
|
|
||||||
void PluginManager::destroyPlugins()
|
void PluginManager::destroyPlugins()
|
||||||
{
|
{
|
||||||
for (CutterPlugin *plugin : plugins) {
|
plugins.clear();
|
||||||
plugin->terminate();
|
|
||||||
delete plugin;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QDir> PluginManager::getPluginDirectories() const
|
QVector<QDir> PluginManager::getPluginDirectories() const
|
||||||
@ -144,12 +147,12 @@ void PluginManager::loadNativePlugins(const QDir &directory)
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CutterPlugin *cutterPlugin = qobject_cast<CutterPlugin *>(plugin);
|
PluginPtr cutterPlugin{qobject_cast<CutterPlugin *>(plugin)};
|
||||||
if (!cutterPlugin) {
|
if (!cutterPlugin) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cutterPlugin->setupPlugin();
|
cutterPlugin->setupPlugin();
|
||||||
plugins.append(cutterPlugin);
|
plugins.push_back(std::move(cutterPlugin));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +172,12 @@ void PluginManager::loadPythonPlugins(const QDir &directory)
|
|||||||
} else {
|
} else {
|
||||||
moduleName = fileName;
|
moduleName = fileName;
|
||||||
}
|
}
|
||||||
CutterPlugin *cutterPlugin = loadPythonPlugin(moduleName.toLocal8Bit().constData());
|
PluginPtr cutterPlugin{loadPythonPlugin(moduleName.toLocal8Bit().constData())};
|
||||||
if (!cutterPlugin) {
|
if (!cutterPlugin) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cutterPlugin->setupPlugin();
|
cutterPlugin->setupPlugin();
|
||||||
plugins.append(cutterPlugin);
|
plugins.push_back(std::move(cutterPlugin));
|
||||||
}
|
}
|
||||||
|
|
||||||
PythonManager::ThreadHolder threadHolder;
|
PythonManager::ThreadHolder threadHolder;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CutterPlugin;
|
class CutterPlugin;
|
||||||
|
|
||||||
@ -14,6 +16,13 @@ Q_OBJECT
|
|||||||
public:
|
public:
|
||||||
static PluginManager *getInstance();
|
static PluginManager *getInstance();
|
||||||
|
|
||||||
|
class PluginTerminator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator()(CutterPlugin*) const;
|
||||||
|
};
|
||||||
|
using PluginPtr = std::unique_ptr<CutterPlugin, PluginTerminator>;
|
||||||
|
|
||||||
PluginManager();
|
PluginManager();
|
||||||
~PluginManager();
|
~PluginManager();
|
||||||
|
|
||||||
@ -27,13 +36,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void destroyPlugins();
|
void destroyPlugins();
|
||||||
|
|
||||||
const QList<CutterPlugin *> &getPlugins() { return plugins; }
|
const std::vector<PluginPtr> &getPlugins() { return plugins; }
|
||||||
|
|
||||||
QVector<QDir> getPluginDirectories() const;
|
QVector<QDir> getPluginDirectories() const;
|
||||||
QString getUserPluginsDirectory() const;
|
QString getUserPluginsDirectory() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<CutterPlugin *> plugins;
|
std::vector<PluginPtr> plugins;
|
||||||
|
|
||||||
void loadNativePlugins(const QDir &directory);
|
void loadNativePlugins(const QDir &directory);
|
||||||
void loadPluginsFromDir(const QDir &pluginsDir, bool writable = false);
|
void loadPluginsFromDir(const QDir &pluginsDir, bool writable = false);
|
||||||
|
@ -42,25 +42,66 @@ class FortuneWidget(cutter.CutterDockWidget):
|
|||||||
|
|
||||||
|
|
||||||
class CutterSamplePlugin(cutter.CutterPlugin):
|
class CutterSamplePlugin(cutter.CutterPlugin):
|
||||||
name = "SamplePlugin"
|
name = "Sample Plugin"
|
||||||
description = "A sample plugin written in python."
|
description = "A sample plugin written in python."
|
||||||
version = "1.0"
|
version = "1.1"
|
||||||
author = "xarkes and thestr4ng3r :-P"
|
author = "Cutter developers"
|
||||||
|
|
||||||
|
# Override CutterPlugin methods
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CutterSamplePlugin, self).__init__()
|
super(CutterSamplePlugin, self).__init__()
|
||||||
|
self.disassembly_actions = []
|
||||||
|
self.addressable_item_actions = []
|
||||||
|
self.disas_action = None
|
||||||
|
self.addr_submenu = None
|
||||||
|
self.main = None
|
||||||
|
|
||||||
def setupPlugin(self):
|
def setupPlugin(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def setupInterface(self, main):
|
def setupInterface(self, main):
|
||||||
|
# Dock widget
|
||||||
action = QAction("Sample Python Plugin", main)
|
action = QAction("Sample Python Plugin", main)
|
||||||
action.setCheckable(True)
|
action.setCheckable(True)
|
||||||
widget = FortuneWidget(main, action)
|
widget = FortuneWidget(main, action)
|
||||||
main.addPluginDockWidget(widget, action)
|
main.addPluginDockWidget(widget, action)
|
||||||
|
|
||||||
|
# Dissassembly context menu
|
||||||
|
menu = main.getContextMenuExtensions(cutter.MainWindow.ContextMenuType.Disassembly)
|
||||||
|
self.disas_action = menu.addAction("CutterSamplePlugin dissassembly action")
|
||||||
|
self.disas_action.triggered.connect(self.handle_disassembler_action)
|
||||||
|
self.main = main
|
||||||
|
|
||||||
|
# Context menu for tables with addressable items like Flags,Functions,Strings,Search results,...
|
||||||
|
addressable_item_menu = main.getContextMenuExtensions(cutter.MainWindow.ContextMenuType.Addressable)
|
||||||
|
self.addr_submenu = addressable_item_menu.addMenu("CutterSamplePlugin") # create submenu
|
||||||
|
adrr_action = self.addr_submenu.addAction("Action 1")
|
||||||
|
self.addr_submenu.addSeparator() # can use separator and other qt functionality
|
||||||
|
adrr_action2 = self.addr_submenu.addAction("Action 2")
|
||||||
|
adrr_action.triggered.connect(self.handle_addressable_item_action)
|
||||||
|
adrr_action2.triggered.connect(self.handle_addressable_item_action)
|
||||||
|
|
||||||
def terminate(self): # optional
|
def terminate(self): # optional
|
||||||
print("CutterSamplePlugin shutting down")
|
print("CutterSamplePlugin shutting down")
|
||||||
|
if self.main:
|
||||||
|
menu = self.main.getContextMenuExtensions(cutter.MainWindow.ContextMenuType.Disassembly)
|
||||||
|
menu.removeAction(self.disas_action)
|
||||||
|
addressable_item_menu = self.main.getContextMenuExtensions(cutter.MainWindow.ContextMenuType.Addressable)
|
||||||
|
submenu_action = self.addr_submenu.menuAction()
|
||||||
|
addressable_item_menu.removeAction(submenu_action)
|
||||||
|
print("CutterSamplePlugin finished clean up")
|
||||||
|
|
||||||
|
# Plugin methods
|
||||||
|
|
||||||
|
def handle_addressable_item_action(self):
|
||||||
|
# for actions in plugin menu Cutter sets data to current item address
|
||||||
|
submenu_action = self.addr_submenu.menuAction()
|
||||||
|
cutter.message("Context menu action callback 0x{:x}".format(submenu_action.data()))
|
||||||
|
|
||||||
|
def handle_disassembler_action(self):
|
||||||
|
# for actions in plugin menu Cutter sets data to address for current dissasembly line
|
||||||
|
cutter.message("Dissasembly menu action callback 0x{:x}".format(self.disas_action.data()))
|
||||||
|
|
||||||
|
|
||||||
# This function will be called by Cutter and should return an instance of the plugin.
|
# This function will be called by Cutter and should return an instance of the plugin.
|
||||||
|
Loading…
Reference in New Issue
Block a user