mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-24 23:46:41 +00:00
Move new extension creation wizard to python scripting
* We remove the operations and interactions from the extension manager and leave it purely for browsing extensions and enabling/disabling them.
This commit is contained in:
@@ -8,6 +8,9 @@ Example extensions can be found at the `community contributed repository <https:
|
||||
Creating extensions
|
||||
-------------------
|
||||
|
||||
.. tip::
|
||||
You can ask RenderDoc to create an empty extension for you from the :doc:`python scripting <../window/python_scripting>` window.
|
||||
|
||||
Extensions are simply python modules located in the user's RenderDoc config folder, with a json manifest. The config folder varies by platform, on Windows it's ``%APPDATA%\qrenderdoc\extensions`` and on linux it's ``~/.local/share/qrenderdoc/extensions``. Each extension is a python module subfolder under this root. You can nest subfolders, e.g. ``extensions/foo/bar/first`` would be the extension ``foo.bar.first``, and treated independently from ``extensions/foo/bar/second``.
|
||||
|
||||
Next to each python module's ``__init__.py`` you should create a file ``extension.json`` following this template:
|
||||
|
||||
@@ -14,7 +14,9 @@ In any subdirectory under this path you can register an extension by creating a
|
||||
|
||||
Extension Manager: Configures installed extensions.
|
||||
|
||||
To streamline setup we will ask RenderDoc to create a new extension for us. Open the extension manager by opening the :guilabel:`Tools` menu and select :guilabel:`Manage Extensions`, then click the :guilabel:`Create New...` button and enter a package name such as ``tutorialext``. This will create the ``extension.json`` and ``__init__.py`` files in a new folder ``tutorialext`` for us.
|
||||
To streamline setup we will ask RenderDoc to create a new extension for us. Open the python scripting window from :guilabel:`Window` → :guilabel:`Python Scripting`. Then either double click the :guilabel:`Create New...` item under the :guilabel:`UI Extensions` section, or right click on the section title and select the option from the context menu.
|
||||
|
||||
From the dialog that appears enter a package name such as ``tutorialext``. This will create the ``extension.json`` and ``__init__.py`` files in a new folder ``tutorialext`` for us.
|
||||
|
||||
For more information about the registration of python extensions see :doc:`../how/how_python_extension`
|
||||
|
||||
|
||||
@@ -56,8 +56,6 @@ ExtensionManager::ExtensionManager(ICaptureContext &ctx)
|
||||
ui->version->setText(lit("---"));
|
||||
ui->author->setText(lit("---"));
|
||||
ui->URL->setText(lit("---"));
|
||||
ui->reload->setEnabled(false);
|
||||
ui->debug->setEnabled(false);
|
||||
ui->alwaysLoad->setEnabled(false);
|
||||
|
||||
QObject::connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
@@ -105,12 +103,8 @@ ExtensionManager::~ExtensionManager()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ExtensionManager::on_reload_clicked()
|
||||
void ExtensionManager::loadExtension(RDTreeWidgetItem *item)
|
||||
{
|
||||
RDTreeWidgetItem *item = ui->extensions->currentItem();
|
||||
if(!item)
|
||||
return;
|
||||
|
||||
int idx = ui->extensions->indexOfTopLevelItem(item);
|
||||
|
||||
if(idx >= 0 && idx < m_Extensions.count())
|
||||
@@ -139,85 +133,6 @@ void ExtensionManager::on_reload_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionManager::on_debug_clicked()
|
||||
{
|
||||
if(m_Extensions.empty())
|
||||
return;
|
||||
|
||||
RDTreeWidgetItem *item = ui->extensions->currentItem();
|
||||
if(!item)
|
||||
return;
|
||||
|
||||
int idx = ui->extensions->indexOfTopLevelItem(item);
|
||||
|
||||
if(idx >= 0 && idx < m_Extensions.count())
|
||||
{
|
||||
const ExtensionMetadata &e = m_Extensions[idx];
|
||||
if(!e.name.isEmpty())
|
||||
{
|
||||
PythonContext::PrepareDebuggerWait();
|
||||
|
||||
LambdaThread *thread = new LambdaThread([this]() {
|
||||
PythonContext::WaitForDebugger();
|
||||
|
||||
GUIInvoke::call(this, [this]() { on_reload_clicked(); });
|
||||
});
|
||||
|
||||
thread->selfDelete(true);
|
||||
thread->start();
|
||||
|
||||
PythonContext::LaunchDebugger(this, m_Ctx.Config(), QFileInfo(e.filePath).absoluteFilePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionManager::on_output_clicked()
|
||||
{
|
||||
m_Ctx.ShowPythonShell();
|
||||
m_Ctx.GetPythonShell()->ShowOutput();
|
||||
|
||||
RDTreeWidgetItem *item = ui->extensions->currentItem();
|
||||
if(item)
|
||||
{
|
||||
int idx = ui->extensions->indexOfTopLevelItem(item);
|
||||
|
||||
if(idx >= 0 && idx < m_Extensions.count())
|
||||
{
|
||||
const ExtensionMetadata &e = m_Extensions[idx];
|
||||
if(!e.package.isEmpty())
|
||||
{
|
||||
m_Ctx.GetPythonShell()->SetExtensionOutputFilter(e.package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void ExtensionManager::on_openLocation_clicked()
|
||||
{
|
||||
if(m_Extensions.empty())
|
||||
{
|
||||
QDesktopServices::openUrl(QString(ConfigFilePath("extensions")));
|
||||
return;
|
||||
}
|
||||
|
||||
RDTreeWidgetItem *item = ui->extensions->currentItem();
|
||||
if(!item)
|
||||
return;
|
||||
|
||||
int idx = ui->extensions->indexOfTopLevelItem(item);
|
||||
|
||||
if(idx >= 0 && idx < m_Extensions.count())
|
||||
{
|
||||
const ExtensionMetadata &e = m_Extensions[idx];
|
||||
if(!e.name.isEmpty())
|
||||
{
|
||||
QDesktopServices::openUrl(QFileInfo(e.filePath).absoluteFilePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionManager::on_alwaysLoad_toggled(bool checked)
|
||||
{
|
||||
RDTreeWidgetItem *item = ui->extensions->currentItem();
|
||||
@@ -240,176 +155,6 @@ void ExtensionManager::on_alwaysLoad_toggled(bool checked)
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionManager::on_createExtension_clicked()
|
||||
{
|
||||
QDialog dialog;
|
||||
RDLabel label;
|
||||
RDLineEdit extensionName;
|
||||
QDialogButtonBox buttons;
|
||||
|
||||
dialog.setWindowTitle(tr("Create new UI extension"));
|
||||
dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
label.setText(
|
||||
tr("Create a new UI extension, with some example code.\n"
|
||||
"\n"
|
||||
"This will create the directory structure for the specified package name, with a default\n"
|
||||
"extension metadata json and some simple example code to give you a starting point."));
|
||||
|
||||
extensionName.setPlaceholderText(tr("myname.example"));
|
||||
|
||||
buttons.setOrientation(Qt::Horizontal);
|
||||
buttons.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
buttons.setCenterButtons(true);
|
||||
|
||||
QObject::connect(&buttons, &QDialogButtonBox::accepted, [this, &dialog, &extensionName]() {
|
||||
QString extName = extensionName.text().trimmed();
|
||||
|
||||
if(extName.isEmpty())
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Invalid extension name"),
|
||||
tr("Must specify a name for the new extension."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(extName.startsWith(lit("renderdoc.")))
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Invalid extension name"),
|
||||
tr("Extension name conflicts with builtin module 'renderdoc'."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(extName.contains(QLatin1Char(' ')) || extName.contains(QLatin1Char('\t')))
|
||||
{
|
||||
RDDialog::critical(
|
||||
&dialog, tr("Invalid extension name"),
|
||||
tr("Extension names should be valid python package names, note including whitespace."));
|
||||
return;
|
||||
}
|
||||
|
||||
for(const ExtensionMetadata &e : m_Extensions)
|
||||
{
|
||||
if(QString(e.package) == extName)
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Extension name in use"),
|
||||
tr("The extension name '%1' already exists.").arg(e.package));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList locations = PythonContext::GetApplicationExtensionsPaths();
|
||||
|
||||
if(!locations.empty())
|
||||
{
|
||||
QDir dir(locations[0]);
|
||||
|
||||
QStringList paths = extName.split(QLatin1Char('.'));
|
||||
|
||||
bool nonexist = false;
|
||||
|
||||
while(!paths.empty())
|
||||
{
|
||||
QString dirname = paths[0];
|
||||
paths.pop_front();
|
||||
|
||||
if(!dir.cd(dirname))
|
||||
{
|
||||
nonexist = true;
|
||||
break;
|
||||
}
|
||||
|
||||
qInfo() << dir.absolutePath();
|
||||
}
|
||||
|
||||
if(!nonexist && dir.exists() && !dir.isEmpty())
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Directory already exists"),
|
||||
tr("Extension directory already exists:\n%1").arg(dir.absolutePath()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dialog.accept();
|
||||
});
|
||||
QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(&dialog);
|
||||
layout->addWidget(&label);
|
||||
layout->addWidget(&extensionName);
|
||||
layout->addWidget(&buttons);
|
||||
|
||||
if(!RDDialog::show(&dialog))
|
||||
return;
|
||||
|
||||
if(dialog.result() == QDialog::Accepted)
|
||||
{
|
||||
QStringList locations = PythonContext::GetApplicationExtensionsPaths();
|
||||
QDir dir(locations[0]);
|
||||
|
||||
QString extName = extensionName.text().trimmed();
|
||||
QStringList paths = extName.split(QLatin1Char('.'));
|
||||
|
||||
while(!paths.empty())
|
||||
{
|
||||
QString dirname = paths[0];
|
||||
paths.pop_front();
|
||||
|
||||
dir.mkdir(dirname);
|
||||
|
||||
if(!dir.cd(dirname))
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Couldn't create directory"),
|
||||
tr("Failed to create %1 in %2").arg(dirname).arg(dir.absolutePath()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
paths = extName.split(QLatin1Char('.'));
|
||||
|
||||
QString metadata = lit(R"({
|
||||
"extension_api": 1,
|
||||
"name": "%3",
|
||||
"version": "1.0",
|
||||
"minimum_renderdoc": "%1.%2",
|
||||
"description": "Template extension %4",
|
||||
"author": "My Name <my.email@example.com>",
|
||||
"url": "https://github.com/example/example"
|
||||
}
|
||||
)")
|
||||
.arg(RENDERDOC_VERSION_MAJOR)
|
||||
.arg(RENDERDOC_VERSION_MINOR)
|
||||
.arg(paths.back())
|
||||
.arg(extName);
|
||||
|
||||
{
|
||||
QFile ext(dir.absoluteFilePath(lit("extension.json")));
|
||||
if(ext.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
ext.write(metadata.toUtf8());
|
||||
}
|
||||
|
||||
QFile init(dir.absoluteFilePath(lit("__init__.py")));
|
||||
if(init.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
init.write(R"(
|
||||
# Blank RenderDoc UI extension
|
||||
|
||||
import renderdoc as rd
|
||||
import qrenderdoc as qrd
|
||||
|
||||
def register(version: str, pyrenderdoc: qrd.CaptureContext):
|
||||
print(f"New UI extension loaded in RenderDoc {version}")
|
||||
|
||||
def unregister():
|
||||
print(f"New UI extension being unloaded")
|
||||
)");
|
||||
}
|
||||
}
|
||||
|
||||
PopulateExtensionList();
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionManager::on_extensions_currentItemChanged(RDTreeWidgetItem *item, RDTreeWidgetItem *)
|
||||
{
|
||||
update_currentItem(item);
|
||||
@@ -435,7 +180,7 @@ void ExtensionManager::on_extensions_itemChanged(RDTreeWidgetItem *item, int col
|
||||
if(!loaded)
|
||||
{
|
||||
if(item->checkState(2) == Qt::Checked)
|
||||
on_reload_clicked();
|
||||
loadExtension(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,14 +219,6 @@ void ExtensionManager::update_currentItem(RDTreeWidgetItem *item)
|
||||
ui->author->setText(e.author);
|
||||
|
||||
bool loaded = item->checkState(2) == Qt::Checked;
|
||||
ui->reload->setEnabled(true);
|
||||
ui->reload->setText(loaded ? tr("Reload") : tr("Load"));
|
||||
ui->output->setEnabled(loaded);
|
||||
ui->debug->setEnabled(loaded && PythonContext::IsDebuggingEnabled());
|
||||
ui->debug->setToolTip(QString());
|
||||
if(loaded && !PythonContext::IsDebuggingEnabled())
|
||||
ui->debug->setToolTip(
|
||||
tr("Debugging not supported - check documentation for setup instructions"));
|
||||
ui->alwaysLoad->setEnabled(loaded);
|
||||
|
||||
ui->alwaysLoad->setChecked(m_Ctx.Config().AlwaysLoad_Extensions.contains(e.package));
|
||||
|
||||
@@ -48,18 +48,14 @@ public:
|
||||
|
||||
private slots:
|
||||
// automatic slots
|
||||
void on_reload_clicked();
|
||||
void on_debug_clicked();
|
||||
void on_output_clicked();
|
||||
void on_openLocation_clicked();
|
||||
void on_alwaysLoad_toggled(bool checked);
|
||||
void on_createExtension_clicked();
|
||||
void on_extensions_currentItemChanged(RDTreeWidgetItem *item, RDTreeWidgetItem *);
|
||||
void on_extensions_itemChanged(RDTreeWidgetItem *item, int col);
|
||||
|
||||
private:
|
||||
void update_currentItem(RDTreeWidgetItem *item);
|
||||
|
||||
void loadExtension(RDTreeWidgetItem *item);
|
||||
void PopulateExtensionList();
|
||||
|
||||
Ui::ExtensionManager *ui;
|
||||
|
||||
@@ -50,32 +50,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="createContainer" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="createExtension">
|
||||
<property name="text">
|
||||
<string>Create New...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -236,34 +210,6 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="openLocation">
|
||||
<property name="text">
|
||||
<string>Open Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reload">
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="output">
|
||||
<property name="text">
|
||||
<string>View output</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="debug">
|
||||
<property name="text">
|
||||
<string>Debug</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="alwaysLoad">
|
||||
<property name="text">
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QAbstractItemView>
|
||||
#include <QCompleter>
|
||||
#include <QDesktopServices>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QFontDatabase>
|
||||
#include <QKeyEvent>
|
||||
@@ -400,6 +401,11 @@ PythonShell::PythonShell(ICaptureContext &ctx, QWidget *parent)
|
||||
m_UIExtensions->setBold(true);
|
||||
m_UIExtensions->setIcon(0, Icons::plugin());
|
||||
|
||||
m_NewExtension = new RDTreeWidgetItem({tr("Create new...")});
|
||||
m_NewExtension->setData(0, Qt::UserRole + 1, m_NewExtension->text(0));
|
||||
m_NewExtension->setItalic(true);
|
||||
m_NewExtension->setIcon(0, Icons::plugin_add());
|
||||
|
||||
m_RecentFiles = new RDTreeWidgetItem({lit("Recent files")});
|
||||
m_RecentFiles->setData(0, Qt::UserRole + 1, m_UIExtensions->text(0));
|
||||
m_RecentFiles->setSelectable(false);
|
||||
@@ -663,6 +669,8 @@ void PythonShell::updateExtensionProjects()
|
||||
m_UIExtensions->addChild(root);
|
||||
}
|
||||
|
||||
m_UIExtensions->addChild(m_NewExtension);
|
||||
|
||||
ui->projectExplorer->endUpdate();
|
||||
|
||||
ui->projectExplorer->applyExpansion(expansion, 0, Qt::UserRole + 1);
|
||||
@@ -1418,7 +1426,11 @@ void PythonShell::on_projectExplorer_itemActivated(RDTreeWidgetItem *item, int c
|
||||
if(item == m_Examples || item == m_UIExtensions || item == m_RecentFiles)
|
||||
return;
|
||||
|
||||
if(item->parent() == m_Examples)
|
||||
if(item == m_NewExtension)
|
||||
{
|
||||
createExtension_clicked();
|
||||
}
|
||||
else if(item->parent() == m_Examples)
|
||||
{
|
||||
QString filename = tr("Example: ") + item->text(0);
|
||||
QString text = item->data(0, Qt::UserRole).toString();
|
||||
@@ -1726,6 +1738,9 @@ void PythonShell::projectExplorer_contextMenu(const QPoint &pos)
|
||||
QAction viewOutput(tr("&View output"), this);
|
||||
viewOutput.setIcon(Icons::filter());
|
||||
|
||||
QAction createExtension(tr("Create &New Extension"), this);
|
||||
createExtension.setIcon(Icons::plugin_add());
|
||||
|
||||
QObject::connect(&expandAll, &QAction::triggered,
|
||||
[this, item]() { ui->projectExplorer->expandAllItems(item); });
|
||||
|
||||
@@ -1795,12 +1810,196 @@ void PythonShell::projectExplorer_contextMenu(const QPoint &pos)
|
||||
[this, diskLocation]() { QDesktopServices::openUrl(diskLocation); });
|
||||
}
|
||||
}
|
||||
else if(item == m_UIExtensions)
|
||||
{
|
||||
contextMenu.addSeparator();
|
||||
|
||||
contextMenu.addAction(&createExtension);
|
||||
|
||||
QObject::connect(&createExtension, &QAction::triggered, [this]() { createExtension_clicked(); });
|
||||
}
|
||||
|
||||
RDDialog::show(&contextMenu, ui->projectExplorer->viewport()->mapToGlobal(pos));
|
||||
|
||||
m_ContextMenuVisible = false;
|
||||
}
|
||||
|
||||
void PythonShell::createExtension_clicked()
|
||||
{
|
||||
QDialog dialog;
|
||||
RDLabel label;
|
||||
RDLineEdit extensionName;
|
||||
QDialogButtonBox buttons;
|
||||
|
||||
dialog.setWindowTitle(tr("Create new UI extension"));
|
||||
dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
label.setText(
|
||||
tr("Create a new UI extension, with some example code.\n"
|
||||
"\n"
|
||||
"This will create the directory structure for the specified package name, with a default\n"
|
||||
"extension metadata json and some simple example code to give you a starting point."));
|
||||
|
||||
extensionName.setPlaceholderText(tr("myname.example"));
|
||||
|
||||
buttons.setOrientation(Qt::Horizontal);
|
||||
buttons.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
buttons.setCenterButtons(true);
|
||||
|
||||
QObject::connect(&buttons, &QDialogButtonBox::accepted, [this, &dialog, &extensionName]() {
|
||||
QString extName = extensionName.text().trimmed();
|
||||
|
||||
if(extName.isEmpty())
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Invalid extension name"),
|
||||
tr("Must specify a name for the new extension."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(extName.startsWith(lit("renderdoc.")))
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Invalid extension name"),
|
||||
tr("Extension name conflicts with builtin module 'renderdoc'."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(extName.contains(QLatin1Char(' ')) || extName.contains(QLatin1Char('\t')))
|
||||
{
|
||||
RDDialog::critical(
|
||||
&dialog, tr("Invalid extension name"),
|
||||
tr("Extension names should be valid python package names, note including whitespace."));
|
||||
return;
|
||||
}
|
||||
|
||||
for(const ExtensionMetadata &e : m_Ctx.Extensions().GetInstalledExtensions())
|
||||
{
|
||||
if(QString(e.package) == extName)
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Extension name in use"),
|
||||
tr("The extension name '%1' already exists.").arg(e.package));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList locations = PythonContext::GetApplicationExtensionsPaths();
|
||||
|
||||
if(!locations.empty())
|
||||
{
|
||||
QDir dir(locations[0]);
|
||||
|
||||
QStringList paths = extName.split(QLatin1Char('.'));
|
||||
|
||||
bool nonexist = false;
|
||||
|
||||
while(!paths.empty())
|
||||
{
|
||||
QString dirname = paths[0];
|
||||
paths.pop_front();
|
||||
|
||||
if(!dir.cd(dirname))
|
||||
{
|
||||
nonexist = true;
|
||||
break;
|
||||
}
|
||||
|
||||
qInfo() << dir.absolutePath();
|
||||
}
|
||||
|
||||
if(!nonexist && dir.exists() && !dir.isEmpty())
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Directory already exists"),
|
||||
tr("Extension directory already exists:\n%1").arg(dir.absolutePath()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dialog.accept();
|
||||
});
|
||||
QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(&dialog);
|
||||
layout->addWidget(&label);
|
||||
layout->addWidget(&extensionName);
|
||||
layout->addWidget(&buttons);
|
||||
|
||||
if(!RDDialog::show(&dialog))
|
||||
return;
|
||||
|
||||
if(dialog.result() == QDialog::Accepted)
|
||||
{
|
||||
QStringList locations = PythonContext::GetApplicationExtensionsPaths();
|
||||
QDir dir(locations[0]);
|
||||
|
||||
QString extName = extensionName.text().trimmed();
|
||||
QStringList paths = extName.split(QLatin1Char('.'));
|
||||
|
||||
while(!paths.empty())
|
||||
{
|
||||
QString dirname = paths[0];
|
||||
paths.pop_front();
|
||||
|
||||
dir.mkdir(dirname);
|
||||
|
||||
if(!dir.cd(dirname))
|
||||
{
|
||||
RDDialog::critical(&dialog, tr("Couldn't create directory"),
|
||||
tr("Failed to create %1 in %2").arg(dirname).arg(dir.absolutePath()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
paths = extName.split(QLatin1Char('.'));
|
||||
|
||||
QString metadata = lit(R"({
|
||||
"extension_api": 1,
|
||||
"name": "%3",
|
||||
"version": "1.0",
|
||||
"minimum_renderdoc": "%1.%2",
|
||||
"description": "Template extension %4",
|
||||
"author": "My Name <my.email@example.com>",
|
||||
"url": "https://github.com/example/example"
|
||||
}
|
||||
)")
|
||||
.arg(RENDERDOC_VERSION_MAJOR)
|
||||
.arg(RENDERDOC_VERSION_MINOR)
|
||||
.arg(paths.back())
|
||||
.arg(extName);
|
||||
|
||||
{
|
||||
QFile ext(dir.absoluteFilePath(lit("extension.json")));
|
||||
if(ext.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
ext.write(metadata.toUtf8());
|
||||
}
|
||||
|
||||
QFile init(dir.absoluteFilePath(lit("__init__.py")));
|
||||
if(init.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
init.write(R"(
|
||||
# Blank RenderDoc UI extension
|
||||
|
||||
import renderdoc as rd
|
||||
import qrenderdoc as qrd
|
||||
|
||||
def register(version: str, pyrenderdoc: qrd.CaptureContext):
|
||||
print(f"New UI extension loaded in RenderDoc {version}")
|
||||
|
||||
def unregister():
|
||||
print(f"New UI extension being unloaded")
|
||||
)");
|
||||
}
|
||||
}
|
||||
|
||||
updateExtensionProjects();
|
||||
|
||||
LoadScriptFromFilename(dir.absoluteFilePath(lit("__init__.py")));
|
||||
|
||||
m_Editors.back()->setUIExtension(true);
|
||||
|
||||
editorTab_Changed(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void PythonShell::selectedHelp(QString word)
|
||||
{
|
||||
ui->helpSearch->setText(word);
|
||||
|
||||
@@ -155,6 +155,7 @@ private slots:
|
||||
void projectExplorer_contextMenu(const QPoint &pos);
|
||||
void editorTab_Changed(int index);
|
||||
void doSyntaxCheck();
|
||||
void createExtension_clicked();
|
||||
|
||||
void openFileModified(const QString &path);
|
||||
void updateExtensionProjects();
|
||||
@@ -176,7 +177,7 @@ private:
|
||||
|
||||
bool m_IgnoreRecovered = false;
|
||||
|
||||
RDTreeWidgetItem *m_UIExtensions, *m_Examples, *m_RecentFiles;
|
||||
RDTreeWidgetItem *m_UIExtensions, *m_Examples, *m_RecentFiles, *m_NewExtension;
|
||||
|
||||
QFileSystemWatcher *m_Watcher = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user