forked from qt-creator/qt-creator
QmlDesigner: Show more information on import 3D dialog list
Preview image and some additional info are now shown on 3D import dialog's list of imported objects. Individual items can be removed from the list by clicking "x" button on the list or pressing delete key. Fixes: QDS-12900 Change-Id: Iad366ea308203a25bc3379b47c1d9c4f75f13fa7 Reviewed-by: Ali Kianian <ali.kianian@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -18,6 +18,7 @@ public:
|
|||||||
ActiveSceneChanged,
|
ActiveSceneChanged,
|
||||||
ActiveSplitChanged,
|
ActiveSplitChanged,
|
||||||
RenderModelNodePreviewImage,
|
RenderModelNodePreviewImage,
|
||||||
|
Import3DPreviewIcon,
|
||||||
Import3DPreviewImage,
|
Import3DPreviewImage,
|
||||||
Import3DSupport,
|
Import3DSupport,
|
||||||
NodeAtPos,
|
NodeAtPos,
|
||||||
|
@@ -16,6 +16,11 @@ Import3dConnectionManager::Import3dConnectionManager()
|
|||||||
connections().emplace_back("Import 3D", "import3dmode");
|
connections().emplace_back("Import 3D", "import3dmode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Import3dConnectionManager::setPreviewIconCallback(IconCallback callback)
|
||||||
|
{
|
||||||
|
m_previewIconCallback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void Import3dConnectionManager::setPreviewImageCallback(ImageCallback callback)
|
void Import3dConnectionManager::setPreviewImageCallback(ImageCallback callback)
|
||||||
{
|
{
|
||||||
m_previewImageCallback = std::move(callback);
|
m_previewImageCallback = std::move(callback);
|
||||||
@@ -29,6 +34,15 @@ void Import3dConnectionManager::dispatchCommand(const QVariant &command,
|
|||||||
if (command.typeId() == commandType) {
|
if (command.typeId() == commandType) {
|
||||||
auto cmd = command.value<PuppetToCreatorCommand>();
|
auto cmd = command.value<PuppetToCreatorCommand>();
|
||||||
switch (cmd.type()) {
|
switch (cmd.type()) {
|
||||||
|
case PuppetToCreatorCommand::Import3DPreviewIcon: {
|
||||||
|
const QVariantList data = cmd.data().toList();
|
||||||
|
const QString assetName = data[0].toString();
|
||||||
|
ImageContainer container = qvariant_cast<ImageContainer>(data[1]);
|
||||||
|
QImage image = container.image();
|
||||||
|
if (!image.isNull())
|
||||||
|
m_previewIconCallback(assetName, image);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case PuppetToCreatorCommand::Import3DPreviewImage: {
|
case PuppetToCreatorCommand::Import3DPreviewImage: {
|
||||||
ImageContainer container = qvariant_cast<ImageContainer>(cmd.data());
|
ImageContainer container = qvariant_cast<ImageContainer>(cmd.data());
|
||||||
QImage image = container.image();
|
QImage image = container.image();
|
||||||
|
@@ -12,16 +12,19 @@ namespace QmlDesigner {
|
|||||||
class Import3dConnectionManager : public InteractiveConnectionManager
|
class Import3dConnectionManager : public InteractiveConnectionManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using IconCallback = std::function<void(const QString &, const QImage &)>;
|
||||||
using ImageCallback = std::function<void(const QImage &)>;
|
using ImageCallback = std::function<void(const QImage &)>;
|
||||||
|
|
||||||
Import3dConnectionManager();
|
Import3dConnectionManager();
|
||||||
|
|
||||||
|
void setPreviewIconCallback(IconCallback callback);
|
||||||
void setPreviewImageCallback(ImageCallback callback);
|
void setPreviewImageCallback(ImageCallback callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void dispatchCommand(const QVariant &command, Connection &connection) override;
|
void dispatchCommand(const QVariant &command, Connection &connection) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
IconCallback m_previewIconCallback;
|
||||||
ImageCallback m_previewImageCallback;
|
ImageCallback m_previewImageCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -7,6 +7,8 @@
|
|||||||
#include "import3dcanvas.h"
|
#include "import3dcanvas.h"
|
||||||
#include "import3dconnectionmanager.h"
|
#include "import3dconnectionmanager.h"
|
||||||
|
|
||||||
|
#include <designeractionmanager.h>
|
||||||
|
#include <designericons.h>
|
||||||
#include <model.h>
|
#include <model.h>
|
||||||
#include <model/modelutils.h>
|
#include <model/modelutils.h>
|
||||||
#include <nodeinstanceview.h>
|
#include <nodeinstanceview.h>
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
|
|
||||||
#include <theme.h>
|
#include <theme.h>
|
||||||
#include <utils/outputformatter.h>
|
#include <utils/outputformatter.h>
|
||||||
|
#include <utils/stylehelper.h>
|
||||||
|
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/projectmanager.h>
|
#include <projectexplorer/projectmanager.h>
|
||||||
@@ -25,7 +28,9 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QFontMetrics>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QLocale>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
@@ -63,6 +68,17 @@ void addFormattedMessage(Utils::OutputFormatter *formatter,
|
|||||||
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QIcon iconFromIconFont(Theme::Icon iconType, const QColor &color)
|
||||||
|
{
|
||||||
|
const QString unicode = Theme::getIconUnicode(iconType);
|
||||||
|
const QString fontName = "qtds_propertyIconFont.ttf";
|
||||||
|
|
||||||
|
const auto helper = Utils::StyleHelper::IconFontHelper(
|
||||||
|
unicode, color, QSize(28, 28), QIcon::Normal);
|
||||||
|
|
||||||
|
return Utils::StyleHelper::getIconFromIconFont(fontName, {helper});
|
||||||
|
}
|
||||||
|
|
||||||
const int rowHeight = 32;
|
const int rowHeight = 32;
|
||||||
const int checkBoxColWidth = 18;
|
const int checkBoxColWidth = 18;
|
||||||
const int labelMinWidth = 130;
|
const int labelMinWidth = 130;
|
||||||
@@ -88,6 +104,11 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
|||||||
setModal(true);
|
setModal(true);
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
m_selectedRemoveIcon = iconFromIconFont(Theme::Icon::delete_small,
|
||||||
|
Theme::getColor(Theme::IconsBaseColor));
|
||||||
|
m_unselectedRemoveIcon = iconFromIconFont(Theme::Icon::delete_small,
|
||||||
|
Theme::getColor(Theme::IconsDisabledColor));
|
||||||
|
|
||||||
m_outputFormatter = new Utils::OutputFormatter;
|
m_outputFormatter = new Utils::OutputFormatter;
|
||||||
m_outputFormatter->setPlainTextEdit(ui->plainTextEdit);
|
m_outputFormatter->setPlainTextEdit(ui->plainTextEdit);
|
||||||
|
|
||||||
@@ -239,8 +260,8 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
|||||||
|
|
||||||
connect(ui->advancedSettingsButton, &QPushButton::clicked,
|
connect(ui->advancedSettingsButton, &QPushButton::clicked,
|
||||||
this, &ItemLibraryAssetImportDialog::toggleAdvanced);
|
this, &ItemLibraryAssetImportDialog::toggleAdvanced);
|
||||||
connect(ui->importList, &QListWidget::currentRowChanged,
|
connect(ui->importList, &QListWidget::currentItemChanged,
|
||||||
this, &ItemLibraryAssetImportDialog::onCurrentRowChanged);
|
this, &ItemLibraryAssetImportDialog::onCurrentItemChanged);
|
||||||
|
|
||||||
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::updateUi);
|
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::updateUi);
|
||||||
|
|
||||||
@@ -383,6 +404,15 @@ void ItemLibraryAssetImportDialog::updateImport(AbstractView *view,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemLibraryAssetImportDialog::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if ((event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete)
|
||||||
|
&& ui->importList->currentItem()) {
|
||||||
|
onRemoveAsset(assetNameForListItem(ui->importList->currentItem()));
|
||||||
|
}
|
||||||
|
return QDialog::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex,
|
void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex,
|
||||||
const QJsonObject &groups)
|
const QJsonObject &groups)
|
||||||
{
|
{
|
||||||
@@ -828,6 +858,15 @@ void ItemLibraryAssetImportDialog::updateUi()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ItemLibraryAssetImportDialog::assetNameForListItem(QListWidgetItem *item)
|
||||||
|
{
|
||||||
|
for (const ImportData &data : std::as_const(m_importData)) {
|
||||||
|
if (data.listItem == item)
|
||||||
|
return data.previewData.name;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool ItemLibraryAssetImportDialog::isSimpleGroup(const QString &id)
|
bool ItemLibraryAssetImportDialog::isSimpleGroup(const QString &id)
|
||||||
{
|
{
|
||||||
static QStringList simpleGroups {
|
static QStringList simpleGroups {
|
||||||
@@ -859,8 +898,8 @@ bool ItemLibraryAssetImportDialog::isHiddenOption(const QString &id)
|
|||||||
|
|
||||||
bool ItemLibraryAssetImportDialog::optionsChanged()
|
bool ItemLibraryAssetImportDialog::optionsChanged()
|
||||||
{
|
{
|
||||||
for (const ItemLibraryAssetImporter::PreviewData &data : std::as_const(m_previewData)) {
|
for (const ImportData &data : std::as_const(m_importData)) {
|
||||||
if (data.renderedOptions != data.currentOptions)
|
if (data.previewData.renderedOptions != data.previewData.currentOptions)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -883,6 +922,7 @@ Rectangle {
|
|||||||
|
|
||||||
property alias sceneNode: sceneNode
|
property alias sceneNode: sceneNode
|
||||||
property alias view3d: view3d
|
property alias view3d: view3d
|
||||||
|
property alias iconView3d: iconView3d
|
||||||
property string extents
|
property string extents
|
||||||
property string sceneModelName
|
property string sceneModelName
|
||||||
|
|
||||||
@@ -897,30 +937,40 @@ Rectangle {
|
|||||||
camera: viewCamera
|
camera: viewCamera
|
||||||
|
|
||||||
environment: SceneEnvironment {
|
environment: SceneEnvironment {
|
||||||
|
id: sceneEnvironment
|
||||||
antialiasingMode: SceneEnvironment.MSAA
|
antialiasingMode: SceneEnvironment.MSAA
|
||||||
antialiasingQuality: SceneEnvironment.VeryHigh
|
antialiasingQuality: SceneEnvironment.VeryHigh
|
||||||
}
|
}
|
||||||
|
|
||||||
PerspectiveCamera {
|
|
||||||
id: viewCamera
|
|
||||||
x: 600
|
|
||||||
y: 600
|
|
||||||
z: 600
|
|
||||||
eulerRotation.x: -45
|
|
||||||
eulerRotation.y: -45
|
|
||||||
clipFar: 100000
|
|
||||||
clipNear: 10
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionalLight {
|
|
||||||
rotation: viewCamera.rotation
|
|
||||||
}
|
|
||||||
|
|
||||||
Node {
|
Node {
|
||||||
id: sceneNode
|
id: sceneNode
|
||||||
|
PerspectiveCamera {
|
||||||
|
id: viewCamera
|
||||||
|
x: 600
|
||||||
|
y: 600
|
||||||
|
z: 600
|
||||||
|
eulerRotation.x: -45
|
||||||
|
eulerRotation.y: -45
|
||||||
|
clipFar: 100000
|
||||||
|
clipNear: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectionalLight {
|
||||||
|
rotation: viewCamera.rotation
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
View3D {
|
||||||
|
id: iconView3d
|
||||||
|
importScene: sceneNode
|
||||||
|
camera: viewCamera
|
||||||
|
environment: sceneEnvironment
|
||||||
|
visible: false
|
||||||
|
width: 48
|
||||||
|
height: 48
|
||||||
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
@@ -966,6 +1016,15 @@ Rectangle {
|
|||||||
|
|
||||||
m_nodeInstanceView->setTarget(m_view->nodeInstanceView()->target());
|
m_nodeInstanceView->setTarget(m_view->nodeInstanceView()->target());
|
||||||
|
|
||||||
|
auto previewIconCallback = [this](const QString &assetName, const QImage &image) {
|
||||||
|
if (!m_importData.contains(assetName)) {
|
||||||
|
addWarning(tr("Preview icon generated for non-existent asset: %1").arg(assetName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_importData[assetName].iconLabel)
|
||||||
|
m_importData[assetName].iconLabel->setPixmap(QPixmap::fromImage(image));
|
||||||
|
};
|
||||||
|
|
||||||
auto previewImageCallback = [this](const QImage &image) {
|
auto previewImageCallback = [this](const QImage &image) {
|
||||||
canvas()->updateRenderImage(image);
|
canvas()->updateRenderImage(image);
|
||||||
};
|
};
|
||||||
@@ -975,6 +1034,7 @@ Rectangle {
|
|||||||
cleanupPreviewPuppet();
|
cleanupPreviewPuppet();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
m_connectionManager->setPreviewIconCallback(std::move(previewIconCallback));
|
||||||
m_connectionManager->setPreviewImageCallback(std::move(previewImageCallback));
|
m_connectionManager->setPreviewImageCallback(std::move(previewImageCallback));
|
||||||
m_nodeInstanceView->setCrashCallback(std::move(crashCallback));
|
m_nodeInstanceView->setCrashCallback(std::move(crashCallback));
|
||||||
|
|
||||||
@@ -992,8 +1052,10 @@ void ItemLibraryAssetImportDialog::cleanupPreviewPuppet()
|
|||||||
if (m_nodeInstanceView)
|
if (m_nodeInstanceView)
|
||||||
m_nodeInstanceView->setCrashCallback({});
|
m_nodeInstanceView->setCrashCallback({});
|
||||||
|
|
||||||
if (m_connectionManager)
|
if (m_connectionManager) {
|
||||||
|
m_connectionManager->setPreviewIconCallback({});
|
||||||
m_connectionManager->setPreviewImageCallback({});
|
m_connectionManager->setPreviewImageCallback({});
|
||||||
|
}
|
||||||
|
|
||||||
delete m_rewriterView;
|
delete m_rewriterView;
|
||||||
delete m_nodeInstanceView;
|
delete m_nodeInstanceView;
|
||||||
@@ -1007,17 +1069,17 @@ Import3dCanvas *ItemLibraryAssetImportDialog::canvas()
|
|||||||
|
|
||||||
void ItemLibraryAssetImportDialog::resetOptionControls()
|
void ItemLibraryAssetImportDialog::resetOptionControls()
|
||||||
{
|
{
|
||||||
const QString currentName = ui->importList->currentItem()->text();
|
const QString currentName = assetNameForListItem(ui->importList->currentItem());
|
||||||
if (!m_previewData.contains(currentName))
|
if (!m_importData.contains(currentName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_updatingControlStates = true;
|
m_updatingControlStates = true;
|
||||||
|
|
||||||
const ItemLibraryAssetImporter::PreviewData &data = m_previewData[currentName];
|
const ImportData &data = m_importData[currentName];
|
||||||
const QJsonObject options = data.currentOptions;
|
const QJsonObject options = data.previewData.currentOptions;
|
||||||
const QStringList optKeys = options.keys();
|
const QStringList optKeys = options.keys();
|
||||||
for (const QString &optKey : optKeys) {
|
for (const QString &optKey : optKeys) {
|
||||||
QWidget *w = m_labelToControlWidgetMaps[data.optionsIndex].value(optKey);
|
QWidget *w = m_labelToControlWidgetMaps[data.previewData.optionsIndex].value(optKey);
|
||||||
const QJsonObject optObj = options.value(optKey).toObject();
|
const QJsonObject optObj = options.value(optKey).toObject();
|
||||||
const QJsonValue optValue = optObj.value("value");
|
const QJsonValue optValue = optObj.value("value");
|
||||||
if (auto *cb = qobject_cast<QCheckBox *>(w))
|
if (auto *cb = qobject_cast<QCheckBox *>(w))
|
||||||
@@ -1048,10 +1110,10 @@ void ItemLibraryAssetImportDialog::updatePreviewOptions()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (ui->importList->currentRow() >= 0) {
|
if (ui->importList->currentRow() >= 0) {
|
||||||
const QString assetName = ui->importList->currentItem()->text();
|
const QString assetName = assetNameForListItem(ui->importList->currentItem());
|
||||||
if (m_previewData.contains(assetName)) {
|
if (m_importData.contains(assetName)) {
|
||||||
ItemLibraryAssetImporter::PreviewData &data = m_previewData[assetName];
|
ImportData &data = m_importData[assetName];
|
||||||
data.currentOptions = m_importOptions[data.optionsIndex];
|
data.previewData.currentOptions = m_importOptions[data.previewData.optionsIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1079,25 +1141,26 @@ void ItemLibraryAssetImportDialog::onImport()
|
|||||||
{
|
{
|
||||||
ui->importButton->setEnabled(false);
|
ui->importButton->setEnabled(false);
|
||||||
ui->tabWidget->setEnabled(false);
|
ui->tabWidget->setEnabled(false);
|
||||||
|
ui->importList->setEnabled(false);
|
||||||
|
|
||||||
const ItemLibraryAssetImporter::PreviewData &data
|
if (!m_importData.isEmpty() && !optionsChanged()) {
|
||||||
= m_previewData.value(ui->importList->currentIndex().data().toString());
|
|
||||||
|
|
||||||
if (!data.name.isEmpty() && !optionsChanged()) {
|
|
||||||
cleanupPreviewPuppet();
|
cleanupPreviewPuppet();
|
||||||
m_importer.finalizeQuick3DImport();
|
m_importer.finalizeQuick3DImport();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString assetName = assetNameForListItem(ui->importList->currentItem());
|
||||||
|
const ImportData &data = m_importData.value(assetName);
|
||||||
|
|
||||||
setCloseButtonState(true);
|
setCloseButtonState(true);
|
||||||
ui->progressBar->setValue(0);
|
ui->progressBar->setValue(0);
|
||||||
|
|
||||||
if (!m_quick3DFiles.isEmpty()) {
|
if (!m_quick3DFiles.isEmpty()) {
|
||||||
if (!m_previewData.isEmpty()) {
|
if (!m_importData.isEmpty()) {
|
||||||
QHash<QString , QJsonObject> importOptions;
|
QHash<QString , QJsonObject> importOptions;
|
||||||
for (const ItemLibraryAssetImporter::PreviewData &data : std::as_const(m_previewData)) {
|
for (const ImportData &data : std::as_const(m_importData)) {
|
||||||
if (data.renderedOptions != data.currentOptions)
|
if (data.previewData.renderedOptions != data.previewData.currentOptions)
|
||||||
importOptions.insert(data.name, data.currentOptions);
|
importOptions.insert(data.previewData.name, data.previewData.currentOptions);
|
||||||
}
|
}
|
||||||
m_importer.reImportQuick3D(importOptions);
|
m_importer.reImportQuick3D(importOptions);
|
||||||
} else {
|
} else {
|
||||||
@@ -1121,16 +1184,79 @@ void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &t
|
|||||||
void ItemLibraryAssetImportDialog::onImportReadyForPreview(
|
void ItemLibraryAssetImportDialog::onImportReadyForPreview(
|
||||||
const QString &path, const QList<ItemLibraryAssetImporter::PreviewData> &previewData)
|
const QString &path, const QList<ItemLibraryAssetImporter::PreviewData> &previewData)
|
||||||
{
|
{
|
||||||
|
if (previewData.isEmpty()) {
|
||||||
|
m_importer.cancelImport();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap placeHolder = QPixmap(":/navigator/icon/tooltip_placeholder.png").scaled(48, 48);
|
||||||
|
|
||||||
|
int maxNameLen = 150;
|
||||||
|
|
||||||
QStringList assetNames;
|
QStringList assetNames;
|
||||||
for (const ItemLibraryAssetImporter::PreviewData &data : previewData) {
|
for (const ItemLibraryAssetImporter::PreviewData &data : previewData) {
|
||||||
m_previewData[data.name] = data;
|
const QString assetName = data.name;
|
||||||
assetNames.append(data.name);
|
assetNames.append(assetName);
|
||||||
|
if (!m_importData.contains(assetName)) {
|
||||||
|
ImportData impData;
|
||||||
|
impData.previewData = data;
|
||||||
|
auto lwi = new QListWidgetItem();
|
||||||
|
impData.listItem = lwi;
|
||||||
|
auto w = new QWidget(ui->importList);
|
||||||
|
w->setToolTip(assetName);
|
||||||
|
auto layout = new QHBoxLayout(w);
|
||||||
|
auto iconLabel = new QLabel(w);
|
||||||
|
iconLabel->setPixmap(placeHolder);
|
||||||
|
impData.iconLabel = iconLabel;
|
||||||
|
layout->addWidget(iconLabel);
|
||||||
|
auto infoLabel = new QLabel(w);
|
||||||
|
infoLabel->setFixedWidth(maxNameLen);
|
||||||
|
impData.infoLabel = infoLabel;
|
||||||
|
layout->addWidget(infoLabel);
|
||||||
|
layout->addStretch(1);
|
||||||
|
auto removeButton = new QPushButton(m_unselectedRemoveIcon, {}, w);
|
||||||
|
removeButton->setFlat(true);
|
||||||
|
impData.removeButton = removeButton;
|
||||||
|
layout->addWidget(removeButton, 0, Qt::AlignRight);
|
||||||
|
layout->setSizeConstraint(QLayout::SetNoConstraint);
|
||||||
|
w->setLayout(layout);
|
||||||
|
w->resize(w->height(), ui->importList->width());
|
||||||
|
lwi->setSizeHint(w->sizeHint());
|
||||||
|
ui->importList->addItem(lwi);
|
||||||
|
ui->importList->setItemWidget(lwi, w);
|
||||||
|
m_importData[assetName] = impData;
|
||||||
|
QObject::connect(removeButton, &QPushButton::clicked, this, [this, assetName]() {
|
||||||
|
onRemoveAsset(assetName);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
m_importData[assetName].previewData = data;
|
||||||
|
}
|
||||||
|
|
||||||
auto items = ui->importList->findItems(data.name, Qt::MatchExactly);
|
if (!m_importData.contains(assetName))
|
||||||
if (items.isEmpty())
|
return;
|
||||||
ui->importList->addItem(data.name);
|
|
||||||
|
|
||||||
addInfo(tr("Import ready for preview: %1").arg(data.name));
|
const ImportData &impData = m_importData[assetName];
|
||||||
|
|
||||||
|
if (QLabel *l = impData.infoLabel) {
|
||||||
|
QFontMetrics fm = l->fontMetrics();
|
||||||
|
QString truncNameBase = assetName;
|
||||||
|
QString truncName = assetName;
|
||||||
|
int truncNameLen = fm.boundingRect(truncName).width();
|
||||||
|
while (!truncNameBase.isEmpty() && truncNameLen > maxNameLen) {
|
||||||
|
truncNameBase.chop(1);
|
||||||
|
truncName = truncNameBase + "...";
|
||||||
|
truncNameLen = fm.boundingRect(truncName).width();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString s;
|
||||||
|
s += truncName + '\n';
|
||||||
|
s += tr("Object Type: %1\n").arg(data.type);
|
||||||
|
s += tr("Imported Size: %1").arg(QLocale::system().formattedDataSize(
|
||||||
|
data.size, 2, QLocale::DataSizeTraditionalFormat));
|
||||||
|
l->setText(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
addInfo(tr("Import ready for preview: %1").arg(assetName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_firstImport) {
|
if (m_firstImport) {
|
||||||
@@ -1147,11 +1273,11 @@ void ItemLibraryAssetImportDialog::onImportReadyForPreview(
|
|||||||
if (!m_nodeInstanceView)
|
if (!m_nodeInstanceView)
|
||||||
return;
|
return;
|
||||||
for (const QString &assetName : std::as_const(assetNames)) {
|
for (const QString &assetName : std::as_const(assetNames)) {
|
||||||
const ItemLibraryAssetImporter::PreviewData &data = m_previewData.value(assetName);
|
const ImportData &data = m_importData.value(assetName);
|
||||||
if (!data.name.isEmpty()) {
|
if (!data.previewData.name.isEmpty()) {
|
||||||
QVariantHash msgData;
|
QVariantHash msgData;
|
||||||
msgData.insert("name", data.name);
|
msgData.insert("name", data.previewData.name);
|
||||||
msgData.insert("folder", data.folderName);
|
msgData.insert("folder", data.previewData.folderName);
|
||||||
m_nodeInstanceView->view3DAction(View3DActionType::Import3dAddPreviewModel, msgData);
|
m_nodeInstanceView->view3DAction(View3DActionType::Import3dAddPreviewModel, msgData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1159,6 +1285,7 @@ void ItemLibraryAssetImportDialog::onImportReadyForPreview(
|
|||||||
|
|
||||||
ui->importButton->setEnabled(true);
|
ui->importButton->setEnabled(true);
|
||||||
ui->tabWidget->setEnabled(true);
|
ui->tabWidget->setEnabled(true);
|
||||||
|
ui->importList->setEnabled(true);
|
||||||
updatePreviewOptions();
|
updatePreviewOptions();
|
||||||
if (ui->importList->currentRow() < 0)
|
if (ui->importList->currentRow() < 0)
|
||||||
ui->importList->setCurrentRow(0);
|
ui->importList->setCurrentRow(0);
|
||||||
@@ -1202,23 +1329,33 @@ void ItemLibraryAssetImportDialog::onImportFinished()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::onCurrentRowChanged(int)
|
void ItemLibraryAssetImportDialog::onCurrentItemChanged(QListWidgetItem *current, QListWidgetItem *)
|
||||||
{
|
{
|
||||||
QTimer::singleShot(0, this, [this]() {
|
if (!current)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const ImportData &data : std::as_const(m_importData)) {
|
||||||
|
if (data.removeButton) {
|
||||||
|
if (current == data.listItem)
|
||||||
|
data.removeButton->setIcon(m_selectedRemoveIcon);
|
||||||
|
else
|
||||||
|
data.removeButton->setIcon(m_unselectedRemoveIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const QString assetName = assetNameForListItem(ui->importList->currentItem());
|
||||||
|
resetOptionControls();
|
||||||
|
|
||||||
|
const ImportData data = m_importData.value(assetName);
|
||||||
|
for (int i = 0; i < ui->tabWidget->count(); ++i)
|
||||||
|
ui->tabWidget->widget(i)->setVisible(i == data.previewData.optionsIndex);
|
||||||
|
ui->tabWidget->setCurrentIndex(data.previewData.optionsIndex);
|
||||||
|
|
||||||
|
QTimer::singleShot(0, this, [this, assetName]() {
|
||||||
if (!m_nodeInstanceView)
|
if (!m_nodeInstanceView)
|
||||||
return;
|
return;
|
||||||
int row = ui->importList->currentRow();
|
if (m_importData.contains(assetName)) {
|
||||||
QString compName;
|
m_nodeInstanceView->view3DAction(View3DActionType::Import3dSetCurrentPreviewModel,
|
||||||
if (row >= 0)
|
assetName);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1268,4 +1405,20 @@ void ItemLibraryAssetImportDialog::toggleAdvanced()
|
|||||||
updateUi();
|
updateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemLibraryAssetImportDialog::onRemoveAsset(const QString &assetName)
|
||||||
|
{
|
||||||
|
m_importer.removeAssetFromImport(assetName);
|
||||||
|
if (m_importData.contains(assetName)) {
|
||||||
|
ImportData data = m_importData.take(assetName);
|
||||||
|
addInfo(tr("Removed %1 from the import.").arg(assetName));
|
||||||
|
if (data.listItem) {
|
||||||
|
ui->importList->removeItemWidget(data.listItem);
|
||||||
|
delete data.listItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_importData.isEmpty())
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -9,12 +9,15 @@
|
|||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QIcon>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QGridLayout;
|
class QGridLayout;
|
||||||
|
class QLabel;
|
||||||
|
class QListWidgetItem;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
@@ -23,7 +26,6 @@ class OutputFormatter;
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
class ItemLibraryAssetImporter;
|
|
||||||
class Import3dCanvas;
|
class Import3dCanvas;
|
||||||
class Import3dConnectionManager;
|
class Import3dConnectionManager;
|
||||||
class NodeInstanceView;
|
class NodeInstanceView;
|
||||||
@@ -53,6 +55,8 @@ public:
|
|||||||
const QVariantMap &supportedExts,
|
const QVariantMap &supportedExts,
|
||||||
const QVariantMap &supportedOpts);
|
const QVariantMap &supportedOpts);
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
@@ -62,6 +66,22 @@ private slots:
|
|||||||
void addInfo(const QString &info, const QString &srcPath = {});
|
void addInfo(const QString &info, const QString &srcPath = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ImportData
|
||||||
|
{
|
||||||
|
QListWidgetItem *listItem = {};
|
||||||
|
QLabel *iconLabel = {};
|
||||||
|
QLabel *infoLabel = {};
|
||||||
|
QPushButton *removeButton = {};
|
||||||
|
ItemLibraryAssetImporter::PreviewData previewData;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OptionsData
|
||||||
|
{
|
||||||
|
int optionsRows = 0;
|
||||||
|
int optionsHeight = 0;
|
||||||
|
QList<QWidget *> contentWidgets;
|
||||||
|
};
|
||||||
|
|
||||||
void setCloseButtonState(bool importing);
|
void setCloseButtonState(bool importing);
|
||||||
void updatePreviewOptions();
|
void updatePreviewOptions();
|
||||||
|
|
||||||
@@ -73,15 +93,17 @@ private:
|
|||||||
void onRequestRotation(const QPointF &delta);
|
void onRequestRotation(const QPointF &delta);
|
||||||
void onImportNearlyFinished();
|
void onImportNearlyFinished();
|
||||||
void onImportFinished();
|
void onImportFinished();
|
||||||
void onCurrentRowChanged(int row);
|
void onCurrentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
|
||||||
void onClose();
|
void onClose();
|
||||||
void doClose();
|
void doClose();
|
||||||
void toggleAdvanced();
|
void toggleAdvanced();
|
||||||
|
void onRemoveAsset(const QString &assetName);
|
||||||
|
|
||||||
void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
|
void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
|
||||||
QGridLayout *createOptionsGrid(QWidget *contentWidget, bool advanced, int optionsIndex,
|
QGridLayout *createOptionsGrid(QWidget *contentWidget, bool advanced, int optionsIndex,
|
||||||
const QJsonObject &groups);
|
const QJsonObject &groups);
|
||||||
void updateUi();
|
void updateUi();
|
||||||
|
QString assetNameForListItem(QListWidgetItem *item);
|
||||||
|
|
||||||
bool isSimpleGroup(const QString &id);
|
bool isSimpleGroup(const QString &id);
|
||||||
bool isSimpleOption(const QString &id);
|
bool isSimpleOption(const QString &id);
|
||||||
@@ -101,16 +123,9 @@ private:
|
|||||||
QPointer<AbstractView> m_view;
|
QPointer<AbstractView> m_view;
|
||||||
ModelPointer m_model;
|
ModelPointer m_model;
|
||||||
|
|
||||||
QMap<QString, ItemLibraryAssetImporter::PreviewData> m_previewData;
|
QMap<QString, ImportData> m_importData;
|
||||||
Utils::FilePath m_previewFile;
|
Utils::FilePath m_previewFile;
|
||||||
|
|
||||||
struct OptionsData
|
|
||||||
{
|
|
||||||
int optionsRows = 0;
|
|
||||||
int optionsHeight = 0;
|
|
||||||
QList<QWidget *> contentWidgets; // Tab content widgets
|
|
||||||
};
|
|
||||||
|
|
||||||
QStringList m_quick3DFiles;
|
QStringList m_quick3DFiles;
|
||||||
QString m_quick3DImportPath;
|
QString m_quick3DImportPath;
|
||||||
ItemLibraryAssetImporter m_importer;
|
ItemLibraryAssetImporter m_importer;
|
||||||
@@ -126,5 +141,7 @@ private:
|
|||||||
bool m_explicitClose = false;
|
bool m_explicitClose = false;
|
||||||
bool m_updatingControlStates = true;
|
bool m_updatingControlStates = true;
|
||||||
bool m_firstImport = true;
|
bool m_firstImport = true;
|
||||||
|
QIcon m_selectedRemoveIcon;
|
||||||
|
QIcon m_unselectedRemoveIcon;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>150</width>
|
<width>250</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@@ -238,7 +238,6 @@ void ItemLibraryAssetImporter::reset()
|
|||||||
delete m_tempDir;
|
delete m_tempDir;
|
||||||
m_tempDir = new QTemporaryDir(QDir::tempPath() + tempDirNameBase());
|
m_tempDir = new QTemporaryDir(QDir::tempPath() + tempDirNameBase());
|
||||||
m_importFiles.clear();
|
m_importFiles.clear();
|
||||||
m_overwrittenImports.clear();
|
|
||||||
m_puppetProcess.reset();
|
m_puppetProcess.reset();
|
||||||
m_parseData.clear();
|
m_parseData.clear();
|
||||||
m_requiredImports.clear();
|
m_requiredImports.clear();
|
||||||
@@ -337,14 +336,14 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa
|
|||||||
overwriteFiles = dlg.selectedFiles();
|
overwriteFiles = dlg.selectedFiles();
|
||||||
if (!overwriteFiles.isEmpty()) {
|
if (!overwriteFiles.isEmpty()) {
|
||||||
overwriteFiles.append(::Utils::toList(alwaysOverwrite));
|
overwriteFiles.append(::Utils::toList(alwaysOverwrite));
|
||||||
m_overwrittenImports.insert(pd.targetDirPath, overwriteFiles);
|
pd.overwrittenImports.insert(pd.targetDirPath, overwriteFiles);
|
||||||
} else {
|
} else {
|
||||||
addWarning(tr("No files selected for overwrite, skipping import: \"%1\".").arg(pd.assetName));
|
addWarning(tr("No files selected for overwrite, skipping import: \"%1\".").arg(pd.assetName));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
m_overwrittenImports.insert(pd.targetDirPath, {});
|
pd.overwrittenImports.insert(pd.targetDirPath, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,9 +395,7 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
|
|||||||
qmlInfo.append(".");
|
qmlInfo.append(".");
|
||||||
qmlInfo.append(pd.assetName);
|
qmlInfo.append(pd.assetName);
|
||||||
qmlInfo.append('\n');
|
qmlInfo.append('\n');
|
||||||
const QString reqImp = QStringLiteral("%1.%2").arg(
|
const QString reqImp = generateRequiredImportForAsset(pd.assetName);
|
||||||
QmlDesignerPlugin::instance()->documentManager()
|
|
||||||
.generatedComponentUtils().import3dTypePrefix(), pd.assetName);
|
|
||||||
if (!m_requiredImports.contains(reqImp))
|
if (!m_requiredImports.contains(reqImp))
|
||||||
m_requiredImports.append(reqImp);
|
m_requiredImports.append(reqImp);
|
||||||
while (qmlIt.hasNext()) {
|
while (qmlIt.hasNext()) {
|
||||||
@@ -480,9 +477,13 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
|
|||||||
|
|
||||||
// Gather all generated files
|
// Gather all generated files
|
||||||
QDirIterator dirIt(outDir.path(), QDir::Files, QDirIterator::Subdirectories);
|
QDirIterator dirIt(outDir.path(), QDir::Files, QDirIterator::Subdirectories);
|
||||||
|
pd.assetSize = 0;
|
||||||
while (dirIt.hasNext()) {
|
while (dirIt.hasNext()) {
|
||||||
dirIt.next();
|
dirIt.next();
|
||||||
insertAsset(dirIt.filePath());
|
insertAsset(dirIt.filePath());
|
||||||
|
QFileInfo fi = dirIt.fileInfo();
|
||||||
|
if (fi.isFile())
|
||||||
|
pd.assetSize += fi.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the original asset into a subdirectory
|
// Copy the original asset into a subdirectory
|
||||||
@@ -492,14 +493,17 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
|
|||||||
|
|
||||||
void ItemLibraryAssetImporter::copyImportedFiles()
|
void ItemLibraryAssetImporter::copyImportedFiles()
|
||||||
{
|
{
|
||||||
if (!m_overwrittenImports.isEmpty()) {
|
QHash<QString, QStringList> allOverwrites;
|
||||||
|
for (const ParseData &pd: std::as_const(m_parseData))
|
||||||
|
allOverwrites.insert(pd.overwrittenImports);
|
||||||
|
if (!allOverwrites.isEmpty()) {
|
||||||
const QString progressTitle = tr("Removing old overwritten assets.");
|
const QString progressTitle = tr("Removing old overwritten assets.");
|
||||||
addInfo(progressTitle);
|
addInfo(progressTitle);
|
||||||
notifyProgress(0, progressTitle);
|
notifyProgress(0, progressTitle);
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
auto it = m_overwrittenImports.constBegin();
|
auto it = allOverwrites.constBegin();
|
||||||
while (it != m_overwrittenImports.constEnd()) {
|
while (it != allOverwrites.constEnd()) {
|
||||||
Utils::FilePath dir = Utils::FilePath::fromUserInput(it.key());
|
Utils::FilePath dir = Utils::FilePath::fromUserInput(it.key());
|
||||||
if (dir.exists()) {
|
if (dir.exists()) {
|
||||||
const auto &overwrittenFiles = it.value();
|
const auto &overwrittenFiles = it.value();
|
||||||
@@ -512,7 +516,7 @@ void ItemLibraryAssetImporter::copyImportedFiles()
|
|||||||
QFile::remove(fileName);
|
QFile::remove(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notifyProgress((100 * ++counter) / m_overwrittenImports.size(), progressTitle);
|
notifyProgress((100 * ++counter) / allOverwrites.size(), progressTitle);
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -568,6 +572,13 @@ QString ItemLibraryAssetImporter::generateAssetFolderName(const QString &assetNa
|
|||||||
return assetName + "_QDS_" + QString::number(counter++);
|
return assetName + "_QDS_" + QString::number(counter++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ItemLibraryAssetImporter::generateRequiredImportForAsset(const QString &assetName) const
|
||||||
|
{
|
||||||
|
return QStringLiteral("%1.%2").arg(
|
||||||
|
QmlDesignerPlugin::instance()->documentManager()
|
||||||
|
.generatedComponentUtils().import3dTypePrefix(), assetName);
|
||||||
|
}
|
||||||
|
|
||||||
ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAssetOverwrite(const QString &assetName)
|
ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAssetOverwrite(const QString &assetName)
|
||||||
{
|
{
|
||||||
const QString title = tr("Overwrite Existing Asset?");
|
const QString title = tr("Overwrite Existing Asset?");
|
||||||
@@ -653,8 +664,11 @@ void ItemLibraryAssetImporter::postImport()
|
|||||||
data.renderedOptions = pd.options;
|
data.renderedOptions = pd.options;
|
||||||
data.currentOptions = pd.options;
|
data.currentOptions = pd.options;
|
||||||
data.optionsIndex = pd.optionsIndex;
|
data.optionsIndex = pd.optionsIndex;
|
||||||
|
data.type = pd.sourceInfo.suffix().toLower();
|
||||||
|
data.size = pd.assetSize;
|
||||||
dataList.append(data);
|
dataList.append(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit importReadyForPreview(m_tempDir->path(), dataList);
|
emit importReadyForPreview(m_tempDir->path(), dataList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -716,8 +730,12 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
|
|||||||
addError(tr("Failed to update imports: %1").arg(e.description()));
|
addError(tr("Failed to update imports: %1").arg(e.description()));
|
||||||
}
|
}
|
||||||
} else if (counter >= 50) {
|
} else if (counter >= 50) {
|
||||||
if (!m_overwrittenImports.isEmpty())
|
for (const ParseData &pd : std::as_const(m_parseData)) {
|
||||||
model->rewriterView()->emitCustomNotification("asset_import_update");
|
if (!pd.overwrittenImports.isEmpty()) {
|
||||||
|
model->rewriterView()->emitCustomNotification("asset_import_update");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
timer->stop();
|
timer->stop();
|
||||||
notifyFinished();
|
notifyFinished();
|
||||||
}
|
}
|
||||||
@@ -732,6 +750,13 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemLibraryAssetImporter::removeAssetFromImport(const QString &assetName)
|
||||||
|
{
|
||||||
|
m_parseData.remove(assetName);
|
||||||
|
m_importFiles.remove(assetName);
|
||||||
|
m_requiredImports.removeOne(generateRequiredImportForAsset(assetName));
|
||||||
|
}
|
||||||
|
|
||||||
QString ItemLibraryAssetImporter::sourceSceneTargetFilePath(const ParseData &pd)
|
QString ItemLibraryAssetImporter::sourceSceneTargetFilePath(const ParseData &pd)
|
||||||
{
|
{
|
||||||
return pd.targetDirPath + QStringLiteral("/source scene/") + pd.sourceInfo.fileName();
|
return pd.targetDirPath + QStringLiteral("/source scene/") + pd.sourceInfo.fileName();
|
||||||
|
@@ -47,6 +47,7 @@ public:
|
|||||||
QString tempDirNameBase() const { return "/qds3dimport"; }
|
QString tempDirNameBase() const { return "/qds3dimport"; }
|
||||||
|
|
||||||
void finalizeQuick3DImport();
|
void finalizeQuick3DImport();
|
||||||
|
void removeAssetFromImport(const QString &assetName);
|
||||||
|
|
||||||
struct PreviewData
|
struct PreviewData
|
||||||
{
|
{
|
||||||
@@ -55,6 +56,8 @@ public:
|
|||||||
QJsonObject currentOptions;
|
QJsonObject currentOptions;
|
||||||
QString name;
|
QString name;
|
||||||
QString folderName;
|
QString folderName;
|
||||||
|
QString type;
|
||||||
|
qint64 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -78,8 +81,10 @@ private:
|
|||||||
QFileInfo sourceInfo;
|
QFileInfo sourceInfo;
|
||||||
QString assetName;
|
QString assetName;
|
||||||
QString originalAssetName;
|
QString originalAssetName;
|
||||||
|
qint64 assetSize;
|
||||||
int importId = -1;
|
int importId = -1;
|
||||||
int optionsIndex = -1;
|
int optionsIndex = -1;
|
||||||
|
QHash<QString, QStringList> overwrittenImports;
|
||||||
};
|
};
|
||||||
|
|
||||||
void notifyFinished();
|
void notifyFinished();
|
||||||
@@ -96,6 +101,7 @@ private:
|
|||||||
void notifyProgress(int value);
|
void notifyProgress(int value);
|
||||||
void keepUiAlive() const;
|
void keepUiAlive() const;
|
||||||
QString generateAssetFolderName(const QString &assetName) const;
|
QString generateAssetFolderName(const QString &assetName) const;
|
||||||
|
QString generateRequiredImportForAsset(const QString &assetName) const;
|
||||||
|
|
||||||
enum class OverwriteResult {
|
enum class OverwriteResult {
|
||||||
Skip,
|
Skip,
|
||||||
@@ -109,7 +115,6 @@ private:
|
|||||||
QString sourceSceneTargetFilePath(const ParseData &pd);
|
QString sourceSceneTargetFilePath(const ParseData &pd);
|
||||||
|
|
||||||
QHash<QString, QHash<QString, QString>> m_importFiles; // Key: asset name
|
QHash<QString, QHash<QString, QString>> m_importFiles; // Key: asset name
|
||||||
QHash<QString, QStringList> m_overwrittenImports;
|
|
||||||
bool m_isImporting = false;
|
bool m_isImporting = false;
|
||||||
bool m_cancelled = false;
|
bool m_cancelled = false;
|
||||||
QString m_importPath;
|
QString m_importPath;
|
||||||
|
@@ -35,7 +35,7 @@ Qt5Import3dNodeInstanceServer::Qt5Import3dNodeInstanceServer(NodeInstanceClientI
|
|||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
m_generalHelper = new Internal::GeneralHelper();
|
m_generalHelper = new Internal::GeneralHelper();
|
||||||
QObject::connect(m_generalHelper, &Internal::GeneralHelper::requestRender, this, [this]() {
|
QObject::connect(m_generalHelper, &Internal::GeneralHelper::requestRender, this, [this]() {
|
||||||
startRenderTimer();
|
addCurrentNodeToRenderQueue();
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -54,16 +54,22 @@ void Qt5Import3dNodeInstanceServer::createScene(const CreateSceneCommand &comman
|
|||||||
|
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
QObject *obj = rootItem();
|
QObject *obj = rootItem();
|
||||||
QQmlProperty viewProp(obj, "view3d", context());
|
auto initView = [&obj, this](const QString &viewId, QQuick3DViewport *&view3D) {
|
||||||
QObject *viewObj = viewProp.read().value<QObject *>();
|
QQmlProperty viewProp(obj, viewId, context());
|
||||||
m_view3D = qobject_cast<QQuick3DViewport *>(viewObj);
|
QObject *viewObj = viewProp.read().value<QObject *>();
|
||||||
|
view3D = qobject_cast<QQuick3DViewport *>(viewObj);
|
||||||
|
};
|
||||||
|
initView("view3d", m_view3D);
|
||||||
|
initView("iconView3d", m_iconView3D);
|
||||||
|
|
||||||
if (m_view3D) {
|
if (m_view3D) {
|
||||||
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
|
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
|
||||||
m_sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
|
m_sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
|
||||||
|
m_defaultCameraRotation = m_view3D->camera()->rotation();
|
||||||
|
m_defaultCameraPosition = m_view3D->camera()->position();
|
||||||
|
addInitToRenderQueue();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
startRenderTimer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DActionCommand &command)
|
void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DActionCommand &command)
|
||||||
@@ -79,7 +85,7 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
|||||||
wProp.write(size.width());
|
wProp.write(size.width());
|
||||||
hProp.write(size.height());
|
hProp.write(size.height());
|
||||||
resizeCanvasToRootItem();
|
resizeCanvasToRootItem();
|
||||||
startRenderTimer();
|
addCurrentNodeToRenderQueue();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -92,8 +98,8 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
|||||||
QPointF delta = command.value().toPointF();
|
QPointF delta = command.value().toPointF();
|
||||||
m_generalHelper->orbitCamera(m_view3D->camera(), m_view3D->camera()->eulerRotation(),
|
m_generalHelper->orbitCamera(m_view3D->camera(), m_view3D->camera()->eulerRotation(),
|
||||||
data.lookAt, {}, {float(delta.x()), float(delta.y()), 0.f});
|
data.lookAt, {}, {float(delta.x()), float(delta.y()), 0.f});
|
||||||
m_keepRendering = true;
|
// Add 2 renders to keep render timer alive for smooth rotation
|
||||||
startRenderTimer();
|
addCurrentNodeToRenderQueue(2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -123,28 +129,23 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
|||||||
engine()->setObjectOwnership(data.node, QJSEngine::CppOwnership);
|
engine()->setObjectOwnership(data.node, QJSEngine::CppOwnership);
|
||||||
data.node->setParentItem(m_sceneNode);
|
data.node->setParentItem(m_sceneNode);
|
||||||
data.node->setParent(m_sceneNode);
|
data.node->setParent(m_sceneNode);
|
||||||
|
|
||||||
|
addInitToRenderQueue();
|
||||||
|
|
||||||
|
if (m_currentNode == name)
|
||||||
|
addCurrentNodeToRenderQueue();
|
||||||
|
|
||||||
|
addIconToRenderQueue(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_currentNode == data.name) {
|
|
||||||
m_renderCount = 0;
|
|
||||||
startRenderTimer();
|
|
||||||
} else if (data.node) {
|
|
||||||
data.node->setVisible(false);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case View3DActionType::Import3dSetCurrentPreviewModel: {
|
case View3DActionType::Import3dSetCurrentPreviewModel: {
|
||||||
QString newName = command.value().toString();
|
QString newName = command.value().toString();
|
||||||
if (m_previewData.contains(newName) && m_currentNode != newName) {
|
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;
|
m_currentNode = newName;
|
||||||
startRenderTimer();
|
addInitToRenderQueue();
|
||||||
|
addCurrentNodeToRenderQueue();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -157,8 +158,10 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
|||||||
|
|
||||||
void Qt5Import3dNodeInstanceServer::startRenderTimer()
|
void Qt5Import3dNodeInstanceServer::startRenderTimer()
|
||||||
{
|
{
|
||||||
if (m_keepRendering && timerMode() == TimerMode::NormalTimer)
|
#ifdef QUICK3D_MODULE
|
||||||
|
if (!m_renderQueue.isEmpty() && timerMode() == TimerMode::NormalTimer)
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
NodeInstanceServer::startRenderTimer();
|
NodeInstanceServer::startRenderTimer();
|
||||||
}
|
}
|
||||||
@@ -173,6 +176,45 @@ void Qt5Import3dNodeInstanceServer::cleanup()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef QUICK3D_MODULE
|
||||||
|
void Qt5Import3dNodeInstanceServer::addInitToRenderQueue()
|
||||||
|
{
|
||||||
|
startRenderTimer();
|
||||||
|
|
||||||
|
// "Init" render is simply a rendering of the entire scene without producing any images.
|
||||||
|
// This is done to make sure everything is initialized properly for subsequent renders.
|
||||||
|
|
||||||
|
if (m_renderQueue.isEmpty() || m_renderQueue[0] != RenderType::Init)
|
||||||
|
m_renderQueue.prepend(RenderType::Init);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Qt5Import3dNodeInstanceServer::addCurrentNodeToRenderQueue(int count)
|
||||||
|
{
|
||||||
|
startRenderTimer();
|
||||||
|
|
||||||
|
int remaining = count;
|
||||||
|
for (const RenderType &type : std::as_const(m_renderQueue)) {
|
||||||
|
if (type == RenderType::CurrentNode && --remaining <= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = !m_renderQueue.isEmpty() && m_renderQueue[0] == RenderType::Init ? 1 : 0;
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
m_renderQueue.insert(index, RenderType::CurrentNode);
|
||||||
|
--remaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Qt5Import3dNodeInstanceServer::addIconToRenderQueue(const QString &assetName)
|
||||||
|
{
|
||||||
|
startRenderTimer();
|
||||||
|
|
||||||
|
m_generateIconQueue.append(assetName);
|
||||||
|
m_renderQueue.append(RenderType::NextIcon);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Qt5Import3dNodeInstanceServer::collectItemChangesAndSendChangeCommands()
|
void Qt5Import3dNodeInstanceServer::collectItemChangesAndSendChangeCommands()
|
||||||
{
|
{
|
||||||
static bool inFunction = false;
|
static bool inFunction = false;
|
||||||
@@ -194,54 +236,112 @@ void Qt5Import3dNodeInstanceServer::collectItemChangesAndSendChangeCommands()
|
|||||||
void Qt5Import3dNodeInstanceServer::render()
|
void Qt5Import3dNodeInstanceServer::render()
|
||||||
{
|
{
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
++m_renderCount;
|
if (m_renderQueue.isEmpty() || !m_view3D || !m_iconView3D)
|
||||||
|
return;
|
||||||
|
|
||||||
// Render scene at least once before calculating bounds to ensure geometries are intialized
|
RenderType currentType = m_renderQueue.takeFirst();
|
||||||
if (m_renderCount == 2 && m_view3D && m_previewData.contains(m_currentNode)) {
|
PreviewData data;
|
||||||
PreviewData &data = m_previewData[m_currentNode];
|
QQuick3DViewport *currentView = m_view3D;
|
||||||
m_generalHelper->calculateBoundsAndFocusCamera(m_view3D->camera(), data.node,
|
QVector3D cameraPosition = m_view3D->camera()->position();
|
||||||
m_view3D, 1050, false, data.lookAt,
|
QQuaternion cameraRotation = m_view3D->camera()->rotation();
|
||||||
data.extents);
|
|
||||||
|
|
||||||
auto getExtentStr = [&data](int idx) -> QString {
|
if (currentType == RenderType::Init) {
|
||||||
int prec = 0;
|
m_view3D->setVisible(true);
|
||||||
float val = data.extents[idx];
|
m_iconView3D->setVisible(true);
|
||||||
while (val < 100.f) {
|
} else {
|
||||||
++prec;
|
auto showNode = [this](const QString &name) {
|
||||||
val *= 10.f;
|
for (const PreviewData &data : std::as_const(m_previewData))
|
||||||
}
|
data.node->setVisible(data.name == name);
|
||||||
// Strip unnecessary zeroes after decimal separator
|
|
||||||
if (prec > 0) {
|
|
||||||
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(data.extents[idx], 'f', prec);
|
|
||||||
return retval;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QQmlProperty extentsProp(rootItem(), "extents", context());
|
if (currentType == RenderType::CurrentNode) {
|
||||||
extentsProp.write(tr("Dimensions: %1 x %2 x %3").arg(getExtentStr(0))
|
if (m_previewData.contains(m_currentNode)) {
|
||||||
.arg(getExtentStr(1))
|
showNode(m_currentNode);
|
||||||
.arg(getExtentStr(2)));
|
data = m_previewData[m_currentNode];
|
||||||
|
m_view3D->setVisible(true);
|
||||||
|
m_iconView3D->setVisible(false);
|
||||||
|
}
|
||||||
|
} else if (currentType == RenderType::NextIcon) {
|
||||||
|
if (!m_generateIconQueue.isEmpty()) {
|
||||||
|
const QString assetName = m_generateIconQueue.takeFirst();
|
||||||
|
if (m_previewData.contains(assetName)) {
|
||||||
|
m_view3D->setVisible(false);
|
||||||
|
m_iconView3D->setVisible(true);
|
||||||
|
showNode(assetName);
|
||||||
|
data = m_previewData[assetName];
|
||||||
|
m_refocus = true;
|
||||||
|
currentView = m_iconView3D;
|
||||||
|
currentView->camera()->setRotation(m_defaultCameraRotation);
|
||||||
|
currentView->camera()->setPosition(m_defaultCameraPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_refocus && data.node) {
|
||||||
|
m_generalHelper->calculateBoundsAndFocusCamera(currentView->camera(), data.node,
|
||||||
|
currentView, 1050, false, data.lookAt,
|
||||||
|
data.extents);
|
||||||
|
if (currentType == RenderType::CurrentNode) {
|
||||||
|
auto getExtentStr = [&data](int idx) -> QString {
|
||||||
|
int prec = 0;
|
||||||
|
float val = data.extents[idx];
|
||||||
|
|
||||||
|
if (val == 0.f) {
|
||||||
|
prec = 1;
|
||||||
|
} else {
|
||||||
|
while (val < 100.f) {
|
||||||
|
++prec;
|
||||||
|
val *= 10.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Strip unnecessary zeroes after decimal separator
|
||||||
|
if (prec > 0) {
|
||||||
|
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(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))
|
||||||
|
.arg(getExtentStr(2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootNodeInstance().updateDirtyNodeRecursive();
|
currentView->update();
|
||||||
QImage renderImage = grabWindow();
|
QImage renderImage = grabWindow();
|
||||||
|
|
||||||
if (m_renderCount >= 2) {
|
if (currentType == RenderType::Init) {
|
||||||
ImageContainer imgContainer(0, renderImage, m_renderCount);
|
m_refocus = true;
|
||||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
} else if (currentType == RenderType::CurrentNode) {
|
||||||
{PuppetToCreatorCommand::Import3DPreviewImage,
|
if (m_previewData.contains(m_currentNode)) {
|
||||||
QVariant::fromValue(imgContainer)});
|
ImageContainer imgContainer(0, renderImage, 1000000);
|
||||||
|
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||||
if (!m_keepRendering)
|
{PuppetToCreatorCommand::Import3DPreviewImage, QVariant::fromValue(imgContainer)});
|
||||||
slowDownRenderTimer();
|
}
|
||||||
|
} else if (currentType == RenderType::NextIcon) {
|
||||||
m_keepRendering = false;
|
if (!data.name.isEmpty()) {
|
||||||
|
QSizeF iconSize = m_iconView3D->size();
|
||||||
|
QImage iconImage = renderImage.copy(0, 0, iconSize.width(), iconSize.height());
|
||||||
|
ImageContainer imgContainer(0, iconImage, 1000001);
|
||||||
|
QVariantList cmdData;
|
||||||
|
cmdData.append(data.name);
|
||||||
|
cmdData.append(QVariant::fromValue(imgContainer));
|
||||||
|
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||||
|
{PuppetToCreatorCommand::Import3DPreviewIcon, cmdData});
|
||||||
|
}
|
||||||
|
m_refocus = true;
|
||||||
|
currentView->camera()->setRotation(cameraRotation);
|
||||||
|
currentView->camera()->setPosition(cameraPosition);
|
||||||
}
|
}
|
||||||
|
if (m_renderQueue.isEmpty())
|
||||||
|
slowDownRenderTimer();
|
||||||
#else
|
#else
|
||||||
slowDownRenderTimer();
|
slowDownRenderTimer();
|
||||||
#endif
|
#endif
|
||||||
|
@@ -35,11 +35,13 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
int m_renderCount = 0;
|
|
||||||
bool m_keepRendering = false;
|
|
||||||
|
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
|
void addInitToRenderQueue();
|
||||||
|
void addCurrentNodeToRenderQueue(int count = 1);
|
||||||
|
void addIconToRenderQueue(const QString &assetName);
|
||||||
|
|
||||||
QQuick3DViewport *m_view3D = nullptr;
|
QQuick3DViewport *m_view3D = nullptr;
|
||||||
|
QQuick3DViewport *m_iconView3D = nullptr;
|
||||||
Internal::GeneralHelper *m_generalHelper = nullptr;
|
Internal::GeneralHelper *m_generalHelper = nullptr;
|
||||||
|
|
||||||
struct PreviewData
|
struct PreviewData
|
||||||
@@ -50,8 +52,21 @@ private:
|
|||||||
QQuick3DNode *node = {};
|
QQuick3DNode *node = {};
|
||||||
};
|
};
|
||||||
QHash<QString, PreviewData> m_previewData;
|
QHash<QString, PreviewData> m_previewData;
|
||||||
|
|
||||||
|
enum class RenderType
|
||||||
|
{
|
||||||
|
Init,
|
||||||
|
CurrentNode,
|
||||||
|
NextIcon
|
||||||
|
};
|
||||||
|
QList<RenderType> m_renderQueue;
|
||||||
|
|
||||||
|
bool m_refocus = false;
|
||||||
QString m_currentNode;
|
QString m_currentNode;
|
||||||
QQuick3DNode *m_sceneNode = {};
|
QQuick3DNode *m_sceneNode = {};
|
||||||
|
QStringList m_generateIconQueue;
|
||||||
|
QQuaternion m_defaultCameraRotation;
|
||||||
|
QVector3D m_defaultCameraPosition;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user