mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-12 21:10:42 +00:00
Allow registering window, panel and context menu items with callbacks
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include <QProgressDialog>
|
||||
#include <QRegularExpression>
|
||||
#include <QTimer>
|
||||
#include "Code/Resources.h"
|
||||
#include "Code/pyrenderdoc/PythonContext.h"
|
||||
#include "Windows/APIInspector.h"
|
||||
#include "Windows/BufferViewer.h"
|
||||
@@ -348,10 +349,309 @@ bool CaptureContext::LoadExtension(rdcstr name)
|
||||
}
|
||||
});
|
||||
|
||||
m_MainWindow->CleanMenus();
|
||||
for(QAction *a : m_MainWindow->GetMenuActions())
|
||||
CleanMenu(a);
|
||||
|
||||
m_RegisteredMenuItems.removeAll(NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CaptureContext::RegisterWindowMenu(WindowMenu base, const rdcarray<rdcstr> &submenus,
|
||||
ExtensionCallback callback)
|
||||
{
|
||||
if(base == WindowMenu::Unknown)
|
||||
{
|
||||
qCritical() << "Can't register menu for WindowMenu::Unknown";
|
||||
return;
|
||||
}
|
||||
|
||||
if(submenus.isEmpty())
|
||||
{
|
||||
qCritical() << "Empty list of submenus";
|
||||
return;
|
||||
}
|
||||
|
||||
if(base == WindowMenu::NewMenu && submenus.count() == 1)
|
||||
{
|
||||
qCritical() << "Need at least two items in submenus for WindowMenu::NewMenu";
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu *menu = m_MainWindow->GetBaseMenu(base, submenus[0]);
|
||||
|
||||
if(!menu)
|
||||
{
|
||||
qCritical() << "Couldn't get base menu";
|
||||
return;
|
||||
}
|
||||
|
||||
std::function<void()> slotcallback = [this, callback]() { callback(this, {}); };
|
||||
|
||||
// if it's a new menu, GetBaseMenu already did the work, so skip the 0th element of submenus
|
||||
if(base == WindowMenu::NewMenu)
|
||||
{
|
||||
rdcarray<rdcstr> items = submenus;
|
||||
items.erase(0);
|
||||
AddSortedMenuItem(menu, false, items, slotcallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddSortedMenuItem(menu, false, submenus, slotcallback);
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureContext::RegisterPanelMenu(PanelMenu base, const rdcarray<rdcstr> &submenus,
|
||||
ExtensionCallback callback)
|
||||
{
|
||||
if(base == PanelMenu::Unknown)
|
||||
{
|
||||
qCritical() << "Can't register menu for PanelMenu::Unknown";
|
||||
return;
|
||||
}
|
||||
|
||||
RegisteredMenuItem *item = new RegisteredMenuItem();
|
||||
item->panel = base;
|
||||
item->submenus = submenus;
|
||||
item->callback = callback;
|
||||
m_RegisteredMenuItems.push_back(item);
|
||||
m_PendingExtensionObjects.push_back(item);
|
||||
}
|
||||
|
||||
void CaptureContext::RegisterContextMenu(ContextMenu base, const rdcarray<rdcstr> &submenus,
|
||||
ExtensionCallback callback)
|
||||
{
|
||||
if(base == ContextMenu::Unknown)
|
||||
{
|
||||
qCritical() << "Can't register menu for ContextMenu::Unknown";
|
||||
return;
|
||||
}
|
||||
|
||||
RegisteredMenuItem *item = new RegisteredMenuItem();
|
||||
item->context = base;
|
||||
item->submenus = submenus;
|
||||
item->callback = callback;
|
||||
m_RegisteredMenuItems.push_back(item);
|
||||
m_PendingExtensionObjects.push_back(item);
|
||||
}
|
||||
|
||||
void CaptureContext::MenuDisplaying(ContextMenu contextMenu, QMenu *menu,
|
||||
const ExtensionCallbackData &data)
|
||||
{
|
||||
ContextMenu contextMenuAlt = contextMenu;
|
||||
|
||||
switch(contextMenu)
|
||||
{
|
||||
case ContextMenu::MeshPreview_GSOutVertex:
|
||||
case ContextMenu::MeshPreview_VSInVertex:
|
||||
case ContextMenu::MeshPreview_VSOutVertex:
|
||||
contextMenuAlt = ContextMenu::MeshPreview_Vertex;
|
||||
break;
|
||||
case ContextMenu::TextureViewer_InputThumbnail:
|
||||
case ContextMenu::TextureViewer_OutputThumbnail:
|
||||
contextMenuAlt = ContextMenu::TextureViewer_Thumbnail;
|
||||
break;
|
||||
}
|
||||
|
||||
for(RegisteredMenuItem *item : m_RegisteredMenuItems)
|
||||
{
|
||||
if(item->context == contextMenu || item->context == contextMenuAlt)
|
||||
{
|
||||
AddSortedMenuItem(menu, true, item->submenus, [this, item, data]() {
|
||||
rdcarray<rdcpair<rdcstr, PyObject *>> args;
|
||||
|
||||
PythonContext::ConvertPyArgs(data, args);
|
||||
|
||||
item->callback(this, args);
|
||||
|
||||
PythonContext::FreePyArgs(args);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureContext::MenuDisplaying(PanelMenu panelMenu, QWidget *extensionButton,
|
||||
const ExtensionCallbackData &data)
|
||||
{
|
||||
QMenu contextMenu(m_MainWindow);
|
||||
|
||||
for(RegisteredMenuItem *item : m_RegisteredMenuItems)
|
||||
{
|
||||
if(item->panel == panelMenu)
|
||||
{
|
||||
AddSortedMenuItem(&contextMenu, false, item->submenus, [this, item, data]() {
|
||||
rdcarray<rdcpair<rdcstr, PyObject *>> args;
|
||||
|
||||
PythonContext::ConvertPyArgs(data, args);
|
||||
|
||||
item->callback(this, args);
|
||||
|
||||
PythonContext::FreePyArgs(args);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QAction emptyAction(tr("No extension commands configured"), m_MainWindow);
|
||||
|
||||
if(contextMenu.isEmpty())
|
||||
{
|
||||
contextMenu.addAction(&emptyAction);
|
||||
QObject::connect(&emptyAction, &QAction::triggered,
|
||||
[this]() { m_MainWindow->showExtensionManager(); });
|
||||
}
|
||||
|
||||
RDDialog::show(&contextMenu, extensionButton->mapToGlobal(extensionButton->rect().bottomLeft()));
|
||||
}
|
||||
|
||||
void CaptureContext::AddSortedMenuItem(QMenu *menu, bool rootMenu, const rdcarray<rdcstr> &items,
|
||||
std::function<void()> callback)
|
||||
{
|
||||
QAction *beforeAction = NULL;
|
||||
bool addIcon = rootMenu;
|
||||
|
||||
// if we're inserting into a pre-existing menu, try to find an __examples__ action which tells us
|
||||
// where
|
||||
// to be inserting
|
||||
{
|
||||
QList<QAction *> children = menu->actions();
|
||||
int idx = 0;
|
||||
for(; idx < children.count(); idx++)
|
||||
{
|
||||
if(children[idx]->text() == lit("__extensions__"))
|
||||
break;
|
||||
}
|
||||
|
||||
// if we found it, set beforeAction
|
||||
if(idx < children.count())
|
||||
{
|
||||
// search back to find the right place alphabetically to place this, if there are existing
|
||||
// menus
|
||||
|
||||
for(; idx > 0;)
|
||||
{
|
||||
// if the previous child is a separator, break, there are no more previous menus
|
||||
if(children[idx - 1]->isSeparator())
|
||||
break;
|
||||
|
||||
// if we should be sorted before the previous child, move backwards
|
||||
if(children[idx - 1]->text() > items[0])
|
||||
{
|
||||
idx--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we found the right place, break
|
||||
break;
|
||||
}
|
||||
|
||||
beforeAction = children[idx];
|
||||
addIcon = true;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < items.count() - 1; i++)
|
||||
{
|
||||
QList<QAction *> children = menu->actions();
|
||||
|
||||
bool found = false;
|
||||
|
||||
// see if this submenu already exists, if so just iterate down to it
|
||||
for(QAction *a : children)
|
||||
{
|
||||
if(a->text() == items[i])
|
||||
{
|
||||
menu = a->menu();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(found)
|
||||
{
|
||||
addIcon = false;
|
||||
beforeAction = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// create the new submenu
|
||||
QMenu *submenu = new QMenu(items[i], m_MainWindow);
|
||||
|
||||
// if we don't have a beforeAction, find where to insert this to keep alphabetical order.
|
||||
if(!beforeAction)
|
||||
{
|
||||
for(QAction *a : children)
|
||||
{
|
||||
if(submenu->menuAction()->text() < a->text())
|
||||
{
|
||||
beforeAction = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(beforeAction)
|
||||
menu->insertMenu(beforeAction, submenu);
|
||||
else
|
||||
menu->addMenu(submenu);
|
||||
|
||||
if(addIcon)
|
||||
submenu->setIcon(Icons::plugin());
|
||||
|
||||
addIcon = false;
|
||||
|
||||
beforeAction = NULL;
|
||||
|
||||
menu = submenu;
|
||||
}
|
||||
|
||||
QAction *action = new QAction(m_MainWindow);
|
||||
|
||||
action->setText(items.back());
|
||||
|
||||
QObject::connect(action, &QAction::triggered, callback);
|
||||
|
||||
if(!beforeAction)
|
||||
{
|
||||
QList<QAction *> children = menu->actions();
|
||||
|
||||
for(QAction *a : children)
|
||||
{
|
||||
if(action->text() < a->text())
|
||||
{
|
||||
beforeAction = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(beforeAction)
|
||||
menu->insertAction(beforeAction, action);
|
||||
else
|
||||
menu->addAction(action);
|
||||
|
||||
if(addIcon)
|
||||
action->setIcon(Icons::plugin());
|
||||
|
||||
m_PendingExtensionObjects.push_back(action);
|
||||
}
|
||||
|
||||
void CaptureContext::CleanMenu(QAction *action)
|
||||
{
|
||||
QMenu *menu = action->menu();
|
||||
|
||||
// if this isn't a menu, nothing to do - return
|
||||
if(!menu)
|
||||
return;
|
||||
|
||||
// first clean all our children
|
||||
for(QAction *a : menu->actions())
|
||||
CleanMenu(a);
|
||||
|
||||
// if we no longer have any children in this menu, delete it.
|
||||
if(menu->actions().isEmpty())
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void CaptureContext::LoadCapture(const rdcstr &captureFile, const rdcstr &origFilename,
|
||||
bool temporary, bool local)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user