forked from qt-creator/qt-creator
QmlDesigner: Add support for previewing multiple 3D imports
Imported items are shown on a list in import dialog and a preview is generated for each. Options are also specified per-import rather than applying to all imports. Fixes: QDS-10806 Change-Id: I6be09880afc0f8886585c4e768da1197b46bc71a Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -58,7 +58,9 @@ enum class View3DActionType {
|
||||
EditCameraStopAllMoves,
|
||||
SetLastSceneEnvData,
|
||||
Import3dUpdatePreviewImage,
|
||||
Import3dRotatePreviewModel
|
||||
Import3dRotatePreviewModel,
|
||||
Import3dAddPreviewModel,
|
||||
Import3dSetCurrentPreviewModel
|
||||
};
|
||||
|
||||
constexpr bool isNanotraceEnabled()
|
||||
|
@@ -239,20 +239,18 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
||||
|
||||
connect(ui->advancedSettingsButton, &QPushButton::clicked,
|
||||
this, &ItemLibraryAssetImportDialog::toggleAdvanced);
|
||||
connect(ui->importList, &QListWidget::currentRowChanged,
|
||||
this, &ItemLibraryAssetImportDialog::onCurrentRowChanged);
|
||||
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::updateUi);
|
||||
|
||||
if (m_quick3DFiles.size() != 1) {
|
||||
addInfo(tr("Select import options and press \"Import\" to import the following files:"));
|
||||
} else {
|
||||
addInfo(tr("Importing:"));
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
|
||||
}
|
||||
addInfo(tr("Importing:"));
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
|
||||
|
||||
for (const auto &file : std::as_const(m_quick3DFiles))
|
||||
addInfo(file);
|
||||
|
||||
updateImportButtonState();
|
||||
m_updatingControlStates = false;
|
||||
}
|
||||
|
||||
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
|
||||
@@ -501,7 +499,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
QJsonValue value(optCheck->isChecked());
|
||||
optObj.insert("value", value);
|
||||
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
});
|
||||
} else {
|
||||
// Simple options also exist in advanced, so don't connect simple controls directly
|
||||
@@ -512,13 +510,13 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
QObject::connect(optCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
|
||||
if (advCheck->isChecked() != optCheck->isChecked()) {
|
||||
advCheck->setChecked(optCheck->isChecked());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
QObject::connect(advCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
|
||||
if (advCheck->isChecked() != optCheck->isChecked()) {
|
||||
optCheck->setChecked(advCheck->isChecked());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -555,7 +553,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
QJsonValue value(optSpin->value());
|
||||
optObj.insert("value", value);
|
||||
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
});
|
||||
} else {
|
||||
auto *advSpin = qobject_cast<QDoubleSpinBox *>(
|
||||
@@ -566,14 +564,14 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
|
||||
this, [this, optSpin, advSpin] {
|
||||
if (advSpin->value() != optSpin->value()) {
|
||||
advSpin->setValue(optSpin->value());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
QObject::connect(advSpin, &QDoubleSpinBox::valueChanged,
|
||||
this, [this, optSpin, advSpin] {
|
||||
if (advSpin->value() != optSpin->value()) {
|
||||
optSpin->setValue(advSpin->value());
|
||||
updateImportButtonState();
|
||||
updatePreviewOptions();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -859,6 +857,15 @@ bool ItemLibraryAssetImportDialog::isHiddenOption(const QString &id)
|
||||
return hiddenOptions.contains(id);
|
||||
}
|
||||
|
||||
bool ItemLibraryAssetImportDialog::optionsChanged()
|
||||
{
|
||||
for (const ItemLibraryAssetImporter::PreviewData &data : std::as_const(m_previewData)) {
|
||||
if (data.renderedOptions != data.currentOptions)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::startPreview()
|
||||
{
|
||||
cleanupPreviewPuppet();
|
||||
@@ -877,7 +884,7 @@ Rectangle {
|
||||
property alias sceneNode: sceneNode
|
||||
property alias view3d: view3d
|
||||
property string extents
|
||||
property string sceneModelName: "%3"
|
||||
property string sceneModelName
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 1.0; color: "#222222" }
|
||||
@@ -925,7 +932,7 @@ Rectangle {
|
||||
)";
|
||||
|
||||
QSize size = canvas()->size();
|
||||
previewQml = previewQml.arg(size.width()).arg(size.height()).arg(m_previewCompName);
|
||||
previewQml = previewQml.arg(size.width()).arg(size.height());
|
||||
|
||||
m_previewFile.writeFileContents(previewQml.toUtf8());
|
||||
|
||||
@@ -998,6 +1005,31 @@ Import3dCanvas *ItemLibraryAssetImportDialog::canvas()
|
||||
return ui->import3dcanvas;
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::resetOptionControls()
|
||||
{
|
||||
const QString currentName = ui->importList->currentItem()->text();
|
||||
if (!m_previewData.contains(currentName))
|
||||
return;
|
||||
|
||||
m_updatingControlStates = true;
|
||||
|
||||
const ItemLibraryAssetImporter::PreviewData &data = m_previewData[currentName];
|
||||
const QJsonObject options = data.currentOptions;
|
||||
const QStringList optKeys = options.keys();
|
||||
for (const QString &optKey : optKeys) {
|
||||
QWidget *w = m_labelToControlWidgetMaps[data.optionsIndex].value(optKey);
|
||||
const QJsonObject optObj = options.value(optKey).toObject();
|
||||
const QJsonValue optValue = optObj.value("value");
|
||||
if (auto *cb = qobject_cast<QCheckBox *>(w))
|
||||
cb->setChecked(optValue.toBool());
|
||||
else if (auto *spin = qobject_cast<QDoubleSpinBox *>(w))
|
||||
spin->setValue(optValue.toDouble());
|
||||
}
|
||||
|
||||
m_updatingControlStates = false;
|
||||
updatePreviewOptions();
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
m_dialogHeight = event->size().height();
|
||||
@@ -1010,9 +1042,20 @@ void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
|
||||
ui->closeButton->setText(importing ? tr("Cancel") : tr("Close"));
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::updateImportButtonState()
|
||||
void ItemLibraryAssetImportDialog::updatePreviewOptions()
|
||||
{
|
||||
ui->importButton->setText(m_previewOptions == m_importOptions ? tr("Accept") : tr("Import"));
|
||||
if (m_updatingControlStates)
|
||||
return;
|
||||
|
||||
if (ui->importList->currentRow() >= 0) {
|
||||
const QString assetName = ui->importList->currentItem()->text();
|
||||
if (m_previewData.contains(assetName)) {
|
||||
ItemLibraryAssetImporter::PreviewData &data = m_previewData[assetName];
|
||||
data.currentOptions = m_importOptions[data.optionsIndex];
|
||||
}
|
||||
}
|
||||
|
||||
ui->importButton->setText(optionsChanged() ? tr("Import") : tr("Accept"));
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::addError(const QString &error, const QString &srcPath)
|
||||
@@ -1035,8 +1078,12 @@ void ItemLibraryAssetImportDialog::addInfo(const QString &info, const QString &s
|
||||
void ItemLibraryAssetImportDialog::onImport()
|
||||
{
|
||||
ui->importButton->setEnabled(false);
|
||||
ui->tabWidget->setEnabled(false);
|
||||
|
||||
if (!m_previewCompName.isEmpty() && m_previewOptions == m_importOptions) {
|
||||
const ItemLibraryAssetImporter::PreviewData &data
|
||||
= m_previewData.value(ui->importList->currentIndex().data().toString());
|
||||
|
||||
if (!data.name.isEmpty() && !optionsChanged()) {
|
||||
cleanupPreviewPuppet();
|
||||
m_importer.finalizeQuick3DImport();
|
||||
return;
|
||||
@@ -1046,8 +1093,13 @@ void ItemLibraryAssetImportDialog::onImport()
|
||||
ui->progressBar->setValue(0);
|
||||
|
||||
if (!m_quick3DFiles.isEmpty()) {
|
||||
if (!m_previewCompName.isEmpty()) {
|
||||
m_importer.reImportQuick3D(m_previewCompName, m_importOptions);
|
||||
if (!m_previewData.isEmpty()) {
|
||||
QHash<QString , QJsonObject> importOptions;
|
||||
for (const ItemLibraryAssetImporter::PreviewData &data : std::as_const(m_previewData)) {
|
||||
if (data.renderedOptions != data.currentOptions)
|
||||
importOptions.insert(data.name, data.currentOptions);
|
||||
}
|
||||
m_importer.reImportQuick3D(importOptions);
|
||||
} else {
|
||||
m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
|
||||
m_importOptions, m_extToImportOptionsMap,
|
||||
@@ -1066,19 +1118,50 @@ void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &t
|
||||
ui->progressBar->setValue(value);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onImportReadyForPreview(const QString &path, const QString &compName)
|
||||
void ItemLibraryAssetImportDialog::onImportReadyForPreview(
|
||||
const QString &path, const QList<ItemLibraryAssetImporter::PreviewData> &previewData)
|
||||
{
|
||||
addInfo(tr("Import is ready for preview."));
|
||||
if (m_previewCompName.isEmpty())
|
||||
addInfo(tr("Click \"Accept\" to finish the import or adjust options and click \"Import\" to import again."));
|
||||
QStringList assetNames;
|
||||
for (const ItemLibraryAssetImporter::PreviewData &data : previewData) {
|
||||
m_previewData[data.name] = data;
|
||||
assetNames.append(data.name);
|
||||
|
||||
m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
|
||||
m_previewCompName = compName;
|
||||
m_previewOptions = m_importOptions;
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
|
||||
auto items = ui->importList->findItems(data.name, Qt::MatchExactly);
|
||||
if (items.isEmpty())
|
||||
ui->importList->addItem(data.name);
|
||||
|
||||
addInfo(tr("Import ready for preview: %1").arg(data.name));
|
||||
}
|
||||
|
||||
if (m_firstImport) {
|
||||
addInfo(tr("Click \"Accept\" to finish the import or adjust options and click \"Import\" to import again."));
|
||||
m_firstImport = false;
|
||||
}
|
||||
|
||||
if (m_previewFile.isEmpty()) {
|
||||
m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
|
||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
|
||||
}
|
||||
|
||||
QTimer::singleShot(0, this, [this, assetNames]() {
|
||||
if (!m_nodeInstanceView)
|
||||
return;
|
||||
for (const QString &assetName : std::as_const(assetNames)) {
|
||||
const ItemLibraryAssetImporter::PreviewData &data = m_previewData.value(assetName);
|
||||
if (!data.name.isEmpty()) {
|
||||
QVariantHash msgData;
|
||||
msgData.insert("name", data.name);
|
||||
msgData.insert("folder", data.folderName);
|
||||
m_nodeInstanceView->view3DAction(View3DActionType::Import3dAddPreviewModel, msgData);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui->importButton->setEnabled(true);
|
||||
updateImportButtonState();
|
||||
ui->tabWidget->setEnabled(true);
|
||||
updatePreviewOptions();
|
||||
if (ui->importList->currentRow() < 0)
|
||||
ui->importList->setCurrentRow(0);
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onRequestImageUpdate()
|
||||
@@ -1119,6 +1202,27 @@ void ItemLibraryAssetImportDialog::onImportFinished()
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onCurrentRowChanged(int)
|
||||
{
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
if (!m_nodeInstanceView)
|
||||
return;
|
||||
int row = ui->importList->currentRow();
|
||||
QString compName;
|
||||
if (row >= 0)
|
||||
compName = ui->importList->item(row)->text();
|
||||
m_nodeInstanceView->view3DAction(View3DActionType::Import3dSetCurrentPreviewModel, compName);
|
||||
resetOptionControls();
|
||||
|
||||
if (m_previewData.contains(compName)) {
|
||||
const ItemLibraryAssetImporter::PreviewData data = m_previewData[compName];
|
||||
for (int i = 0; i < ui->tabWidget->count(); ++i)
|
||||
ui->tabWidget->widget(i)->setVisible(i == data.optionsIndex);
|
||||
ui->tabWidget->setCurrentIndex(data.optionsIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImportDialog::onClose()
|
||||
{
|
||||
ui->importButton->setEnabled(false);
|
||||
|
@@ -63,15 +63,17 @@ private slots:
|
||||
|
||||
private:
|
||||
void setCloseButtonState(bool importing);
|
||||
void updateImportButtonState();
|
||||
void updatePreviewOptions();
|
||||
|
||||
void onImport();
|
||||
void setImportProgress(int value, const QString &text);
|
||||
void onImportReadyForPreview(const QString &path, const QString &compName);
|
||||
void onImportReadyForPreview(const QString &path,
|
||||
const QList<ItemLibraryAssetImporter::PreviewData> &previewData);
|
||||
void onRequestImageUpdate();
|
||||
void onRequestRotation(const QPointF &delta);
|
||||
void onImportNearlyFinished();
|
||||
void onImportFinished();
|
||||
void onCurrentRowChanged(int row);
|
||||
void onClose();
|
||||
void doClose();
|
||||
void toggleAdvanced();
|
||||
@@ -84,10 +86,12 @@ private:
|
||||
bool isSimpleGroup(const QString &id);
|
||||
bool isSimpleOption(const QString &id);
|
||||
bool isHiddenOption(const QString &id);
|
||||
bool optionsChanged();
|
||||
|
||||
void startPreview();
|
||||
void cleanupPreviewPuppet();
|
||||
Import3dCanvas *canvas();
|
||||
void resetOptionControls();
|
||||
|
||||
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
|
||||
Utils::OutputFormatter *m_outputFormatter = nullptr;
|
||||
@@ -96,8 +100,9 @@ private:
|
||||
QPointer<RewriterView> m_rewriterView;
|
||||
QPointer<AbstractView> m_view;
|
||||
ModelPointer m_model;
|
||||
|
||||
QMap<QString, ItemLibraryAssetImporter::PreviewData> m_previewData;
|
||||
Utils::FilePath m_previewFile;
|
||||
QString m_previewCompName;
|
||||
|
||||
struct OptionsData
|
||||
{
|
||||
@@ -110,7 +115,6 @@ private:
|
||||
QString m_quick3DImportPath;
|
||||
ItemLibraryAssetImporter m_importer;
|
||||
QVector<QJsonObject> m_importOptions;
|
||||
QVector<QJsonObject> m_previewOptions;
|
||||
QHash<QString, int> m_extToImportOptionsMap;
|
||||
QSet<QString> m_preselectedFilesForOverwrite;
|
||||
bool m_closeOnFinish = true;
|
||||
@@ -120,5 +124,7 @@ private:
|
||||
bool m_advancedMode = false;
|
||||
int m_dialogHeight = 350;
|
||||
bool m_explicitClose = false;
|
||||
bool m_updatingControlStates = true;
|
||||
bool m_firstImport = true;
|
||||
};
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1100</width>
|
||||
<width>1280</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -14,6 +14,42 @@
|
||||
<string>Asset Import</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="listLabel">
|
||||
<property name="text">
|
||||
<string>Imported objects</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="importList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
|
@@ -91,50 +91,60 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryAssetImporter::reImportQuick3D(const QString &assetName,
|
||||
const QVector<QJsonObject> &options)
|
||||
void ItemLibraryAssetImporter::reImportQuick3D(const QHash<QString, QJsonObject> &importOptions)
|
||||
{
|
||||
if (!assetName.isEmpty() && !m_parseData.contains(assetName)) {
|
||||
addError(tr("Attempted to reimport non-existing asset: %1").arg(assetName));
|
||||
return;
|
||||
}
|
||||
|
||||
ParseData &pd = m_parseData[assetName];
|
||||
// Change outDir just in case reimport generates different files
|
||||
QDir oldDir = pd.outDir;
|
||||
QString assetFolder = generateAssetFolderName(pd.assetName);
|
||||
pd.outDir.cdUp();
|
||||
pd.outDir.mkpath(assetFolder);
|
||||
|
||||
if (!pd.outDir.cd(assetFolder)) {
|
||||
addError(tr("Could not access temporary asset directory: \"%1\".")
|
||||
.arg(pd.outDir.filePath(assetFolder)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldDir.absolutePath().contains(tempDirNameBase()))
|
||||
oldDir.removeRecursively();
|
||||
|
||||
m_isImporting = false;
|
||||
m_cancelled = false;
|
||||
|
||||
int importId = 1;
|
||||
|
||||
m_puppetProcess.reset();
|
||||
m_requiredImports.clear();
|
||||
m_currentImportId = 0;
|
||||
m_puppetQueue.clear();
|
||||
|
||||
for (ParseData &pd : m_parseData)
|
||||
pd.importId = -1;
|
||||
|
||||
pd.options = options[pd.optionsIndex];
|
||||
pd.importId = 1;
|
||||
|
||||
m_importFiles.remove(assetName);
|
||||
|
||||
m_importIdToAssetNameMap.clear();
|
||||
m_importIdToAssetNameMap[pd.importId] = assetName;
|
||||
|
||||
m_puppetQueue.append(pd.importId);
|
||||
if (importOptions.isEmpty()) {
|
||||
addError(tr("Attempted to reimport no assets."));
|
||||
cancelImport();
|
||||
return;
|
||||
}
|
||||
|
||||
const QStringList keys = importOptions.keys();
|
||||
for (const QString &key : keys) {
|
||||
if (!key.isEmpty() && !m_parseData.contains(key)) {
|
||||
addError(tr("Attempted to reimport non-existing asset: %1").arg(key));
|
||||
cancelImport();
|
||||
return;
|
||||
}
|
||||
|
||||
ParseData &pd = m_parseData[key];
|
||||
// Change outDir just in case reimport generates different files
|
||||
QDir oldDir = pd.outDir;
|
||||
QString assetFolder = generateAssetFolderName(pd.assetName);
|
||||
pd.outDir.cdUp();
|
||||
pd.outDir.mkpath(assetFolder);
|
||||
|
||||
if (!pd.outDir.cd(assetFolder)) {
|
||||
addError(tr("Could not access temporary asset directory: \"%1\".")
|
||||
.arg(pd.outDir.filePath(assetFolder)));
|
||||
cancelImport();
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldDir.absolutePath().contains(tempDirNameBase()))
|
||||
oldDir.removeRecursively();
|
||||
|
||||
for (ParseData &pd : m_parseData)
|
||||
pd.importId = -1;
|
||||
|
||||
pd.options = importOptions[key];
|
||||
pd.importId = importId++;
|
||||
|
||||
m_importFiles.remove(key);
|
||||
m_importIdToAssetNameMap[pd.importId] = key;
|
||||
|
||||
m_puppetQueue.append(pd.importId);
|
||||
}
|
||||
startNextImportProcess();
|
||||
}
|
||||
|
||||
@@ -386,10 +396,11 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
|
||||
qmlInfo.append(".");
|
||||
qmlInfo.append(pd.assetName);
|
||||
qmlInfo.append('\n');
|
||||
m_requiredImports.append(
|
||||
QStringLiteral("%1.%2").arg(QmlDesignerPlugin::instance()->documentManager()
|
||||
.generatedComponentUtils().import3dTypePrefix(),
|
||||
pd.assetName));
|
||||
const QString reqImp = QStringLiteral("%1.%2").arg(
|
||||
QmlDesignerPlugin::instance()->documentManager()
|
||||
.generatedComponentUtils().import3dTypePrefix(), pd.assetName);
|
||||
if (!m_requiredImports.contains(reqImp))
|
||||
m_requiredImports.append(reqImp);
|
||||
while (qmlIt.hasNext()) {
|
||||
qmlIt.next();
|
||||
QFileInfo fi = QFileInfo(qmlIt.filePath());
|
||||
@@ -633,14 +644,18 @@ void ItemLibraryAssetImporter::postImport()
|
||||
}
|
||||
|
||||
if (!isCancelled()) {
|
||||
// TODO: Currently we only support import preview for single imports
|
||||
if (m_parseData.size() != 1) {
|
||||
finalizeQuick3DImport();
|
||||
} else {
|
||||
const ParseData &pd = m_parseData[m_parseData.keys().first()];
|
||||
const QString importedComponentName = pd.assetName;
|
||||
emit importReadyForPreview(pd.outDir.absolutePath(), importedComponentName);
|
||||
QList<PreviewData> dataList;
|
||||
for (const QString &assetName : std::as_const(m_importIdToAssetNameMap)) {
|
||||
const ParseData &pd = m_parseData[assetName];
|
||||
PreviewData data;
|
||||
data.name = pd.assetName;
|
||||
data.folderName = pd.outDir.dirName();
|
||||
data.renderedOptions = pd.options;
|
||||
data.currentOptions = pd.options;
|
||||
data.optionsIndex = pd.optionsIndex;
|
||||
dataList.append(data);
|
||||
}
|
||||
emit importReadyForPreview(m_tempDir->path(), dataList);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,7 @@ public:
|
||||
const QHash<QString, int> &extToImportOptionsMap,
|
||||
const QSet<QString> &preselectedFilesForOverwrite);
|
||||
|
||||
void reImportQuick3D(const QString &assetName, const QVector<QJsonObject> &options);
|
||||
void reImportQuick3D(const QHash<QString, QJsonObject> &importOptions);
|
||||
|
||||
bool isImporting() const;
|
||||
void cancelImport();
|
||||
@@ -48,12 +48,21 @@ public:
|
||||
|
||||
void finalizeQuick3DImport();
|
||||
|
||||
struct PreviewData
|
||||
{
|
||||
int optionsIndex = 0;
|
||||
QJsonObject renderedOptions;
|
||||
QJsonObject currentOptions;
|
||||
QString name;
|
||||
QString folderName;
|
||||
};
|
||||
|
||||
signals:
|
||||
void errorReported(const QString &, const QString &);
|
||||
void warningReported(const QString &, const QString &);
|
||||
void infoReported(const QString &, const QString &);
|
||||
void progressChanged(int value, const QString &text);
|
||||
void importReadyForPreview(const QString &path, const QString &compName);
|
||||
void importReadyForPreview(const QString &path, const QList<PreviewData> &previewData);
|
||||
void importNearlyFinished();
|
||||
void importFinished();
|
||||
|
||||
|
@@ -17,9 +17,12 @@
|
||||
|
||||
#include <QQmlProperty>
|
||||
|
||||
#include <private/qquickdesignersupport_p.h>
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
#include <private/qquick3dnode_p.h>
|
||||
#include <private/qquick3dviewport_p.h>
|
||||
#include <private/qquickdesignersupport_p.h>
|
||||
#endif
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
@@ -48,11 +51,24 @@ void Qt5Import3dNodeInstanceServer::createScene(const CreateSceneCommand &comman
|
||||
registerFonts(command.resourceUrl);
|
||||
setTranslationLanguage(command.language);
|
||||
setupScene(command);
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
QObject *obj = rootItem();
|
||||
QQmlProperty viewProp(obj, "view3d", context());
|
||||
QObject *viewObj = viewProp.read().value<QObject *>();
|
||||
m_view3D = qobject_cast<QQuick3DViewport *>(viewObj);
|
||||
if (m_view3D) {
|
||||
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
|
||||
m_sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
|
||||
}
|
||||
#endif
|
||||
|
||||
startRenderTimer();
|
||||
}
|
||||
|
||||
void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DActionCommand &command)
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
switch (command.type()) {
|
||||
case View3DActionType::Import3dUpdatePreviewImage: {
|
||||
QObject *obj = rootItem();
|
||||
@@ -63,7 +79,6 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
||||
wProp.write(size.width());
|
||||
hProp.write(size.height());
|
||||
resizeCanvasToRootItem();
|
||||
|
||||
startRenderTimer();
|
||||
}
|
||||
break;
|
||||
@@ -72,18 +87,72 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
||||
QObject *obj = rootItem();
|
||||
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
|
||||
auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
|
||||
if (sceneNode) {
|
||||
if (sceneNode && m_previewData.contains(m_currentNode)) {
|
||||
const PreviewData &data = m_previewData[m_currentNode];
|
||||
QPointF delta = command.value().toPointF();
|
||||
m_generalHelper->orbitCamera(m_view3D->camera(), m_view3D->camera()->eulerRotation(),
|
||||
m_lookAt, {}, {float(delta.x()), float(delta.y()), 0.f});
|
||||
data.lookAt, {}, {float(delta.x()), float(delta.y()), 0.f});
|
||||
m_keepRendering = true;
|
||||
startRenderTimer();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case View3DActionType::Import3dAddPreviewModel: {
|
||||
const QVariantHash cmd = command.value().toHash();
|
||||
const QString name = cmd["name"].toString();
|
||||
const QString folder = cmd["folder"].toString();
|
||||
|
||||
if (m_previewData.contains(name)) {
|
||||
QQuick3DNode *node = m_previewData[name].node;
|
||||
if (node) {
|
||||
node->setParentItem({});
|
||||
node->setParent({});
|
||||
node->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
PreviewData &data = m_previewData[name];
|
||||
data.name = name;
|
||||
data.lookAt = {};
|
||||
|
||||
QFileInfo fi(fileUrl().toLocalFile());
|
||||
QString compPath = fi.absolutePath() + '/' + folder + '/' + name + ".qml";
|
||||
QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous);
|
||||
data.node = qobject_cast<QQuick3DNode *>(comp.create(context()));
|
||||
if (data.node) {
|
||||
engine()->setObjectOwnership(data.node, QJSEngine::CppOwnership);
|
||||
data.node->setParentItem(m_sceneNode);
|
||||
data.node->setParent(m_sceneNode);
|
||||
}
|
||||
|
||||
if (m_currentNode == data.name) {
|
||||
m_renderCount = 0;
|
||||
startRenderTimer();
|
||||
} else if (data.node) {
|
||||
data.node->setVisible(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case View3DActionType::Import3dSetCurrentPreviewModel: {
|
||||
QString newName = command.value().toString();
|
||||
if (m_previewData.contains(newName) && m_currentNode != newName) {
|
||||
const PreviewData &newData = m_previewData[newName];
|
||||
const PreviewData oldData = m_previewData.value(m_currentNode);
|
||||
if (oldData.node)
|
||||
oldData.node->setVisible(false);
|
||||
if (newData.node)
|
||||
newData.node->setVisible(true);
|
||||
m_renderCount = 0;
|
||||
m_currentNode = newName;
|
||||
startRenderTimer();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Qt5Import3dNodeInstanceServer::startRenderTimer()
|
||||
@@ -97,16 +166,13 @@ void Qt5Import3dNodeInstanceServer::startRenderTimer()
|
||||
void Qt5Import3dNodeInstanceServer::cleanup()
|
||||
{
|
||||
#ifdef QUICK3D_MODULE
|
||||
delete m_previewNode;
|
||||
for (const PreviewData &data : std::as_const(m_previewData))
|
||||
delete data.node;
|
||||
m_previewData.clear();
|
||||
delete m_generalHelper;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Qt5Import3dNodeInstanceServer::finish()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Qt5Import3dNodeInstanceServer::collectItemChangesAndSendChangeCommands()
|
||||
{
|
||||
static bool inFunction = false;
|
||||
@@ -130,53 +196,32 @@ void Qt5Import3dNodeInstanceServer::render()
|
||||
#ifdef QUICK3D_MODULE
|
||||
++m_renderCount;
|
||||
|
||||
if (m_renderCount == 1) {
|
||||
QObject *obj = rootItem();
|
||||
QQmlProperty viewProp(obj, "view3d", context());
|
||||
QObject *viewObj = viewProp.read().value<QObject *>();
|
||||
m_view3D = qobject_cast<QQuick3DViewport *>(viewObj);
|
||||
if (m_view3D) {
|
||||
QQmlProperty sceneModelNameProp(obj, "sceneModelName", context());
|
||||
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
|
||||
auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
|
||||
if (sceneNode) {
|
||||
QString sceneModelName = sceneModelNameProp.read().toString();
|
||||
QFileInfo fi(fileUrl().toLocalFile());
|
||||
QString compPath = fi.absolutePath() + '/' + sceneModelName + ".qml";
|
||||
QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous);
|
||||
m_previewNode = qobject_cast<QQuick3DNode *>(comp.create(context()));
|
||||
if (m_previewNode) {
|
||||
engine()->setObjectOwnership(m_previewNode, QJSEngine::CppOwnership);
|
||||
m_previewNode->setParentItem(sceneNode);
|
||||
m_previewNode->setParent(sceneNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Render scene at least once before calculating bounds to ensure geometries are intialized
|
||||
if (m_renderCount == 2 && m_view3D && m_previewData.contains(m_currentNode)) {
|
||||
PreviewData &data = m_previewData[m_currentNode];
|
||||
m_generalHelper->calculateBoundsAndFocusCamera(m_view3D->camera(), data.node,
|
||||
m_view3D, 1050, false, data.lookAt,
|
||||
data.extents);
|
||||
|
||||
// Render scene once to ensure geometries are intialized so bounds calculations work correctly
|
||||
if (m_renderCount == 2 && m_view3D) {
|
||||
QVector3D extents;
|
||||
m_generalHelper->calculateBoundsAndFocusCamera(m_view3D->camera(), m_previewNode,
|
||||
m_view3D, 1050, false, m_lookAt, extents);
|
||||
auto getExtentStr = [&extents](int idx) -> QString {
|
||||
auto getExtentStr = [&data](int idx) -> QString {
|
||||
int prec = 0;
|
||||
float val = extents[idx];
|
||||
float val = data.extents[idx];
|
||||
while (val < 100.f) {
|
||||
++prec;
|
||||
val *= 10.f;
|
||||
}
|
||||
// Strip unnecessary zeroes after decimal separator
|
||||
if (prec > 0) {
|
||||
QString checkStr = QString::number(extents[idx], 'f', prec);
|
||||
QString checkStr = QString::number(data.extents[idx], 'f', prec);
|
||||
while (prec > 0 && (checkStr.last(1) == "0" || checkStr.last(1) == ".")) {
|
||||
--prec;
|
||||
checkStr.chop(1);
|
||||
}
|
||||
}
|
||||
QString retval = QLocale().toString(extents[idx], 'f', prec);
|
||||
QString retval = QLocale().toString(data.extents[idx], 'f', prec);
|
||||
return retval;
|
||||
};
|
||||
|
||||
QQmlProperty extentsProp(rootItem(), "extents", context());
|
||||
extentsProp.write(tr("Dimensions: %1 x %2 x %3").arg(getExtentStr(0))
|
||||
.arg(getExtentStr(1))
|
||||
|
@@ -3,12 +3,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "generalhelper.h"
|
||||
#include "qt5nodeinstanceserver.h"
|
||||
|
||||
#ifdef QUICK3D_MODULE
|
||||
#include "generalhelper.h"
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQuick3DNode;
|
||||
QT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
@@ -31,7 +33,6 @@ protected:
|
||||
void startRenderTimer() override;
|
||||
|
||||
private:
|
||||
void finish();
|
||||
void cleanup();
|
||||
|
||||
int m_renderCount = 0;
|
||||
@@ -40,8 +41,17 @@ private:
|
||||
#ifdef QUICK3D_MODULE
|
||||
QQuick3DViewport *m_view3D = nullptr;
|
||||
Internal::GeneralHelper *m_generalHelper = nullptr;
|
||||
QQuick3DNode *m_previewNode = nullptr;
|
||||
QVector3D m_lookAt;
|
||||
|
||||
struct PreviewData
|
||||
{
|
||||
QString name;
|
||||
QVector3D lookAt;
|
||||
QVector3D extents;
|
||||
QQuick3DNode *node = {};
|
||||
};
|
||||
QHash<QString, PreviewData> m_previewData;
|
||||
QString m_currentNode;
|
||||
QQuick3DNode *m_sceneNode = {};
|
||||
#endif
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user