1
0
Fork 0

GUI: MenuBuilder class for building menus in one central place (runtime variation of the menu structure is possible)

This commit is contained in:
mrexodia 2015-11-22 07:37:13 +01:00
parent 58168e024b
commit 087362d578
5 changed files with 337 additions and 263 deletions

View File

@ -10,6 +10,7 @@
#include <QMenu>
#include "StringUtil.h"
#include "Configuration.h"
#include "MenuBuilder.h"
//Hacky class that fixes a really annoying cursor problem
class AbstractTableScrollBar : public QScrollBar
@ -240,6 +241,18 @@ private:
}
protected:
inline QMenu* makeMenu(const QString & title)
{
return new QMenu(title, this);
}
inline QMenu* makeMenu(const QIcon & icon, const QString & title)
{
QMenu* menu = new QMenu(title, this);
menu->setIcon(icon);
return menu;
}
inline QAction* makeAction(const QString & text, const char* slot)
{
return connectAction(new QAction(text, this), slot);

View File

@ -171,233 +171,203 @@ void CPUDisassembly::setupFollowReferenceMenu(dsint wVA, QMenu* menu, bool isRef
*/
void CPUDisassembly::contextMenuEvent(QContextMenuEvent* event)
{
if(getSize() != 0)
{
int wI;
QMenu* wMenu = new QMenu(this);
duint wVA = rvaToVa(getInitialSelection());
BPXTYPE wBpType = DbgGetBpxTypeAt(wVA);
// Build Menu
wMenu->addMenu(mBinaryMenu);
wMenu->addMenu(mCopyMenu);
dsint start = rvaToVa(getSelectionStart());
dsint end = rvaToVa(getSelectionEnd());
if(DbgFunctions()->PatchInRange(start, end)) //nothing patched in selected range
wMenu->addAction(mUndoSelection);
// BP Menu
mBPMenu->clear();
// Soft BP
mBPMenu->addAction(mToggleInt3BpAction);
// Hardware BP
if((wBpType & bp_hardware) == bp_hardware)
{
mBPMenu->addAction(mClearHwBpAction);
}
else
{
BPMAP wBPList;
DbgGetBpList(bp_hardware, &wBPList);
//get enabled hwbp count
int enabledCount = wBPList.count;
for(int i = 0; i < wBPList.count; i++)
if(!wBPList.bp[i].enabled)
enabledCount--;
if(enabledCount < 4)
{
mBPMenu->addAction(mSetHwBpAction);
}
else
{
REGDUMP wRegDump;
DbgGetRegDump(&wRegDump);
for(wI = 0; wI < 4; wI++)
{
switch(wBPList.bp[wI].slot)
{
case 0:
msetHwBPOnSlot0Action->setText("Replace Slot 0 (0x" + QString("%1").arg(wBPList.bp[wI].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
case 1:
msetHwBPOnSlot1Action->setText("Replace Slot 1 (0x" + QString("%1").arg(wBPList.bp[wI].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
case 2:
msetHwBPOnSlot2Action->setText("Replace Slot 2 (0x" + QString("%1").arg(wBPList.bp[wI].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
case 3:
msetHwBPOnSlot3Action->setText("Replace Slot 3 (0x" + QString("%1").arg(wBPList.bp[wI].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
default:
break;
}
}
mHwSlotSelectMenu->addAction(msetHwBPOnSlot0Action);
mHwSlotSelectMenu->addAction(msetHwBPOnSlot1Action);
mHwSlotSelectMenu->addAction(msetHwBPOnSlot2Action);
mHwSlotSelectMenu->addAction(msetHwBPOnSlot3Action);
mBPMenu->addMenu(mHwSlotSelectMenu);
}
if(wBPList.count)
BridgeFree(wBPList.bp);
}
wMenu->addMenu(mBPMenu);
wMenu->addMenu(mFollowMenu);
setupFollowReferenceMenu(wVA, mFollowMenu, false);
if(DbgFunctions()->GetSourceFromAddr(wVA, 0, 0))
wMenu->addAction(mOpenSourceAction);
mDecompileMenu->clear();
if(DbgFunctionGet(wVA, 0, 0))
mDecompileMenu->addAction(mDecompileFunctionAction);
mDecompileMenu->addAction(mDecompileSelectionAction);
wMenu->addMenu(mDecompileMenu);
wMenu->addAction(mEnableHighlightingMode);
wMenu->addSeparator();
wMenu->addAction(mSetLabelAction);
wMenu->addAction(mSetCommentAction);
wMenu->addAction(mSetBookmarkAction);
duint selection_start = rvaToVa(getSelectionStart());
duint selection_end = rvaToVa(getSelectionEnd());
if(!DbgFunctionOverlaps(selection_start, selection_end))
{
mToggleFunctionAction->setText("Add function");
wMenu->addAction(mToggleFunctionAction);
}
else if(DbgFunctionOverlaps(selection_start, selection_end))
{
mToggleFunctionAction->setText("Delete function");
wMenu->addAction(mToggleFunctionAction);
}
wMenu->addAction(mAssembleAction);
wMenu->addAction(mPatchesAction);
wMenu->addAction(mYaraAction);
wMenu->addSeparator();
// New origin
wMenu->addAction(mSetNewOriginHere);
// Goto Menu
mGotoMenu->clear();
mGotoMenu->addAction(mGotoOriginAction);
if(historyHasPrevious())
mGotoMenu->addAction(mGotoPreviousAction);
if(historyHasNext())
mGotoMenu->addAction(mGotoNextAction);
mGotoMenu->addAction(mGotoExpressionAction);
char modname[MAX_MODULE_SIZE] = "";
if(DbgGetModuleAt(wVA, modname))
mGotoMenu->addAction(mGotoFileOffsetAction);
mGotoMenu->addAction(mGotoStartAction);
mGotoMenu->addAction(mGotoEndAction);
wMenu->addMenu(mGotoMenu);
wMenu->addSeparator();
wMenu->addMenu(mSearchMenu);
wMenu->addMenu(mReferencesMenu);
setupFollowReferenceMenu(wVA, mReferencesMenu, true);
wMenu->addSeparator();
wMenu->addActions(mPluginMenu->actions());
wMenu->exec(event->globalPos());
}
QMenu wMenu(this);
mMenuBuilder->build(&wMenu);
wMenu.exec(event->globalPos());
}
/************************************************************************************
Context Menu Management
************************************************************************************/
void CPUDisassembly::setupRightClickContextMenu()
{
mBinaryMenu = new QMenu("&Binary", this);
mBinaryMenu->setIcon(QIcon(":/icons/images/binary.png"));
mBinaryEditAction = makeShortcutMenuAction(mBinaryMenu, "&Edit", SLOT(binaryEditSlot()), "ActionBinaryEdit");
mBinaryFillAction = makeShortcutMenuAction(mBinaryMenu, "&Fill...", SLOT(binaryFillSlot()), "ActionBinaryFill");
mBinaryFillNopsAction = makeShortcutMenuAction(mBinaryMenu, "Fill with &NOPs", SLOT(binaryFillNopsSlot()), "ActionBinaryFillNops");
mBinaryMenu->addSeparator();
mBinaryCopyAction = makeShortcutMenuAction(mBinaryMenu, "&Copy", SLOT(binaryCopySlot()), "ActionBinaryCopy");
mBinaryPasteAction = makeShortcutMenuAction(mBinaryMenu, "&Paste", SLOT(binaryPasteSlot()), "ActionBinaryPaste");
mBinaryPasteIgnoreSizeAction = makeShortcutMenuAction(mBinaryMenu, "Paste (&Ignore Size)", SLOT(binaryPasteIgnoreSizeSlot()), "ActionBinaryPasteIgnoreSize");
mMenuBuilder = new MenuBuilder(this, [](QMenu*)
{
return DbgIsDebugging();
});
mUndoSelection = makeShortcutAction("&Restore selection", SLOT(undoSelectionSlot()), "ActionUndoSelection");
mSetLabelAction = makeShortcutAction(QIcon(":/icons/images/label.png"), "Label", SLOT(setLabelSlot()), "ActionSetLabel");
mSetCommentAction = makeShortcutAction(QIcon(":/icons/images/comment.png"), "Comment", SLOT(setCommentSlot()), "ActionSetComment");
mSetBookmarkAction = makeShortcutAction(QIcon(":/icons/images/bookmark.png"), "Bookmark", SLOT(setBookmarkSlot()), "ActionToggleBookmark");
mToggleFunctionAction = makeShortcutAction(QIcon(":/icons/images/functions.png"), "Function", SLOT(toggleFunctionSlot()), "ActionToggleFunction");
mAssembleAction = makeShortcutAction("Assemble", SLOT(assembleSlot()), "ActionAssemble");
MenuBuilder* binaryMenu = new MenuBuilder(this);
binaryMenu->addAction(makeShortcutAction("&Edit", SLOT(binaryEditSlot()), "ActionBinaryEdit"));
binaryMenu->addAction(makeShortcutAction("&Fill...", SLOT(binaryFillSlot()), "ActionBinaryFill"));
binaryMenu->addAction(makeShortcutAction("Fill with &NOPs", SLOT(binaryFillNopsSlot()), "ActionBinaryFillNops"));
binaryMenu->addSeparator();
binaryMenu->addAction(makeShortcutAction("&Copy", SLOT(binaryCopySlot()), "ActionBinaryCopy"));
binaryMenu->addAction(makeShortcutAction("&Paste", SLOT(binaryPasteSlot()), "ActionBinaryPaste"));
binaryMenu->addAction(makeShortcutAction("Paste (&Ignore Size)", SLOT(binaryPasteIgnoreSizeSlot()), "ActionBinaryPasteIgnoreSize"));
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/binary.png"), "&Binary"), binaryMenu);
mBPMenu = new QMenu("Breakpoint", this);
mBPMenu->setIcon(QIcon(":/icons/images/breakpoint.png"));
mToggleInt3BpAction = makeShortcutAction("Toggle", SLOT(toggleInt3BPActionSlot()), "ActionToggleBreakpoint");
MenuBuilder* copyMenu = new MenuBuilder(this);
copyMenu->addAction(makeShortcutAction("&Selection", SLOT(copySelectionSlot()), "ActionCopy"));
copyMenu->addAction(makeAction("Selection (&No Bytes)", SLOT(copySelectionNoBytesSlot())));
copyMenu->addAction(makeShortcutAction("&Address", SLOT(copyAddressSlot()), "ActionCopyAddress"));
copyMenu->addAction(makeAction("&RVA", SLOT(copyRvaSlot())));
copyMenu->addAction(makeAction("Disassembly", SLOT(copyDisassemblySlot())));
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/copy.png"), "&Copy"), copyMenu);
mHwSlotSelectMenu = new QMenu("Set Hardware on Execution", this);
mSetHwBpAction = makeAction("Set Hardware on Execution", SLOT(toggleHwBpActionSlot()));
mClearHwBpAction = makeAction("Remove Hardware", SLOT(toggleHwBpActionSlot()));
msetHwBPOnSlot0Action = makeAction("Set Hardware on Execution on Slot 0 (Free)", SLOT(setHwBpOnSlot0ActionSlot()));
msetHwBPOnSlot1Action = makeAction("Set Hardware on Execution on Slot 1 (Free)", SLOT(setHwBpOnSlot1ActionSlot()));
msetHwBPOnSlot2Action = makeAction("Set Hardware on Execution on Slot 2 (Free)", SLOT(setHwBpOnSlot2ActionSlot()));
msetHwBPOnSlot3Action = makeAction("Set Hardware on Execution on Slot 3 (Free)", SLOT(setHwBpOnSlot3ActionSlot()));
mMenuBuilder->addAction(makeShortcutAction("&Restore selection", SLOT(undoSelectionSlot()), "ActionUndoSelection"), [this](QMenu*)
{
dsint start = rvaToVa(getSelectionStart());
dsint end = rvaToVa(getSelectionEnd());
return DbgFunctions()->PatchInRange(start, end); //something patched in selected range
});
mPatchesAction = makeShortcutAction(QIcon(":/icons/images/patch.png"), "Patches", SLOT(showPatchesSlot()), "ViewPatches");
removeAction(mPatchesAction); //prevent conflicting shortcut with the MainWindow
mYaraAction = makeShortcutAction(QIcon(":/icons/images/yara.png"), "&Yara...", SLOT(yaraSlot()), "ActionYara");
mSetNewOriginHere = makeShortcutAction("Set New Origin Here", SLOT(setNewOriginHereActionSlot()), "ActionSetNewOriginHere");
QAction* toggleBreakpointAction = makeShortcutAction("Toggle", SLOT(toggleInt3BPActionSlot()), "ActionToggleBreakpoint");
QAction* setHwBreakpointAction = makeAction("Set Hardware on Execution", SLOT(toggleHwBpActionSlot()));
QAction* removeHwBreakpointAction = makeAction("Remove Hardware", SLOT(toggleHwBpActionSlot()));
mGotoMenu = new QMenu("Go to", this);
mGotoOriginAction = makeShortcutAction("Origin", SLOT(gotoOriginSlot()), "ActionGotoOrigin");
mGotoPreviousAction = makeShortcutAction("Previous", SLOT(gotoPreviousSlot()), "ActionGotoPrevious");
mGotoNextAction = makeShortcutAction("Next", SLOT(gotoNextSlot()), "ActionGotoNext");
mGotoExpressionAction = makeShortcutAction("Expression", SLOT(gotoExpressionSlot()), "ActionGotoExpression");
mGotoFileOffsetAction = makeShortcutAction("File Offset", SLOT(gotoFileOffsetSlot()), "ActionGotoFileOffset");
mGotoStartAction = makeShortcutAction("Start of Page", SLOT(gotoStartSlot()), "ActionGotoStart");
mGotoEndAction = makeShortcutAction("End of Page", SLOT(gotoEndSlot()), "ActionGotoEnd");
QMenu* replaceSlotMenu = makeMenu("Set Hardware on Execution");
QAction* replaceSlot0Action = makeMenuAction(replaceSlotMenu, "Replace Slot 0 (Free)", SLOT(setHwBpOnSlot0ActionSlot()));
QAction* replaceSlot1Action = makeMenuAction(replaceSlotMenu, "Replace Slot 1 (Free)", SLOT(setHwBpOnSlot1ActionSlot()));
QAction* replaceSlot2Action = makeMenuAction(replaceSlotMenu, "Replace Slot 2 (Free)", SLOT(setHwBpOnSlot2ActionSlot()));
QAction* replaceSlot3Action = makeMenuAction(replaceSlotMenu, "Replace Slot 3 (Free)", SLOT(setHwBpOnSlot3ActionSlot()));
mFollowMenu = new QMenu("&Follow in Dump", this);
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/breakpoint.png"), "Breakpoint"), [=](QMenu* menu)
{
BPXTYPE bpType = DbgGetBpxTypeAt(rvaToVa(getInitialSelection()));
mCopyMenu = new QMenu("&Copy", this);
mCopyMenu->setIcon(QIcon(":/icons/images/copy.png"));
mCopySelectionAction = makeShortcutMenuAction(mCopyMenu, "&Selection", SLOT(copySelectionSlot()), "ActionCopy");
mCopySelectionNoBytesAction = makeMenuAction(mCopyMenu, "Selection (&No Bytes)", SLOT(copySelectionNoBytesSlot()));
mCopyAddressAction = makeShortcutMenuAction(mCopyMenu, "&Address", SLOT(copyAddressSlot()), "ActionCopyAddress");
mCopyRvaAction = makeMenuAction(mCopyMenu, "&RVA", SLOT(copyRvaSlot()));
mCopyDisassemblyAction = makeMenuAction(mCopyMenu, "Disassembly", SLOT(copyDisassemblySlot()));
menu->addAction(toggleBreakpointAction);
mOpenSourceAction = makeAction(QIcon(":/icons/images/source.png"), "Open Source File", SLOT(openSourceSlot()));
if((bpType & bp_hardware) == bp_hardware)
{
menu->addAction(removeHwBreakpointAction);
}
else
{
BPMAP bpList;
DbgGetBpList(bp_hardware, &bpList);
mDecompileMenu = new QMenu("Decompile");
mDecompileMenu->setIcon(QIcon(":/icons/images/snowman.png"));
mDecompileSelectionAction = makeShortcutAction("Selection", SLOT(decompileSelectionSlot()), "ActionDecompileSelection");
mDecompileFunctionAction = makeShortcutAction("Function", SLOT(decompileFunctionSlot()), "ActionDecompileFunction");
//get enabled hwbp count
int enabledCount = bpList.count;
for(int i = 0; i < bpList.count; i++)
if(!bpList.bp[i].enabled)
enabledCount--;
if(enabledCount < 4)
{
menu->addAction(setHwBreakpointAction);
}
else
{
REGDUMP wRegDump;
DbgGetRegDump(&wRegDump);
for(int i = 0; i < 4; i++)
{
switch(bpList.bp[i].slot)
{
case 0:
replaceSlot0Action->setText("Replace Slot 0 (0x" + QString("%1").arg(bpList.bp[i].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
case 1:
replaceSlot1Action->setText("Replace Slot 1 (0x" + QString("%1").arg(bpList.bp[i].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
case 2:
replaceSlot2Action->setText("Replace Slot 2 (0x" + QString("%1").arg(bpList.bp[i].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
case 3:
replaceSlot3Action->setText("Replace Slot 3 (0x" + QString("%1").arg(bpList.bp[i].addr, 8, 16, QChar('0')).toUpper() + ")");
break;
default:
break;
}
}
menu->addMenu(replaceSlotMenu);
}
if(bpList.count)
BridgeFree(bpList.bp);
}
return true;
});
mMenuBuilder->addMenu(makeMenu("&Follow in Dump"), [this](QMenu* menu)
{
setupFollowReferenceMenu(rvaToVa(getInitialSelection()), menu, false);
return true;
});
mMenuBuilder->addAction(makeAction(QIcon(":/icons/images/source.png"), "Open Source File", SLOT(openSourceSlot())), [this](QMenu*)
{
return DbgFunctions()->GetSourceFromAddr(rvaToVa(getInitialSelection()), 0, 0);
});
MenuBuilder* decompileMenu = new MenuBuilder(this);
decompileMenu->addAction(makeShortcutAction("Selection", SLOT(decompileSelectionSlot()), "ActionDecompileSelection"), [this](QMenu*)
{
return DbgFunctionGet(rvaToVa(getInitialSelection()), 0, 0);
});
decompileMenu->addAction(makeShortcutAction("Function", SLOT(decompileFunctionSlot()), "ActionDecompileFunction"));
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/snowman.png"), "Decompile"), decompileMenu);
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/highlight.png"), "&Highlighting mode", SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode"));
mMenuBuilder->addSeparator();
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/label.png"), "Label", SLOT(setLabelSlot()), "ActionSetLabel"));
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/comment.png"), "Comment", SLOT(setCommentSlot()), "ActionSetComment"));
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/bookmark.png"), "Bookmark", SLOT(setBookmarkSlot()), "ActionToggleBookmark"));
QAction* toggleFunctionAction = makeShortcutAction(QIcon(":/icons/images/functions.png"), "Function", SLOT(toggleFunctionSlot()), "ActionToggleFunction");
mMenuBuilder->addAction(toggleFunctionAction, [this, toggleFunctionAction](QMenu*)
{
if(!DbgFunctionOverlaps(rvaToVa(getSelectionStart()), rvaToVa(getSelectionEnd())))
toggleFunctionAction->setText("Add function");
else
toggleFunctionAction->setText("Delete function");
return true;
});
mMenuBuilder->addAction(makeShortcutAction("Assemble", SLOT(assembleSlot()), "ActionAssemble"));
removeAction(mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/patch.png"), "Patches", SLOT(showPatchesSlot()), "ViewPatches"))); //prevent conflicting shortcut with the MainWindow
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/yara.png"), "&Yara...", SLOT(yaraSlot()), "ActionYara"));
mMenuBuilder->addSeparator();
mMenuBuilder->addAction(makeShortcutAction("Set New Origin Here", SLOT(setNewOriginHereActionSlot()), "ActionSetNewOriginHere"));
MenuBuilder* gotoMenu = new MenuBuilder(this);
gotoMenu->addAction(makeShortcutAction("Origin", SLOT(gotoOriginSlot()), "ActionGotoOrigin"));
gotoMenu->addAction(makeShortcutAction("Previous", SLOT(gotoPreviousSlot()), "ActionGotoPrevious"), [this](QMenu*)
{
return historyHasPrevious();
});
gotoMenu->addAction(makeShortcutAction("Next", SLOT(gotoNextSlot()), "ActionGotoNext"), [this](QMenu*)
{
return historyHasNext();
});
gotoMenu->addAction(makeShortcutAction("Expression", SLOT(gotoExpressionSlot()), "ActionGotoExpression"));
gotoMenu->addAction(makeShortcutAction("File Offset", SLOT(gotoFileOffsetSlot()), "ActionGotoFileOffset"), [this](QMenu*)
{
char modname[MAX_MODULE_SIZE] = "";
return DbgGetModuleAt(rvaToVa(getInitialSelection()), modname);
});
gotoMenu->addAction(makeShortcutAction("Start of Page", SLOT(gotoStartSlot()), "ActionGotoStart"));
gotoMenu->addAction(makeShortcutAction("End of Page", SLOT(gotoEndSlot()), "ActionGotoEnd"));
mMenuBuilder->addMenu(makeMenu("Go to"), gotoMenu);
mMenuBuilder->addSeparator();
MenuBuilder* searchMenu = new MenuBuilder(this);
searchMenu->addAction(makeShortcutAction("C&ommand", SLOT(findCommandSlot()), "ActionFind"));
searchMenu->addAction(makeAction("&Constant", SLOT(findConstantSlot())));
searchMenu->addAction(makeAction("&String references", SLOT(findStringsSlot())));
searchMenu->addAction(makeAction("&Intermodular calls", SLOT(findCallsSlot())));
searchMenu->addAction(makeShortcutAction("&Pattern", SLOT(findPatternSlot()), "ActionFindPattern"));
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/search-for.png"), "&Search for"), searchMenu);
mReferencesMenu = new QMenu("Find &references to", this);
mReferenceSelectedAddressAction = makeShortcutAction("&Selected Address(es)", SLOT(findReferencesSlot()), "ActionFindReferencesToSelectedAddress");
mReferenceSelectedAddressAction->setFont(QFont("Courier New", 8));
mSearchMenu = new QMenu("&Search for", this);
mSearchMenu->setIcon(QIcon(":/icons/images/search-for.png"));
mSearchCommand = makeShortcutMenuAction(mSearchMenu, "C&ommand", SLOT(findCommandSlot()), "ActionFind");
mSearchConstant = makeMenuAction(mSearchMenu, "&Constant", SLOT(findConstantSlot()));
mSearchStrings = makeMenuAction(mSearchMenu, "&String references", SLOT(findStringsSlot()));
mSearchCalls = makeMenuAction(mSearchMenu, "&Intermodular calls", SLOT(findCallsSlot()));
mSearchPattern = makeShortcutMenuAction(mSearchMenu, "&Pattern", SLOT(findPatternSlot()), "ActionFindPattern");
mEnableHighlightingMode = makeShortcutAction(QIcon(":/icons/images/highlight.png"), "&Highlighting mode", SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode");
mMenuBuilder->addMenu(makeMenu("Find &references to"), [this](QMenu* menu)
{
setupFollowReferenceMenu(rvaToVa(getInitialSelection()), menu, true);
return true;
});
// Plugins
mPluginMenu = new QMenu(this);
Bridge::getBridge()->emitMenuAddToList(this, mPluginMenu, GUI_DISASM_MENU);
mMenuBuilder->addSeparator();
mMenuBuilder->addBuilder(new MenuBuilder(this, [this](QMenu* menu)
{
menu->addActions(mPluginMenu->actions());
return true;
}));
}
void CPUDisassembly::gotoOriginSlot()
@ -471,14 +441,6 @@ void CPUDisassembly::setHwBpOnSlot3ActionSlot()
void CPUDisassembly::setHwBpAt(duint va, int slot)
{
BPXTYPE wBpType = DbgGetBpxTypeAt(va);
if((wBpType & bp_hardware) == bp_hardware)
{
mBPMenu->addAction(mClearHwBpAction);
}
int wI = 0;
int wSlotIndex = -1;
BPMAP wBPList;

View File

@ -88,68 +88,19 @@ protected:
private:
// Menus
QMenu* mBinaryMenu;
QMenu* mGotoMenu;
QMenu* mFollowMenu;
QMenu* mBPMenu;
QMenu* mHwSlotSelectMenu;
QMenu* mReferencesMenu;
QMenu* mSearchMenu;
QMenu* mCopyMenu;
QMenu* mPluginMenu;
QMenu* mDecompileMenu;
// Actions
QAction* mBinaryEditAction;
QAction* mBinaryFillAction;
QAction* mBinaryFillNopsAction;
QAction* mBinaryCopyAction;
QAction* mBinaryPasteAction;
QAction* mBinaryPasteIgnoreSizeAction;
QAction* mUndoSelection;
QAction* mToggleInt3BpAction;
QAction* mSetHwBpAction;
QAction* mClearHwBpAction;
QAction* mSetNewOriginHere;
QAction* mGotoOriginAction;
QAction* mSetCommentAction;
QAction* mSetLabelAction;
QAction* mSetBookmarkAction;
QAction* mToggleFunctionAction;
QAction* mAssembleAction;
QAction* msetHwBPOnSlot0Action;
QAction* msetHwBPOnSlot1Action;
QAction* msetHwBPOnSlot2Action;
QAction* msetHwBPOnSlot3Action;
QAction* mGotoExpressionAction;
QAction* mGotoFileOffsetAction;
QAction* mGotoPreviousAction;
QAction* mGotoNextAction;
QAction* mGotoStartAction;
QAction* mGotoEndAction;
QAction* mReferenceSelectedAddressAction;
QAction* mSearchCommand;
QAction* mSearchConstant;
QAction* mSearchStrings;
QAction* mSearchCalls;
QAction* mSearchPattern;
QAction* mEnableHighlightingMode;
QAction* mPatchesAction;
QAction* mYaraAction;
QAction* mCopySelectionAction;
QAction* mCopySelectionNoBytesAction;
QAction* mCopyAddressAction;
QAction* mCopyRvaAction;
QAction* mCopyDisassemblyAction;
QAction* mOpenSourceAction;
QAction* mDecompileSelectionAction;
QAction* mDecompileFunctionAction;
// Goto dialog specific
GotoDialog* mGoto;
// Parent CPU window
CPUWidget *mParentCPUWindow;
MenuBuilder* mMenuBuilder;
};
#endif // CPUDISASSEMBLY_H

View File

@ -0,0 +1,147 @@
#ifndef MENUBUILDER
#define MENUBUILDER
#include <QAction>
#include <QMenu>
#include <functional>
class MenuBuilder : public QObject
{
Q_OBJECT
public:
typedef std::function<bool(QMenu*)> BuildCallback;
inline MenuBuilder(QObject* parent, BuildCallback callback = nullptr)
: QObject(parent),
_callback(callback)
{
}
inline void addSeparator()
{
_containers.push_back(Container());
}
inline QAction* addAction(QAction* action)
{
_containers.push_back(Container(action));
return action;
}
inline QAction* addAction(QAction* action, BuildCallback callback)
{
addBuilder(new MenuBuilder(action->parent(), callback))->addAction(action);
return action;
}
inline QMenu* addMenu(QMenu* menu)
{
_containers.push_back(Container(menu));
return menu;
}
inline QMenu* addMenu(QMenu* submenu, BuildCallback callback)
{
addBuilder(new MenuBuilder(submenu->parent(), [submenu, callback](QMenu* menu)
{
submenu->clear();
if(callback(submenu));
menu->addMenu(submenu);
return true;
}));
return submenu;
}
inline QMenu* addMenu(QMenu* submenu, MenuBuilder* builder)
{
addBuilder(new MenuBuilder(submenu->parent(), [submenu, builder](QMenu* menu)
{
submenu->clear();
builder->build(submenu);
menu->addMenu(submenu);
return true;
}));
return submenu;
}
inline MenuBuilder* addBuilder(MenuBuilder* builder)
{
_containers.push_back(Container(builder));
return builder;
}
inline void build(QMenu* menu) const
{
if(_callback && !_callback(menu))
return;
for(const Container & container : _containers)
{
switch(container.type)
{
case Container::Separator:
menu->addSeparator();
break;
case Container::Action:
menu->addAction(container.action);
break;
case Container::Menu:
menu->addMenu(container.menu);
break;
case Container::Builder:
container.builder->build(menu);
break;
default:
break;
}
}
}
private:
struct Container
{
enum Type
{
Separator,
Action,
Menu,
Builder
};
inline Container()
: type(Separator)
{
}
inline Container(QAction* action)
: type(Action),
action(action)
{
}
inline Container(QMenu* menu)
: type(Menu),
menu(menu)
{
}
inline Container(MenuBuilder* builder)
: type(Builder),
builder(builder)
{
}
Type type;
union
{
QAction* action;
QMenu* menu ;
MenuBuilder* builder;
};
};
BuildCallback _callback;
std::vector<Container> _containers;
};
#endif // MENUBUILDER

View File

@ -217,7 +217,8 @@ HEADERS += \
Src/QEntropyView/QEntropyView.h \
Src/Gui/EntropyDialog.h \
Src/Gui/NotesManager.h \
Src/Gui/NotepadView.h
Src/Gui/NotepadView.h \
Src/Utils/MenuBuilder.h
FORMS += \
Src/Gui/MainWindow.ui \