mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
Put the MainWindow in charge of handling 'global' type shortcuts
* QShortcut falls down on duplicates. It can have activatedAmbiguously events, but these happen in arbitrary order and the shortcuts on menu items just swallow the ambiguous activate so it's not useful. * Instead we just let MainWindow pick up ShortcutOverride events and consult a mapping of which shortcuts to use. We can use a smarter selection method to choose the more 'local' shortcut if two shortcuts that conflict exist.
This commit is contained in:
@@ -93,13 +93,40 @@ struct CaptureSettings
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(CaptureSettings);
|
||||
|
||||
DOCUMENT("The main parent window of the application.");
|
||||
DOCUMENT(R"(The main parent window of the application.
|
||||
|
||||
.. function:: ShortcutCallback()
|
||||
|
||||
Not a member function - the signature for any ``ShortcutCallback`` callbacks.
|
||||
)");
|
||||
struct IMainWindow
|
||||
{
|
||||
typedef std::function<void()> ShortcutCallback;
|
||||
|
||||
DOCUMENT(
|
||||
"Retrieves the QWidget for this :class:`MainWindow` if PySide2 is available, or ``None``.");
|
||||
virtual QWidget *Widget() = 0;
|
||||
|
||||
DOCUMENT(R"(Register a callback for a particular key shortcut.
|
||||
|
||||
This creates a managed shortcut. Qt's shortcut system doesn't allow specialisation/duplication, so
|
||||
you can't use ``Ctrl+S`` for a shortcut in a window to update some changes if there's also a global
|
||||
``Ctrl+S`` shortcut on the window. In the end, neither shortcut will be called.
|
||||
|
||||
Instead this function allows the main window to manage shortcuts internally, and it will pick the
|
||||
closest shortcut to a given action. The search goes from the widget with the focus currently up the
|
||||
chain of parents, with the first match being used. If no matches are found, then a 'global' default
|
||||
will be invoked, if it exists.
|
||||
|
||||
:param str shortcut: The text string representing the shortcut, e.g. 'Ctrl+S'.
|
||||
:param QWidget widget: A handle to the widget to use as the context for this shortcut, or ``None``
|
||||
for a global shortcut. Note that if an existing global shortcut exists the new one will not be
|
||||
registered.
|
||||
:rtype: ``str``
|
||||
)");
|
||||
virtual void RegisterShortcut(const QString &shortcut, QWidget *widget,
|
||||
ShortcutCallback callback) = 0;
|
||||
|
||||
protected:
|
||||
IMainWindow() = default;
|
||||
~IMainWindow() = default;
|
||||
|
||||
@@ -134,19 +134,20 @@ EventBrowser::EventBrowser(ICaptureContext &ctx, QWidget *parent)
|
||||
};
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
QShortcut *sc = new QShortcut(QKeySequence(keys[i] | Qt::ControlModifier), this);
|
||||
QObject::connect(sc, &QShortcut::activated, [this, i]() { jumpToBookmark(i); });
|
||||
ctx.GetMainWindow()->RegisterShortcut(QKeySequence(keys[i] | Qt::ControlModifier).toString(),
|
||||
NULL, [this, i]() { jumpToBookmark(i); });
|
||||
}
|
||||
|
||||
{
|
||||
QShortcut *sc = new QShortcut(QKeySequence(Qt::Key_Left | Qt::ControlModifier), this);
|
||||
QObject::connect(sc, &QShortcut::activated, this, &EventBrowser::on_stepPrev_clicked);
|
||||
}
|
||||
ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_Left | Qt::ControlModifier).toString(),
|
||||
NULL, [this]() { on_stepPrev_clicked(); });
|
||||
|
||||
{
|
||||
QShortcut *sc = new QShortcut(QKeySequence(Qt::Key_Right | Qt::ControlModifier), this);
|
||||
QObject::connect(sc, &QShortcut::activated, this, &EventBrowser::on_stepNext_clicked);
|
||||
}
|
||||
ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_Right | Qt::ControlModifier).toString(),
|
||||
NULL, [this]() { on_stepNext_clicked(); });
|
||||
|
||||
ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_Escape).toString(), ui->findStrip,
|
||||
[this]() { on_HideFindJump(); });
|
||||
ctx.GetMainWindow()->RegisterShortcut(QKeySequence(Qt::Key_Escape).toString(), ui->jumpStrip,
|
||||
[this]() { on_HideFindJump(); });
|
||||
|
||||
ui->events->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QObject::connect(ui->events, &RDTreeWidget::customContextMenuRequested, this,
|
||||
|
||||
@@ -323,9 +323,6 @@
|
||||
<iconset resource="../Resources/resources.qrc">
|
||||
<normaloff>:/cross.png</normaloff>:/cross.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Esc</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -436,9 +433,6 @@
|
||||
<iconset resource="../Resources/resources.qrc">
|
||||
<normaloff>:/cross.png</normaloff>:/cross.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Esc</string>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
||||
@@ -57,6 +57,8 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
installEventFilter(this);
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
QObject::connect(ui->action_Load_Default_Layout, &QAction::triggered, this,
|
||||
@@ -166,8 +168,6 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
ui->action_Resolve_Symbols->setEnabled(false);
|
||||
ui->action_Resolve_Symbols->setText(tr("Resolve Symbols"));
|
||||
|
||||
bool loaded = LoadLayout(0);
|
||||
|
||||
LambdaThread *th = new LambdaThread([this]() {
|
||||
m_Ctx.Config().AddAndroidHosts();
|
||||
for(RemoteHost *host : m_Ctx.Config().RemoteHosts)
|
||||
@@ -176,46 +176,6 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
th->selfDelete(true);
|
||||
th->start();
|
||||
|
||||
// create default layout if layout failed to load
|
||||
if(!loaded)
|
||||
{
|
||||
QWidget *eventBrowser = m_Ctx.GetEventBrowser()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(eventBrowser, ToolWindowManager::EmptySpace);
|
||||
|
||||
QWidget *textureViewer = m_Ctx.GetTextureViewer()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
textureViewer,
|
||||
ToolWindowManager::AreaReference(ToolWindowManager::RightOf,
|
||||
ui->toolWindowManager->areaOf(eventBrowser), 0.75f));
|
||||
|
||||
QWidget *pipe = m_Ctx.GetPipelineViewer()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
pipe, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->toolWindowManager->areaOf(textureViewer)));
|
||||
|
||||
QWidget *mesh = m_Ctx.GetMeshPreview()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
mesh, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->toolWindowManager->areaOf(textureViewer)));
|
||||
|
||||
QWidget *capDialog = m_Ctx.GetCaptureDialog()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
capDialog, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->toolWindowManager->areaOf(textureViewer)));
|
||||
|
||||
QWidget *apiInspector = m_Ctx.GetAPIInspector()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
apiInspector,
|
||||
ToolWindowManager::AreaReference(ToolWindowManager::BottomOf,
|
||||
ui->toolWindowManager->areaOf(eventBrowser), 0.3f));
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN32)
|
||||
if(GetModuleHandleA("rdocself.dll"))
|
||||
{
|
||||
@@ -244,6 +204,27 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
#endif
|
||||
|
||||
m_Ctx.AddLogViewer(this);
|
||||
|
||||
QList<QAction *> actions = ui->menuBar->actions();
|
||||
|
||||
// register all the UI-designer created shortcut keys
|
||||
for(int i = 0; i < actions.count(); i++)
|
||||
{
|
||||
QAction *a = actions[i];
|
||||
|
||||
QKeySequence ks = a->shortcut();
|
||||
if(!ks.isEmpty())
|
||||
{
|
||||
m_GlobalShortcutCallbacks[ks] = [a]() {
|
||||
if(a->isEnabled())
|
||||
a->trigger();
|
||||
};
|
||||
}
|
||||
|
||||
// recurse into submenus by appending to the end of the list.
|
||||
if(a->menu())
|
||||
actions.append(a->menu()->actions());
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
@@ -845,6 +826,53 @@ ToolWindowManager::AreaReference MainWindow::leftToolArea()
|
||||
return ToolWindowManager::AreaReference(ToolWindowManager::LastUsedArea);
|
||||
}
|
||||
|
||||
void MainWindow::show()
|
||||
{
|
||||
bool loaded = LoadLayout(0);
|
||||
|
||||
// create default layout if layout failed to load
|
||||
if(!loaded)
|
||||
{
|
||||
QWidget *eventBrowser = m_Ctx.GetEventBrowser()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(eventBrowser, ToolWindowManager::EmptySpace);
|
||||
|
||||
QWidget *textureViewer = m_Ctx.GetTextureViewer()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
textureViewer,
|
||||
ToolWindowManager::AreaReference(ToolWindowManager::RightOf,
|
||||
ui->toolWindowManager->areaOf(eventBrowser), 0.75f));
|
||||
|
||||
QWidget *pipe = m_Ctx.GetPipelineViewer()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
pipe, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->toolWindowManager->areaOf(textureViewer)));
|
||||
|
||||
QWidget *mesh = m_Ctx.GetMeshPreview()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
mesh, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->toolWindowManager->areaOf(textureViewer)));
|
||||
|
||||
QWidget *capDialog = m_Ctx.GetCaptureDialog()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
capDialog, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->toolWindowManager->areaOf(textureViewer)));
|
||||
|
||||
QWidget *apiInspector = m_Ctx.GetAPIInspector()->Widget();
|
||||
|
||||
ui->toolWindowManager->addToolWindow(
|
||||
apiInspector,
|
||||
ToolWindowManager::AreaReference(ToolWindowManager::BottomOf,
|
||||
ui->toolWindowManager->areaOf(eventBrowser), 0.3f));
|
||||
}
|
||||
|
||||
QMainWindow::show();
|
||||
}
|
||||
|
||||
void MainWindow::recentLog(const QString &filename)
|
||||
{
|
||||
if(QFileInfo::exists(filename))
|
||||
@@ -1258,6 +1286,71 @@ void MainWindow::OnEventChanged(uint32_t eventID)
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::RegisterShortcut(const QString &shortcut, QWidget *widget, ShortcutCallback callback)
|
||||
{
|
||||
QKeySequence ks = QKeySequence::fromString(shortcut);
|
||||
|
||||
if(widget)
|
||||
{
|
||||
m_WidgetShortcutCallbacks[ks][widget] = callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_GlobalShortcutCallbacks[ks])
|
||||
{
|
||||
qCritical() << "Assigning duplicate global shortcut for" << ks;
|
||||
return;
|
||||
}
|
||||
|
||||
m_GlobalShortcutCallbacks[ks] = callback;
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if(event->type() == QEvent::ShortcutOverride)
|
||||
{
|
||||
QKeyEvent *ke = (QKeyEvent *)event;
|
||||
|
||||
QKeySequence pressed(ke->modifiers() | ke->key());
|
||||
|
||||
// first see if there's a widget shortcut registered for this key. If so, check the focus
|
||||
// hierarchy to see if we have any matches
|
||||
QWidget *focus = QApplication::focusWidget();
|
||||
|
||||
if(focus && m_WidgetShortcutCallbacks.contains(pressed))
|
||||
{
|
||||
const QMap<QWidget *, ShortcutCallback> callbacks = m_WidgetShortcutCallbacks[pressed];
|
||||
QList<QWidget *> widgets = callbacks.keys();
|
||||
|
||||
while(focus)
|
||||
{
|
||||
// if we find a direct ancestor to the focus widget which is registered for this shortcut,
|
||||
// then use that callback
|
||||
if(widgets.contains(focus))
|
||||
{
|
||||
callbacks[focus]();
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
// keep searching up the hierarchy
|
||||
focus = focus->parentWidget();
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't find matches or no such shortcut is registered, try global shortcuts
|
||||
if(m_GlobalShortcutCallbacks.contains(pressed))
|
||||
{
|
||||
m_GlobalShortcutCallbacks[pressed]();
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QMainWindow::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Close_Log_triggered()
|
||||
{
|
||||
PromptCloseLog();
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
|
||||
// IMainWindow
|
||||
QWidget *Widget() override { return this; }
|
||||
void RegisterShortcut(const QString &shortcut, QWidget *widget, ShortcutCallback callback);
|
||||
// ILogViewerForm
|
||||
void OnLogfileLoaded() override;
|
||||
void OnLogfileClosed() override;
|
||||
@@ -63,6 +64,8 @@ public:
|
||||
ToolWindowManager::AreaReference mainToolArea();
|
||||
ToolWindowManager::AreaReference leftToolArea();
|
||||
|
||||
void show();
|
||||
|
||||
void setProgress(float val);
|
||||
void takeLogOwnership() { m_OwnTempLog = true; }
|
||||
void LoadFromFilename(const QString &filename);
|
||||
@@ -133,6 +136,8 @@ private:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
QString dragFilename(const QMimeData *mimeData);
|
||||
|
||||
Ui::MainWindow *ui;
|
||||
@@ -140,6 +145,9 @@ private:
|
||||
|
||||
QList<LiveCapture *> m_LiveCaptures;
|
||||
|
||||
QMap<QKeySequence, ShortcutCallback> m_GlobalShortcutCallbacks;
|
||||
QMap<QKeySequence, QMap<QWidget *, ShortcutCallback>> m_WidgetShortcutCallbacks;
|
||||
|
||||
RDLabel *statusIcon;
|
||||
RDLabel *statusText;
|
||||
QProgressBar *statusProgress;
|
||||
|
||||
@@ -199,9 +199,6 @@
|
||||
<property name="text">
|
||||
<string>E&xit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Alt+F4</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Python_Shell">
|
||||
<property name="text">
|
||||
|
||||
@@ -217,9 +217,8 @@ void ShaderViewer::editShader(bool customShader, const QString &entryPoint, cons
|
||||
m_FindState = FindState();
|
||||
});
|
||||
|
||||
// TODO - shortcuts
|
||||
QObject::connect(new QShortcut(QKeySequence(Qt::Key_S | Qt::ControlModifier), scintilla),
|
||||
&QShortcut::activated, this, &ShaderViewer::on_save_clicked);
|
||||
m_Ctx.GetMainWindow()->RegisterShortcut(QKeySequence(QKeySequence::Save).toString(), this,
|
||||
[this]() { on_save_clicked(); });
|
||||
|
||||
QWidget *w = (QWidget *)scintilla;
|
||||
w->setProperty("filename", f);
|
||||
|
||||
Reference in New Issue
Block a user