From d2cc440c688540f85b7bd925625397511230f307 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 2 Jun 2022 17:05:26 +0300 Subject: QmlDesigner: Add checkerboard background in navigator preview tooltip Checkerboard helps visualizing alpha channel in previewed images. Fixes: QDS-7060 Change-Id: Idb0139f8d8fcbf595bbfba3b333cd3d49f18d8af Reviewed-by: Thomas Hartmann Reviewed-by: Mahmoud Badri Reviewed-by: --- .../qmldesigner/components/navigator/checkers.png | Bin 0 -> 80 bytes .../qmldesigner/components/navigator/navigator.qrc | 1 + .../components/navigator/previewtooltip.cpp | 14 +++- .../components/navigator/previewtooltip.ui | 88 +++++++++++++++------ .../designercore/instances/nodeinstanceview.cpp | 12 ++- 5 files changed, 91 insertions(+), 24 deletions(-) create mode 100644 src/plugins/qmldesigner/components/navigator/checkers.png diff --git a/src/plugins/qmldesigner/components/navigator/checkers.png b/src/plugins/qmldesigner/components/navigator/checkers.png new file mode 100644 index 0000000000..72cb9f0350 Binary files /dev/null and b/src/plugins/qmldesigner/components/navigator/checkers.png differ diff --git a/src/plugins/qmldesigner/components/navigator/navigator.qrc b/src/plugins/qmldesigner/components/navigator/navigator.qrc index fca836a09b..e595bae0f9 100644 --- a/src/plugins/qmldesigner/components/navigator/navigator.qrc +++ b/src/plugins/qmldesigner/components/navigator/navigator.qrc @@ -13,5 +13,6 @@ export_unchecked.png export_unchecked@2x.png tooltip_placeholder.png + checkers.png diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp index 800104bfb3..b352f1daa2 100644 --- a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp @@ -28,7 +28,8 @@ #include -#include +#include +#include namespace QmlDesigner { @@ -43,6 +44,17 @@ PreviewToolTip::PreviewToolTip(QWidget *parent) m_ui->typeLabel->setElideMode(Qt::ElideLeft); m_ui->infoLabel->setElideMode(Qt::ElideLeft); setStyleSheet(QString("QWidget { background-color: %1 }").arg(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal).name())); + m_ui->imageLabel->setStyleSheet("background-color: rgba(0, 0, 0, 0)"); + + static QPixmap checkers; + if (checkers.isNull()) { + checkers = {150, 150}; + QPainter painter(&checkers); + painter.setBrush(QPixmap(":/navigator/icon/checkers.png")); + painter.drawRect(0, 0, 150, 150); + } + m_ui->labelBackground->setPixmap(checkers); + } PreviewToolTip::~PreviewToolTip() diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.ui b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui index 1c06a248f0..c8520751a8 100644 --- a/src/plugins/qmldesigner/components/navigator/previewtooltip.ui +++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.ui @@ -81,28 +81,72 @@ 6 - - - - 0 - 0 - - - - - 150 - 150 - - - - QFrame::Box - - - QFrame::Plain - - - Qt::AlignCenter - + + + + + 0 + 0 + 150 + 150 + + + + + 0 + 0 + + + + + 150 + 150 + + + + QFrame::Box + + + QFrame::Plain + + + false + + + Qt::AlignCenter + + + + + + 0 + 0 + 150 + 150 + + + + + 0 + 0 + + + + + 150 + 150 + + + + QFrame::Box + + + QFrame::Plain + + + Qt::AlignCenter + + diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 29bf14d026..db22d27fc3 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -103,6 +103,7 @@ #include #include #include +#include #include @@ -1756,7 +1757,16 @@ void NodeInstanceView::timerEvent(QTimerEvent *event) QVariant NodeInstanceView::modelNodePreviewImageDataToVariant(const ModelNodePreviewImageData &imageData) { - static const QPixmap placeHolder(":/navigator/icon/tooltip_placeholder.png"); + static QPixmap placeHolder; + if (placeHolder.isNull()) { + QPixmap placeHolderSrc(":/navigator/icon/tooltip_placeholder.png"); + placeHolder = {150, 150}; + // Placeholder has transparency, but we don't want to show the checkerboard, so + // paint in the correct background color + placeHolder.fill(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal)); + QPainter painter(&placeHolder); + painter.drawPixmap(0, 0, 150, 150, placeHolderSrc); + } QVariantMap map; map.insert("type", imageData.type); -- cgit v1.2.1 From 7269aafbd8a1fddb7d43f783ac20b4d97bbc20c5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 7 Jun 2022 13:39:25 +0300 Subject: QmlDesigner: Ensure material library is created when needed Added material library accessor to AbstractView, which creates the material library and moves existing materials under it in case it doesn't yet exist. Also added material assignment function to AbstractView. The reason these were added to AbstractView instead of being handled e.g. via custom notification in material editor is that they need to be called from multiple different views in the same transaction that triggers the need of material library. Fixes: QDS-7081 Change-Id: If2bb884f87d04c9f3599c2342df66ef51ec238ee Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../qmldesigner/components/edit3d/edit3dcanvas.cpp | 43 +++------- .../qmldesigner/components/formeditor/dragtool.cpp | 15 ++++ .../qmldesigner/components/formeditor/dragtool.h | 1 + .../materialeditor/materialeditorview.cpp | 49 +----------- .../components/materialeditor/materialeditorview.h | 2 - .../components/navigator/navigatortreemodel.cpp | 83 ++++++------------- .../components/navigator/navigatortreemodel.h | 1 - .../designercore/include/abstractview.h | 3 + .../designercore/model/abstractview.cpp | 92 ++++++++++++++++++++++ 9 files changed, 144 insertions(+), 145 deletions(-) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index efb9e24c1c..02d798c1f6 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -186,42 +186,17 @@ void Edit3DCanvas::dragEnterEvent(QDragEnterEvent *e) void Edit3DCanvas::dropEvent(QDropEvent *e) { - auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode(); - QTC_ASSERT(modelNode.isValid(), return); - - e->accept(); - m_parent->view()->setSelectedModelNode(modelNode); - - // if added node is a Model, assign it a material - if (modelNode.isSubclassOf("QtQuick3D.Model")) { - ModelNode matLib = m_parent->view()->modelNodeForId(Constants::MATERIAL_LIB_ID); - QTC_ASSERT(matLib.isValid(), return); - - const QList materials = matLib.directSubModelNodes(); - ModelNode material; - if (materials.size() > 0) { - for (const ModelNode &mat : materials) { - if (mat.isSubclassOf("QtQuick3D.Material")) { - material = mat; - break; - } - } - } + m_parent->view()->executeInTransaction(__FUNCTION__, [&] { + auto modelNode = QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene).modelNode(); + QTC_ASSERT(modelNode.isValid(), return); - // if no valid material, create a new default material - if (!material.isValid()) { - NodeMetaInfo metaInfo = m_parent->view()->model()->metaInfo("QtQuick3D.DefaultMaterial"); - material = m_parent->view()->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), - metaInfo.minorVersion()); - VariantProperty matNameProp = material.variantProperty("objectName"); - matNameProp.setValue("New Material"); - material.validId(); - matLib.defaultNodeListProperty().reparentHere(material); - } + e->accept(); + m_parent->view()->setSelectedModelNode(modelNode); - BindingProperty modelMatsProp = modelNode.bindingProperty("materials"); - modelMatsProp.setExpression(material.id()); - } + // if added node is a Model, assign it a material + if (modelNode.isSubclassOf("QtQuick3D.Model")) + m_parent->view()->assignMaterialTo3dModel(modelNode); + }); } void Edit3DCanvas::focusOutEvent(QFocusEvent *focusEvent) diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index c4a64adf8f..819bf58b34 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -33,6 +33,8 @@ #include #include "qmldesignerconstants.h" +#include + #include #include #include @@ -405,10 +407,23 @@ void DragTool::move(const QPointF &scenePosition, const QList & void DragTool::commitTransaction() { try { + handleView3dDrop(); m_rewriterTransaction.commit(); } catch (const RewritingException &e) { e.showException(); } } +void DragTool::handleView3dDrop() +{ + // If a View3D is dropped, we need to assign material to the included model + for (const QmlItemNode &dragNode : qAsConst(m_dragNodes)) { + if (dragNode.modelNode().isSubclassOf("QtQuick3D.View3D")) { + const QList models = dragNode.modelNode().subModelNodesOfType("QtQuick3D.Model"); + QTC_ASSERT(models.size() == 1, return); + view()->assignMaterialTo3dModel(models.at(0)); + } + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h index 63d3de6e8f..bb6f562263 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.h +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h @@ -90,6 +90,7 @@ protected: void move(const QPointF &scenePos, const QList &itemList); void createDragNodes(const QMimeData *mimeData, const QPointF &scenePosition, const QList &itemList); void commitTransaction(); + void handleView3dDrop(); private: MoveManipulator m_moveManipulator; diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 29a74304d8..28c17d7561 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -78,47 +78,6 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) m_stackedWidget->setMinimumWidth(250); } -void MaterialEditorView::ensureMaterialLibraryNode() -{ - if (!m_hasQuick3DImport) - return; - - m_materialLibrary = modelNodeForId(Constants::MATERIAL_LIB_ID); - if (m_materialLibrary.isValid()) - return; - - // create material library node - TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" : "QtQuick.Item"; - NodeMetaInfo metaInfo = model()->metaInfo(nodeType); - m_materialLibrary = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion()); - - m_materialLibrary.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID); - rootModelNode().defaultNodeListProperty().reparentHere(m_materialLibrary); - - const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); - if (materials.isEmpty()) - return; - - RewriterTransaction transaction = beginRewriterTransaction( - "MaterialEditorView::ensureMaterialLibraryNode"); - - try { - // move all materials to under material library node - for (const ModelNode &node : materials) { - // if material has no name, set name to id - QString matName = node.variantProperty("objectName").value().toString(); - if (matName.isEmpty()) { - VariantProperty objNameProp = node.variantProperty("objectName"); - objNameProp.setValue(node.id()); - } - - m_materialLibrary.defaultNodeListProperty().reparentHere(node); - } - } catch (Exception &e) { - e.showException(); - } -} - MaterialEditorView::~MaterialEditorView() { qDeleteAll(m_qmlBackendHash); @@ -447,15 +406,13 @@ void MaterialEditorView::handleToolBarAction(int action) } case MaterialEditorContextObject::AddNewMaterial: { - ensureMaterialLibraryNode(); - executeInTransaction("MaterialEditorView:handleToolBarAction", [&] { NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), metaInfo.minorVersion()); renameMaterial(newMatNode, "New Material"); - m_materialLibrary.defaultNodeListProperty().reparentHere(newMatNode); + materialLibraryNode().defaultNodeListProperty().reparentHere(newMatNode); }); break; } @@ -759,8 +716,6 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) { QTC_ASSERT(material.isValid(), return); - ensureMaterialLibraryNode(); - TypeName matType = material.type(); QmlObjectNode sourceMat(material); @@ -786,7 +741,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression()); } - m_materialLibrary.defaultNodeListProperty().reparentHere(duplicateMat); + materialLibraryNode().defaultNodeListProperty().reparentHere(duplicateMat); }); } diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index 3e8632d26f..d9c9e4c1ba 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -99,7 +99,6 @@ private: void highlightSupportedProperties(bool highlight = true); QString generateIdFromName(const QString &name); - void ensureMaterialLibraryNode(); void requestPreviewRender(); void applyMaterialToSelectedModels(const ModelNode &material, bool add = false); @@ -115,7 +114,6 @@ private: bool noValidSelection() const; ModelNode m_selectedMaterial; - ModelNode m_materialLibrary; QShortcut *m_updateShortcut = nullptr; int m_timerId = 0; QStackedWidget *m_stackedWidget = nullptr; diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 0a92f81d93..d610014d5b 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -686,18 +686,31 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in bool validContainer = false; ModelNode targetNode = targetProperty.parentModelNode(); - // don't allow dropping materials on any node but Models - QString itemType = QString::fromLatin1(itemLibraryEntry.typeName()); - if (itemType.startsWith("QtQuick3D.") && itemType.endsWith("Material") - && !targetNode.isSubclassOf("QtQuick3D.Model")) { - return; - } - QmlObjectNode newQmlObjectNode; m_view->executeInTransaction("NavigatorTreeModel::handleItemLibraryItemDrop", [&] { newQmlObjectNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, QPointF(), targetProperty, false); ModelNode newModelNode = newQmlObjectNode.modelNode(); if (newModelNode.isValid()) { + if (newModelNode.isSubclassOf("QtQuick3D.Material")) { + // Don't allow dropping materials on any node but Models + if (!targetNode.isSubclassOf("QtQuick3D.Model")) { + newQmlObjectNode.destroy(); + return; + } + // We can't have material initially parented if material library is created in this + // same transaction (rewriter will not allow it for some reason) + ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); + if (!matLib.isValid()) { + newQmlObjectNode.destroy(); + newQmlObjectNode = QmlItemNode::createQmlObjectNode( + m_view, itemLibraryEntry, QPointF(), NodeAbstractProperty(), false); + newModelNode = newQmlObjectNode.modelNode(); + if (!newModelNode.isValid()) + return; + } + m_view->assignMaterialTo3dModel(targetNode, newModelNode); + } + ChooseFromPropertyListDialog *dialog = ChooseFromPropertyListDialog::createIfNeeded( targetNode, newModelNode, Core::ICore::dialogParent()); if (dialog) { @@ -734,28 +747,10 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in if (newModelNode.isSubclassOf("QtQuick3D.View3D")) { const QList models = newModelNode.subModelNodesOfType("QtQuick3D.Model"); - QTC_ASSERT(models.size() == 1, return); - - assignMaterialToModel(models.at(0)); + m_view->assignMaterialTo3dModel(models.at(0)); } else if (newModelNode.isSubclassOf("QtQuick3D.Model")) { - assignMaterialToModel(newModelNode); - } - - // dropping a material on a model - if (newModelNode.isSubclassOf("QtQuick3D.Material") - && targetNode.isSubclassOf("QtQuick3D.Model")) { - // parent material to material library and assign it to target model - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - - QTC_ASSERT(matLib.isValid(), return); - - VariantProperty objName = newModelNode.variantProperty("objectName"); - objName.setValue("New Material"); - BindingProperty matsProp = targetNode.bindingProperty("materials"); - matsProp.setExpression(newModelNode.id()); - matLib.defaultNodeListProperty().reparentHere(newModelNode); - return; + m_view->assignMaterialTo3dModel(newModelNode); } if (!validContainer) { @@ -1089,40 +1084,6 @@ ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targ return {}; } -// Add a material to a Quick3D.Model node -void NavigatorTreeModel::assignMaterialToModel(const ModelNode &node) -{ - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - - QTC_ASSERT(matLib.isValid(), return); - QTC_ASSERT(node.isSubclassOf("QtQuick3D.Model"), return); - - const QList materials = matLib.directSubModelNodes(); - ModelNode material; - if (materials.size() > 0) { - for (const ModelNode &mat : materials) { - if (mat.isSubclassOf("QtQuick3D.Material")) { - material = mat; - break; - } - } - } - - // if no valid material, create a new default material - if (!material.isValid()) { - NodeMetaInfo metaInfo = m_view->model()->metaInfo("QtQuick3D.DefaultMaterial"); - material = m_view->createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), - metaInfo.minorVersion()); - VariantProperty matNameProp = material.variantProperty("objectName"); - matNameProp.setValue("New Material"); - material.validId(); - matLib.defaultNodeListProperty().reparentHere(material); - } - - BindingProperty modelMatsProp = node.bindingProperty("materials"); - modelMatsProp.setExpression(material.id()); -} - TypeName propertyType(const NodeAbstractProperty &property) { return property.parentModelNode().metaInfo().propertyTypeName(property.name()); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 0fcb7aab3e..9652981607 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -130,7 +130,6 @@ private: bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp, const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter); ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath); - void assignMaterialToModel(const ModelNode &node); QList nodesToPersistentIndex(const QList &modelNodes); void addImport(const QString &importName); QList filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const; diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index e37ed0fb4b..18380aadb1 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -259,6 +259,9 @@ public: void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); + ModelNode materialLibraryNode(); + void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {}); + NodeInstanceView *nodeInstanceView() const; RewriterView *rewriterView() const; diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 26040ba23d..86dab97031 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -31,6 +31,10 @@ #include "nodeinstanceview.h" #include #include +#include +#include +#include +#include #ifndef QMLDESIGNER_TEST #include @@ -805,6 +809,94 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion); } +// Returns ModelNode for project's material library. +// If the material library doesn't exist yet, it is created and all existing materials are moved +// under material library. +// This function should be called only form inside a transaction, as it potentially does many +// changes to model. +ModelNode AbstractView::materialLibraryNode() +{ + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + if (matLib.isValid()) + return matLib; + + // Create material library node + TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" + : "QtQuick.Item"; + NodeMetaInfo metaInfo = model()->metaInfo(nodeType); + matLib = createModelNode(nodeType, metaInfo.majorVersion(), metaInfo.minorVersion()); + + matLib.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID); + rootModelNode().defaultNodeListProperty().reparentHere(matLib); + + const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); + if (materials.isEmpty()) + return matLib; + + // Move all materials to under material library node + for (const ModelNode &node : materials) { + // If material has no name, set name to id + QString matName = node.variantProperty("objectName").value().toString(); + if (matName.isEmpty()) { + VariantProperty objNameProp = node.variantProperty("objectName"); + objNameProp.setValue(node.id()); + } + + matLib.defaultNodeListProperty().reparentHere(node); + } + + return matLib; +} + +// Assigns given material to a 3D model. +// The assigned material is also inserted into material library if not already there. +// If given material is not valid, first existing material from material library is used, +// or if material library is empty, a new material is created. +// This function should be called only from inside a transaction, as it potentially does many +// changes to model. +void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode) +{ + QTC_ASSERT(modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Model"), return); + + ModelNode matLib = materialLibraryNode(); + ModelNode newMaterialNode; + + if (materialNode.isValid() && materialNode.isSubclassOf("QtQuick3D.Material")) { + newMaterialNode = materialNode; + } else { + const QList materials = matLib.directSubModelNodes(); + if (materials.size() > 0) { + for (const ModelNode &mat : materials) { + if (mat.isSubclassOf("QtQuick3D.Material")) { + newMaterialNode = mat; + break; + } + } + } + + // if no valid material, create a new default material + if (!newMaterialNode.isValid()) { + NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); + newMaterialNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), + metaInfo.minorVersion()); + newMaterialNode.validId(); + } + } + + QTC_ASSERT(newMaterialNode.isValid(), return); + + VariantProperty matNameProp = newMaterialNode.variantProperty("objectName"); + if (matNameProp.value().isNull()) + matNameProp.setValue("New Material"); + + if (!newMaterialNode.hasParentProperty() + || newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) { + matLib.defaultNodeListProperty().reparentHere(newMaterialNode); + } + BindingProperty modelMatsProp = modelNode.bindingProperty("materials"); + modelMatsProp.setExpression(newMaterialNode.id()); +} + ModelNode AbstractView::currentStateNode() const { if (model()) -- cgit v1.2.1 From 04b3962daf7f46e6ce053c79635eaabe6bb75f4c Mon Sep 17 00:00:00 2001 From: Brook Cronin Date: Tue, 31 May 2022 11:21:06 +0200 Subject: QmlDesigner: add new timeline animation icon Change-Id: I69efb2ed5a56fbf1848d00963ae70002f11b2e75 Reviewed-by: Alessandro Portale Reviewed-by: --- .../qtquickplugin/images/timeline-animation-16px.png | Bin 389 -> 296 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png index d4ecf00031..31b8fed666 100644 Binary files a/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png and b/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png differ -- cgit v1.2.1 From 9bd51f3d557b8e52e42a9b6536da5c8c09853006 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 8 Jun 2022 14:08:50 +0200 Subject: QmlDesigner: Make text label visible in 3d wizard Task-number: QDS-7054 Change-Id: I44a2d01c799b619b553c6b1e76c003324e7b80ba Reviewed-by: Thomas Hartmann --- .../projects/application-3d/Screen01.ui.qml.tpl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl index 338621b72e..24566ef2cc 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl @@ -16,12 +16,6 @@ Rectangle { color: Constants.backgroundColor - Text { - text: qsTr("Hello %{ProjectName}") - anchors.centerIn: parent - font.family: Constants.font.family - } - View3D { id: view3D anchors.fill: parent @@ -62,5 +56,12 @@ Rectangle { objectName: "Default Material" diffuseColor: "#4aee45" } + + Text { + text: qsTr("Hello %{ProjectName}") + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 100 + font.family: Constants.font.family } } -- cgit v1.2.1 From 55cf108f96564304db9b1b4951b93f24279451d6 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 8 Jun 2022 15:05:53 +0200 Subject: QmlDesigner: Update QDS version in template Change-Id: I0bfbd469d49568ec2be0b6b936c46bbc9160fbcb Reviewed-by: Thomas Hartmann --- .../qmldesigner/studio_templates/projects/common/app.qmlproject.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl index 3d2490e8d9..6b2195d6d1 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -90,7 +90,7 @@ Project { /* Required for deployment */ targetDirectory: "/opt/%{ProjectName}" - qdsVersion: "3.4" + qdsVersion: "3.5" quickVersion: "%{QtQuickVersion}" -- cgit v1.2.1 From 6d1478e1db134d37935b1c65adb226edf60e9f6e Mon Sep 17 00:00:00 2001 From: Artem Sokolovskii Date: Fri, 3 Jun 2022 15:10:46 +0200 Subject: Clang Format: Fix misplaced cursor after undo Fixed behavior, when after undo function cursor, jumps to the start of a file. Join the undo block generated by auto format with the last available undo block. This will place the cursor at the last edit position instead of the document beginning when triggering undo. Fixes: QTCREATORBUG-27608 Change-Id: I1bb630af00e997ac53f178594445293ceebcfa26 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/cppeditor/cppeditordocument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index e79d8a1767..f821440126 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -487,7 +487,7 @@ bool CppEditorDocument::save(QString *errorString, const Utils::FilePath &filePa if (!editedRanges.empty()) { QTextCursor cursor(document()); - cursor.beginEditBlock(); + cursor.joinPreviousEditBlock(); indenter()->format(editedRanges); cursor.endEditBlock(); } -- cgit v1.2.1 From 2e5892fbf0db0397b77556d3145faa68f8be11a2 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Wed, 8 Jun 2022 14:58:28 +0200 Subject: QmlDesigner: Fix node component missing state prop Fix node components not showing the states property in the property editor. This is caused by querying majorVersion instead of majorQtQuickVersion. Task-number: QDS-6981 Change-Id: I0a87d921ce985f7fd58b92f526531c49622bb235 Reviewed-by: Mahmoud Badri Reviewed-by: --- .../qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml index 7cded878a1..1a17b82808 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml @@ -33,7 +33,7 @@ PropertyEditorPane { id: itemPane ComponentSection { - showState: majorVersion >= 6 + showState: majorQtQuickVersion >= 6 } Column { -- cgit v1.2.1 From 1c6fa836480808a9fee2ddd9461fc4ad2c4b3058 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 23 May 2022 00:04:31 +0200 Subject: QmlDesigner: Change FileResourcesModel Change FileResourcesModel to have one list of FileResourcesItem with properties absoluteFilePath, relativeFilePath and fileName instead of having two separated lists. Change-Id: Ib4b4884a6739658434844d2adb9c05c3871104e7 Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- .../imports/HelperWidgets/FontComboBox.qml | 4 +- .../imports/HelperWidgets/UrlChooser.qml | 33 +++++---- .../propertyeditor/fileresourcesmodel.cpp | 81 +++++++++++++--------- .../components/propertyeditor/fileresourcesmodel.h | 54 ++++++++++++--- 4 files changed, 115 insertions(+), 57 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 4b5f5caf4a..6d9f56b178 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -55,8 +55,8 @@ StudioControls.ComboBox { function setupModel() { var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] // default fonts - for (var i = 0; i < fileModel.fullPathModel.length; ++i) { // add custom fonts - var fontLoader = createFontLoader(fileModel.docPath + "/" + fileModel.fullPathModel[i]) + for (var i = 0; i < fileModel.model.length; ++i) { // add custom fonts + var fontLoader = createFontLoader(fileModel.docPath + "/" + fileModel.model[i].relativeFilePath) familyNames.push(fontLoader.name) } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index f6766234d0..ee80d95a96 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -88,7 +88,8 @@ Row { } delegate: ItemDelegate { - required property string fullPath + required property string absoluteFilePath + required property string relativeFilePath required property string name required property int group required property int index @@ -150,9 +151,9 @@ Row { } ToolTip { - id: itemToolTip - visible: delegateRoot.hovered && comboBox.highlightedIndex === index - text: fullPath + id: delegateToolTip + visible: delegateRoot.hovered + text: delegateRoot.relativeFilePath delay: StudioTheme.Values.toolTipDelay height: StudioTheme.Values.toolTipHeight background: Rectangle { @@ -197,8 +198,9 @@ Row { if (root.backendValue.isBound) { comboBox.textValue = root.backendValue.expression } else { - var fullPath = root.backendValue.valueToString - comboBox.textValue = fullPath.substr(fullPath.lastIndexOf('/') + 1) + // Can be absolute or relative file path + var filePath = root.backendValue.valueToString + comboBox.textValue = filePath.substr(filePath.lastIndexOf('/') + 1) } comboBox.setCurrentText(comboBox.textValue) @@ -230,7 +232,7 @@ Row { // Check if value set by user matches with a name in the model then pick the full path let index = comboBox.find(inputValue) if (index !== -1) - inputValue = comboBox.items.get(index).model.fullPath + inputValue = comboBox.items.get(index).model.relativeFilePath root.backendValue.value = inputValue comboBox.dirty = false @@ -252,7 +254,7 @@ Row { let inputValue = comboBox.editText if (index >= 0) - inputValue = comboBox.items.get(index).model.fullPath + inputValue = comboBox.items.get(index).model.relativeFilePath if (root.backendValue.value !== inputValue) root.backendValue.value = inputValue @@ -284,17 +286,22 @@ Row { if (root.defaultItems !== undefined) { for (var i = 0; i < root.defaultItems.length; ++i) { comboBox.listModel.append({ - fullPath: root.defaultItems[i], + absoluteFilePath: "", + relativeFilePath: root.defaultItems[i], name: root.defaultItems[i], group: 0 }) } } - for (var j = 0; j < fileModel.fullPathModel.length; ++j) { + const myModel = fileModel.model + for (var j = 0; j < myModel.length; ++j) { + let item = myModel[j] + comboBox.listModel.append({ - fullPath: fileModel.fullPathModel[j], - name: fileModel.fileNameModel[j], + absoluteFilePath: item.absoluteFilePath, + relativeFilePath: item.relativeFilePath, + name: item.fileName, group: 1 }) } @@ -304,7 +311,7 @@ Row { Connections { target: fileModel - function onFullPathModelChanged() { + function onModelChanged() { root.createModel() comboBox.setCurrentText(comboBox.textValue) } diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp index e15ff49744..18fcba3efc 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp @@ -29,11 +29,11 @@ #include -#include #include +#include -#include #include +#include #include #include @@ -46,11 +46,13 @@ FileResourcesModel::FileResourcesModel(QObject *parent) , m_filter(QLatin1String("(*.*)")) { ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile( - QmlDesigner::DocumentManager::currentFilePath()); + QmlDesigner::DocumentManager::currentFilePath()); if (project) { - connect(project, &ProjectExplorer::Project::fileListChanged, - this, &FileResourcesModel::refreshModel); + connect(project, + &ProjectExplorer::Project::fileListChanged, + this, + &FileResourcesModel::refreshModel); } } @@ -58,14 +60,14 @@ void FileResourcesModel::setModelNodeBackend(const QVariant &modelNodeBackend) { auto modelNodeBackendObject = modelNodeBackend.value(); - const auto backendObjectCasted = - qobject_cast(modelNodeBackendObject); + const auto backendObjectCasted = qobject_cast( + modelNodeBackendObject); if (backendObjectCasted) { QmlDesigner::Model *model = backendObjectCasted->qmlObjectNode().modelNode().model(); m_docPath = QDir{QFileInfo{model->fileUrl().toLocalFile()}.absolutePath()}; - m_path = QUrl::fromLocalFile(QmlDesigner::DocumentManager::currentProjectDirPath() - .toFileInfo().absoluteFilePath()); + m_path = QUrl::fromLocalFile( + QmlDesigner::DocumentManager::currentProjectDirPath().toFileInfo().absoluteFilePath()); } setupModel(); @@ -96,6 +98,8 @@ void FileResourcesModel::setPath(const QUrl &url) { m_path = url; setupModel(); + + emit pathChanged(url); } QUrl FileResourcesModel::path() const @@ -110,10 +114,13 @@ QUrl FileResourcesModel::docPath() const void FileResourcesModel::setFilter(const QString &filter) { - if (m_filter != filter) { - m_filter = filter; - setupModel(); - } + if (m_filter == filter) + return; + + m_filter = filter; + setupModel(); + + emit filterChanged(filter); } QString FileResourcesModel::filter() const @@ -121,14 +128,9 @@ QString FileResourcesModel::filter() const return m_filter; } -QStringList FileResourcesModel::fullPathModel() const +QList FileResourcesModel::model() const { - return m_fullPathModel; -} - -QStringList FileResourcesModel::fileNameModel() const -{ - return m_fileNameModel; + return m_model; } void FileResourcesModel::openFileDialog() @@ -164,6 +166,25 @@ void FileResourcesModel::openFileDialog() } } +QString FileResourcesModel::resolve(const QString &relative) const +{ + if (relative.startsWith('#')) + return relative; + + if (QDir::isAbsolutePath(relative)) + return relative; + + if (!QUrl::fromUserInput(relative, m_docPath.path()).isLocalFile()) + return relative; + + return QFileInfo(m_docPath, relative).absoluteFilePath(); +} + +bool FileResourcesModel::isLocal(const QString &path) const +{ + return QUrl::fromUserInput(path, m_docPath.path()).isLocalFile(); +} + void FileResourcesModel::registerDeclarativeType() { qmlRegisterType("HelperWidgets", 2, 0, "FileResourcesModel"); @@ -207,8 +228,7 @@ void FileResourcesModel::setupModel() void FileResourcesModel::refreshModel() { - m_fullPathModel.clear(); - m_fileNameModel.clear(); + m_model.clear(); QStringList filterList = m_filter.split(QLatin1Char(' ')); @@ -216,18 +236,17 @@ void FileResourcesModel::refreshModel() while (it.hasNext()) { QString absolutePath = it.next(); if (filterMetaIcons(absolutePath)) { - QString filePath = m_docPath.relativeFilePath(absolutePath); - m_fullPathModel.append(filePath); + QString relativeFilePath = m_docPath.relativeFilePath(absolutePath); + m_model.append( + FileResourcesItem(absolutePath, + relativeFilePath, + relativeFilePath.mid(relativeFilePath.lastIndexOf('/') + 1))); } } - Utils::sort(m_fullPathModel, [](const QString &s1, const QString &s2) { - return s1.mid(s1.lastIndexOf('/') + 1).toLower() < s2.mid(s2.lastIndexOf('/') + 1).toLower(); + Utils::sort(m_model, [](const FileResourcesItem &i1, const FileResourcesItem &i2) { + return i1.fileName().toLower() < i2.fileName().toLower(); }); - for (const QString &fullPath : qAsConst(m_fullPathModel)) - m_fileNameModel.append(fullPath.mid(fullPath.lastIndexOf('/') + 1)); - - emit fullPathModelChanged(); - emit fileNameModelChanged(); + emit modelChanged(); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h index f0380c5a52..5f49c936cb 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h @@ -33,17 +33,47 @@ #include #include +class FileResourcesItem +{ + Q_GADGET + + Q_PROPERTY(QString absoluteFilePath READ absoluteFilePath CONSTANT) + Q_PROPERTY(QString relativeFilePath READ relativeFilePath CONSTANT) + Q_PROPERTY(QString fileName READ fileName CONSTANT) + +public: + FileResourcesItem(const QString &absoluteFilePath, + const QString &relativeFilePath, + const QString &fileName) + : m_absoluteFilePath(absoluteFilePath) + , m_relativeFilePath(relativeFilePath) + , m_fileName(fileName) + {} + + FileResourcesItem() = default; + FileResourcesItem(const FileResourcesItem &other) = default; + FileResourcesItem &operator=(const FileResourcesItem &other) = default; + + const QString &absoluteFilePath() const { return m_absoluteFilePath; } + const QString &relativeFilePath() const { return m_relativeFilePath; } + const QString &fileName() const { return m_fileName; } + +private: + QString m_absoluteFilePath; + QString m_relativeFilePath; + QString m_fileName; +}; + class FileResourcesModel : public QObject { Q_OBJECT Q_PROPERTY(QString fileName READ fileName WRITE setFileNameStr NOTIFY fileNameChanged) - Q_PROPERTY(QString filter READ filter WRITE setFilter) + Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) - Q_PROPERTY(QUrl path READ path WRITE setPath) - Q_PROPERTY(QUrl docPath READ docPath) - Q_PROPERTY(QStringList fullPathModel READ fullPathModel NOTIFY fullPathModelChanged) - Q_PROPERTY(QStringList fileNameModel READ fileNameModel NOTIFY fileNameModelChanged) + Q_PROPERTY(QUrl path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(QUrl docPath READ docPath CONSTANT) + Q_PROPERTY(QList model READ model NOTIFY modelChanged) public: explicit FileResourcesModel(QObject *parent = nullptr); @@ -57,20 +87,23 @@ public: QUrl docPath() const; void setFilter(const QString &filter); QString filter() const; - QStringList fullPathModel() const; - QStringList fileNameModel() const; + QList model() const; + void setupModel(); void refreshModel(); Q_INVOKABLE void openFileDialog(); + Q_INVOKABLE QString resolve(const QString &relative) const; + Q_INVOKABLE bool isLocal(const QString &path) const; static void registerDeclarativeType(); signals: void fileNameChanged(const QUrl &fileName); + void filterChanged(const QString &filte); void modelNodeBackendChanged(); - void fullPathModelChanged(); - void fileNameModelChanged(); + void pathChanged(const QUrl &path); + void modelChanged(); private: QVariant modelNodeBackend() const; @@ -83,8 +116,7 @@ private: QString m_filter; QString m_currentPath; QString m_lastResourcePath; - QStringList m_fullPathModel; - QStringList m_fileNameModel; + QList m_model; }; QML_DECLARE_TYPE(FileResourcesModel) -- cgit v1.2.1 From bd51b4fdc2eb080b5883ebecea4a31320aa6ae2d Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 3 Jun 2022 14:34:11 +0200 Subject: QmlDesigner: Add tooltips to UrlChooser * Add tooltips with thumbnails to UrlChooser enable preview of image formats and meshes * Add property editor image provider which makes use of the image cache * Add mesh image cache collector in order to create thumbnails for meshes and built-in primitves * Fix typo in explicit image cache image provider * Add return value in time stamp provider if provided file does not exist Change-Id: I2290d2ace87ddd90e9899e343f2ad1ecd2993fdf Reviewed-by: Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/UrlChooser.qml | 150 +++++++++++++++++++-- src/plugins/qmldesigner/CMakeLists.txt | 4 +- .../propertyeditor/propertyeditorimageprovider.cpp | 68 ++++++++++ .../propertyeditor/propertyeditorimageprovider.h | 48 +++++++ .../propertyeditor/propertyeditorqmlbackend.cpp | 13 +- .../propertyeditor/propertyeditorqmlbackend.h | 3 +- .../propertyeditor/propertyeditorview.cpp | 24 ++-- .../components/propertyeditor/propertyeditorview.h | 4 +- .../propertyeditor/quick2propertyeditorview.cpp | 7 +- .../propertyeditor/quick2propertyeditorview.h | 2 +- .../imagecache/explicitimagecacheimageprovider.cpp | 16 ++- .../imagecache/meshimagecachecollector.cpp | 112 +++++++++++++++ .../imagecache/meshimagecachecollector.h | 70 ++++++++++ .../imagecache/smallimagecacheprovider.cpp | 87 ++++++++++++ .../imagecache/smallimagecacheprovider.h | 68 ++++++++++ .../designercore/imagecache/timestampprovider.cpp | 8 +- .../qmldesigner/designercore/include/viewmanager.h | 3 +- .../qmldesigner/designercore/model/viewmanager.cpp | 7 +- src/plugins/qmldesigner/qmldesignercore.cmake | 2 + src/plugins/qmldesigner/qmldesignerplugin.cpp | 3 +- src/plugins/qmldesigner/qmldesignerplugin.qbs | 6 + .../qmldesigner/qmldesignerprojectmanager.cpp | 33 +++-- .../qmldesigner/qmldesignerprojectmanager.h | 1 + 23 files changed, 682 insertions(+), 57 deletions(-) create mode 100644 src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp create mode 100644 src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h create mode 100644 src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp create mode 100644 src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h create mode 100644 src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp create mode 100644 src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index ee80d95a96..ec246f56f2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -44,6 +44,9 @@ Row { // by QtQuick3D to add built-in primitives to the model. property var defaultItems + // Current item + property string absoluteFilePath: "" + FileResourcesModel { id: fileModel modelNodeBackendProperty: modelNodeBackend @@ -74,16 +77,64 @@ Row { visible: comboBox.hover && toolTip.text !== "" text: root.backendValue.valueToString delay: StudioTheme.Values.toolTipDelay - height: StudioTheme.Values.toolTipHeight + background: Rectangle { color: StudioTheme.Values.themeToolTipBackground border.color: StudioTheme.Values.themeToolTipOutline border.width: StudioTheme.Values.border } - contentItem: Text { - color: StudioTheme.Values.themeToolTipText - text: toolTip.text - verticalAlignment: Text.AlignVCenter + + contentItem: RowLayout { + spacing: 10 + + Item { + visible: thumbnail.status === Image.Ready + Layout.preferredWidth: 100 + Layout.preferredHeight: 100 + + Image { + id: checker + visible: !root.isMesh(root.absoluteFilePath) + anchors.fill: parent + fillMode: Image.Tile + source: "images/checkers.png" + } + + Image { + id: thumbnail + asynchronous: true + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: { + if (root.isBuiltInPrimitive(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + + root.absoluteFilePath.substring(1, root.absoluteFilePath.length) + + ".builtin" + + if (fileModel.isLocal(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + root.absoluteFilePath + + return root.absoluteFilePath + } + } + } + + ColumnLayout { + Text { + text: root.fileName(toolTip.text) + color: StudioTheme.Values.themeToolTipText + font: toolTip.font + } + + Text { + Layout.fillWidth: true + text: root.isBuiltInPrimitive(toolTip.text) ? qsTr("Built-in primitive") + : toolTip.text + font: toolTip.font + color: StudioTheme.Values.themeToolTipText + wrapMode: Text.WordWrap + } + } } } @@ -155,16 +206,62 @@ Row { visible: delegateRoot.hovered text: delegateRoot.relativeFilePath delay: StudioTheme.Values.toolTipDelay - height: StudioTheme.Values.toolTipHeight + background: Rectangle { color: StudioTheme.Values.themeToolTipBackground border.color: StudioTheme.Values.themeToolTipOutline border.width: StudioTheme.Values.border } - contentItem: Text { - color: StudioTheme.Values.themeToolTipText - text: itemToolTip.text - verticalAlignment: Text.AlignVCenter + + contentItem: RowLayout { + spacing: 10 + + Item { + visible: delegateThumbnail.status === Image.Ready + Layout.preferredWidth: 100 + Layout.preferredHeight: 100 + + Image { + id: delegateChecker + visible: !root.isMesh(delegateRoot.absoluteFilePath) + anchors.fill: parent + fillMode: Image.Tile + source: "images/checkers.png" + } + + Image { + id: delegateThumbnail + asynchronous: true + anchors.fill: parent + fillMode: Image.PreserveAspectFit + source: { + if (root.isBuiltInPrimitive(delegateRoot.name)) + return "image://qmldesigner_thumbnails/" + + delegateRoot.name.substring(1, delegateRoot.name.length) + + ".builtin" + + return "image://qmldesigner_thumbnails/" + delegateRoot.absoluteFilePath + } + } + } + + ColumnLayout { + Text { + text: delegateRoot.name + color: StudioTheme.Values.themeToolTipText + font: delegateToolTip.font + } + + Text { + Layout.fillWidth: true + text: root.isBuiltInPrimitive(delegateToolTip.text) + ? qsTr("Built-in primitive") + : delegateToolTip.text + font: delegateToolTip.font + color: StudioTheme.Values.themeToolTipText + wrapMode: Text.WordWrap + } + } } } } @@ -235,6 +332,10 @@ Row { inputValue = comboBox.items.get(index).model.relativeFilePath root.backendValue.value = inputValue + + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + comboBox.dirty = false } @@ -259,6 +360,9 @@ Row { if (root.backendValue.value !== inputValue) root.backendValue.value = inputValue + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + comboBox.dirty = false } @@ -275,6 +379,23 @@ Row { } } + function isBuiltInPrimitive(value) { + return value.startsWith('#') + } + + function isMesh(value) { + return root.isBuiltInPrimitive(value) + || root.hasFileExtension(root.fileName(value), "mesh") + } + + function hasFileExtension(fileName, extension) { + return fileName.split('.').pop() === extension + } + + function fileName(filePath) { + return filePath.substr(filePath.lastIndexOf('/') + 1) + } + function createModel() { // Build the combobox model comboBox.listModel.clear() @@ -322,6 +443,9 @@ Row { Component.onCompleted: { root.createModel() comboBox.updateTextValue() + + if (!root.backendValue.isBound) + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) } function indexOf(model, criteria) { @@ -340,7 +464,7 @@ Row { if (comboBox.popup.opened && !root.backendValue.isBound) { var index = root.indexOf(comboBox.items, function(item) { - return item.fullPath === root.backendValue.value + return item.relativeFilePath === root.backendValue.value }) if (index !== -1) { @@ -359,8 +483,10 @@ Row { iconColor: root.textColor onClicked: { fileModel.openFileDialog() - if (fileModel.fileName !== "") + if (fileModel.fileName !== "") { root.backendValue.value = fileModel.fileName + root.absoluteFilePath = fileModel.resolve(root.backendValue.value) + } } } } diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 1d56e323e9..1ac2f477bf 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -302,6 +302,7 @@ extend_qtc_plugin(QmlDesigner gradientpresetitem.cpp gradientpresetitem.h gradientpresetlistmodel.cpp gradientpresetlistmodel.h propertyeditorcontextobject.cpp propertyeditorcontextobject.h + propertyeditorimageprovider.cpp propertyeditorimageprovider.h propertyeditorqmlbackend.cpp propertyeditorqmlbackend.h propertyeditortransaction.cpp propertyeditortransaction.h propertyeditorvalue.cpp propertyeditorvalue.h @@ -389,7 +390,8 @@ extend_qtc_plugin(QmlDesigner SOURCES explicitimagecacheimageprovider.cpp explicitimagecacheimageprovider.h - + smallimagecacheprovider.cpp + smallimagecacheprovider.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp new file mode 100644 index 0000000000..2037e1509e --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "propertyeditorimageprovider.h" +#include "assetslibrarymodel.h" + +#include +#include +#include + +#include +#include + +namespace QmlDesigner { + +QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QString &id, + const QSize &requestedSize) +{ + const QString suffix = "*." + id.split('.').last().toLower(); + + if (suffix == "*.mesh") + return m_smallImageCacheProvider.requestImageResponse(id, requestedSize); + + if (suffix == "*.builtin") + return m_smallImageCacheProvider.requestImageResponse("#" + id.split('.').first(), + requestedSize); + + QImage image; + auto response = std::make_unique(image); + + QMetaObject::invokeMethod( + response.get(), + [response = QPointer(response.get()), image, suffix, id] { + if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) + response->setImage(QImage(Utils::StyleHelper::dpiSpecificImageFile(id))); + else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) + response->setImage(HdrImage{id}.image()); + else + response->abort(); + }, + Qt::QueuedConnection); + + return response.release(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h new file mode 100644 index 0000000000..bb883e4450 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "imagecache/smallimagecacheprovider.h" + +#include + +namespace QmlDesigner { + +class PropertyEditorImageProvider : public QQuickAsyncImageProvider +{ +public: + PropertyEditorImageProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {}) + : m_smallImageCacheProvider(imageCache, defaultImage) + {} + + QQuickImageResponse *requestImageResponse(const QString &id, + const QSize &requestedSize) override; + +private: + SmallImageCacheProvider m_smallImageCacheProvider; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index c73290bf76..d00957fa8c 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -95,9 +95,12 @@ static QObject *variantToQObject(const QVariant &value) namespace QmlDesigner { -PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor) : - m_view(new Quick2PropertyEditorView), m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor)), m_dummyPropertyEditorValue(new PropertyEditorValue()), - m_contextObject(new PropertyEditorContextObject()) +PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor, + AsynchronousImageCache &imageCache) + : m_view(new Quick2PropertyEditorView(imageCache)) + , m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor)) + , m_dummyPropertyEditorValue(new PropertyEditorValue()) + , m_contextObject(new PropertyEditorContextObject()) { m_view->engine()->setOutputWarningsToStandardError(QmlDesignerPlugin::instance() ->settings().value(DesignerSettingsKey::SHOW_PROPERTYEDITOR_WARNINGS).toBool()); @@ -115,7 +118,9 @@ PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyE PropertyEditorQmlBackend::~PropertyEditorQmlBackend() = default; -void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name, PropertyEditorView *propertyEditor, const QString &type) +void PropertyEditorQmlBackend::setupPropertyEditorValue(const PropertyName &name, + PropertyEditorView *propertyEditor, + const QString &type) { QmlDesigner::PropertyName propertyName(name); propertyName.replace('.', '_'); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h index 983a917f2f..7abfc550d8 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h @@ -50,7 +50,8 @@ class PropertyEditorQmlBackend public: - PropertyEditorQmlBackend(PropertyEditorView *propertyEditor); + PropertyEditorQmlBackend(PropertyEditorView *propertyEditor, + class AsynchronousImageCache &imageCache); ~PropertyEditorQmlBackend(); void setup(const QmlObjectNode &fxObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 7f190b6288..586c4dec05 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -69,16 +69,16 @@ static bool propertyIsAttachedLayoutProperty(const PropertyName &propertyName) return propertyName.contains("Layout."); } -PropertyEditorView::PropertyEditorView(QWidget *parent) : - AbstractView(parent), - m_parent(parent), - m_updateShortcut(nullptr), - m_timerId(0), - m_stackedWidget(new PropertyEditorWidget(parent)), - m_qmlBackEndForCurrentType(nullptr), - m_locked(false), - m_setupCompleted(false), - m_singleShotTimer(new QTimer(this)) +PropertyEditorView::PropertyEditorView(AsynchronousImageCache &imageCache) + : AbstractView() + , m_imageCache(imageCache) + , m_updateShortcut(nullptr) + , m_timerId(0) + , m_stackedWidget(new PropertyEditorWidget()) + , m_qmlBackEndForCurrentType(nullptr) + , m_locked(false) + , m_setupCompleted(false) + , m_singleShotTimer(new QTimer(this)) { m_qmlDir = PropertyEditorQmlBackend::propertyEditorResourcesPath(); @@ -117,7 +117,7 @@ void PropertyEditorView::setupPane(const TypeName &typeName) PropertyEditorQmlBackend *qmlBackend = m_qmlBackendHash.value(qmlFile.toString()); if (!qmlBackend) { - qmlBackend = new PropertyEditorQmlBackend(this); + qmlBackend = new PropertyEditorQmlBackend(this, m_imageCache); qmlBackend->initialSetup(typeName, qmlSpecificsFile, this); qmlBackend->setSource(qmlFile); @@ -484,7 +484,7 @@ void PropertyEditorView::setupQmlBackend() QString currentStateName = currentState().isBaseState() ? currentState().name() : QStringLiteral("invalid state"); if (!currentQmlBackend) { - currentQmlBackend = new PropertyEditorQmlBackend(this); + currentQmlBackend = new PropertyEditorQmlBackend(this, m_imageCache); m_stackedWidget->addWidget(currentQmlBackend->widget()); m_qmlBackendHash.insert(qmlFile.toString(), currentQmlBackend); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 06e86fd57c..3bbe502050 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -51,7 +51,7 @@ class PropertyEditorView: public AbstractView Q_OBJECT public: - PropertyEditorView(QWidget *parent = nullptr); + PropertyEditorView(class AsynchronousImageCache &imageCache); ~PropertyEditorView() override; bool hasWidget() const override; @@ -119,8 +119,8 @@ private: //functions bool noValidSelection() const; private: //variables + AsynchronousImageCache &m_imageCache; ModelNode m_selectedNode; - QWidget *m_parent; QShortcut *m_updateShortcut; int m_timerId; PropertyEditorWidget* m_stackedWidget; diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp index 35b74111d1..08358353c1 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp @@ -36,6 +36,7 @@ #include "gradientpresetdefaultlistmodel.h" #include "itemfiltermodel.h" #include "propertyeditorcontextobject.h" +#include "propertyeditorimageprovider.h" #include "propertyeditorqmlbackend.h" #include "propertyeditorvalue.h" #include "qmlanchorbindingproxy.h" @@ -45,11 +46,13 @@ namespace QmlDesigner { -Quick2PropertyEditorView::Quick2PropertyEditorView(QWidget *parent) : - QQuickWidget(parent) +Quick2PropertyEditorView::Quick2PropertyEditorView(AsynchronousImageCache &imageCache) + : QQuickWidget() { setResizeMode(QQuickWidget::SizeRootObjectToView); Theme::setupTheme(engine()); + engine()->addImageProvider("qmldesigner_thumbnails", + new PropertyEditorImageProvider(imageCache)); } void Quick2PropertyEditorView::registerQmlTypes() diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h index 7bfc6f1558..ca92f2a6ef 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h @@ -35,7 +35,7 @@ class Quick2PropertyEditorView : public QQuickWidget Q_OBJECT public: - explicit Quick2PropertyEditorView(QWidget *parent = nullptr); + explicit Quick2PropertyEditorView(class AsynchronousImageCache &imageCache); static void registerQmlTypes(); }; diff --git a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp index d94221f382..57a96f1c1c 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp @@ -30,12 +30,12 @@ #include #include -namespace QmlDesigner { +namespace { -class ImageRespose : public QQuickImageResponse +class ImageResponse : public QQuickImageResponse { public: - ImageRespose(const QImage &defaultImage) + ImageResponse(const QImage &defaultImage) : m_image(defaultImage) {} @@ -57,14 +57,18 @@ private: QImage m_image; }; +} // namespace + +namespace QmlDesigner { + QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const QString &id, const QSize &) { - auto response = std::make_unique(m_defaultImage); + auto response = std::make_unique<::ImageResponse>(m_defaultImage); m_cache.requestImage( id, - [response = QPointer(response.get())](const QImage &image) { + [response = QPointer<::ImageResponse>(response.get())](const QImage &image) { QMetaObject::invokeMethod( response, [response, image] { @@ -73,7 +77,7 @@ QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const }, Qt::QueuedConnection); }, - [response = QPointer(response.get())](ImageCache::AbortReason abortReason) { + [response = QPointer<::ImageResponse>(response.get())](ImageCache::AbortReason abortReason) { QMetaObject::invokeMethod( response, [response, abortReason] { diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp new file mode 100644 index 0000000000..7602ee7a11 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "meshimagecachecollector.h" +#include "imagecacheconnectionmanager.h" + +#include +#include +#include + +#include + +namespace QmlDesigner { + +MeshImageCacheCollector::MeshImageCacheCollector( + ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, + ImageCacheCollectorNullImageHandling nullImageHandling) + : m_imageCacheCollector(connectionManager, + captureImageMinimumSize, + captureImageMaximumSize, + nullImageHandling) +{} + +MeshImageCacheCollector::~MeshImageCacheCollector() = default; + +void MeshImageCacheCollector::start(Utils::SmallStringView name, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData, + CaptureCallback captureCallback, + AbortCallback abortCallback) +{ + QTemporaryFile file(QDir::tempPath() + "/mesh-XXXXXX.qml"); + if (file.open()) { + QString qtQuickVersion; + QString qtQuick3DVersion; + QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit()); + if (qtVersion && qtVersion->qtVersion() < QtSupport::QtVersionNumber(6, 0, 0)) { + qtQuickVersion = "2.15"; + qtQuick3DVersion = "1.15"; + } + + QString content{ + R"(import QtQuick %1 + import QtQuick3D %2 + Node { + Model { + source: "%3" + DefaultMaterial { id: defaultMaterial; diffuseColor: "#ff999999" } + materials: [ defaultMaterial ] + } + })"}; + + content = content.arg(qtQuickVersion, qtQuick3DVersion, QString(name)); + + file.write(content.toUtf8()); + file.close(); + } + + Utils::PathString path{file.fileName()}; + + m_imageCacheCollector.start(path, state, auxiliaryData, captureCallback, abortCallback); +} + +std::pair MeshImageCacheCollector::createImage(Utils::SmallStringView, + Utils::SmallStringView, + const ImageCache::AuxiliaryData &) +{ + return {}; +} + +QIcon MeshImageCacheCollector::createIcon(Utils::SmallStringView, + Utils::SmallStringView, + const ImageCache::AuxiliaryData &) +{ + return {}; +} + +void MeshImageCacheCollector::setTarget(ProjectExplorer::Target *target) +{ + m_imageCacheCollector.setTarget(target); +} + +ProjectExplorer::Target *MeshImageCacheCollector::target() const +{ + return m_imageCacheCollector.target(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h new file mode 100644 index 0000000000..c2cc63bfd9 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "imagecachecollectorinterface.h" +#include "imagecachecollector.h" + +namespace ProjectExplorer { +class Target; +} + +namespace QmlDesigner { + +class ImageCacheConnectionManager; + +class MeshImageCacheCollector final : public ImageCacheCollectorInterface +{ +public: + MeshImageCacheCollector(ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, + ImageCacheCollectorNullImageHandling nullImageHandling = {}); + + ~MeshImageCacheCollector(); + + void start(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData, + CaptureCallback captureCallback, + AbortCallback abortCallback) override; + + std::pair createImage(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData) override; + + QIcon createIcon(Utils::SmallStringView filePath, + Utils::SmallStringView state, + const ImageCache::AuxiliaryData &auxiliaryData) override; + + void setTarget(ProjectExplorer::Target *target); + ProjectExplorer::Target *target() const; + +private: + ImageCacheCollector m_imageCacheCollector; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp new file mode 100644 index 0000000000..36bd55c2fe --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "smallimagecacheprovider.h" + +#include + +#include + +namespace QmlDesigner { + +QQuickTextureFactory *ImageResponse::textureFactory() const +{ + return QQuickTextureFactory::textureFactoryForImage(m_image); +} + +void ImageResponse::setImage(const QImage &image) +{ + m_image = image; + + emit finished(); +} + +void ImageResponse::abort() +{ + emit finished(); +} + +QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString &id, const QSize &) +{ + auto response = std::make_unique(m_defaultImage); + + m_cache.requestSmallImage( + id, + [response = QPointer(response.get())](const QImage &image) { + QMetaObject::invokeMethod( + response, + [response, image] { + if (response) + response->setImage(image); + }, + Qt::QueuedConnection); + }, + [response = QPointer(response.get())]( + ImageCache::AbortReason abortReason) { + QMetaObject::invokeMethod( + response, + [response, abortReason] { + switch (abortReason) { + case ImageCache::AbortReason::Failed: + if (response) + response->abort(); + break; + case ImageCache::AbortReason::Abort: + response->cancel(); + break; + } + }, + Qt::QueuedConnection); + }); + + return response.release(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h new file mode 100644 index 0000000000..05674143e6 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include + +namespace QmlDesigner { + +class AsynchronousImageCache; + +class ImageResponse : public QQuickImageResponse +{ +public: + ImageResponse(const QImage &defaultImage) + : m_image(defaultImage) + {} + + QQuickTextureFactory *textureFactory() const override; + + void setImage(const QImage &image); + + void abort(); + +private: + QImage m_image; +}; + +class SmallImageCacheProvider : public QQuickAsyncImageProvider +{ +public: + SmallImageCacheProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {}) + : m_cache{imageCache} + , m_defaultImage(defaultImage) + {} + + QQuickImageResponse *requestImageResponse(const QString &id, + const QSize &requestedSize) override; + +private: + AsynchronousImageCache &m_cache; + QImage m_defaultImage; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp index 99573f175f..67ccc7b75c 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp @@ -28,11 +28,17 @@ #include #include +#include + namespace QmlDesigner { Sqlite::TimeStamp TimeStampProvider::timeStamp(Utils::SmallStringView name) const { - return QFileInfo{QString{name}}.lastModified().toSecsSinceEpoch(); + QFileInfo info{QString{name}}; + if (info.exists()) + return info.lastModified().toSecsSinceEpoch(); + + return {std::numeric_limits::max()}; } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index dd77c07f45..1be785655a 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -51,7 +51,8 @@ class ViewManagerData; class QMLDESIGNERCORE_EXPORT ViewManager { public: - ViewManager(class AsynchronousImageCache &imageCache); + ViewManager(class AsynchronousImageCache &imageCache, + class AsynchronousImageCache &meshImageCache); ~ViewManager(); void attachRewriterView(); diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index 8e96507cd5..2896c1571d 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -62,8 +62,9 @@ static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg) class ViewManagerData { public: - ViewManagerData(AsynchronousImageCache &imageCache) + ViewManagerData(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache) : itemLibraryView(imageCache) + , propertyEditorView(meshImageCache) {} InteractiveConnectionManager connectionManager; @@ -94,8 +95,8 @@ static CrumbleBar *crumbleBar() { return QmlDesignerPlugin::instance()->mainWidget()->crumbleBar(); } -ViewManager::ViewManager(AsynchronousImageCache &imageCache) - : d(std::make_unique(imageCache)) +ViewManager::ViewManager(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache) + : d(std::make_unique(imageCache, meshImageCache)) { d->formEditorView.setGotoErrorCallback([this](int line, int column) { d->textEditorView.gotoCursorPosition(line, column); diff --git a/src/plugins/qmldesigner/qmldesignercore.cmake b/src/plugins/qmldesigner/qmldesignercore.cmake index 83870a36fe..9a2b0b6f3e 100644 --- a/src/plugins/qmldesigner/qmldesignercore.cmake +++ b/src/plugins/qmldesigner/qmldesignercore.cmake @@ -123,6 +123,8 @@ function(extend_with_qmldesigner_core target_name) imagecache/imagecachegeneratorinterface.h imagecache/imagecachestorage.h imagecache/imagecachestorageinterface.h + imagecache/meshimagecachecollector.cpp + imagecache/meshimagecachecollector.h imagecache/synchronousimagecache.cpp imagecache/timestampprovider.cpp imagecache/timestampprovider.h diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index e6f40d14fc..5ab50135eb 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -137,7 +137,8 @@ class QmlDesignerPluginPrivate { public: QmlDesignerProjectManager projectManager; - ViewManager viewManager{projectManager.asynchronousImageCache()}; + ViewManager viewManager{projectManager.asynchronousImageCache(), + projectManager.asynchronousMeshImageCache()}; DocumentManager documentManager; ShortCutManager shortCutManager; SettingsPage settingsPage; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index ed113d4fe5..5266a146a3 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -442,6 +442,10 @@ Project { "imagecache/imagecachegenerator.h", "imagecache/imagecachestorageinterface.h", "imagecache/imagecachestorage.h", + "imagecache/meshimagecachecollector.cpp", + "imagecache/meshimagecachecollector.h", + "imagecache/smallimagecacheprovider.cpp", + "imagecache/smallimagecacheprovider.h", "imagecache/synchronousimagecache.cpp", "imagecache/timestampproviderinterface.h", "imagecache/timestampprovider.h", @@ -737,6 +741,8 @@ Project { "propertyeditor/gradientpresetlistmodel.h", "propertyeditor/propertyeditorcontextobject.cpp", "propertyeditor/propertyeditorcontextobject.h", + "propertyeditor/propertyeditorimageprovider.cpp", + "propertyeditor/propertyeditorimageprovider.h", "propertyeditor/propertyeditortransaction.cpp", "propertyeditor/propertyeditortransaction.h", "propertyeditor/propertyeditorvalue.cpp", diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 43070221bc..90e54ba65b 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -51,7 +51,8 @@ #include #include #include -#include +#include +#include #include @@ -79,7 +80,7 @@ QString defaultImagePath() return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem()); } -class TimeStampProvider : public TimeStampProviderInterface +class PreviewTimeStampProvider : public TimeStampProviderInterface { public: Sqlite::TimeStamp timeStamp(Utils::SmallStringView) const override @@ -102,15 +103,18 @@ class QmlDesignerProjectManager::ImageCacheData { public: Sqlite::Database database{Utils::PathString{ - Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, + Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, Sqlite::JournalMode::Wal, Sqlite::LockingMode::Normal}; ImageCacheStorage storage{database}; ImageCacheConnectionManager connectionManager; - ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}}; - ImageCacheGenerator generator{collector, storage}; + MeshImageCacheCollector meshImageCollector{connectionManager, QSize{300, 300}, QSize{600, 600}}; + ImageCacheGenerator meshGenerator{meshImageCollector, storage}; + ImageCacheCollector nodeInstanceCollector{connectionManager, QSize{300, 300}, QSize{600, 600}}; + ImageCacheGenerator nodeInstanceGenerator{nodeInstanceCollector, storage}; TimeStampProvider timeStampProvider; - AsynchronousImageCache asynchronousImageCache{storage, generator, timeStampProvider}; + AsynchronousImageCache asynchronousImageCache{storage, nodeInstanceGenerator, timeStampProvider}; + AsynchronousImageCache asynchronousMeshImageCache{storage, meshGenerator, timeStampProvider}; }; class QmlDesignerProjectManager::PreviewImageCacheData @@ -135,7 +139,7 @@ public: QSize{300, 300}, QSize{1000, 1000}, ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; - TimeStampProvider timeStampProvider; + PreviewTimeStampProvider timeStampProvider; AsynchronousImageFactory factory; ::ProjectExplorer::Target *activeTarget = nullptr; }; @@ -180,6 +184,11 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache() return imageCacheData()->asynchronousImageCache; } +AsynchronousImageCache &QmlDesignerProjectManager::asynchronousMeshImageCache() +{ + return imageCacheData()->asynchronousMeshImageCache; +} + void QmlDesignerProjectManager::editorOpened(::Core::IEditor *) {} void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *) @@ -218,17 +227,21 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache m_imageCacheData = std::make_unique(); auto setTargetInImageCache = [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { - if (target == imageCacheData->collector.target()) + if (target == imageCacheData->nodeInstanceCollector.target()) return; if (target) imageCacheData->asynchronousImageCache.clean(); - imageCacheData->collector.setTarget(target); + // TODO wrap in function in image cache data + imageCacheData->meshImageCollector.setTarget(target); + imageCacheData->nodeInstanceCollector.setTarget(target); }; if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { - m_imageCacheData->collector.setTarget(project->activeTarget()); + // TODO wrap in function in image cache data + m_imageCacheData->meshImageCollector.setTarget(project->activeTarget()); + m_imageCacheData->nodeInstanceCollector.setTarget(project->activeTarget()); QObject::connect(project, &ProjectExplorer::Project::activeTargetChanged, this, diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h index 6b94fa9e6f..68cd809be3 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h @@ -59,6 +59,7 @@ public: void registerPreviewImageProvider(QQmlEngine *engine) const; class AsynchronousImageCache &asynchronousImageCache(); + class AsynchronousImageCache &asynchronousMeshImageCache(); private: void editorOpened(::Core::IEditor *editor); -- cgit v1.2.1 From 519f6fbda11cd6849e2ddbc804e20af2d2030012 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 3 Jun 2022 13:40:39 +0200 Subject: QmlDesigner: Add drag'n'drop to PropertyEditorView * Implement drag and drop for UrlChooser and FontComboBox * Change the style of controls accepting drag payload and drag hovering. Utilize states for those styles. * Fix aspect ratio of drag pixmap * Fix issue that causes drag to continue after pressing the escape key Change-Id: I5cf67175abe936e60e8af00fa8c2f7a2dec355b3 Reviewed-by: Thomas Hartmann Reviewed-by: Reviewed-by: Mahmoud Badri --- .../imports/HelperWidgets/FontComboBox.qml | 34 +++++++++++++++-- .../imports/HelperWidgets/UrlChooser.qml | 27 ++++++++++++- .../imports/StudioControls/CheckIndicator.qml | 13 ++++++- .../imports/StudioControls/ComboBox.qml | 44 +++++++++++++--------- .../imports/StudioControls/ComboBoxInput.qml | 17 ++++++--- .../imports/StudioControls/FilterComboBox.qml | 32 +++++++++++++++- .../assetslibrary/assetslibraryiconprovider.cpp | 2 +- .../assetslibrary/assetslibrarywidget.cpp | 4 -- .../components/itemlibrary/itemlibrarywidget.cpp | 4 -- .../propertyeditor/propertyeditorcontextobject.cpp | 13 +++++++ .../propertyeditor/propertyeditorcontextobject.h | 8 ++++ .../propertyeditor/propertyeditorvalue.cpp | 2 + .../propertyeditor/propertyeditorview.cpp | 27 ++++++++++--- .../components/propertyeditor/propertyeditorview.h | 3 ++ .../qmldesigner/designercore/model/model.cpp | 4 +- 15 files changed, 191 insertions(+), 43 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 6d9f56b178..8c05fa2f87 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -36,6 +36,7 @@ StudioControls.ComboBox { property string fontFilter: "*.ttf *.otf" property bool showExtendedFunctionButton: true + hasActiveDrag: activeDragSuffix !== "" && root.fontFilter.includes(activeDragSuffix) labelColor: colorLogic.textColor editable: true @@ -47,16 +48,43 @@ StudioControls.ComboBox { filter: root.fontFilter } + DropArea { + id: dropArea + + anchors.fill: parent + + property string assetPath: "" + + onEntered: function(drag) { + dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0] + drag.accepted = root.hasActiveDrag + root.hasActiveHoverDrag = drag.accepted + } + + onExited: root.hasActiveHoverDrag = false + + onDropped: function(drop) { + drop.accepted = root.hasActiveHoverDrag + var fontLoader = root.createFontLoader("file:///" + dropArea.assetPath) + root.backendValue.value = fontLoader.name + root.currentIndex = root.find(root.backendValue.value) + root.hasActiveHoverDrag = false + root.backendValue.commitDrop(dropArea.assetPath) + } + } + function createFontLoader(fontUrl) { return Qt.createQmlObject('import QtQuick 2.0; FontLoader { source: "' + fontUrl + '"; }', root, "dynamicFontLoader") } function setupModel() { - var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] // default fonts + // default fonts + var familyNames = ["Arial", "Times New Roman", "Courier", "Verdana", "Tahoma"] for (var i = 0; i < fileModel.model.length; ++i) { // add custom fonts - var fontLoader = createFontLoader(fileModel.docPath + "/" + fileModel.model[i].relativeFilePath) + var fontLoader = root.createFontLoader(fileModel.docPath + "/" + + fileModel.model[i].relativeFilePath) familyNames.push(fontLoader.name) } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index ec246f56f2..ecb4936bd7 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -63,6 +63,7 @@ Row { property ListModel listModel: ListModel {} + hasActiveDrag: activeDragSuffix !== "" && root.filter.includes(activeDragSuffix) implicitWidth: StudioTheme.Values.singleControlColumnWidth + StudioTheme.Values.actionIndicatorWidth width: implicitWidth @@ -72,6 +73,30 @@ Row { // when the combobox is closed by focusing on some other control. property int hoverIndex: -1 + DropArea { + id: dropArea + + anchors.fill: parent + + property string assetPath: "" + + onEntered: function(drag) { + dropArea.assetPath = drag.getDataAsString(drag.keys[0]).split(",")[0] + drag.accepted = comboBox.hasActiveDrag + comboBox.hasActiveHoverDrag = drag.accepted + } + + onExited: comboBox.hasActiveHoverDrag = false + + onDropped: function(drop) { + drop.accepted = comboBox.hasActiveHoverDrag + comboBox.editText = dropArea.assetPath + comboBox.accepted() + comboBox.hasActiveHoverDrag = false + root.backendValue.commitDrop(dropArea.assetPath) + } + } + ToolTip { id: toolTip visible: comboBox.hover && toolTip.text !== "" diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml index 2d3bb74c3f..5af0f5fe6e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml @@ -37,6 +37,9 @@ Rectangle { property bool pressed: checkIndicatorMouseArea.containsPress property bool checked: false + property bool hasActiveDrag: myControl.hasActiveDrag ?? false + property bool hasActiveHoverDrag: myControl.hasActiveHoverDrag ?? false + color: StudioTheme.Values.themeControlBackground border.width: 0 @@ -79,12 +82,20 @@ Rectangle { name: "default" when: myControl.enabled && checkIndicator.enabled && !myControl.edit && !checkIndicator.hover && !myControl.hover && !myControl.drag - && !checkIndicator.checked + && !checkIndicator.checked && !checkIndicator.hasActiveDrag PropertyChanges { target: checkIndicator color: StudioTheme.Values.themeControlBackground } }, + State { + name: "dragHover" + when: myControl.enabled && checkIndicator.hasActiveHoverDrag + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: myControl.enabled && checkIndicator.enabled && !myControl.drag diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index 70cbdf000e..f57a1c404e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -50,9 +50,6 @@ T.ComboBox { property alias textInput: comboBoxInput - property int borderWidth: myComboBox.hasActiveHoverDrag ? StudioTheme.Values.borderHover - : StudioTheme.Values.border - signal compressedActivated(int index, int reason) enum ActivatedReason { EditingFinished, Other } @@ -61,7 +58,7 @@ T.ComboBox { height: StudioTheme.Values.defaultControlHeight leftPadding: actionIndicator.width - rightPadding: popupIndicator.width + myComboBox.borderWidth + rightPadding: popupIndicator.width + StudioTheme.Values.border font.pixelSize: StudioTheme.Values.myFontSize wheelEnabled: false @@ -91,7 +88,6 @@ T.ComboBox { myControl: myComboBox text: myComboBox.editText - borderWidth: myComboBox.borderWidth onEditingFinished: { comboBoxInput.deselect() @@ -113,16 +109,16 @@ T.ComboBox { myControl: myComboBox myPopup: myComboBox.popup x: comboBoxInput.x + comboBoxInput.width - y: myComboBox.borderWidth - width: StudioTheme.Values.checkIndicatorWidth - myComboBox.borderWidth - height: StudioTheme.Values.checkIndicatorHeight - myComboBox.borderWidth * 2 + y: StudioTheme.Values.border + width: StudioTheme.Values.checkIndicatorWidth - StudioTheme.Values.border + height: StudioTheme.Values.checkIndicatorHeight - StudioTheme.Values.border * 2 } background: Rectangle { id: comboBoxBackground color: StudioTheme.Values.themeControlBackground border.color: StudioTheme.Values.themeControlOutline - border.width: myComboBox.borderWidth + border.width: StudioTheme.Values.border x: actionIndicator.width width: myComboBox.width - actionIndicator.width height: myComboBox.height @@ -149,7 +145,7 @@ T.ComboBox { width: comboBoxPopup.width - comboBoxPopup.leftPadding - comboBoxPopup.rightPadding - (comboBoxPopupScrollBar.visible ? comboBoxPopupScrollBar.contentItem.implicitWidth + 2 : 0) // TODO Magic number - height: StudioTheme.Values.height - 2 * myComboBox.borderWidth + height: StudioTheme.Values.height - 2 * StudioTheme.Values.border padding: 0 enabled: model.enabled === undefined ? true : model.enabled @@ -203,9 +199,9 @@ T.ComboBox { popup: T.Popup { id: comboBoxPopup - x: actionIndicator.width + myComboBox.borderWidth + x: actionIndicator.width + StudioTheme.Values.border y: myComboBox.height - width: myComboBox.width - actionIndicator.width - myComboBox.borderWidth * 2 + width: myComboBox.width - actionIndicator.width - StudioTheme.Values.border * 2 // TODO Setting the height on the popup solved the problem with the popup of height 0, // but it has the problem that it sometimes extend over the border of the actual window // and is then cut off. @@ -213,7 +209,7 @@ T.ComboBox { + comboBoxPopup.bottomPadding, myComboBox.Window.height - topMargin - bottomMargin, StudioTheme.Values.maxComboBoxPopupHeight) - padding: myComboBox.borderWidth + padding: StudioTheme.Values.border margins: 0 // If not defined margin will be -1 closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside @@ -245,7 +241,7 @@ T.ComboBox { State { name: "default" when: myComboBox.enabled && !myComboBox.hover && !myComboBox.edit && !myComboBox.open - && !myComboBox.activeFocus + && !myComboBox.activeFocus && !myComboBox.hasActiveDrag PropertyChanges { target: myComboBox wheelEnabled: false @@ -257,9 +253,23 @@ T.ComboBox { PropertyChanges { target: comboBoxBackground color: StudioTheme.Values.themeControlBackground - border.color: myComboBox.hasActiveDrag ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeControlOutline - border.width: myComboBox.borderWidth + } + }, + State { + name: "acceptsDrag" + when: myComboBox.enabled && myComboBox.hasActiveDrag && !myComboBox.hasActiveHoverDrag + PropertyChanges { + target: comboBoxBackground + border.color: StudioTheme.Values.themeControlOutlineInteraction + } + }, + State { + name: "dragHover" + when: myComboBox.enabled && myComboBox.hasActiveHoverDrag + PropertyChanges { + target: comboBoxBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeControlOutlineInteraction } }, // This state is intended for ComboBoxes which aren't editable, but have focus e.g. via diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml index c6b91dc1ad..e259687698 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml @@ -34,7 +34,6 @@ TextInput { property bool edit: textInput.activeFocus property bool hover: mouseArea.containsMouse && textInput.enabled - property int borderWidth: StudioTheme.Values.border z: 2 font: myControl.font @@ -56,11 +55,11 @@ TextInput { Rectangle { id: textInputBackground - x: textInput.borderWidth - y: textInput.borderWidth + x: StudioTheme.Values.border + y: StudioTheme.Values.border z: -1 width: textInput.width - height: StudioTheme.Values.height - textInput.borderWidth * 2 + height: StudioTheme.Values.height - StudioTheme.Values.border * 2 color: StudioTheme.Values.themeControlBackground border.width: 0 } @@ -94,7 +93,7 @@ TextInput { State { name: "default" when: myControl.enabled && !textInput.edit && !textInput.hover && !myControl.hover - && !myControl.open + && !myControl.open && !myControl.hasActiveDrag PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackground @@ -105,6 +104,14 @@ TextInput { acceptedButtons: Qt.LeftButton } }, + State { + name: "dragHover" + when: myControl.enabled && myControl.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: myControl.hover && !textInput.hover && !textInput.edit && !myControl.open diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml index 30142652ab..c41fe060e5 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml @@ -87,6 +87,9 @@ Item { property alias popupScrollBar: popupScrollBar property alias popupMouseArea: popupMouseArea + property bool hasActiveDrag: false // an item that can be dropped here is being dragged + property bool hasActiveHoverDrag: false // an item that can be dropped her is being hovered on top + width: StudioTheme.Values.defaultControlWidth height: StudioTheme.Values.defaultControlHeight implicitHeight: StudioTheme.Values.defaultControlHeight @@ -468,9 +471,11 @@ Item { State { name: "default" when: root.enabled && !textInput.edit && !root.hover && !root.open + && !root.hasActiveDrag PropertyChanges { target: textInputBackground color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline } PropertyChanges { target: textInputMouseArea @@ -478,6 +483,23 @@ Item { acceptedButtons: Qt.LeftButton } }, + State { + name: "acceptsDrag" + when: root.enabled && root.hasActiveDrag && !root.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + border.color: StudioTheme.Values.themeInteraction + } + }, + State { + name: "dragHover" + when: root.enabled && root.hasActiveHoverDrag + PropertyChanges { + target: textInputBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeInteraction + } + }, State { name: "globalHover" when: root.hover && !textInput.hover && !textInput.edit && !root.open @@ -585,12 +607,20 @@ Item { name: "default" when: root.enabled && checkIndicator.enabled && !root.edit && !checkIndicator.hover && !root.hover - && !checkIndicator.checked + && !checkIndicator.checked && !root.hasActiveHoverDrag PropertyChanges { target: checkIndicator color: StudioTheme.Values.themeControlBackground } }, + State { + name: "dragHover" + when: root.enabled && root.hasActiveHoverDrag + PropertyChanges { + target: checkIndicator + color: StudioTheme.Values.themeControlBackgroundInteraction + } + }, State { name: "globalHover" when: root.enabled && checkIndicator.enabled diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp index 9d11d26400..943693f223 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp @@ -75,7 +75,7 @@ QPixmap AssetsLibraryIconProvider::requestPixmap(const QString &id, QSize *size, pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); if (requestedSize.isValid()) - return pixmap.scaled(requestedSize); + return pixmap.scaled(requestedSize, Qt::KeepAspectRatio); return pixmap; } diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 7cf91158d6..632574fb0f 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -91,10 +91,6 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_assetsToDrag.clear(); } } - } else if (event->type() == QMouseEvent::MouseButtonRelease) { - m_assetsToDrag.clear(); - if (m_model) - m_model->endDrag(); } return QObject::eventFilter(obj, event); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index e6f2b2825e..109078e156 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -126,10 +126,6 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_itemToDrag = {}; } } - } else if (event->type() == QMouseEvent::MouseButtonRelease) { - m_itemToDrag = {}; - if (model) - model->endDrag(); } return QObject::eventFilter(obj, event); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index 3a9a138b2a..8ba1325efa 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -322,6 +322,19 @@ void PropertyEditorContextObject::insertKeyframe(const QString &propertyName) }); } +QString PropertyEditorContextObject::activeDragSuffix() const +{ + return m_activeDragSuffix; +} + +void PropertyEditorContextObject::setActiveDragSuffix(const QString &suffix) +{ + if (m_activeDragSuffix != suffix) { + m_activeDragSuffix = suffix; + emit activeDragSuffixChanged(); + } +} + int PropertyEditorContextObject::majorVersion() const { return m_majorVersion; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h index 6a3e410c8a..f5a2224c8b 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h @@ -56,6 +56,8 @@ class PropertyEditorContextObject : public QObject Q_PROPERTY(int majorQtQuickVersion READ majorQtQuickVersion WRITE setMajorQtQuickVersion NOTIFY majorQtQuickVersionChanged) Q_PROPERTY(int minorQtQuickVersion READ minorQtQuickVersion WRITE setMinorQtQuickVersion NOTIFY minorQtQuickVersionChanged) + Q_PROPERTY(QString activeDragSuffix READ activeDragSuffix NOTIFY activeDragSuffixChanged) + Q_PROPERTY(bool hasAliasExport READ hasAliasExport NOTIFY hasAliasExportChanged) Q_PROPERTY(bool hasActiveTimeline READ hasActiveTimeline NOTIFY hasActiveTimelineChanged) @@ -102,6 +104,9 @@ public: Q_INVOKABLE bool isBlocked(const QString &propName) const; + QString activeDragSuffix() const; + void setActiveDragSuffix(const QString &suffix); + int majorVersion() const; int majorQtQuickVersion() const; int minorQtQuickVersion() const; @@ -134,6 +139,7 @@ signals: void specificQmlComponentChanged(); void hasAliasExportChanged(); void hasActiveTimelineChanged(); + void activeDragSuffixChanged(); public slots: @@ -182,6 +188,8 @@ private: bool m_aliasExport = false; bool m_setHasActiveTimeline = false; + + QString m_activeDragSuffix; }; class EasingCurveEditor : public QObject diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 1ef95365e1..867fd9bd65 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -537,6 +537,8 @@ void PropertyEditorValue::commitDrop(const QString &path) // assign the texture to the property setExpressionWithEmit(texture.id()); } + + m_modelNode.view()->model()->endDrag(); } QStringList PropertyEditorValue::generateStringList(const QString &string) const diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 586c4dec05..b516bba9c9 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -26,8 +26,8 @@ #include "propertyeditorview.h" #include "propertyeditorqmlbackend.h" -#include "propertyeditorvalue.h" #include "propertyeditortransaction.h" +#include "propertyeditorvalue.h" #include #include @@ -850,7 +850,26 @@ void PropertyEditorView::nodeReparented(const ModelNode &node, m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(m_selectedNode)); } -void PropertyEditorView::setValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value) +void PropertyEditorView::dragStarted(QMimeData *mimeData) +{ + if (!mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) + return; + + const QString assetPath = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)) + .split(',')[0]; + const QString suffix = "*." + assetPath.split('.').last().toLower(); + + m_qmlBackEndForCurrentType->contextObject()->setActiveDragSuffix(suffix); +} + +void PropertyEditorView::dragEnded() +{ + m_qmlBackEndForCurrentType->contextObject()->setActiveDragSuffix(""); +} + +void PropertyEditorView::setValue(const QmlObjectNode &qmlObjectNode, + const PropertyName &name, + const QVariant &value) { m_locked = true; m_qmlBackEndForCurrentType->setValue(qmlObjectNode, name, value); @@ -869,6 +888,4 @@ void PropertyEditorView::reloadQml() resetView(); } - -} //QmlDesigner - +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 3bbe502050..09d6dc7f41 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -87,6 +87,9 @@ public: const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; + void dragStarted(QMimeData *mimeData) override; + void dragEnded() override; + void changeValue(const QString &name); void changeExpression(const QString &name); void exportPropertyAsAlias(const QString &name); diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 4e38fb3cfb..47ce515f9e 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -1517,7 +1517,9 @@ void Model::startDrag(QMimeData *mimeData, const QPixmap &icon) auto drag = new QDrag(this); drag->setPixmap(icon); drag->setMimeData(mimeData); - drag->exec(); + if (drag->exec() == Qt::IgnoreAction) + endDrag(); + drag->deleteLater(); } -- cgit v1.2.1 From a5d501d22e78948c2bf300b5e6bf01ecd44352a0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 9 Jun 2022 09:30:24 +0200 Subject: QmlDesigner: Fix template Add missing '}' Task-number: QDS-7125 Change-Id: I7ecf80d681de0400368e28b98179488db560381e Reviewed-by: Thomas Hartmann --- .../studio_templates/projects/application-3d/Screen01.ui.qml.tpl | 1 + 1 file changed, 1 insertion(+) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl index 24566ef2cc..843185a029 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl @@ -56,6 +56,7 @@ Rectangle { objectName: "Default Material" diffuseColor: "#4aee45" } + } Text { text: qsTr("Hello %{ProjectName}") -- cgit v1.2.1 From ab635dd4b220b88c96dd240ddc03670b7ddf8175 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 9 Jun 2022 12:33:48 +0200 Subject: QmlDesigner: Do license check only once We should only make the license check once. An evaluationLicense is handled as enterprise license. Change-Id: Ib4b53795a7d735c10b5238f1e7b76346a9bcc8e1 Reviewed-by: Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/dynamiclicensecheck.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/dynamiclicensecheck.h b/src/plugins/qmldesigner/dynamiclicensecheck.h index fb1e3661b8..8ddcf55a15 100644 --- a/src/plugins/qmldesigner/dynamiclicensecheck.h +++ b/src/plugins/qmldesigner/dynamiclicensecheck.h @@ -37,6 +37,7 @@ namespace QmlDesigner { enum FoundLicense { + noLicense, community, professional, enterprise @@ -58,12 +59,28 @@ ExtensionSystem::IPlugin *licenseCheckerPlugin() FoundLicense checkLicense() { + static FoundLicense license = noLicense; + + if (license != noLicense) + return license; + if (auto plugin = Internal::licenseCheckerPlugin()) { bool retVal = false; + bool success = QMetaObject::invokeMethod(plugin, - "qdsEnterpriseLicense", + "evaluationLicense", Qt::DirectConnection, Q_RETURN_ARG(bool, retVal)); + + if (success && retVal) + return enterprise; + + retVal = false; + + success = QMetaObject::invokeMethod(plugin, + "qdsEnterpriseLicense", + Qt::DirectConnection, + Q_RETURN_ARG(bool, retVal)); if (success && retVal) return enterprise; else -- cgit v1.2.1 From 8ca39444f4cadff3ae543877008cd9f6443380db Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Mon, 6 Jun 2022 10:36:41 +0300 Subject: Doc: Add documentation for Material Editor and Browser - Add Material Editor and Browser docs - Reorganize and edit current materials docs Task-number: QDS-6991 Change-Id: Ibea128dc48c0c2e167abf36e7700d4516673b45b Reviewed-by: Mahmoud Badri --- doc/qtdesignstudio/images/icons/apply-material.png | Bin 0 -> 779 bytes .../images/material-editor-browser.webp | Bin 0 -> 49886 bytes .../images/materials-remove-material.png | Bin 0 -> 15142 bytes .../images/navigator-material-texture.png | Bin 0 -> 3820 bytes .../images/studio-qtquick-3d-default-material.webp | Bin 0 -> 13236 bytes .../images/studio-qtquick-3d-material.webp | Bin 0 -> 35562 bytes doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc | 1 + .../qtquick3d-editor/qtdesignstudio-3d-editor.qdoc | 2 +- .../qtdesignstudio-3d-materials-shaders.qdoc | 173 +------------- .../src/views/qtquick-components-view.qdoc | 2 +- .../src/views/studio-material-editor.qdoc | 266 +++++++++++++++++++++ 11 files changed, 278 insertions(+), 166 deletions(-) create mode 100644 doc/qtdesignstudio/images/icons/apply-material.png create mode 100644 doc/qtdesignstudio/images/material-editor-browser.webp create mode 100644 doc/qtdesignstudio/images/materials-remove-material.png create mode 100644 doc/qtdesignstudio/images/navigator-material-texture.png create mode 100644 doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp create mode 100644 doc/qtdesignstudio/images/studio-qtquick-3d-material.webp create mode 100644 doc/qtdesignstudio/src/views/studio-material-editor.qdoc diff --git a/doc/qtdesignstudio/images/icons/apply-material.png b/doc/qtdesignstudio/images/icons/apply-material.png new file mode 100644 index 0000000000..d0b347470b Binary files /dev/null and b/doc/qtdesignstudio/images/icons/apply-material.png differ diff --git a/doc/qtdesignstudio/images/material-editor-browser.webp b/doc/qtdesignstudio/images/material-editor-browser.webp new file mode 100644 index 0000000000..d3963b522e Binary files /dev/null and b/doc/qtdesignstudio/images/material-editor-browser.webp differ diff --git a/doc/qtdesignstudio/images/materials-remove-material.png b/doc/qtdesignstudio/images/materials-remove-material.png new file mode 100644 index 0000000000..9ef0a91e5b Binary files /dev/null and b/doc/qtdesignstudio/images/materials-remove-material.png differ diff --git a/doc/qtdesignstudio/images/navigator-material-texture.png b/doc/qtdesignstudio/images/navigator-material-texture.png new file mode 100644 index 0000000000..4256e959c6 Binary files /dev/null and b/doc/qtdesignstudio/images/navigator-material-texture.png differ diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp new file mode 100644 index 0000000000..0306408df1 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp differ diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp new file mode 100644 index 0000000000..1c5b1cecf2 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp differ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index f3a7a0d4f7..8cba9a7307 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -39,6 +39,7 @@ \list \li \l{Form Editor} \li \l{3D Editor} + \li \l{Material Editor and Browser} \li \l{Components} \li \l{Assets} \li \l{Navigator} diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index dee9a01a9d..1995c343b8 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -26,7 +26,7 @@ /*! \previouspage qtquick-form-editor.html \page studio-3d-editor.html - \nextpage quick-components-view.html + \nextpage studio-material-editor.html \title 3D Editor diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc index 73d4f66937..abddc903a9 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc @@ -32,7 +32,7 @@ \title Materials and Shaders - \image studio-qtquick-3d-material.png "Material attached to model in Design mode" + \image studio-qtquick-3d-material.webp "Material attached to model in Design mode" Materials and shaders define how object surfaces are rendered in \QDS and live preview. As you change the properties of materials, new shaders are @@ -40,6 +40,10 @@ a shader depends on a combination of the properties that are set on it, and the context of the scene itself. + It is recommended that you use the \l {Material Editor and Browser} when + working with materials, but you can also add materials using the components + library. + The materials that you used in your imported scenes are imported to \QDS as \l{Qt Quick 3D} components. When you add a View3D component, it contains a DefaultMaterial component. You can use the following predefined Qt Quick @@ -62,171 +66,12 @@ defines an image and how the image is mapped to meshes in a 3D scene. For more information, see \l {Textures}. - You can modify material properties in the \uicontrol Properties view, as - instructed in the following sections. The availability of the properties - depends on the material type. - - \image studio-qtquick-3d-default-material.png "DefaultMaterial properties" + You can create and modify materials in + \uicontrol {Material Editor} and \uicontrol {Material Browser}. The availability + of the properties depends on the material type. - To enable the material to use vertex colors from the mesh, select the - \uicontrol {Enable vertex colors} check box. These are multiplied - by any other colors specified for the material. + \image studio-qtquick-3d-default-material.webp "DefaultMaterial properties" You can animate material properties in the \uicontrol Timeline view, as instructed in \l {Creating Timeline Animations}. - - \section1 Blending Colors - - To determine how the colors of a model blend with the colors of the models - behind it, set the \uicontrol {Blend mode} property. To make opaque objects - occlude the objects behind them, select \uicontrol {SourceOver}. - - For a lighter result, select \uicontrol Screen to blend colors using an - inverted multiply or \uicontrol ColorDodge to blend them by inverted - division. Color dodge procudes an even lighter result than screen. - - For a darker result, select \uicontrol Multiply to blend colors using a - multiply or \uicontrol ColorBurn to blend them by inverted division, where - the result also is inverted. Color burn produces an even darker result than - multiply. - - The screen and multiply modes are order-independent, so select them to - avoid \e popping, which can happen when using semi-opaque objects and - sorting the back and front faces or models. - - For a result with higher contrast, select \uicontrol Overlay, which is a mix - of the multiply and screen modes. - - \section1 Lighting Materials - - To set the lighting method for generating a material, use the - \uicontrol Lighting property. Select \uicontrol {Fragment lighting} to - calculate diffuse and specular lighting for each rendered pixel. Some - effects, such as Fresnel or a bump map, require fragment lighting. - - To skip lighting calculation, select \uicontrol {No lighting}. This is very - fast and quite effective when using image maps that do not need to be shaded - by lighting. - - To set the base color for the material, use the \uicontrol {Diffuse Color} - property. You can either use the color picker or specify a RBG value. Set - the diffuse color to black to create purely-specular materials, such as - metals or mirrors. To apply a texture to a material, set it as the value of - the \uicontrol {Diffuse map} property. Using a texture with transparency - also applies the alpha channel as an \uicontrol {Opacity map}. You can set - the opacity of the material independently of the model as the value of the - \uicontrol Opacity property. - - \section1 Self-Illuminating Materials - - To set the color and amount of self-illumination for a material, use the - \uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In - a scene with black ambient lighting, a material with an emissive factor of 0 - is black where the light does not shine on it. Setting the emissive factor - to 1 shows the material in its diffuse color instead. - - To use a Texture for specifying the emissive factor for different parts of - the material, set the \uicontrol {Emissive map} property. Using a grayscale - image does not affect the color of the result, while using a color image - produces glowing regions with the color affected by the emissive map. - - \section1 Using Highlights and Reflections - - You can control the highlights and reflections on a material by setting the - properties in the \uicontrol Specular group. You can use the color picker - or set a RGB value to specify the color used to adjust specular reflections. - Use white for no effect - - To use a color texture to modulate the amount and the color of specularity - across the surface of a material, set the \uicontrol {Specular map} - property. Set the \uicontrol {Specular amount} property to specify the - strength of specularity. This property does not affect the specular - reflection map, but it does affect the amount of reflections from a scene's - light probe. - - \note Unless your mesh is high-resolution, you may need to use fragment - lighting to get good specular highlights from scene lights. - - To determine how to calculate specular highlights for lights in the scene, - set the \uicontrol {Specular model}. In addition to the default mode, you - can use the GGX or Ward lighting model. - - To use a Texture for specular highlighting on a material, set the - \uicontrol {Reflection map} property. When the texture is applied using - environmental mapping (not UV mapping), the map appears to be reflecting - from the environment as you rotate the model. Specular reflection maps are - an easy way to add a high-quality look at a relatively low cost. - - To specify an image to use as the specular reflection map, set the - \uicontrol {Light probe} property. - - Crisp images cause your material to look very glossy. The more you - blur your image, the softer your material appears. - - To decrease head-on reflections (looking directly at the surface) - while maintaining reflections seen at grazing angles, set the - \uicontrol {Fresnel power} property. To select the angles to control, - set the \uicontrol {Index of refraction} property. - - To control the size of the specular highlights generated from lights and the - clarity of reflections in general, set the \uicontrol {Specular roughness} - property. Larger values increase the roughness, while softening specular - highlights and blurring reflections. To control the specular roughness of - the material using a Texture, set the \uicontrol {Roughness map property}. - - \section1 Simulating Geometry Displacement - - Specify the properties in the \uicontrol {Bump/Normal} group to simulate - fine geometry displacement across the surface of the material. Set the - \uicontrol {Bump map} property to use a grayscale texture for the - simulation. Brighter pixels indicate raised regions. - - To use a RGB image for simulation, set the \uicontrol {Normal map} property. - The RGB channels indicate XYZ normal deviations. - - The amount of displacement is controlled by the \uicontrol {Bump amount} - property. - - Bump and normal maps do not affect the silhouette of a model. To affect the - silhouette, set the \uicontrol {Displacement map} property. It specifies a - grayscale image used to offset the vertices of geometry across the surface - of the material. The \uicontrol {Displacement amount} property specifies the - offset amount. - - \section1 Specifying Material Translucency - - Set the properties in the \uicontrol Translucency group to control how much - light can pass through the material from behind. To use a grayscale texture, - specify it as the value of the \uicontrol {Translucency map} property. - - To specify the amount of light wrap for the translucency map, set the - \uicontrol {Diffuse light wrap} property. A value of 0 does not wrap the - light at all, while a value of 1 wraps the light all around the object. - - To specify the amount of falloff for the translucency based on - the angle of the normals of the object to the light source, set - the \uicontrol {Translucency falloff} property. - - \section1 Culling Faces - - Set the \uicontrol {Culling mode} property to determine whether the front - and back faces of a model are rendered. Culling modes check whether the - points in the polygon appear in clockwise or counter-clockwise order when - projected onto the screen. If front-facing polygons have a clockwise - winding, but the polygon projected on the screen has a counter-clockwise - winding, the projected polygon is rotated to face away from the camera and - is not rendered. Culling makes rendering objects quicker and more efficient - by reducing the number of polygons to draw. - - \section1 Applying Materials to Models - - To apply materials to models, you should first delete the default material, - and then drag-and-drop a new material from \l Assets to a model component - in \l Navigator. - - You can apply the same material to another component as well. Again, - delete the default material first. You should then select the component and - go to the \uicontrol Properties view. Find the \uicontrol Materials property, - select the \inlineimage icons/plus.png - icon, and choose the new material in the dropdown menu. */ diff --git a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc index 464926ea35..2d800909d6 100644 --- a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc @@ -25,7 +25,7 @@ /*! \page quick-components-view.html - \previouspage studio-3d-editor.html + \previouspage studio-material-editor.html \nextpage quick-assets.html \title Components diff --git a/doc/qtdesignstudio/src/views/studio-material-editor.qdoc b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc new file mode 100644 index 0000000000..fcfa9823e9 --- /dev/null +++ b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \page studio-material-editor.html + \previouspage studio-3d-editor.html + \nextpage quick-components-view.html + + + \title Material Editor and Browser + + In the \uicontrol {Material Editor} and \uicontrol {Material Browser} views, + you create and manage materials. + + \image material-editor-browser.webp "Material Editor and Browser" + + \section1 Creating a Material + + To create a new material, do one of the following: + + \list + \li In \uicontrol {Material Browser}, select \inlineimage icons/plus.png + . + \li In \uicontrol {Material Editor}, select \inlineimage icons/plus.png + . + \endlist + + \section1 Editing a Material + + To edit a material, select it in \uicontrol{Material Browser} and edit its + properties in \uicontrol{Material Editor}. If \uicontrol {Material Editor} + is closed, open it in one of the following ways: + + \list + \li In \uicontrol{Navigator}, right-click an object that has the material + assigned to it and select \uicontrol {Edit Material}. + \li In \uicontrol{Material Browser}, double-click a material. + \endlist + + \section1 Assigning a Material to an Object + + To assign a material to a 3D object in your project, first select the object + in \uicontrol Navigator or \uicontrol {3D Editor}. Then, do one of the + following: + + \list + \li In \uicontrol {Material Browser}, right-click the material and select + \uicontrol {Apply to Selected}. If there already is any material assigned + to the object, you can select whether to replace the material or to add + another material to the object. + \li In \uicontrol {Material Editor}, select + \inlineimage icons/apply-material.png + . This replaces any material already assigned to the object. + \endlist + + \section1 Removing a Material from an Object + + To remove an assigned material from an object: + \list 1 + \li In \uicontrol{Navigator}, select the object. + \li In \uicontrol{Properties}, select + \inlineimage icons/close.png + next to the material. + \image materials-remove-material.png + \endlist + + \section1 Using Texture Maps + + In \QDS you can add many different texture maps to your material. + + To add a texture map to a material: + \list 1 + \li Select the material in \uicontrol{Material Browser}. + \li From \uicontrol {Assets}, drag an image to the correct map field + in \uicontrol {Material Editor}. For example, to add a diffuse map, drag + the image to \uicontrol{Diffuse Map} in \uicontrol{Material Editor}. + \endlist + + \section2 Using a Reflection Map for Environmental Mapping + + To use a texture for environmental mapping, you need to set the mapping + mode to \e {environment}. + + To add a reflection map for environmental mapping to a material: + + \list 1 + \li Select the material in \uicontrol {Material Browser}. + \li From \uicontrol{Assets}, drag an image to + \uicontrol{Reflection Map}. + \li In \uicontrol {Navigator}, select + \inlineimage icons/filtericon.png + and then clear \uicontrol {Show Only Visible Components}. Now the + texture you just added to the material is visible in + \uicontrol {Navigator}. + \image navigator-material-texture.png + \li In \uicontrol {Navigator}, select the texture. + \li In \uicontrol {Properties}, set \uicontrol {Texture Mapping} to + \uicontrol {Environment}. + \endlist + + \section1 Blending Colors + + To determine how the colors of a model blend with the colors of the models + behind it, set the \uicontrol {Blend mode} property. To make opaque objects + occlude the objects behind them, select \uicontrol {SourceOver}. + + For a lighter result, select \uicontrol Screen to blend colors using an + inverted multiply or \uicontrol ColorDodge to blend them by inverted + division. Color dodge produces an even lighter result than screen. + + For a darker result, select \uicontrol Multiply to blend colors using a + multiply or \uicontrol ColorBurn to blend them by inverted division, where + the result also is inverted. Color burn produces an even darker result than + multiply. + + The screen and multiply modes are order-independent, so select them to + avoid \e popping, which can happen when using semi-opaque objects and + sorting the back and front faces or models. + + For a result with higher contrast, select \uicontrol Overlay, which is a mix + of the multiply and screen modes. + + \section1 Lighting Materials + + To set the lighting method for generating a material, use the + \uicontrol Lighting property. Select \uicontrol {Fragment lighting} to + calculate diffuse and specular lighting for each rendered pixel. Some + effects, such as Fresnel or a bump map, require fragment lighting. + + To skip lighting calculation, select \uicontrol {No lighting}. This is very + fast and quite effective when using image maps that do not need to be shaded + by lighting. + + To set the base color for the material, use the \uicontrol {Diffuse Color} + property. You can either use the color picker or specify a RBG value. Set + the diffuse color to black to create purely-specular materials, such as + metals or mirrors. To apply a texture to a material, set it as the value of + the \uicontrol {Diffuse map} property. Using a texture with transparency + also applies the alpha channel as an \uicontrol {Opacity map}. You can set + the opacity of the material independently of the model as the value of the + \uicontrol Opacity property. + + \section1 Self-Illuminating Materials + + To set the color and amount of self-illumination for a material, use the + \uicontrol {Emissive color} and \uicontrol {Emissive factor} properties. In + a scene with black ambient lighting, a material with an emissive factor of 0 + is black where the light does not shine on it. Setting the emissive factor + to 1 shows the material in its diffuse color instead. + + To use a Texture for specifying the emissive factor for different parts of + the material, set the \uicontrol {Emissive map} property. Using a grayscale + image does not affect the color of the result, while using a color image + produces glowing regions with the color affected by the emissive map. + + \section1 Using Highlights and Reflections + + You can control the highlights and reflections on a material by setting the + properties in the \uicontrol Specular group. You can use the color picker + or set a RGB value to specify the color used to adjust specular reflections. + Use white for no effect. + + To use a color texture to modulate the amount and the color of specularity + across the surface of a material, set the \uicontrol {Specular map} + property. Set the \uicontrol {Specular amount} property to specify the + strength of specularity. This property does not affect the specular + reflection map, but it does affect the amount of reflections from a scene's + light probe. + + \note Unless your mesh is high-resolution, you may need to use fragment + lighting to get good specular highlights from scene lights. + + To determine how to calculate specular highlights for lights in the scene, + set the \uicontrol {Specular model}. In addition to the default mode, you + can use the GGX or Ward lighting model. + + To use a Texture for specular highlighting on a material, set the + \uicontrol {Reflection map} property. When the texture is applied using + environmental mapping (not UV mapping), the map appears to be reflecting + from the environment as you rotate the model. Specular reflection maps are + an easy way to add a high-quality look at a relatively low cost. + + To specify an image to use as the specular reflection map, set the + \uicontrol {Light probe} property. + + Crisp images cause your material to look very glossy. The more you + blur your image, the softer your material appears. + + To decrease head-on reflections (looking directly at the surface) + while maintaining reflections seen at grazing angles, set the + \uicontrol {Fresnel power} property. To select the angles to control, + set the \uicontrol {Index of refraction} property. + + To control the size of the specular highlights generated from lights and the + clarity of reflections in general, set the \uicontrol {Specular roughness} + property. Larger values increase the roughness, while softening specular + highlights and blurring reflections. To control the specular roughness of + the material using a Texture, set the \uicontrol {Roughness map property}. + + \section1 Simulating Geometry Displacement + + Specify the properties in the \uicontrol {Bump/Normal} group to simulate + fine geometry displacement across the surface of the material. Set the + \uicontrol {Bump map} property to use a grayscale texture for the + simulation. Brighter pixels indicate raised regions. + + To use an image for simulation, set the \uicontrol {Normal map} property. + The RGB channels indicate XYZ normal deviations. + + The amount of displacement is controlled by the \uicontrol {Bump amount} + property. + + Bump and normal maps do not affect the silhouette of a model. To affect the + silhouette, set the \uicontrol {Displacement map} property. It specifies a + grayscale image used to offset the vertices of geometry across the surface + of the material. The \uicontrol {Displacement amount} property specifies the + offset amount. + + \section1 Specifying Material Translucency + + Set the properties in the \uicontrol Translucency group to control how much + light can pass through the material from behind. To use a grayscale texture, + specify it as the value of the \uicontrol {Translucency map} property. + + To specify the amount of light wrap for the translucency map, set the + \uicontrol {Diffuse light wrap} property. A value of 0 does not wrap the + light at all, while a value of 1 wraps the light all around the object. + + To specify the amount of falloff for the translucency based on + the angle of the normals of the object to the light source, set + the \uicontrol {Translucency falloff} property. + + \section1 Culling Faces + + Set the \uicontrol {Culling mode} property to determine whether the front + and back faces of a model are rendered. Culling modes check whether the + points in the polygon appear in clockwise or counter-clockwise order when + projected onto the screen. If front-facing polygons have a clockwise + winding, but the polygon projected on the screen has a counter-clockwise + winding, the projected polygon is rotated to face away from the camera and + is not rendered. Culling makes rendering objects quicker and more efficient + by reducing the number of polygons to draw. + +*/ -- cgit v1.2.1 From d8c605179ad4934c5f9a2060dd398a13821336c4 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 9 Jun 2022 19:40:23 +0200 Subject: QmlDesigner: Add option for smooth rendering in form editor Smooth rendering turns on MSAA and doubles the resolution for rendered items. With this option enabled everything stays smooth when zooming in. Around factor 8-10 pixels become clearly visible again, but it still looks relatively smooth. I added both MSAA and increased the resolution to one option, for simplicity. The smooth mode takes 4 times the shared memory, which should not be an issue in most cases. For now, the option is not the default. Task-number: QDS-7129 Task-number: QDS-7128 Change-Id: I8a778650bb40f8ba796960db9bc966e8a1efff4e Reviewed-by: Miikka Heikkinen --- .../qml2puppet/instances/qt5nodeinstanceserver.cpp | 11 +++++++++-- .../qml2puppet/instances/quickitemnodeinstance.cpp | 4 ++-- .../designercore/instances/puppetcreator.cpp | 6 ++++++ src/plugins/qmldesigner/designersettings.cpp | 1 + src/plugins/qmldesigner/designersettings.h | 1 + src/plugins/qmldesigner/settingspage.cpp | 2 ++ src/plugins/qmldesigner/settingspage.ui | 17 +++++++++++++++++ 7 files changed, 38 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 32f63a8cd6..e7a98b7427 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -405,6 +405,9 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) QQuickItemPrivate *pItem = QQuickItemPrivate::get(item); const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS"); + const bool smoothRendering = qEnvironmentVariableIsSet("QMLPUPPET_SMOOTH_RENDERING"); + + int scaleFactor = smoothRendering ? 2 : 1; if (renderEffects) { if (parentEffectItem(item)) @@ -470,6 +473,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) // us to render it to a texture that we can grab to an image. QSGRenderContext *rc = QQuickWindowPrivate::get(m_viewData.window.data())->context; QSGLayer *layer = rc->sceneGraphContext()->createLayer(rc); + if (smoothRendering) + layer->setSamples(4); layer->setItem(pItem->itemNode()); layer->setRect(QRectF(renderBoundingRect.x(), @@ -478,8 +483,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) -renderBoundingRect.height())); const QSize minSize = rc->sceneGraphContext()->minimumFBOSize(); - layer->setSize(QSize(qMax(minSize.width(), int(renderBoundingRect.width())), - qMax(minSize.height(), int(renderBoundingRect.height())))); + layer->setSize(QSize(qMax(minSize.width(), int(renderBoundingRect.width() * scaleFactor)), + qMax(minSize.height(), int(renderBoundingRect.height() * scaleFactor)))); layer->scheduleUpdate(); if (layer->updateTexture()) @@ -489,6 +494,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) delete layer; layer = nullptr; + + renderImage.setDevicePixelRatio(scaleFactor); }); m_viewData.renderControl->render(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index 41d0015ce5..5b1f3171ad 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -504,12 +504,12 @@ QImage QuickItemNodeInstance::renderImage() const if (s_unifiedRenderPath) { renderImage = nodeInstanceServer()->grabWindow(); renderImage = renderImage.copy(renderBoundingRect.toRect()); + /* When grabbing an offscren window the device pixel ratio is 1 */ + renderImage.setDevicePixelRatio(1); } else { renderImage = nodeInstanceServer()->grabItem(quickItem()); } - /* When grabbing an offscren window the device pixel ratio is 1 */ - renderImage.setDevicePixelRatio(1); #endif return renderImage; diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index a437e5c0be..7d4beeacd8 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -504,6 +504,12 @@ QProcessEnvironment PuppetCreator::processEnvironment() const #ifndef QMLDESIGNER_TEST const QString controlsStyle = m_designerSettings.value(DesignerSettingsKey:: CONTROLS_STYLE).toString(); + + const bool smoothRendering = m_designerSettings.value(DesignerSettingsKey::SMOOTH_RENDERING) + .toBool(); + + if (smoothRendering) + environment.set("QMLPUPPET_SMOOTH_RENDERING", "true"); #else const QString controlsStyle; #endif diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 20083068c1..5474fd50d3 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -82,6 +82,7 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, true); const QStringList defaultValue = QStringList() << "#222222" << "#999999"; restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, defaultValue); + restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false); settings->endGroup(); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 8c249fc65e..4dbee7752b 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -72,6 +72,7 @@ const char COLOR_PALETTE_FAVORITE[] = "ColorPaletteFavorite"; const char ALWAYS_DESIGN_MODE[] = "AlwaysDesignMode"; const char DISABLE_ITEM_LIBRARY_UPDATE_TIMER[] = "DisableItemLibraryUpdateTimer"; const char ASK_BEFORE_DELETING_ASSET[] = "AskBeforeDeletingAsset"; +const char SMOOTH_RENDERING[] = "SmoothRendering"; } class QMLDESIGNERCORE_EXPORT DesignerSettings : public QHash diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 1af226ae49..700402680a 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -182,6 +182,7 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.designerAlwaysDesignModeCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, m_ui.askBeforeDeletingAssetCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::SMOOTH_RENDERING, m_ui.smoothRendering->isChecked()); return settings; } @@ -264,6 +265,7 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.emulationGroupBox->setVisible(showAdvancedFeatures); m_ui.debugGroupBox->setVisible(showAdvancedFeatures); m_ui.featureTimelineEditorCheckBox->setVisible(standaloneMode); + m_ui.smoothRendering->setChecked(settings.value(DesignerSettingsKey::SMOOTH_RENDERING).toBool()); } void SettingsPageWidget::apply() diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index eace952540..004f8a68eb 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -99,6 +99,23 @@ + + + + Enable Smooth Rendering in Form Editor + + + + + + + + + + Smooth Rendering: + + + -- cgit v1.2.1 From 36dbc62a1d67f02241e5c5860af083d7f4a0d7b5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 7 Jun 2022 16:27:28 +0300 Subject: QmlDesigner: Queue puppet processes during import On some systems launcing multiple simultaneous import processes causes imports to fail. Fixed by only launching single process at a time and queuing the rest. Fixes: QDS-7107 Change-Id: I330c5920dcbd74d3b4f2e7f40899795a4fbaf3ac Reviewed-by: Thomas Hartmann --- .../qml2puppet/iconrenderer/iconrenderer.cpp | 3 +- .../itemlibrary/itemlibraryassetimporter.cpp | 174 +++++++++++---------- .../itemlibrary/itemlibraryassetimporter.h | 16 +- 3 files changed, 103 insertions(+), 90 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp index 2dd653273c..76deb3a3b3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp @@ -198,8 +198,7 @@ void IconRenderer::finishCreateIcon() render(saveFile); - // Allow little time for file operations to finish - QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit); + QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit); } void IconRenderer::render(const QString &fileName) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index e3aae0cb7d..8e8087dd21 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -90,21 +91,16 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, if (!isCancelled()) { const auto parseData = m_parseData; - for (const auto &pd : parseData) { - if (!startImportProcess(pd)) { - addError(tr("Failed to start import 3D asset process."), - pd.sourceInfo.absoluteFilePath()); - m_parseData.remove(pd.importId); - } - } + for (const auto &pd : parseData) + m_puppetQueue.append(pd.importId); + startNextImportProcess(); } if (!isCancelled()) { // Wait for puppet processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { postImport(); } else { - m_qmlPuppetCount = static_cast(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Importing 3D assets."); addInfo(progressTitle); notifyProgress(0, progressTitle); @@ -142,21 +138,14 @@ void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &sr emit infoReported(infoMsg, srcPath); } -void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, - int importId) +void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode) - ++m_qmlImportFinishedCount; - - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); + m_puppetProcess.reset(); - if (m_parseData.contains(importId)) { - const ParseData &pd = m_parseData[importId]; + if (m_parseData.contains(m_currentImportId)) { + const ParseData &pd = m_parseData[m_currentImportId]; QString errStr; if (exitStatus == QProcess::ExitStatus::CrashExit) { errStr = tr("Import process crashed."); @@ -179,15 +168,19 @@ void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::Exi addError(tr("Asset import process failed: \"%1\".") .arg(pd.sourceInfo.absoluteFilePath())); addError(errStr); - m_parseData.remove(importId); + m_parseData.remove(m_currentImportId); } } - if (m_qmlImportFinishedCount == m_qmlPuppetCount) { + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextImportProcess(); + + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport); } else { - notifyProgress(int(100. * (double(m_qmlImportFinishedCount) / double(m_qmlPuppetCount)))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -196,17 +189,17 @@ void ItemLibraryAssetImporter::iconProcessFinished(int exitCode, QProcess::ExitS Q_UNUSED(exitCode) Q_UNUSED(exitStatus) - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); + m_puppetProcess.reset(); + + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextIconProcess(); - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::finalizeQuick3DImport); } else { - notifyProgress(int(100. * (1. - (double(m_qmlPuppetProcesses.size()) / double(m_qmlPuppetCount))))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -225,11 +218,11 @@ void ItemLibraryAssetImporter::reset() m_tempDir = new QTemporaryDir; m_importFiles.clear(); m_overwrittenImports.clear(); - m_qmlPuppetProcesses.clear(); - m_qmlPuppetCount = 0; - m_qmlImportFinishedCount = 0; + m_puppetProcess.reset(); m_parseData.clear(); m_requiredImports.clear(); + m_currentImportId = 0; + m_puppetQueue.clear(); } void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, @@ -351,7 +344,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa return true; } -void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) +void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd) { QDir outDir = pd.outDir; if (pd.originalAssetName != pd.assetName) { @@ -452,8 +445,10 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) "QtQuick3D", impVersionStr)); } } - if (impVersionMajor > 0 && impVersionMajor < 6 - && startIconProcess(24, iconFileName, qmlIt.filePath())) { + if (impVersionMajor > 0 && impVersionMajor < 6) { + pd.iconFile = iconFileName; + pd.iconSource = qmlIt.filePath(); + m_puppetQueue.append(pd.importId); // Since icon is generated by external process, the file won't be // ready for asset gathering below, so assume its generation succeeds // and add it now. @@ -589,84 +584,101 @@ ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAsset return OverwriteResult::Skip; } -bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd) +void ItemLibraryAssetImporter::startNextImportProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - QJsonDocument optDoc(pd.options); - - puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() - << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); - - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - importProcessFinished(exitCode, exitStatus, pd.importId); - }, - puppetArgs); - - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + QJsonDocument optDoc(pd.options); + + puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() + << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); + + m_currentImportId = pd.importId; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + importProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start import 3D asset process."), + pd.sourceInfo.absoluteFilePath()); + m_parseData.remove(pd.importId); + m_puppetProcess.reset(); + } } } - return false; } -bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFile, - const QString &iconSource) +void ItemLibraryAssetImporter::startNextIconProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource; - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - iconProcessFinished(exitCode, exitStatus); - }, - puppetArgs); - - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + puppetArgs << "--rendericon" << QString::number(24) << pd.iconFile << pd.iconSource; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + iconProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start icon generation process."), + pd.sourceInfo.absoluteFilePath()); + m_puppetProcess.reset(); + } } } - return false; } void ItemLibraryAssetImporter::postImport() { - Q_ASSERT(m_qmlPuppetProcesses.empty()); + QTC_ASSERT(m_puppetQueue.isEmpty() && !m_puppetProcess, return); if (!isCancelled()) { - for (const auto &pd : qAsConst(m_parseData)) + for (auto &pd : m_parseData) postParseQuick3DAsset(pd); + startNextIconProcess(); } if (!isCancelled()) { // Wait for icon generation processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { finalizeQuick3DImport(); } else { - m_qmlPuppetCount = static_cast(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Generating icons."); addInfo(progressTitle); notifyProgress(0, progressTitle); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h index 83be9af5f4..1f0009eaab 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h @@ -74,7 +74,7 @@ signals: void importFinished(); private slots: - void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, int importId); + void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); private: @@ -87,6 +87,8 @@ private: QString assetName; QString originalAssetName; int importId; + QString iconFile; + QString iconSource; }; void notifyFinished(); @@ -96,7 +98,7 @@ private: const QSet &preselectedFilesForOverwrite); bool preParseQuick3DAsset(const QString &file, ParseData &pd, const QSet &preselectedFilesForOverwrite); - void postParseQuick3DAsset(const ParseData &pd); + void postParseQuick3DAsset(ParseData &pd); void copyImportedFiles(); void notifyProgress(int value, const QString &text); @@ -110,8 +112,8 @@ private: }; OverwriteResult confirmAssetOverwrite(const QString &assetName); - bool startImportProcess(const ParseData &pd); - bool startIconProcess(int size, const QString &iconFile, const QString &iconSource); + void startNextImportProcess(); + void startNextIconProcess(); void postImport(); void finalizeQuick3DImport(); QString sourceSceneTargetFilePath(const ParseData &pd); @@ -122,12 +124,12 @@ private: bool m_cancelled = false; QString m_importPath; QTemporaryDir *m_tempDir = nullptr; - std::vector m_qmlPuppetProcesses; - int m_qmlPuppetCount = 0; - int m_qmlImportFinishedCount = 0; + QProcessUniquePointer m_puppetProcess; int m_importIdCounter = 0; + int m_currentImportId = 0; QHash m_parseData; QString m_progressTitle; QList m_requiredImports; + QList m_puppetQueue; }; } // QmlDesigner -- cgit v1.2.1 From dedbbc75b564b0a93c89688d76a7cab6dbc06046 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 10 Jun 2022 15:23:16 +0300 Subject: QmlDesigner: Apply root item transform in Node component previews When generating a preview from a component with a 3D node for a root, the root Node transform is now applied when calculating camera zoom. Fixes: QDS-7131 Change-Id: I73054a09b3e82868c999ef6f9797dc941e625b33 Reviewed-by: Mahmoud Badri --- share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml | 2 +- share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml | 2 +- share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp | 6 +++--- share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index 5c8b9e1cd7..b497b0419a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -37,7 +37,7 @@ View3D { function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, model, root, 1040, closeUp); } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 1762e3c9a4..4da76ea097 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -37,7 +37,7 @@ View3D { function fitToViewPort(closeUp) { // The magic number is the distance from camera default pos to origin - _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, sourceModel, root, + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, model, root, 1040, closeUp); } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 74c2eb270e..590785a30e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -812,7 +812,7 @@ QVector3D GeneralHelper::pivotScenePosition(QQuick3DNode *node) const // Calculate bounds for given node, including all child nodes. // Returns true if the tree contains at least one Model node. bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, - QVector3D &maxBounds, bool recursive) + QVector3D &maxBounds) { if (!node) { const float halfExtent = 100.f; @@ -825,7 +825,7 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec auto nodePriv = QQuick3DObjectPrivate::get(node); auto renderNode = static_cast(nodePriv->spatialNode); - if (recursive && renderNode) { + if (renderNode) { #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty)) renderNode->calculateLocalTransform(); @@ -850,7 +850,7 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec if (auto childNode = qobject_cast(child)) { QVector3D newMinBounds = minBounds; QVector3D newMaxBounds = maxBounds; - bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); + bool childHasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds); // Ignore any subtrees that do not have Model in them as we don't need those // for visual bounds calculations if (childHasModel) { diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 5bb1fa1662..8014a71187 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -130,7 +130,7 @@ private: void handlePendingToolStateUpdate(); QVector3D pivotScenePosition(QQuick3DNode *node) const; bool getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, - QVector3D &maxBounds, bool recursive = false); + QVector3D &maxBounds); QTimer m_overlayUpdateTimer; QTimer m_toolStateUpdateTimer; -- cgit v1.2.1 From 13c1b6f2373f3da6198e1111a96f5aee1036023a Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 10 Jun 2022 21:08:56 +0200 Subject: QmlDesigner: Do not apply smooth rendering if root is a 3D node Task-number: QDS-7136 Change-Id: I5260153b8d6131160a8d4b67418e81c6f6e4d862 Reviewed-by: Miikka Heikkinen --- .../qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index e7a98b7427..3ccd6c60dc 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -407,8 +407,6 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS"); const bool smoothRendering = qEnvironmentVariableIsSet("QMLPUPPET_SMOOTH_RENDERING"); - int scaleFactor = smoothRendering ? 2 : 1; - if (renderEffects) { if (parentEffectItem(item)) return renderImage; @@ -430,17 +428,20 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) ServerNodeInstance instance = instanceForObject(item); + const bool rootIs3DObject = rootIsRenderable3DObject(); + // Setting layer enabled to false messes up the bounding rect. // Therefore we calculate it upfront. QRectF renderBoundingRect; if (instance.isValid()) renderBoundingRect = instance.boundingRect(); - - else if (rootIsRenderable3DObject()) + else if (rootIs3DObject) renderBoundingRect = item->boundingRect(); else renderBoundingRect = ServerNodeInstance::effectAdjustedBoundingRect(item); + const int scaleFactor = (smoothRendering && !rootIs3DObject) ? 2 : 1; + // Hide immediate children that have instances and are QQuickItems so we get only // the parent item's content, as compositing is handled on creator side. QSet layerChildren; @@ -521,7 +522,6 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) if (!isLayerEnabled(pItem)) pItem->derefFromEffectItem(false); - #else Q_UNUSED(item) #endif -- cgit v1.2.1 From 7ae288d355b9763ed495c1ebbf198809ed7e50f0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 10 Jun 2022 21:10:52 +0200 Subject: QmlDesigner: Use changed properties to update 3D preview EffectReference is always dirty and it is the only dirty flag. Instead, we update now if any property changed. Task-number: QDS-7079 Change-Id: I157cf2d3b15120c33f4a6b3f53e526d555c7f80c Reviewed-by: Miikka Heikkinen --- .../qml2puppet/instances/qt5rendernodeinstanceserver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 2ff2339576..59e7a4aa82 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -111,8 +111,6 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() } } - clearChangedPropertyList(); - if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { if (windowDirty) nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); @@ -134,13 +132,15 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands() } if (rootIsRenderable3DObject() && rootNodeInstance().contentItem() - && DesignerSupport::isDirty(rootNodeInstance().contentItem(), - DesignerSupport::AllMask) + && !changedPropertyList().isEmpty() && nodeInstanceClient()->bytesToWrite() < 10000) { + Internal::QuickItemNodeInstance::updateDirtyNode(rootNodeInstance().contentItem()); nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand({rootNodeInstance()})); } + clearChangedPropertyList(); + inFunction = false; } } -- cgit v1.2.1 From b307182e7694c433dbd31caa491696c1321c1361 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 13 Jun 2022 14:47:15 +0300 Subject: QmlDesigner: Fix occasional creator side crash related to puppet reset Change-Id: Iee032937b89b8ffcaa012c21b7cac029e1b286cf Reviewed-by: Mahmoud Badri --- src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index db22d27fc3..278d65fcd9 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1717,7 +1717,7 @@ void NodeInstanceView::view3DAction(const View3DActionCommand &command) void NodeInstanceView::requestModelNodePreviewImage(const ModelNode &node, const ModelNode &renderNode) { - if (node.isValid()) { + if (m_nodeInstanceServer && node.isValid()) { auto instance = instanceForModelNode(node); if (instance.isValid()) { qint32 renderItemId = -1; -- cgit v1.2.1 From 50aadacb6e670597fc308d409bcdae96e7efa9c0 Mon Sep 17 00:00:00 2001 From: Samuel Ghinet Date: Wed, 8 Jun 2022 18:00:09 +0300 Subject: QDS Editor 3D: Allow the user to select (and reset) the color of grid lines Task-number: QDS-7122 Change-Id: I686269e61b53bd5e3d5d1225376930612d869072 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../qml/qmlpuppet/commands/createscenecommand.h | 7 +- .../qml/qmlpuppet/commands/view3dactioncommand.h | 1 + .../qml/qmlpuppet/mockfiles/qt5/EditView3D.qml | 18 +++- .../qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml | 1 + .../qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml | 1 + .../qml/qmlpuppet/mockfiles/qt6/EditView3D.qml | 18 +++- .../qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml | 1 + .../qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml | 1 + .../instances/qt5informationnodeinstanceserver.cpp | 30 ++++--- .../instances/qt5informationnodeinstanceserver.h | 2 +- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../components/edit3d/backgroundcolorselection.cpp | 79 ++++++----------- .../components/edit3d/backgroundcolorselection.h | 13 ++- .../components/edit3d/edit3dactions.cpp | 3 +- .../qmldesigner/components/edit3d/edit3dview.cpp | 99 +++++++++++++++------- .../qmldesigner/components/edit3d/edit3dview.h | 6 +- .../components/edit3d/edit3dviewconfig.h | 98 +++++++++++++++++++++ .../designercore/instances/nodeinstanceview.cpp | 31 +++---- src/plugins/qmldesigner/designersettings.cpp | 1 + src/plugins/qmldesigner/designersettings.h | 1 + src/plugins/qmldesigner/qmldesignerconstants.h | 1 + src/plugins/qmldesigner/qmldesignerplugin.qbs | 1 + 22 files changed, 286 insertions(+), 128 deletions(-) create mode 100644 src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h diff --git a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h index c69d478875..47196df8d2 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h @@ -61,7 +61,8 @@ public: QSize captureImageMinimumSize, QSize captureImageMaximumSize, qint32 stateInstanceId, - const QList &edit3dBackgroundColor) + const QList &edit3dBackgroundColor, + const QColor &edit3dGridColor) : instances(instanceContainer) , reparentInstances(reparentContainer) , ids(idVector) @@ -78,6 +79,7 @@ public: , captureImageMaximumSize(captureImageMaximumSize) , stateInstanceId{stateInstanceId} , edit3dBackgroundColor{edit3dBackgroundColor} + , edit3dGridColor{edit3dGridColor} {} friend QDataStream &operator<<(QDataStream &out, const CreateSceneCommand &command) @@ -98,6 +100,7 @@ public: out << command.captureImageMinimumSize; out << command.captureImageMaximumSize; out << command.edit3dBackgroundColor; + out << command.edit3dGridColor; return out; } @@ -120,6 +123,7 @@ public: in >> command.captureImageMinimumSize; in >> command.captureImageMaximumSize; in >> command.edit3dBackgroundColor; + in >> command.edit3dGridColor; return in; } @@ -141,6 +145,7 @@ public: QSize captureImageMaximumSize; qint32 stateInstanceId = 0; QList edit3dBackgroundColor; + QColor edit3dGridColor; }; QDebug operator<<(QDebug debug, const CreateSceneCommand &command); diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h index cc3611df76..a1dc133032 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h @@ -57,6 +57,7 @@ public: ParticlesRestart, ParticlesSeek, SelectBackgroundColor, + SelectGridColor, ResetBackgroundColor, }; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml index 9a95ca34b9..09a4ebdc3f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml @@ -47,6 +47,7 @@ Item { property alias contentItem: contentItem property color backgroundGradientColorStart: "#222222" property color backgroundGradientColorEnd: "#999999" + property color gridColor: "#aaaaaa" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -96,12 +97,14 @@ Item { {"usePerspective": usePerspective, "showSceneLight": showEditLight, "showGrid": showGrid, + "gridColor": gridColor, "importScene": activeScene, "cameraZoomFactor": cameraControl._zoomFactor, "z": 1}); editView.usePerspective = Qt.binding(function() {return usePerspective;}); editView.showSceneLight = Qt.binding(function() {return showEditLight;}); editView.showGrid = Qt.binding(function() {return showGrid;}); + editView.gridColor = Qt.binding(function() {return gridColor;}); editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;}); selectionBoxes.length = 0; @@ -217,10 +220,19 @@ Item { function updateViewStates(viewStates) { if ("selectBackgroundColor" in viewStates) { - var color = viewStates.selectBackgroundColor - backgroundGradientColorStart = color[0]; - backgroundGradientColorEnd = color[1]; + if (Array.isArray(viewStates.selectBackgroundColor)) { + var colors = viewStates.selectBackgroundColor + backgroundGradientColorStart = colors[0]; + backgroundGradientColorEnd = colors[1]; + } else { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color; + backgroundGradientColorEnd = color; + } } + + if ("selectGridColor" in viewStates) + viewRoot.gridColor = viewStates.selectGridColor } // If resetToDefault is true, tool states not specifically set to anything will be reset to diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml index e450a5a796..d9df67fe7c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml @@ -33,6 +33,7 @@ Node { property alias lines: gridGeometry.lines property alias step: gridGeometry.step property alias subdivAlpha: subGridMaterial.opacity + property alias gridColor: mainGridMaterial.diffuseColor eulerRotation.x: 90 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml index 7a376179d8..4032e245ed 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml @@ -32,6 +32,7 @@ View3D { property bool usePerspective: false property alias showSceneLight: sceneLight.visible property alias showGrid: helperGrid.visible + property alias gridColor: helperGrid.gridColor property alias sceneHelpers: sceneHelpers property alias perspectiveCamera: scenePerspectiveCamera property alias orthoCamera: sceneOrthoCamera diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml index 228154a9a4..a3f14e9d11 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -48,6 +48,7 @@ Item { property alias contentItem: contentItem property color backgroundGradientColorStart: "#222222" property color backgroundGradientColorEnd: "#999999" + property color gridColor: "#aaaaaa" enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -100,12 +101,14 @@ Item { {"usePerspective": usePerspective, "showSceneLight": showEditLight, "showGrid": showGrid, + "gridColor": gridColor, "importScene": activeScene, "cameraZoomFactor": cameraControl._zoomFactor, "z": 1}); editView.usePerspective = Qt.binding(function() {return usePerspective;}); editView.showSceneLight = Qt.binding(function() {return showEditLight;}); editView.showGrid = Qt.binding(function() {return showGrid;}); + editView.gridColor = Qt.binding(function() {return gridColor;}); editView.cameraZoomFactor = Qt.binding(function() {return cameraControl._zoomFactor;}); selectionBoxes.length = 0; @@ -211,10 +214,19 @@ Item { function updateViewStates(viewStates) { if ("selectBackgroundColor" in viewStates) { - var color = viewStates.selectBackgroundColor - backgroundGradientColorStart = color[0]; - backgroundGradientColorEnd = color[1]; + if (Array.isArray(viewStates.selectBackgroundColor)) { + var colors = viewStates.selectBackgroundColor + backgroundGradientColorStart = colors[0]; + backgroundGradientColorEnd = colors[1]; + } else { + var color = viewStates.selectBackgroundColor + backgroundGradientColorStart = color; + backgroundGradientColorEnd = color; + } } + + if ("selectGridColor" in viewStates) + viewRoot.gridColor = viewStates.selectGridColor } // If resetToDefault is true, tool states not specifically set to anything will be reset to diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml index 66f383518e..ef10818eed 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml @@ -33,6 +33,7 @@ Node { property alias lines: gridGeometry.lines property alias step: gridGeometry.step property alias subdivAlpha: subGridMaterial.opacity + property alias gridColor: mainGridMaterial.diffuseColor eulerRotation.x: 90 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml index e59392b1ee..1d0e0377d3 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml @@ -32,6 +32,7 @@ View3D { property bool usePerspective: false property alias showSceneLight: sceneLight.visible property alias showGrid: helperGrid.visible + property alias gridColor: helperGrid.gridColor property alias sceneHelpers: sceneHelpers property alias perspectiveCamera: scenePerspectiveCamera property alias orthoCamera: sceneOrthoCamera diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index effa871ce6..d614901ca9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -1742,7 +1742,7 @@ QObject *Qt5InformationNodeInstanceServer::find3DSceneRoot(QObject *obj) const } void Qt5InformationNodeInstanceServer::setup3DEditView(const QList &instanceList, - const QHash &toolStates) + const CreateSceneCommand &command) { #ifdef QUICK3D_MODULE if (!m_editView3DData.rootItem) @@ -1775,6 +1775,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList &toolStates = command.edit3dToolStates; QString lastSceneId; auto helper = qobject_cast(m_3dHelper); if (helper) { @@ -1828,11 +1829,23 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QListcomponentCompleted(createComponentCompletedCommand(instanceList)); if (ViewConfig::isQuick3DMode()) { - setup3DEditView(instanceList, command.edit3dToolStates); + setup3DEditView(instanceList, command); updateRotationBlocks(command.auxiliaryChanges); } @@ -1963,12 +1976,6 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com #ifdef IMPORT_QUICK3D_ASSETS QTimer::singleShot(0, this, &Qt5InformationNodeInstanceServer::resolveImportSupport); #endif - - if (!command.edit3dBackgroundColor.isEmpty()) { - View3DActionCommand backgroundColorCommand(View3DActionCommand::SelectBackgroundColor, - QVariant::fromValue(command.edit3dBackgroundColor)); - view3DAction(backgroundColorCommand); - } } void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList &childList) @@ -2233,9 +2240,12 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c case View3DActionCommand::ShowCameraFrustum: updatedToolState.insert("showCameraFrustum", command.isEnabled()); break; - case View3DActionCommand::SelectBackgroundColor: { + case View3DActionCommand::SelectBackgroundColor: updatedViewState.insert("selectBackgroundColor", command.value()); break; + case View3DActionCommand::SelectGridColor: { + updatedViewState.insert("selectGridColor", command.value()); + break; } #ifdef QUICK3D_PARTICLES_MODULE case View3DActionCommand::ShowParticleEmitter: diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 291b2c3eec..9f6e450690 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -114,7 +114,7 @@ private: void createEditView3D(); void create3DPreviewView(); void setup3DEditView(const QList &instanceList, - const QHash &toolStates); + const CreateSceneCommand &command); void createCameraAndLightGizmos(const QList &instanceList) const; void add3DViewPorts(const QList &instanceList); void add3DScenes(const QList &instanceList); diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 1ac2f477bf..bd55391a31 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -158,6 +158,7 @@ extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/edit3d SOURCES edit3dview.cpp edit3dview.h + edit3dviewconfig.h edit3dwidget.cpp edit3dwidget.h edit3dcanvas.cpp edit3dcanvas.h edit3dactions.cpp edit3dactions.h diff --git a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp index 76db41a177..3d7a9207c0 100644 --- a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp @@ -23,85 +23,56 @@ ** ****************************************************************************/ -#include "backgroundcolorselection.h" +#pragma once + +#include -#include #include -#include -#include + +#include "backgroundcolorselection.h" +#include "edit3dviewconfig.h" using namespace QmlDesigner; -namespace { -QList readBackgroundColorConfiguration() +void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType) { - QVariant var = QmlDesigner::DesignerSettings::getValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); - - if (!var.isValid()) - return {}; - - auto colorNameList = var.value>(); - QTC_ASSERT(colorNameList.size() == 2, return {}); - - return {colorNameList[0], colorNameList[1]}; -} + if (m_dialog) + return; -void setBackgroundColorConfiguration(const QList &colorConfig) -{ - auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); - View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, - QVariant::fromValue(colorConfig)); - view->view3DAction(cmd); -} + m_dialog = BackgroundColorSelection::createColorDialog(parent, key, cmdType); + QTC_ASSERT(m_dialog, return); -void saveBackgroundColorConfiguration(const QList &colorConfig) -{ - QList colorsSaved = {colorConfig[0].name(), colorConfig[1].name()}; - QmlDesigner::DesignerSettings::setValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, - QVariant::fromValue(colorsSaved)); + QObject::connect(m_dialog, &QWidget::destroyed, m_dialog, [&]() { + m_dialog = nullptr; + }); } -} // namespace - -QColorDialog *BackgroundColorSelection::createDialog(QWidget *parent) +QColorDialog *BackgroundColorSelection::createColorDialog(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType) { auto dialog = new QColorDialog(parent); dialog->setModal(true); dialog->setAttribute(Qt::WA_DeleteOnClose); - const QList oldColorConfig = readBackgroundColorConfiguration(); + QList oldColorConfig = Edit3DViewConfig::load(key); dialog->show(); - QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [](const QColor &color) { - setBackgroundColorConfiguration({color, color}); + QObject::connect(dialog, &QColorDialog::currentColorChanged, dialog, [cmdType](const QColor &color) { + Edit3DViewConfig::set(cmdType, color); }); - QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [](const QColor &color) { - saveBackgroundColorConfiguration({color, color}); + QObject::connect(dialog, &QColorDialog::colorSelected, dialog, [key](const QColor &color) { + Edit3DViewConfig::save(key, color); }); - if (!oldColorConfig.isEmpty()) { - QObject::connect(dialog, &QColorDialog::rejected, dialog, [oldColorConfig]() { - setBackgroundColorConfiguration(oldColorConfig); + if (Edit3DViewConfig::isValid(oldColorConfig)) { + QObject::connect(dialog, &QColorDialog::rejected, dialog, [cmdType, oldColorConfig]() { + Edit3DViewConfig::set(cmdType, oldColorConfig); }); } return dialog; } - -void BackgroundColorSelection::showBackgroundColorSelectionWidget(QWidget *parent) -{ - if (m_dialog) - return; - - m_dialog = BackgroundColorSelection::createDialog(parent); - QTC_ASSERT(m_dialog, return); - - QObject::connect(m_dialog, &QWidget::destroyed, m_dialog, [&]() { - m_dialog = nullptr; - }); -} diff --git a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h index d8832f40fd..f7df55b8e3 100644 --- a/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h +++ b/src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h @@ -25,9 +25,13 @@ #pragma once -#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QColorDialog) namespace QmlDesigner { + class BackgroundColorSelection : public QObject { Q_OBJECT @@ -37,10 +41,13 @@ public: : QObject{parent} {} - static void showBackgroundColorSelectionWidget(QWidget *parent); + static void showBackgroundColorSelectionWidget(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType); private: - static QColorDialog *createDialog(QWidget *parent); + static QColorDialog *createColorDialog(QWidget *parent, const QByteArray &key, + View3DActionCommand::Type cmdType); + inline static QColorDialog *m_dialog = nullptr; }; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp index 76343584c9..e90f20767d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp @@ -48,7 +48,8 @@ Edit3DActionTemplate::Edit3DActionTemplate(const QString &description, void Edit3DActionTemplate::actionTriggered(bool b) { - if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor) { + if (m_type != View3DActionCommand::Empty && m_type != View3DActionCommand::SelectBackgroundColor + && m_type != View3DActionCommand::SelectGridColor) { auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); View3DActionCommand cmd(m_type, b); view->view3DAction(cmd); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 1ef3055ada..aa76d58370 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -28,6 +28,8 @@ #include "edit3dcanvas.h" #include "edit3dview.h" #include "edit3dwidget.h" +#include "edit3dviewconfig.h" +#include "backgroundcolorselection.h" #include #include @@ -42,8 +44,6 @@ #include #include -#include - #include #include @@ -266,6 +266,70 @@ void Edit3DView::setSeeker(SeekerSlider *slider) m_seeker = slider; } +Edit3DAction *Edit3DView::createSelectBackgrounColorAction() +{ + QString description = QCoreApplication::translate("SelectBackgroundColorAction", + "Select Background Color"); + QString tooltip = QCoreApplication::translate("SelectBackgroundColorAction", + "Select a color for the background of the 3D Editor."); + + auto operation = [this](const SelectionContext &) { + BackgroundColorSelection::showBackgroundColorSelectionWidget( + edit3DWidget(), + DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, + View3DActionCommand::SelectBackgroundColor); + }; + + return new Edit3DAction( + Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor, + description, + {}, false, false, {}, {}, operation, + tooltip); +} + +Edit3DAction *Edit3DView::createGridColorSelectionAction() +{ + QString description = QCoreApplication::translate("SelectGridColorAction", "Select Grid Color"); + QString tooltip = QCoreApplication::translate("SelectGridColorAction", + "Select a color for the grid lines of the 3D Editor."); + + auto operation = [this](const SelectionContext &) { + BackgroundColorSelection::showBackgroundColorSelectionWidget( + edit3DWidget(), + DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, + View3DActionCommand::SelectGridColor); + }; + + return new Edit3DAction( + Constants::EDIT3D_EDIT_SELECT_GRID_COLOR, View3DActionCommand::SelectGridColor, + description, {}, false, false, {}, {}, operation, + tooltip); +} + +Edit3DAction *Edit3DView::createResetColorAction() +{ + QString description = QCoreApplication::translate("ResetEdit3DColorsAction", "Reset Colors"); + QString tooltip = QCoreApplication::translate("ResetEdit3DColorsAction", + "Reset the background color and the color of the " + "grid lines of the 3D Editor to the default valus."); + + auto operation = [](const SelectionContext &) { + QList bgColors = {QRgb(0x222222), QRgb(0x999999)}; + Edit3DViewConfig::set(View3DActionCommand::SelectBackgroundColor, bgColors); + Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, bgColors); + + QColor gridColor{0xaaaaaa}; + Edit3DViewConfig::set(View3DActionCommand::SelectGridColor, gridColor); + Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, gridColor); + }; + + return new Edit3DAction( + QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor, + description, + {}, false, false, {}, {}, operation, + tooltip); +} + void Edit3DView::createEdit3DActions() { m_selectionModeAction @@ -338,32 +402,6 @@ void Edit3DView::createEdit3DActions() QKeySequence(Qt::Key_G), true, true, {}, {}, nullptr, QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid.")); - SelectionContextOperation showBackgroundColorSelection = [this](const SelectionContext &) { - BackgroundColorSelection::showBackgroundColorSelectionWidget(edit3DWidget()); - }; - - m_backgroundColorSelectionAction = new Edit3DAction( - QmlDesigner::Constants::EDIT3D_EDIT_SELECT_BACKGROUND_COLOR, View3DActionCommand::SelectBackgroundColor, - QCoreApplication::translate("SelectBackgroundColorAction", "Select Background Color"), - {}, false, false, {}, {}, showBackgroundColorSelection, - QCoreApplication::translate("SelectBackgroundColorAction", "Select a color for the background of the 3D Editor.")); - - m_resetBackgroundColorAction = new Edit3DAction( - QmlDesigner::Constants::EDIT3D_EDIT_RESET_BACKGROUND_COLOR, View3DActionCommand::ResetBackgroundColor, - QCoreApplication::translate("ResetBackgroundColorAction", "Reset Background Color"), - {}, false, false, {}, {}, [](const SelectionContext &) { - QList colors = {QRgb(0x222222), QRgb(0x999999)}; - auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); - View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, QVariant::fromValue(colors)); - view->view3DAction(cmd); - - QList colorsToSave = {colors[0].name(), colors[1].name()}; - QmlDesigner::DesignerSettings::setValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, - QVariant::fromValue(colorsToSave)); - }, - QCoreApplication::translate("ResetBackgroundColorAction", "Reset background color of the 3D Editor to the default value.")); - m_showSelectionBoxAction = new Edit3DAction( QmlDesigner::Constants::EDIT3D_EDIT_SHOW_SELECTION_BOX, View3DActionCommand::ShowSelectionBox, QCoreApplication::translate("ShowSelectionBoxAction", "Show Selection Boxes"), @@ -521,8 +559,9 @@ void Edit3DView::createEdit3DActions() m_visibilityToggleActions << m_showCameraFrustumAction; m_visibilityToggleActions << m_showParticleEmitterAction; - m_backgroundColorActions << m_backgroundColorSelectionAction; - m_backgroundColorActions << m_resetBackgroundColorAction; + m_backgroundColorActions << createSelectBackgrounColorAction(); + m_backgroundColorActions << createGridColorSelectionAction(); + m_backgroundColorActions << createResetColorAction(); } QVector Edit3DView::leftActions() const diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index e5cb2aba51..b817c20d1a 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -85,6 +85,10 @@ private: void createEdit3DWidget(); void checkImports(); + Edit3DAction *createSelectBackgrounColorAction(); + Edit3DAction *createGridColorSelectionAction(); + Edit3DAction *createResetColorAction(); + QPointer m_edit3DWidget; QVector m_leftActions; QVector m_rightActions; @@ -101,8 +105,6 @@ private: Edit3DAction *m_orientationModeAction = nullptr; Edit3DAction *m_editLightAction = nullptr; Edit3DAction *m_showGridAction = nullptr; - Edit3DAction *m_backgroundColorSelectionAction = nullptr; - Edit3DAction *m_resetBackgroundColorAction = nullptr; Edit3DAction *m_showSelectionBoxAction = nullptr; Edit3DAction *m_showIconGizmoAction = nullptr; Edit3DAction *m_showCameraFrustumAction = nullptr; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h b/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h new file mode 100644 index 0000000000..8e4081176a --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace QmlDesigner { + +class Edit3DViewConfig +{ +public: + static QList load(const char key[]) + { + QVariant var = DesignerSettings::getValue(key); + + if (!var.isValid()) + return {}; + + auto colorNameList = var.value(); + + return Utils::transform(colorNameList, [](const QString &colorName) { + return QColor{colorName}; + }); + } + + static void set(View3DActionCommand::Type type, const QList &colorConfig) + { + if (colorConfig.size() == 1) + set(type, colorConfig.at(0)); + else + setVariant(type, QVariant::fromValue(colorConfig)); + } + + static void set(View3DActionCommand::Type type, const QColor &color) + { + setVariant(type, QVariant::fromValue(color)); + } + + static void save(const QByteArray &key, const QList &colorConfig) + { + QStringList colorNames = Utils::transform(colorConfig, [](const QColor &color) { + return color.name(); + }); + + saveVariant(key, QVariant::fromValue(colorNames)); + } + + static void save(const QByteArray &key, const QColor &color) + { + saveVariant(key, QVariant::fromValue(color.name())); + } + + static bool isValid(const QList &colorConfig) { return !colorConfig.isEmpty(); } + +private: + static void setVariant(View3DActionCommand::Type type, const QVariant &colorConfig) + { + auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView(); + View3DActionCommand cmd(type, colorConfig); + view->view3DAction(cmd); + } + + static void saveVariant(const QByteArray &key, const QVariant &colorConfig) + { + DesignerSettings::setValue(key, colorConfig); + } +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 278d65fcd9..196faf2848 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -94,6 +94,8 @@ #include +#include + #include #include @@ -983,17 +985,6 @@ QList filterNodesForSkipItems(const QList &nodeList) return filteredNodeList; } -QList readBackgroundColorConfiguration(const QVariant &var) -{ - if (!var.isValid()) - return {}; - - auto colorNameList = var.value>(); - QTC_ASSERT(colorNameList.size() == 2, return {}); - - return {colorNameList[0], colorNameList[1]}; -} - CreateSceneCommand NodeInstanceView::createCreateSceneCommand() { QList nodeList = allModelNodes(); @@ -1148,16 +1139,15 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) stateInstanceId = stateNode.internalId(); - QVariant value + QColor gridColor; + QList backgroundColor; + #ifndef QMLDESIGNER_TEST - = QmlDesigner::DesignerSettings::getValue( - QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); -#else - = {}; + backgroundColor = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR); + QList gridColorList = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR); + if (!gridColorList.isEmpty()) + gridColor = gridColorList.at(0); #endif - QList edit3dBackgroundColor; - if (value.isValid()) - edit3dBackgroundColor = readBackgroundColorConfiguration(value); return CreateSceneCommand( instanceContainerList, @@ -1180,7 +1170,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() m_captureImageMinimumSize, m_captureImageMaximumSize, stateInstanceId, - edit3dBackgroundColor); + backgroundColor, + gridColor); } ClearSceneCommand NodeInstanceView::createClearSceneCommand() const diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 5474fd50d3..1b9651d471 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -82,6 +82,7 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET, true); const QStringList defaultValue = QStringList() << "#222222" << "#999999"; restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR, defaultValue); + restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR, "#aaaaaa"); restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 4dbee7752b..f39268b186 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -50,6 +50,7 @@ const char WARNING_FOR_DESIGNER_FEATURES_IN_EDITOR[] = "WarnAboutQtQuickDesigner const char SHOW_DEBUGVIEW[] = "ShowQtQuickDesignerDebugView"; const char ENABLE_DEBUGVIEW[] = "EnableQtQuickDesignerDebugView"; const char EDIT3DVIEW_BACKGROUND_COLOR[] = "Edit3DViewBackgroundColor"; +const char EDIT3DVIEW_GRID_COLOR[] = "Edit3DViewGridLineColor"; const char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar"; const char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet"; const char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory"; diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 8dc2b94749..b2ed51cd87 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -66,6 +66,7 @@ const char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle"; const char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle"; const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid"; const char EDIT3D_EDIT_SELECT_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.SelectBackgroundColor"; +const char EDIT3D_EDIT_SELECT_GRID_COLOR[] = "QmlDesigner.Editor3D.SelectGridColor"; const char EDIT3D_EDIT_RESET_BACKGROUND_COLOR[] = "QmlDesigner.Editor3D.ResetBackgroundColor"; const char EDIT3D_EDIT_SHOW_SELECTION_BOX[] = "QmlDesigner.Editor3D.ToggleSelectionBox"; const char EDIT3D_EDIT_SHOW_ICON_GIZMO[] = "QmlDesigner.Editor3D.ToggleIconGizmo"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 5266a146a3..be482a22ca 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -530,6 +530,7 @@ Project { "debugview/debugviewwidget.ui", "edit3d/edit3dview.cpp", "edit3d/edit3dview.h", + "edit3d/edit3dviewconfig.h", "edit3d/backgroundcolorselection.cpp", "edit3d/backgroundcolorselection.h", "edit3d/edit3dwidget.cpp", -- cgit v1.2.1 From 9c3636af497f8bdb2745bf85cc0286c9c6675987 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 13 Jun 2022 14:51:27 +0300 Subject: QmlDesigner: Ensure materials render properly after puppet reset This is a workaround for quick3d issue QTBUG-103316, where material library materials for editor are properly initialized only if the first encountered View3D in the scene is also rendered first. Fixes: QDS-7084 Change-Id: I8bb6a8e6bfe2fcffddfe86f92157d386fdf4095d Reviewed-by: Reviewed-by: Thomas Hartmann --- .../instances/qt5informationnodeinstanceserver.cpp | 42 +++++++++++++++++++++- .../instances/qt5informationnodeinstanceserver.h | 1 + 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index d614901ca9..97a60b5405 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -848,6 +848,18 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D(bool timerC m_activeSceneIdUpdateTimer.stop(); } + // We may have to substitute another scene to work around QTBUG-103316 + // The worked around issue is that if a material is used in multiple scenes, there is some + // kind of ownership for it in the first View3D that uses it, so if that view is not rendered + // first, the material will not be properly initialized for other views using it. + // To make materials work properly, we ensure that views are rendered at least once in the + // order they appear in the scene. + if (!m_priorityView3DsToRender.isEmpty()) { + QObject *sceneRoot = find3DSceneRoot(m_priorityView3DsToRender.first()); + if (sceneRoot) + activeSceneVar = objectToVariant(sceneRoot); + } + QMetaObject::invokeMethod(m_editView3DData.rootItem, "setActiveScene", Qt::QueuedConnection, Q_ARG(QVariant, activeSceneVar), Q_ARG(QVariant, QVariant::fromValue(sceneId))); @@ -1010,7 +1022,7 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() // If we have only one or no render queued, send the result to the creator side. // Otherwise, we'll hold on that until we have rendered all pending frames to ensure sent // results are correct. - if (m_need3DEditViewRender <= 1) { + if (m_priorityView3DsToRender.isEmpty() && m_need3DEditViewRender <= 1) { nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::Render3DView, QVariant::fromValue(imgContainer)}); #ifdef QUICK3D_PARTICLES_MODULE @@ -1021,6 +1033,25 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView() #endif } + if (!m_priorityView3DsToRender.isEmpty()) { + static int tryCounter = 0; + QObject *sceneRoot = find3DSceneRoot(m_priorityView3DsToRender.first()); + bool needAnotherRender = false; + if (sceneRoot) { + // Active scene is updated asynchronously, so verify we are actually rendering + // the correct priority scene + QObject *activeScene = QQmlProperty::read(m_editView3DData.rootItem, "activeScene").value(); + needAnotherRender = activeScene != sceneRoot; + } + + if (!needAnotherRender || ++tryCounter > 10) { + m_priorityView3DsToRender.removeFirst(); + updateActiveSceneToEditView3D(); + tryCounter = 0; + } + ++m_need3DEditViewRender; + } + if (m_need3DEditViewRender > 0) { // We queue another render even if the requested render count was one, because another // render is needed to ensure gizmo geometries are properly updated. @@ -1057,6 +1088,13 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView() { // This crashes on Qt 6.0.x due to QtQuick3D issue, so the preview generation is disabled #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) || QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) + if (!m_priorityView3DsToRender.isEmpty()) { + // Postpone any preview renders until we have rendered the priority views to ensure + // materials in material library are properly initialized + m_renderModelNodeImageViewTimer.start(17); + return; + } + RequestModelNodePreviewImageCommand cmd = *m_modelNodePreviewImageCommands.begin(); ServerNodeInstance instance; if (cmd.renderItemId() >= 0) @@ -1574,6 +1612,8 @@ void Qt5InformationNodeInstanceServer::add3DViewPorts(const QList m_view3Ds; QMultiHash m_3DSceneMap; // key: scene root, value: node QObject *m_active3DView = nullptr; + QList m_priorityView3DsToRender; QObject *m_active3DScene = nullptr; QSet m_parentChangedSet; QList m_completedComponentList; -- cgit v1.2.1 From 221376aa3823df2d36dedaf2e1ab97231c0ffbde Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 16 Jun 2022 15:30:25 +0300 Subject: QmlDesigner: Reset puppet when material is added This is workaround for material rendering issues in quick3d when a material is shared by multiple windows. Fixes: QDS-7096 Fixes: QDS-7118 Change-Id: I64fe2e51c5dda8e238502e5d926b6938b7b0731a Reviewed-by: Thomas Hartmann --- .../materialbrowser/materialbrowsermodel.cpp | 5 +++++ .../materialbrowser/materialbrowsermodel.h | 1 + .../materialbrowser/materialbrowserview.cpp | 26 ++++++++++++++++------ .../materialbrowser/materialbrowserview.h | 2 +- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp index d0420163c3..49f313534d 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp @@ -120,6 +120,11 @@ void MaterialBrowserModel::setHasModelSelection(bool b) emit hasModelSelectionChanged(); } +QList MaterialBrowserModel::materials() const +{ + return m_materialList; +} + void MaterialBrowserModel::setSearchText(const QString &searchText) { QString lowerSearchText = searchText.toLower(); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h index 32db357cae..73e6b2f99c 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h @@ -58,6 +58,7 @@ public: bool hasModelSelection() const; void setHasModelSelection(bool b); + QList materials() const; void setMaterials(const QList &materials, bool hasQuick3DImport); void removeMaterial(const ModelNode &material); void updateMaterialName(const ModelNode &material); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 9d6072856e..1af67d4fef 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -97,10 +97,12 @@ void MaterialBrowserView::modelAttached(Model *model) m_widget->clearSearchFilter(); m_hasQuick3DImport = model->hasImport("QtQuick3D"); - QTimer::singleShot(0, this, &MaterialBrowserView::refreshModel); + QTimer::singleShot(0, this, [this]() { + refreshModel(true); + }); } -void MaterialBrowserView::refreshModel() +void MaterialBrowserView::refreshModel(bool updateImages) { ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); QList materials; @@ -115,8 +117,10 @@ void MaterialBrowserView::refreshModel() m_widget->materialBrowserModel()->setMaterials(materials, m_hasQuick3DImport); - for (const ModelNode &node : std::as_const(materials)) - model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + if (updateImages) { + for (const ModelNode &node : std::as_const(materials)) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + } } bool MaterialBrowserView::isMaterial(const ModelNode &node) const @@ -204,8 +208,9 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node, bool matRemoved = oldParentNode.isValid() && oldParentNode.id() == Constants::MATERIAL_LIB_ID; if (matAdded || matRemoved) { - refreshModel(); - + if (matAdded) // Workaround to fix various material issues all likely caused by QTBUG-103316 + resetPuppet(); + refreshModel(!matAdded); int idx = m_widget->materialBrowserModel()->materialIndex(node); m_widget->materialBrowserModel()->selectMaterial(idx); } @@ -252,7 +257,7 @@ void MaterialBrowserView::importsChanged(const QList &addedImports, cons return; m_hasQuick3DImport = hasQuick3DImport; - refreshModel(); + refreshModel(true); } void MaterialBrowserView::customNotification(const AbstractView *view, const QString &identifier, @@ -267,6 +272,13 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt int idx = m_widget->materialBrowserModel()->materialIndex(nodeList.first()); if (idx != -1) m_widget->materialBrowserModel()->selectMaterial(idx); + } else if (identifier == "reset QmlPuppet") { + // Little delay is needed to allow puppet reset to actually be done, as it is async as well + QTimer::singleShot(200, this, [this]() { + const QList materials = m_widget->materialBrowserModel()->materials(); + for (const ModelNode &node : materials) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + }); } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h index e140eede13..c637efa49e 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h @@ -62,7 +62,7 @@ public: const QList &nodeList, const QList &data) override; private: - void refreshModel(); + void refreshModel(bool updateImages); bool isMaterial(const ModelNode &node) const; QPointer m_widget; -- cgit v1.2.1 From 568004e12182458b44222cc53a545611992eba02 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 7 Jun 2022 21:19:44 +0300 Subject: QmlDesigner: Detect asset drag'n'drop support based on property type Handle property support for asset drag based on property type rather than name in order to support properties with any name (like lightProbe). Change-Id: I20fd422119db96aebd505b47888c97f0d94bf7f9 Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../qmldesigner/components/materialeditor/materialeditorview.cpp | 7 ++++++- .../qmldesigner/components/propertyeditor/propertyeditorvalue.cpp | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 28c17d7561..ca76d45966 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -767,11 +767,16 @@ void MaterialEditorView::customNotification(const AbstractView *view, const QStr void QmlDesigner::MaterialEditorView::highlightSupportedProperties(bool highlight) { + if (!m_selectedMaterial.isValid()) + return; + DesignerPropertyMap &propMap = m_qmlBackEnd->backendValuesPropertyMap(); const QStringList propNames = propMap.keys(); + NodeMetaInfo metaInfo = m_selectedMaterial.metaInfo(); + QTC_ASSERT(metaInfo.isValid(), return); for (const QString &propName : propNames) { - if (propName.endsWith("Map")) { + if (metaInfo.propertyTypeName(propName.toLatin1()) == "QtQuick3D.Texture") { QObject *propEditorValObj = propMap.value(propName).value(); PropertyEditorValue *propEditorVal = qobject_cast(propEditorValObj); propEditorVal->setHasActiveDrag(highlight); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 867fd9bd65..fd568911ab 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -518,14 +518,15 @@ bool PropertyEditorValue::idListReplace(int idx, const QString &value) void PropertyEditorValue::commitDrop(const QString &path) { - if (m_modelNode.isSubclassOf("QtQuick3D.Material") && nameAsQString().endsWith("Map")) { + if (m_modelNode.isSubclassOf("QtQuick3D.Material") + && m_modelNode.metaInfo().propertyTypeName(m_name) == "QtQuick3D.Texture") { // create a texture node QmlDesigner::NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo("QtQuick3D.Texture"); QmlDesigner::ModelNode texture = m_modelNode.view()->createModelNode("QtQuick3D.Texture", metaInfo.majorVersion(), metaInfo.minorVersion()); texture.validId(); - modelNode().view()->rootModelNode().defaultNodeListProperty().reparentHere(texture); + m_modelNode.view()->rootModelNode().defaultNodeListProperty().reparentHere(texture); // TODO: group textures under 1 node (just like materials) // set texture source -- cgit v1.2.1 From d080e6331f3a75a28d2d3dd27ace853e7c51c9c0 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 15 Jun 2022 16:54:31 +0300 Subject: QmlDesigner: Parse material library on model attach Parsing has to happen so material in an old project are correctly appearing in the material views. Using a timer to wait until it is ok to create the material editor node. Otherwise errors happen. Change-Id: I54b532211f8a865c5183fab0fd8c12e5f15b983a Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../components/materialeditor/materialeditorview.cpp | 14 ++++++++++++-- .../components/materialeditor/materialeditorview.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index ca76d45966..10cd12a7c7 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -73,6 +73,13 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F7), m_stackedWidget); connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml); + m_ensureMatLibTimer.callOnTimeout([this] { + if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()) { + materialLibraryNode(); // create the material library node + m_ensureMatLibTimer.stop(); + } + }); + m_stackedWidget->setStyleSheet(Theme::replaceCssColors( QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); m_stackedWidget->setMinimumWidth(250); @@ -524,6 +531,11 @@ void MaterialEditorView::modelAttached(Model *model) m_hasQuick3DImport = model->hasImport("QtQuick3D"); + // Creating the material library node on model attach causes errors as long as the type information + // not complete yet, so we keep checking until type info is complete. + if (m_hasQuick3DImport) + m_ensureMatLibTimer.start(500); + if (!m_setupCompleted) { reloadQml(); m_setupCompleted = true; @@ -537,8 +549,6 @@ void MaterialEditorView::modelAboutToBeDetached(Model *model) { AbstractView::modelAboutToBeDetached(model); m_qmlBackEnd->materialEditorTransaction()->end(); - - } void MaterialEditorView::propertiesRemoved(const QList &propertyList) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h index d9c9e4c1ba..ff734ed30b 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h @@ -114,6 +114,7 @@ private: bool noValidSelection() const; ModelNode m_selectedMaterial; + QTimer m_ensureMatLibTimer; QShortcut *m_updateShortcut = nullptr; int m_timerId = 0; QStackedWidget *m_stackedWidget = nullptr; -- cgit v1.2.1 From 74a7e9f00caf6d4a49081ef0081bc99fa47377c5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 17 Jun 2022 13:45:52 +0200 Subject: QmlDesigner: Fix test build Amends 50aadacb6e670. Change-Id: If6cd7a1fc4df380693f3c4deee8791ed9863672a Reviewed-by: Miikka Heikkinen --- src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 196faf2848..3498e74926 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -90,12 +90,11 @@ #include #include #include +#include #endif #include -#include - #include #include -- cgit v1.2.1 From db8dbe25e0528d5e845be5c5f1ca44ec0a923f14 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 24 Feb 2022 16:55:19 +0100 Subject: QmlDesigner: Add a wizard for a ui.qml .qml file pair Task-number: QDS-5963 Change-Id: I16ee8361779f11ca2f24f35877869f3e83279d10 Reviewed-by: Thomas Hartmann --- .../files/qtuiquickform/file.qml.tpl | 5 + .../files/qtuiquickform/fileForm.ui.qml.tpl | 33 ++++++ .../files/qtuiquickform/file_ui.png | Bin 0 -> 1084 bytes .../files/qtuiquickform/file_ui@2.png | Bin 0 -> 1879 bytes .../files/qtuiquickform/wizard.json | 132 +++++++++++++++++++++ 5 files changed, 170 insertions(+) create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png create mode 100644 share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl new file mode 100644 index 0000000000..7bd94416c4 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +%{FormClass} { + button.onClicked: console.log("Button Pressed") +} diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl new file mode 100644 index 0000000000..1fcbbe9756 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl @@ -0,0 +1,33 @@ +/* +This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only. +It is supposed to be strictly declarative and only uses a subset of QML. If you edit +this file manually, you might introduce QML code that is not supported by Qt Design Studio. +Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files. +*/ + +import QtQuick 2.15 +@if %{UseQtQuickControls2} +import QtQuick.Controls 2.15 +@endif +@if %{UseImport} +import %{ApplicationImport} +@endif + +%{RootItem} { +@if %{UseImport} + width: Constants.width + height: Constants.height +@else + width: 1024 + height: 768 +@endif + + property alias button: button + + Button { + id: button + x: 64 + y: 64 + text: qsTr("Button") + } +} diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png new file mode 100644 index 0000000000..473a8430fe Binary files /dev/null and b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png differ diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png new file mode 100644 index 0000000000..9cf67e875b Binary files /dev/null and b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png differ diff --git a/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json new file mode 100644 index 0000000000..26c628f4b3 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json @@ -0,0 +1,132 @@ +{ + "version": 1, + "supportedProjectTypes": [ ], + "id": "Q.QtStudio.QmlUIForm.2", + "category": "B.StudioQtQuickFiles", + "trDescription": "Creates a UI file (.ui.qml) along with a matching QML file for implementation purposes.", + "trDisplayName": "QtQuick UI Form", + "trDisplayCategory": "Qt Quick Files", + "icon": "file_ui.png", + "platformIndependent": true, + + "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", + "options" : [ + { "key": "QmlFile", "value": "%{Class}.%{JS: Util.preferredSuffix('text/x-qml')}" }, + { "key": "UiFile", "value": "%{FormClass}.%{JS: Util.preferredSuffix('application/x-qt.ui+qml')}" }, + { "key": "ApplicationImport", "value": "%{QmlProjectName} 1.0" }, + { "key": "RootItem", "value": "%{JS: %{RootItemCB}.RootItem}" }, + { "key": "UseImportDefault", "value": "%{JS: false}" }, + { "key": "UseQtQuickControls2Default", "value": "%{JS: true}" } + ], + "pages" : + [ + { + "trDisplayName": "Define Class", + "trShortTitle": "Details", + "typeId": "Fields", + "data" : + [ + { + "name": "Class", + "trDisplayName": "Component name:", + "mandatory": true, + "type": "LineEdit", + "data": { + "validator": "(?:[A-Z_][a-zA-Z_0-9]*|)", + "fixup": "%{JS: '%{INPUT}'.charAt(0).toUpperCase() + '%{INPUT}'.slice(1) }" + } + }, + { + "name": "Sp1", + "type": "Spacer", + "data": { "factor": 2 } + }, + { + "name": "FormClass", + "trDisplayName": "Component form name:", + "mandatory": true, + "type": "LineEdit", + "data": { + "validator": "(?:[A-Z_][a-zA-Z_0-9]*|)", + "fixup": "%{JS: '%{INPUT}'.charAt(0).toUpperCase() + '%{INPUT}'.slice(1) }", + "trText": "%{Class}Form" + } + }, + { + "name": "TargetPath", + "type": "PathChooser", + "trDisplayName": "Path:", + "mandatory": true, + "data": + { + "kind": "directory", + "basePath": "%{InitialPath}", + "path": "%{InitialPath}" + } + }, + { + "name": "RootItemCB", + "trDisplayName": "Root Item:", + "type": "ComboBox", + "data": + { + "index": 0, + "items": + [ + { + "trKey": "Item", + "value": + "({ + 'RootItem': 'Item' + })" + }, + { + "trKey": "Rectangle", + "value": + "({ + 'RootItem': 'Rectangle' + })" + } + ] + } + }, + { + "name": "UseImport", + "trDisplayName": "Use Application Import", + "type": "CheckBox", + "data": + { + "checked": "%{UseImportDefault}" + } + }, + { + "name": "UseQtQuickControls2", + "trDisplayName": "Use QtQuick Controls 2", + "type": "CheckBox", + "data": + { + "checked": "%{UseQtQuickControls2Default}" + } + } + ] + } + ], + "generators" : + [ + { + "typeId": "File", + "data": [ + { + "source": "file.qml.tpl", + "target": "%{TargetPath}/%{QmlFile}", + "openInEditor": true + }, + { + "source": "fileForm.ui.qml.tpl", + "target": "%{TargetPath}/%{UiFile}", + "openInEditor": true + } + ] + } + ] +} -- cgit v1.2.1 From 2de2a4808ac3bfc17c6f51d03050afd7909ba120 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 21 Jun 2022 00:21:50 +0200 Subject: QmlDesigner: Fix FontComboBox drag'n'drop * Fix URL schema to also work under macOS * Avoid setting font name and further processing if error during font loading occurred Change-Id: I9d07a3daad8f7c8c464422b0cf3f94d61e4b231d Reviewed-by: Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/FontComboBox.qml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml index 8c05fa2f87..2f087c3b29 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml @@ -65,9 +65,11 @@ StudioControls.ComboBox { onDropped: function(drop) { drop.accepted = root.hasActiveHoverDrag - var fontLoader = root.createFontLoader("file:///" + dropArea.assetPath) - root.backendValue.value = fontLoader.name - root.currentIndex = root.find(root.backendValue.value) + var fontLoader = root.createFontLoader("file:" + dropArea.assetPath) + if (fontLoader.status === FontLoader.Ready) { + root.backendValue.value = fontLoader.name + root.currentIndex = root.find(root.backendValue.value) + } root.hasActiveHoverDrag = false root.backendValue.commitDrop(dropArea.assetPath) } -- cgit v1.2.1 From 281c5348944a1a32aae2582a7712ac98a6b00061 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 21 Jun 2022 14:16:01 +0200 Subject: QmlDesigner: Make inErrorState() private This method should be only for internal use, since it is different from errors.isEmpty(), because the rewriter is only inErrorState if parsing/rewriting fails, not if there is a semantic error. Change-Id: Ib021e5e80750a4edcb4661755e85e6880fd6617c Reviewed-by: Miikka Heikkinen --- src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp | 2 +- .../qmldesigner/components/componentcore/designeractionmanager.cpp | 2 +- .../qmldesigner/designercore/imagecache/imagecachecollector.cpp | 4 ++-- src/plugins/qmldesigner/designercore/include/rewriterview.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp index 81dc1ce486..a565b46445 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp @@ -81,7 +81,7 @@ bool AssetExporterView::saveQmlFile(QString *error) const void AssetExporterView::modelAttached(Model *model) { - if (model->rewriterView() && model->rewriterView()->inErrorState()) + if (model->rewriterView() && !model->rewriterView()->errors().isEmpty()) setState(LoadState::QmlErrorState); AbstractView::modelAttached(model); diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 7f5649ea5f..a0bd7a2389 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -513,7 +513,7 @@ public: ->currentModel(); if (currentModel->rewriterView() - && currentModel->rewriterView()->inErrorState()) { + && !currentModel->rewriterView()->errors().isEmpty()) { throw DocumentError{}; } diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index 429ca328af..0a225d1ab0 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -96,11 +96,11 @@ void ImageCacheCollector::start(Utils::SmallStringView name, model->setRewriterView(&rewriterView); - bool is3DRoot = !rewriterView.inErrorState() + bool is3DRoot = rewriterView.errors().isEmpty() && (rewriterView.rootModelNode().isSubclassOf("QtQuick3D.Node") || rewriterView.rootModelNode().isSubclassOf("QtQuick3D.Material")); - if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() + if (!rewriterView.errors().isEmpty() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() && !is3DRoot)) { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed); diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index e3a4af0b75..4e099290cd 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -127,7 +127,6 @@ public: void addError(const DocumentMessage &error); void enterErrorState(const QString &errorMessage); - bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } void leaveErrorState() { m_rewritingErrorMessage.clear(); } void resetToLastCorrectQml(); @@ -202,6 +201,7 @@ private: //variables void setupCanonicalHashes() const; void handleLibraryInfoUpdate(); void handleProjectUpdate(); + bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } TextModifier *m_textModifier = nullptr; int transactionLevel = 0; -- cgit v1.2.1 From 20bc8b8243ef24a4018096527ab2b0941767d056 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 13 Jun 2022 16:47:17 +0200 Subject: QmlDesigner: Install busy handler for every database access Even for pragma changes the statement can be getting busy. To prevent any exceptions in that case we set the busy handler directly after opening the database. Change-Id: Id10aab20d812d5224f8031fa895c396762858fdf Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- src/libs/sqlite/sqlitedatabase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index 5e72d6660e..96e6a87b8a 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -93,12 +93,12 @@ void Database::activateLogging() void Database::open(LockingMode lockingMode) { m_databaseBackend.open(m_databaseFilePath, m_openMode); - m_databaseBackend.setLockingMode(lockingMode); - m_databaseBackend.setJournalMode(m_journalMode); if (m_busyTimeout > 0ms) m_databaseBackend.setBusyTimeout(m_busyTimeout); else m_databaseBackend.registerBusyHandler(); + m_databaseBackend.setLockingMode(lockingMode); + m_databaseBackend.setJournalMode(m_journalMode); registerTransactionStatements(); m_isOpen = true; } -- cgit v1.2.1 From 3dca62ac1e2f39bdc58dfd3f0f837cee4cb87d2c Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 13 Jun 2022 17:54:29 +0200 Subject: QmlDesigner: Fix crash for dangling target It can be that the target is a dangling pointer. Task-number: QDS-7134 Change-Id: I51b7c9109b0f9193c31ee645144e2a24d1244ba9 Reviewed-by: Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/qmldesignerprojectmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 90e54ba65b..366f1ef04e 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -141,7 +141,7 @@ public: ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; PreviewTimeStampProvider timeStampProvider; AsynchronousImageFactory factory; - ::ProjectExplorer::Target *activeTarget = nullptr; + QPointer<::ProjectExplorer::Target> activeTarget; }; QmlDesignerProjectManager::QmlDesignerProjectManager() -- cgit v1.2.1 From 53642c9a2206efbe94898e682365a7adcf239994 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 21 Jun 2022 15:19:07 +0200 Subject: QmlDesigner: There can be also document messages from the puppet We have to check if the rewriterView()->errors() are actually empty. Change-Id: Icbcc82aa9229078fd51c975e48de3e1f06c29f4d Reviewed-by: Miikka Heikkinen --- src/plugins/qmldesigner/components/formeditor/formeditorview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 6c6e67be81..dc499c03b9 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -472,7 +472,7 @@ void FormEditorView::documentMessagesChanged(const QList &error if (!errors.isEmpty() && !model()->rewriterView()->hasIncompleteTypeInformation()) m_formEditorWidget->showErrorMessageBox(errors); - else + else if (rewriterView()->errors().isEmpty()) m_formEditorWidget->hideErrorMessageBox(); checkRootModelNode(); -- cgit v1.2.1 From 604342c3af64a423a9c60cae85d7dc5aafb8eb1b Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 17 Jun 2022 14:10:03 +0300 Subject: QmlDesigner: Add some delays to material browser refreshing Import change causes puppet to reset, so bit of delay is needed there before triggering material browser refresh. Also added similar delay to refresh done at model attach as it seems puppet reset can sometimes be triggered after attach as well. Fixes: QDS-7172 Change-Id: I47f7af54e55af074fb2b9e8cdb9e78fb051a16cc Reviewed-by: Mahmoud Badri Reviewed-by: Reviewed-by: Qt CI Bot --- .../components/materialbrowser/materialbrowserview.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 1af67d4fef..c0e0f9ad3c 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -97,7 +97,10 @@ void MaterialBrowserView::modelAttached(Model *model) m_widget->clearSearchFilter(); m_hasQuick3DImport = model->hasImport("QtQuick3D"); - QTimer::singleShot(0, this, [this]() { + + // Project load is already very busy and may even trigger puppet reset, so let's wait a moment + // before refreshing the model + QTimer::singleShot(1000, this, [this]() { refreshModel(true); }); } @@ -257,7 +260,17 @@ void MaterialBrowserView::importsChanged(const QList &addedImports, cons return; m_hasQuick3DImport = hasQuick3DImport; - refreshModel(true); + + if (m_hasQuick3DImport) { + // Import change will trigger puppet reset. + // However, it doesn't seem to trigger the notification about the reset, so wait here. + QTimer::singleShot(1000, this, [this]() { + refreshModel(true); + }); + } else { + // No quick3d import, so we can refresh immediately to clear the browser + refreshModel(true); + } } void MaterialBrowserView::customNotification(const AbstractView *view, const QString &identifier, -- cgit v1.2.1 From 62f34622df810ce0f036a08485630ececdc5f932 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 21 Jun 2022 11:14:22 +0300 Subject: QmlDesigner: Improve puppet reset handling in material browser Ensure just one reset call for cases where multiple materials are added at once, and detect reset completion from root instance completion notification instead of reset trigger notification, as it comes later and catches all puppet reset cases. Fixes: QDS-7119 Change-Id: I99baa718bd1c85b4581f07ce75193213110e8e96 Reviewed-by: Thomas Hartmann Reviewed-by: Reviewed-by: Mahmoud Badri --- .../materialbrowser/materialbrowserview.cpp | 40 ++++++++++++---------- .../materialbrowser/materialbrowserview.h | 2 ++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index c0e0f9ad3c..2a06d5acbc 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -211,8 +211,11 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node, bool matRemoved = oldParentNode.isValid() && oldParentNode.id() == Constants::MATERIAL_LIB_ID; if (matAdded || matRemoved) { - if (matAdded) // Workaround to fix various material issues all likely caused by QTBUG-103316 + if (matAdded && !m_puppetResetPending) { + // Workaround to fix various material issues all likely caused by QTBUG-103316 resetPuppet(); + m_puppetResetPending = true; + } refreshModel(!matAdded); int idx = m_widget->materialBrowserModel()->materialIndex(node); m_widget->materialBrowserModel()->selectMaterial(idx); @@ -261,16 +264,8 @@ void MaterialBrowserView::importsChanged(const QList &addedImports, cons m_hasQuick3DImport = hasQuick3DImport; - if (m_hasQuick3DImport) { - // Import change will trigger puppet reset. - // However, it doesn't seem to trigger the notification about the reset, so wait here. - QTimer::singleShot(1000, this, [this]() { - refreshModel(true); - }); - } else { - // No quick3d import, so we can refresh immediately to clear the browser - refreshModel(true); - } + // Import change will trigger puppet reset, so we don't want to update previews immediately + refreshModel(false); } void MaterialBrowserView::customNotification(const AbstractView *view, const QString &identifier, @@ -285,13 +280,22 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt int idx = m_widget->materialBrowserModel()->materialIndex(nodeList.first()); if (idx != -1) m_widget->materialBrowserModel()->selectMaterial(idx); - } else if (identifier == "reset QmlPuppet") { - // Little delay is needed to allow puppet reset to actually be done, as it is async as well - QTimer::singleShot(200, this, [this]() { - const QList materials = m_widget->materialBrowserModel()->materials(); - for (const ModelNode &node : materials) - model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); - }); + } +} + +void MaterialBrowserView::instancesCompleted(const QVector &completedNodeList) +{ + for (const ModelNode &node : completedNodeList) { + // We use root node completion as indication of puppet reset + if (node.isRootNode()) { + m_puppetResetPending = false; + QTimer::singleShot(1000, this, [this]() { + const QList materials = m_widget->materialBrowserModel()->materials(); + for (const ModelNode &node : materials) + model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); + }); + break; + } } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h index c637efa49e..503986a28e 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h @@ -60,6 +60,7 @@ public: void importsChanged(const QList &addedImports, const QList &removedImports) override; void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; + void instancesCompleted(const QVector &completedNodeList) override; private: void refreshModel(bool updateImages); @@ -68,6 +69,7 @@ private: QPointer m_widget; bool m_hasQuick3DImport = false; bool m_autoSelectModelMaterial = false; // TODO: wire this to some action + bool m_puppetResetPending = false; }; } // namespace QmlDesigner -- cgit v1.2.1 From 41986d794279c9a6db2e2893372707a3d5415b82 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 22 Jun 2022 12:19:57 +0300 Subject: QmlDesigner: Show IconButton tooltip also when button is disabled Fixes: QDS-7076 Change-Id: If412827e22c6f71a9f073d1c868dcdb325870c1d Reviewed-by: Mahmoud Badri --- .../imports/HelperWidgets/IconButton.qml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml index 2fc10b1855..dcd4733134 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml @@ -34,10 +34,10 @@ Rectangle { signal clicked() property alias icon: icon.text - property alias enabled: mouseArea.enabled property alias tooltip: toolTip.text property alias iconSize: icon.font.pixelSize + property bool enabled: true property int buttonSize: StudioTheme.Values.height property color normalColor: StudioTheme.Values.themeControlBackground property color hoverColor: StudioTheme.Values.themeControlBackgroundHover @@ -46,9 +46,10 @@ Rectangle { width: buttonSize height: buttonSize - color: mouseArea.pressed ? pressColor - : mouseArea.containsMouse ? hoverColor - : normalColor + color: !enabled ? normalColor + : mouseArea.pressed ? pressColor + : mouseArea.containsMouse ? hoverColor + : normalColor Behavior on color { ColorAnimation { @@ -71,7 +72,11 @@ Rectangle { anchors.fill: parent hoverEnabled: true - onClicked: root.clicked() + onClicked: { + // We need to keep mouse area enabled even when button is disabled to make tooltip work + if (root.enabled) + root.clicked() + } } ToolTip { -- cgit v1.2.1 From 359f4f176755c0504a4a6372835498f8faae3fb0 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 22 Jun 2022 12:48:25 +0300 Subject: QmlDesigner: Fix material editor/browser texts Fixes: QDS-7083 Change-Id: Ib4a5269e275c7811a5645bbff54e3b0ec95ec302 Reviewed-by: Mats Honkamaa Reviewed-by: Mahmoud Badri --- .../qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml | 8 +++++--- .../materialEditorQmlSources/EmptyMaterialEditorPane.qml | 5 +++-- .../materialEditorQmlSources/MaterialEditorToolBar.qml | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index ab061e4289..0419b945b9 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -128,7 +128,7 @@ Item { StudioControls.MenuSeparator {} StudioControls.MenuItem { - text: qsTr("New Material") + text: qsTr("Create New Material") onTriggered: materialBrowserModel.addNewMaterial() } @@ -169,7 +169,8 @@ Item { } Text { - text: qsTr("No materials yet.\nClick '+' above to start.") + text: qsTr("There are no materials in this project.
Select '+' to create one.") + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize horizontalAlignment: Text.AlignHCenter @@ -179,7 +180,8 @@ Item { } Text { - text: qsTr("Add QtQuick3D module using the Components view to enable the Material Browser."); + text: qsTr("To use Material Browser, first add the QtQuick3D module in the Components view."); + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize topPadding: 30 diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml index 80ec524e23..a9e272b6d5 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml @@ -48,8 +48,9 @@ PropertyEditorPane { height: 150 Text { - text: hasQuick3DImport ? qsTr("No materials yet.\nClick '+' above to start.") - : qsTr("Add QtQuick3D module using the Components view to enable the Material Editor.") + text: hasQuick3DImport ? qsTr("There are no materials in this project.
Select '+' to create one.") + : qsTr("To use Material Editor, first add the QtQuick3D module in the Components view.") + textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize horizontalAlignment: Text.AlignHCenter diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml index c610df94c5..80a8d9abbe 100644 --- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml +++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml @@ -63,7 +63,7 @@ Rectangle { buttonSize: root.height enabled: hasQuick3DImport onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial) - tooltip: qsTr("Add a new material.") + tooltip: qsTr("Create new material.") } IconButton { -- cgit v1.2.1 From 2cb45cbb6b12048a1e7e02877a56d63a09e708ed Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 22 Jun 2022 14:43:43 +0300 Subject: QmlDesigner: Reduce number of preview requests from material editor Removed preview request call from setValue, as it is called in long loops during initial project load and added the calls outside those loops where they already weren't there. Fixes: QDS-7175 Change-Id: Ia83814a0de6fe801d954373dc8ce0e4920e8a6a6 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../qmldesigner/components/materialeditor/materialeditorview.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 10cd12a7c7..49cebb3dd4 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -556,6 +556,7 @@ void MaterialEditorView::propertiesRemoved(const QList &proper if (noValidSelection()) return; + bool changed = false; for (const AbstractProperty &property : propertyList) { ModelNode node(property.parentModelNode()); @@ -564,8 +565,11 @@ void MaterialEditorView::propertiesRemoved(const QList &proper if (node == m_selectedMaterial || QmlObjectNode(m_selectedMaterial).propertyChangeForCurrentState() == node) { setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name())); + changed = true; } } + if (changed) + requestPreviewRender(); } void MaterialEditorView::variantPropertiesChanged(const QList &propertyList, PropertyChangeFlags /*propertyChange*/) @@ -670,6 +674,7 @@ void MaterialEditorView::instancePropertyChanged(const QList &propertyPair : propertyList) { const ModelNode modelNode = propertyPair.first; const QmlObjectNode qmlObjectNode(modelNode); @@ -681,8 +686,11 @@ void MaterialEditorView::instancePropertyChanged(const QListsetValue(qmlObjectNode, name, value); - requestPreviewRender(); m_locked = false; } -- cgit v1.2.1 From 092a1fc6a3b9668df3028b071d871f6f43f1e156 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 14:32:02 +0200 Subject: QmlDesigner: Support reparenting to new nodes in transactions When we reparent to a new node that was created during the same transaction, then this node has no position. In this case we have to delete the reparented nodes and they will be created as part of the creation of the new node, since they are children. Change-Id: Icd1d02f29f529fc0f00809f7ecebf3eabfdc9a5c Reviewed-by: Miikka Heikkinen --- .../designercore/model/modeltotextmerger.cpp | 2 +- .../designercore/model/rewriteactioncompressor.cpp | 27 ++++++++ .../designercore/model/rewriteactioncompressor.h | 7 ++- .../qml/qmldesigner/coretests/tst_testcore.cpp | 73 ++++++++++++++++++++++ .../auto/qml/qmldesigner/coretests/tst_testcore.h | 1 + 5 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp index 5a4276a416..14badab2bf 100644 --- a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp @@ -222,7 +222,7 @@ void ModelToTextMerger::applyChanges() return; dumpRewriteActions(QStringLiteral("Before compression")); - RewriteActionCompressor compress(propertyOrder()); + RewriteActionCompressor compress(propertyOrder(), m_rewriterView->positionStorage()); compress(m_rewriteActions, m_rewriterView->textModifier()->tabSettings()); dumpRewriteActions(QStringLiteral("After compression")); diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp index 24342002b3..c014bcd4d7 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp @@ -56,6 +56,7 @@ void RewriteActionCompressor::operator()(QList &actions, compressImports(actions); compressRereparentActions(actions); compressReparentIntoSamePropertyActions(actions); + compressReparentIntoNewPropertyActions(actions); compressPropertyActions(actions); compressAddEditRemoveNodeActions(actions); compressAddEditActions(actions, tabSettings); @@ -152,6 +153,32 @@ void RewriteActionCompressor::compressReparentIntoSamePropertyActions(QList &actions) const +{ + QList actionsToRemove; + + QList removeActions; + + for (int i = actions.size(); --i >= 0; ) { + RewriteAction *action = actions.at(i); + + if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) { + if (m_positionStore->nodeOffset(reparentAction->targetProperty().parentModelNode()) < 0) { + actionsToRemove.append(action); + + removeActions.append(new RemoveNodeRewriteAction(reparentAction->reparentedNode())); + } + } + } + + for (RewriteAction *action : qAsConst(actionsToRemove)) { + actions.removeOne(action); + delete action; + } + + actions.append(removeActions); +} + void RewriteActionCompressor::compressAddEditRemoveNodeActions(QList &actions) const { QList actionsToRemove; diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h index 57139f9811..02c1e3ad48 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h @@ -33,7 +33,10 @@ namespace Internal { class RewriteActionCompressor { public: - RewriteActionCompressor(const PropertyNameList &propertyOrder): m_propertyOrder(propertyOrder) {} + RewriteActionCompressor(const PropertyNameList &propertyOrder, ModelNodePositionStorage *positionStore) : + m_propertyOrder(propertyOrder), + m_positionStore(positionStore) + {} void operator()(QList &actions, const TextEditor::TabSettings &tabSettings) const; @@ -42,6 +45,7 @@ private: void compressRereparentActions(QList &actions) const; void compressReparentIntoSamePropertyActions(QList &actions) const; + void compressReparentIntoNewPropertyActions(QList &actions) const; void compressAddEditRemoveNodeActions(QList &actions) const; void compressPropertyActions(QList &actions) const; void compressAddEditActions(QList &actions, const TextEditor::TabSettings &tabSettings) const; @@ -49,6 +53,7 @@ private: private: PropertyNameList m_propertyOrder; + ModelNodePositionStorage *m_positionStore; }; } // namespace Internal diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index 26b8ddcf8e..f6708d2c8f 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -1152,6 +1152,79 @@ void tst_TestCore::testRewriterTransactionAddingAfterReparenting() } } +void tst_TestCore::testRewriterReparentToNewNode() +{ + const QLatin1String qmlString("\n" + "import QtQuick 2.0\n" + "\n" + "Item {\n" + " Item {}\n" + " Item {}\n" + " Item {}\n" + " Item {}\n" + "}\n"); + + QPlainTextEdit textEdit; + textEdit.setPlainText(qmlString); + NotIndentingTextEditModifier modifier(&textEdit); + + QScopedPointer model(Model::create("QtQuick.Rectangle")); + + QScopedPointer testRewriterView(new TestRewriterView(0, RewriterView::Amend)); + testRewriterView->setTextModifier(&modifier); + model->attachView(testRewriterView.data()); + + QVERIFY(testRewriterView->errors().isEmpty()); + + ModelNode rootModelNode = testRewriterView->rootModelNode(); + QVERIFY(rootModelNode.isValid()); + + const QList children = rootModelNode.directSubModelNodes(); + + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + rootModelNode.nodeListProperty("data").reparentHere(rectangle); + + rectangle.setIdWithoutRefactoring("newParent"); + + QVERIFY(rectangle.isValid()); + + for (const ModelNode &child : children) + rectangle.nodeListProperty("data").reparentHere(child); + + { + RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + rootModelNode.nodeListProperty("data").reparentHere(rectangle); + + rectangle.setIdWithoutRefactoring("newParent2"); + + for (const ModelNode &child : children) + rectangle.nodeListProperty("data").reparentHere(child); + } + + QCOMPARE(testRewriterView->allModelNodes().count(), 7); + + const QLatin1String expectedOutcome("\nimport QtQuick 2.0\n\n" + "Item {\n\n" + " Rectangle {\n" + " id: newParent\n" + " }\n\n" + " Rectangle {\n" + " id: newParent2\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n\n" + " Item {\n" + " }\n" + " }\n}\n"); + + + QCOMPARE(textEdit.toPlainText(), expectedOutcome); +} + void tst_TestCore::testRewriterForGradientMagic() { const QLatin1String qmlString("\n" diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h index 9a8aeb6450..5248763fef 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h @@ -144,6 +144,7 @@ private slots: void testRewriterChangeImports(); void testRewriterUnicodeChars(); void testRewriterTransactionAddingAfterReparenting(); + void testRewriterReparentToNewNode(); // // unit tests QmlModelNodeFacade/QmlModelState -- cgit v1.2.1 From 9caa28754cb76e6ce5ec0e17ad85f3950e00fad2 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 15:54:50 +0200 Subject: QmlDesigner: Use single transaction to move items into a layout Change-Id: Ic8eb3907d06843e7ad0d7b0117154b0b7a987808 Reviewed-by: Miikka Heikkinen --- .../qmldesigner/components/componentcore/modelnodeoperations.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index f4f8547528..11e052b1dd 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -475,19 +475,16 @@ static void layoutHelperFunction(const SelectionContext &selectionContext, const QmlItemNode qmlItemNode = QmlItemNode(selectionContext.firstSelectedModelNode()); if (qmlItemNode.hasInstanceParentItem()) { - ModelNode layoutNode; - selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction1",[=, &layoutNode](){ + + selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction",[=](){ QmlItemNode parentNode = qmlItemNode.instanceParentItem(); NodeMetaInfo metaInfo = selectionContext.view()->model()->metaInfo(layoutType); - layoutNode = selectionContext.view()->createModelNode(layoutType, metaInfo.majorVersion(), metaInfo.minorVersion()); + const ModelNode layoutNode = selectionContext.view()->createModelNode(layoutType, metaInfo.majorVersion(), metaInfo.minorVersion()); reparentTo(layoutNode, parentNode); - }); - - selectionContext.view()->executeInTransaction("DesignerActionManager|layoutHelperFunction2",[=](){ QList sortedSelectedNodes = selectionContext.selectedModelNodes(); Utils::sort(sortedSelectedNodes, lessThan); -- cgit v1.2.1 From cc1bf95dc2d14d4fdce32bb87938108e55c5e63c Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 22 Jun 2022 14:46:27 +0300 Subject: QmlDesigner: Ensure material lib node exists on project launch In this commit material library node is created on model attach. A timer keeps monitoring until it is suitable to create the node. This will properly move materials into material library for projects created with previous QDS versions. Also removed unnecessary handling on new material dragging, as rewriter now works properly with material library creation. Fixes: QDS-7178 Change-Id: Idf6f41906e02bc064961d8de9841ba1644bd3552 Reviewed-by: Thomas Hartmann --- .../materialeditor/materialeditorview.cpp | 7 +++- .../components/navigator/navigatortreemodel.cpp | 11 ----- .../designercore/include/abstractview.h | 1 + .../designercore/model/abstractview.cpp | 47 +++++++++++++--------- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 49cebb3dd4..7ab7cc090c 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -74,8 +74,11 @@ MaterialEditorView::MaterialEditorView(QWidget *parent) connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml); m_ensureMatLibTimer.callOnTimeout([this] { - if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()) { - materialLibraryNode(); // create the material library node + if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation() + && model()->rewriterView()->errors().isEmpty()) { + executeInTransaction("MaterialEditorView::MaterialEditorView", [this] { + ensureMaterialLibraryNode(); + }); m_ensureMatLibTimer.stop(); } }); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index d610014d5b..38c32f65cd 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -697,17 +697,6 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in newQmlObjectNode.destroy(); return; } - // We can't have material initially parented if material library is created in this - // same transaction (rewriter will not allow it for some reason) - ModelNode matLib = m_view->modelNodeForId(Constants::MATERIAL_LIB_ID); - if (!matLib.isValid()) { - newQmlObjectNode.destroy(); - newQmlObjectNode = QmlItemNode::createQmlObjectNode( - m_view, itemLibraryEntry, QPointF(), NodeAbstractProperty(), false); - newModelNode = newQmlObjectNode.modelNode(); - if (!newModelNode.isValid()) - return; - } m_view->assignMaterialTo3dModel(targetNode, newModelNode); } diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 18380aadb1..2eecf8df5a 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -259,6 +259,7 @@ public: void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); + void ensureMaterialLibraryNode(); ModelNode materialLibraryNode(); void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {}); diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 86dab97031..6826c9ed4d 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -809,16 +809,14 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion); } -// Returns ModelNode for project's material library. -// If the material library doesn't exist yet, it is created and all existing materials are moved -// under material library. -// This function should be called only form inside a transaction, as it potentially does many -// changes to model. -ModelNode AbstractView::materialLibraryNode() +// Creates material library if it doesn't exist and moves any existing materials into it +// This function should be called only from inside a transaction, as it potentially does many +// changes to model, or undo stack should be cleared after the call. +void AbstractView::ensureMaterialLibraryNode() { ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); if (matLib.isValid()) - return matLib; + return; // Create material library node TypeName nodeType = rootModelNode().isSubclassOf("QtQuick3D.Node") ? "QtQuick3D.Node" @@ -830,20 +828,28 @@ ModelNode AbstractView::materialLibraryNode() rootModelNode().defaultNodeListProperty().reparentHere(matLib); const QList materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material"); - if (materials.isEmpty()) - return matLib; - - // Move all materials to under material library node - for (const ModelNode &node : materials) { - // If material has no name, set name to id - QString matName = node.variantProperty("objectName").value().toString(); - if (matName.isEmpty()) { - VariantProperty objNameProp = node.variantProperty("objectName"); - objNameProp.setValue(node.id()); - } + if (!materials.isEmpty()) { + // Move all materials to under material library node + for (const ModelNode &node : materials) { + // If material has no name, set name to id + QString matName = node.variantProperty("objectName").value().toString(); + if (matName.isEmpty()) { + VariantProperty objNameProp = node.variantProperty("objectName"); + objNameProp.setValue(node.id()); + } - matLib.defaultNodeListProperty().reparentHere(node); + matLib.defaultNodeListProperty().reparentHere(node); + } } +} + +// Returns ModelNode for project's material library. +ModelNode AbstractView::materialLibraryNode() +{ + ensureMaterialLibraryNode(); + + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); + QTC_ASSERT(matLib.isValid(), return {}); return matLib; } @@ -859,6 +865,9 @@ void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const Mod QTC_ASSERT(modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Model"), return); ModelNode matLib = materialLibraryNode(); + + QTC_ASSERT(matLib.isValid(), return); + ModelNode newMaterialNode; if (materialNode.isValid() && materialNode.isSubclassOf("QtQuick3D.Material")) { -- cgit v1.2.1 From b63675db6ece28e1a7f896f297724f4ebaf47f2e Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 17:10:58 +0200 Subject: QmlDesigner: Show metainfo when node is created in debugview Change-Id: Id377b3e29f0a953a206dc3aa08008bb87f12bf0a Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/components/debugview/debugview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index be09b3864a..831170d302 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -110,9 +110,11 @@ void DebugView::nodeCreated(const ModelNode &createdNode) QString string; message.setString(&string); message << createdNode; + message << createdNode.majorVersion() << "." << createdNode.minorVersion(); message << createdNode.nodeSource(); - message << "MetaInfo " << createdNode.metaInfo().isValid(); + message << "MetaInfo " << createdNode.metaInfo().isValid() << " "; if (createdNode.metaInfo().isValid()) { + message << createdNode.metaInfo().majorVersion() << "." << createdNode.metaInfo().minorVersion(); message << createdNode.metaInfo().componentFileName(); } log("::nodeCreated:", message.readAll()); -- cgit v1.2.1 From 5fa46d665971bc0c7fbd2373400c5f2120ece922 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 17:11:51 +0200 Subject: QmlDesigner: Add createModelNode without explicit versions This makes it easier to create properly versioned ModelNodes. Change-Id: I2a81021daa5e57af6740e447826124f1554a2c78 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/designercore/include/abstractview.h | 2 ++ src/plugins/qmldesigner/designercore/model/abstractview.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 2eecf8df5a..6971f5f39e 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -134,6 +134,8 @@ public: RewriterTransaction beginRewriterTransaction(const QByteArray &identifier); + ModelNode createModelNode(const TypeName &typeName); + ModelNode createModelNode(const TypeName &typeName, int majorVersion, int minorVersion, diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 6826c9ed4d..e728c61358 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -31,6 +31,7 @@ #include "nodeinstanceview.h" #include #include +#include #include #include #include @@ -89,6 +90,12 @@ RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &ide return RewriterTransaction(this, identifier); } +ModelNode AbstractView::createModelNode(const TypeName &typeName) +{ + const NodeMetaInfo metaInfo = model()->metaInfo(typeName); + return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion()); +} + ModelNode AbstractView::createModelNode(const TypeName &typeName, int majorVersion, int minorVersion, -- cgit v1.2.1 From a0d474f2defd3ac14ae118d5a7e3cc99b5aab9f6 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 22 Jun 2022 17:13:25 +0200 Subject: QmlDesigner: Create transitions with proper versions The versions were hard coded which leads to issues. Task-number: QDS-6760 Change-Id: I94c3599348b996bb700da636cd63e74ea4c02be6 Reviewed-by: Reviewed-by: Thomas Hartmann --- .../transitioneditor/transitioneditorview.cpp | 90 +++++++++++----------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp index f487cc18fb..14c5eb6e95 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp @@ -251,50 +251,54 @@ ModelNode TransitionEditorView::addNewTransition() if (!idPropertyList.isEmpty()) { executeInTransaction( - " TransitionEditorView::addNewTransition", [&transition, idPropertyList, root, this]() { - transition = createModelNode("QtQuick.Transition", - 2, - 0, - {{ - "from", - "*", - }, - { - "to", - "*", - }}); - transition.setAuxiliaryData("transitionDuration", 2000); - transition.validId(); - root.nodeListProperty("transitions").reparentHere(transition); - - for (auto it = idPropertyList.cbegin(); it != idPropertyList.cend(); ++it) { - ModelNode parallelAnimation = createModelNode("QtQuick.ParallelAnimation", - 2, - 12); - transition.defaultNodeAbstractProperty().reparentHere(parallelAnimation); - for (const QString &property : it.value()) { - ModelNode sequentialAnimation - = createModelNode("QtQuick.SequentialAnimation", 2, 12); - parallelAnimation.defaultNodeAbstractProperty().reparentHere( - sequentialAnimation); - - ModelNode pauseAnimation = createModelNode("QtQuick.PauseAnimation", - 2, - 12, - {{"duration", 50}}); - sequentialAnimation.defaultNodeAbstractProperty().reparentHere( - pauseAnimation); - - ModelNode propertyAnimation = createModelNode("QtQuick.PropertyAnimation", - 2, - 12, - {{"property", property}, - {"duration", 150}}); - propertyAnimation.bindingProperty("target").setExpression(it.key()); - sequentialAnimation.defaultNodeAbstractProperty().reparentHere( - propertyAnimation); - } + " TransitionEditorView::addNewTransition", [&transition, idPropertyList, root, this]() { + + const NodeMetaInfo transitionMetaInfo = model()->metaInfo("QtQuick.Transition"); + transition = createModelNode("QtQuick.Transition", + transitionMetaInfo.majorVersion(), + transitionMetaInfo.minorVersion(), + {{ + "from", + "*", + }, + { + "to", + "*", + }}); + transition.setAuxiliaryData("transitionDuration", 2000); + transition.validId(); + root.nodeListProperty("transitions").reparentHere(transition); + + for (auto it = idPropertyList.cbegin(); it != idPropertyList.cend(); ++it) { + ModelNode parallelAnimation = createModelNode("QtQuick.ParallelAnimation"); + transition.defaultNodeAbstractProperty().reparentHere(parallelAnimation); + for (const QString &property : it.value()) { + ModelNode sequentialAnimation + = createModelNode("QtQuick.SequentialAnimation"); + parallelAnimation.defaultNodeAbstractProperty().reparentHere( + sequentialAnimation); + + const NodeMetaInfo pauseMetaInfo = model()->metaInfo("QtQuick.PauseAnimation"); + + ModelNode pauseAnimation = createModelNode("QtQuick.PauseAnimation", + pauseMetaInfo.majorVersion(), + pauseMetaInfo.minorVersion(), + {{"duration", 50}}); + sequentialAnimation.defaultNodeAbstractProperty().reparentHere( + pauseAnimation); + + const NodeMetaInfo propertyMetaInfo = model()->metaInfo("QtQuick.PauseAnimation"); + + ModelNode propertyAnimation = createModelNode("QtQuick.PropertyAnimation", + propertyMetaInfo.majorVersion(), + propertyMetaInfo.minorVersion(), + {{"property", property}, + {"duration", 150}}); + propertyAnimation.bindingProperty("target").setExpression(it.key()); + sequentialAnimation.defaultNodeAbstractProperty().reparentHere( + propertyAnimation); } + } }); } else { QString properties; -- cgit v1.2.1 From 5903d82c0b6356d1bb3460ed2b934ba2e87774ce Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 16 Jun 2022 12:29:50 +0200 Subject: QmlDesigner: Fix hover color for ButtonRow Use the default background color for ButtonRow buttons on global hover. This needs to be done to distinguish between hover and global hover on ButtonRow buttons as we unified the two colors as an attempt to make the UI a bit less noisy. Change-Id: I63f9c730367e9b906a772a63210c7ca548647352 Reviewed-by: Brook Cronin Reviewed-by: Reviewed-by: Thomas Hartmann --- .../propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml index 577257de70..c594220d5e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml @@ -136,7 +136,7 @@ T.AbstractButton { when: myButton.globalHover && !myButton.hover && !myButton.pressed && myButton.enabled PropertyChanges { target: buttonBackground - color: StudioTheme.Values.themeControlBackgroundGlobalHover + color: StudioTheme.Values.themeControlBackground } }, State { -- cgit v1.2.1 From b3be9d9802850718c10b08602cf41dd109040c8f Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 11:59:20 +0300 Subject: QmlDesigner: Tweak 3D asset import dialog layout On some font scalings, spinboxes were too tight, especially when there was just one row of options showing, so increased the row height and tweaked layout margins a bit. Fixes: QDS-7186 Change-Id: I0650ab976d96f27fc9cf606c4faa6fa2d7c5e8f4 Reviewed-by: Thomas Hartmann --- .../components/itemlibrary/itemlibraryassetimportdialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 0fe286a998..dc29dab8c1 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -74,7 +74,7 @@ static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString formatter->plainTextEdit()->verticalScrollBar()->maximum()); } -static const int rowHeight = 28; +static const int rowHeight = 32; static const int checkBoxColWidth = 18; static const int labelMinWidth = 130; static const int controlMinWidth = 65; @@ -781,7 +781,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid( int &globalOptionsHeight = advanced ? m_advancedData.optionsHeight : m_simpleData.optionsHeight; globalOptionRows = qMax(globalOptionRows, optionRows); globalOptionsHeight = qMax(rowHeight * optionRows + 20, globalOptionsHeight); - layout->setContentsMargins(8, 8, 8, 0); + layout->setContentsMargins(8, 6, 8, 0); return layout; } -- cgit v1.2.1 From 7aaaccb2812d2eaa237861f914ef3fae3ba1dcee Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 14:13:29 +0300 Subject: QmlDesigner: Remove duplicate assert This assert was redundant, leading to duplicate warnings if triggered. Change-Id: I59b6a7c17345a2ccba0d51ef50a303eec2026422 Reviewed-by: Mahmoud Badri --- src/plugins/qmldesigner/designercore/model/abstractview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index e728c61358..046572d714 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -873,7 +873,8 @@ void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const Mod ModelNode matLib = materialLibraryNode(); - QTC_ASSERT(matLib.isValid(), return); + if (!matLib.isValid()) + return; ModelNode newMaterialNode; -- cgit v1.2.1 From 8a8a2f5c5558d02eb1efb5c5e33d18c7d6b7e35d Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 14:20:56 +0300 Subject: QmlDesigner: Unify the background of 3D preview images Added 3D checkerboard floor on all 3D previews. Since shadows generally look bad for arbitrary 3D scenes, and would mostly be obscured by the model itself as we want the light mostly from the front, removed shadows also from the material preview to unify the previews. Qt5 had issues rendering the 3D floor texture, so used a static image there, as Qt5 only generates previews of one size. Fixes: QDS-7078 Change-Id: I74d094878ed01e6e531ad60df1f8d9d7cf415860 Reviewed-by: Reviewed-by: Mahmoud Badri --- share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc | 2 +- .../qmlpuppet/mockfiles/images/static_floor.png | Bin 0 -> 2685 bytes .../qmlpuppet/mockfiles/qt5/MaterialNodeView.qml | 24 ----------- .../mockfiles/qt5/ModelNode3DImageView.qml | 9 ++--- .../qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml | 2 +- .../qmlpuppet/mockfiles/qt6/MaterialNodeView.qml | 23 ----------- .../mockfiles/qt6/ModelNode3DImageView.qml | 44 +++++++++++++++++++++ .../qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml | 2 +- 8 files changed, 51 insertions(+), 55 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc index 7e023c127b..bbe9a910db 100644 --- a/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc +++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc @@ -13,7 +13,7 @@ mockfiles/images/directional@2x.png mockfiles/images/point.png mockfiles/images/point@2x.png - mockfiles/images/floor_tex.png + mockfiles/images/static_floor.png mockfiles/images/spot.png mockfiles/images/spot@2x.png mockfiles/qt5/AdjustableArrow.qml diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png new file mode 100644 index 0000000000..93073719f5 Binary files /dev/null and b/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png differ diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index c36d8c227c..9fee06e0ad 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -45,10 +45,6 @@ View3D { Node { DirectionalLight { - shadowMapQuality: Light.ShadowMapQualityMedium - shadowFilter: 20 - shadowFactor: 21 - castsShadow: true eulerRotation.x: -26 eulerRotation.y: -57 } @@ -68,25 +64,5 @@ View3D { source: "#Sphere" materials: previewMaterial } - - Model { - id: floorModel - source: "#Rectangle" - scale.y: 8 - scale.x: 8 - eulerRotation.x: -90 - materials: floorMaterial - DefaultMaterial { - id: floorMaterial - diffuseMap: floorTex - - Texture { - id: floorTex - source: "../images/floor_tex.png" - scaleU: floorModel.scale.x - scaleV: floorModel.scale.y - } - } - } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index a6d5c6b1db..70b9dbc4d0 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -123,14 +123,13 @@ Item { anchors.fill: parent } - Rectangle { + // We can use static image in Qt5 as only small previews will be generated + Image { id: backgroundRect anchors.fill: parent z: -1 - gradient: Gradient { - GradientStop { position: 1.0; color: "#222222" } - GradientStop { position: 0.0; color: "#999999" } - } + source: "../images/static_floor.png" + fillMode: Image.Stretch } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index b497b0419a..82688bbef5 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -70,7 +70,7 @@ View3D { materials: [ DefaultMaterial { - diffuseColor: "#4aee45" + diffuseColor: "#999999" } ] } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index ed5cfea56f..94051d5f6e 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -45,10 +45,6 @@ View3D { Node { DirectionalLight { - shadowMapQuality: Light.ShadowMapQualityMedium - shadowFilter: 20 - shadowFactor: 21 - castsShadow: true eulerRotation.x: -26 eulerRotation.y: -57 } @@ -70,24 +66,5 @@ View3D { materials: previewMaterial } - Model { - id: floorModel - source: "#Rectangle" - scale.y: 8 - scale.x: 8 - eulerRotation.x: -90 - materials: floorMaterial - DefaultMaterial { - id: floorMaterial - diffuseMap: floorTex - - Texture { - id: floorTex - source: "../images/floor_tex.png" - scaleU: floorModel.scale.x - scaleV: floorModel.scale.y - } - } - } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 5caac0047c..031d01d65f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -126,6 +126,50 @@ Item { GradientStop { position: 1.0; color: "#222222" } GradientStop { position: 0.0; color: "#999999" } } + + // Use View3D instead of static image to make background look good on all resolutions + View3D { + anchors.fill: parent + environment: sceneEnv + + SceneEnvironment { + id: sceneEnv + antialiasingMode: SceneEnvironment.MSAA + antialiasingQuality: SceneEnvironment.High + } + + DirectionalLight { + eulerRotation.x: -26 + eulerRotation.y: -57 + } + + PerspectiveCamera { + y: 125 + z: 120 + eulerRotation.x: -31 + clipNear: 1 + clipFar: 1000 + } + + Model { + id: floorModel + source: "#Rectangle" + scale.y: 8 + scale.x: 8 + eulerRotation.x: -90 + materials: floorMaterial + DefaultMaterial { + id: floorMaterial + diffuseMap: floorTex + Texture { + id: floorTex + source: "../images/floor_tex.png" + scaleU: floorModel.scale.x + scaleV: floorModel.scale.y + } + } + } + } } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 4da76ea097..ea2e23837f 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -70,7 +70,7 @@ View3D { materials: [ DefaultMaterial { - diffuseColor: "#4aee45" + diffuseColor: "#999999" } ] } -- cgit v1.2.1 From 93cd068d3e6cadb78f007975853828be35a4e1c6 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 23 Jun 2022 15:37:26 +0300 Subject: QmlDesigner: Create material library at import change There are still rewriter issues with Qt5, where component library templates for models contain materials, so create material library when quick3d import is added to ensure we never need to create it when models are added. Change-Id: I7006a39228d316dbfd84f49d19c025bb42b6765c Reviewed-by: Mahmoud Badri --- .../qmldesigner/components/materialeditor/materialeditorview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 7ab7cc090c..8b3d693274 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -718,6 +718,9 @@ void MaterialEditorView::importsChanged(const QList &addedImports, const m_hasQuick3DImport = model()->hasImport("QtQuick3D"); m_qmlBackEnd->contextObject()->setHasQuick3DImport(m_hasQuick3DImport); + if (m_hasQuick3DImport) + m_ensureMatLibTimer.start(500); + resetView(); } -- cgit v1.2.1 From 34491bdfc34e518b902c1dd2085ef64d8680e315 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 23 Jun 2022 16:20:39 +0200 Subject: QmlDesigner: Only remove node with position Extending the test case. Change-Id: I37255de763262e069c2f9d30b1ce584a0347fbcf Reviewed-by: Reviewed-by: Thomas Hartmann --- .../designercore/model/rewriteactioncompressor.cpp | 5 +++- .../qml/qmldesigner/coretests/tst_testcore.cpp | 27 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp index c014bcd4d7..0662da4e86 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp @@ -166,7 +166,10 @@ void RewriteActionCompressor::compressReparentIntoNewPropertyActions(QListnodeOffset(reparentAction->targetProperty().parentModelNode()) < 0) { actionsToRemove.append(action); - removeActions.append(new RemoveNodeRewriteAction(reparentAction->reparentedNode())); + const ModelNode childNode = reparentAction->reparentedNode(); + + if (m_positionStore->nodeOffset(childNode) > 0) + removeActions.append(new RemoveNodeRewriteAction(childNode)); } } } diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index f6708d2c8f..b6ff4903c4 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -1181,7 +1181,7 @@ void tst_TestCore::testRewriterReparentToNewNode() const QList children = rootModelNode.directSubModelNodes(); - ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle"); rootModelNode.nodeListProperty("data").reparentHere(rectangle); rectangle.setIdWithoutRefactoring("newParent"); @@ -1193,7 +1193,7 @@ void tst_TestCore::testRewriterReparentToNewNode() { RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); - ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle", 2, 0); + ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle"); rootModelNode.nodeListProperty("data").reparentHere(rectangle); rectangle.setIdWithoutRefactoring("newParent2"); @@ -1223,6 +1223,29 @@ void tst_TestCore::testRewriterReparentToNewNode() QCOMPARE(textEdit.toPlainText(), expectedOutcome); + + rectangle.destroy(); + + QCOMPARE(testRewriterView->allModelNodes().count(), 6); + + { + RewriterTransaction transaction = testRewriterView->beginRewriterTransaction("TEST"); + + ModelNode newChild = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(newChild); + newChild.setIdWithoutRefactoring("newChild"); + ModelNode newParent = testRewriterView->createModelNode("QtQuick.Rectangle"); + rootModelNode.nodeListProperty("data").reparentHere(newParent); + + newParent.setIdWithoutRefactoring("newParent3"); + + for (const ModelNode &child : children) + newParent.nodeListProperty("data").reparentHere(child); + + newParent.nodeListProperty("data").reparentHere(newChild); + } + + QCOMPARE(testRewriterView->allModelNodes().count(), 8); } void tst_TestCore::testRewriterForGradientMagic() -- cgit v1.2.1 From 21ef02a016f7921fab8f72e3fcea2147bb2cd018 Mon Sep 17 00:00:00 2001 From: Brook Cronin Date: Fri, 24 Jun 2022 11:23:06 +0200 Subject: update fixed version of icon font Change-Id: Iedf945b3718d4df245e24ac1ba756b20f6ed9cf1 Reviewed-by: Thomas Hartmann --- .../imports/StudioTheme/icons.ttf | Bin 23272 -> 23512 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index 5a3e99d459..cefd1d7d86 100644 Binary files a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf and b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf differ -- cgit v1.2.1 From a627d43d39bc17e7144fda724cb41d944bded6a5 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 27 Jun 2022 11:07:32 +0300 Subject: QmlDesigner: Fix crash on mode change Added model pointer validity checks into a few places. Fixes: QDS-7191 Change-Id: I94beb134f4d9a0b1c7fc9dc87da1d02ad255beaa Reviewed-by: Thomas Hartmann --- .../qmldesigner/components/materialbrowser/materialbrowserview.cpp | 2 ++ .../qmldesigner/components/materialeditor/materialeditorview.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 2a06d5acbc..2d02ba1276 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -290,6 +290,8 @@ void MaterialBrowserView::instancesCompleted(const QVector &completed if (node.isRootNode()) { m_puppetResetPending = false; QTimer::singleShot(1000, this, [this]() { + if (!model() || !model()->nodeInstanceView()) + return; const QList materials = m_widget->materialBrowserModel()->materials(); for (const ModelNode &node : materials) model()->nodeInstanceView()->previewImageDataForGenericNode(node, {}); diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp index 8b3d693274..d86ef1463b 100644 --- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp +++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp @@ -416,6 +416,8 @@ void MaterialEditorView::handleToolBarAction(int action) } case MaterialEditorContextObject::AddNewMaterial: { + if (!model()) + break; executeInTransaction("MaterialEditorView:handleToolBarAction", [&] { NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial"); ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(), @@ -634,7 +636,7 @@ void MaterialEditorView::auxiliaryDataChanged(const ModelNode &node, const Prope // request render image for the selected material node void MaterialEditorView::requestPreviewRender() { - if (m_selectedMaterial.isValid()) + if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid()) model()->nodeInstanceView()->previewImageDataForGenericNode(m_selectedMaterial, {}); } @@ -740,6 +742,9 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material) { QTC_ASSERT(material.isValid(), return); + if (!model()) + return; + TypeName matType = material.type(); QmlObjectNode sourceMat(material); -- cgit v1.2.1 From 73af75fe68eb0af6ef396a8ef90693c8fdd0f8e6 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 28 Jun 2022 12:38:12 +0300 Subject: QmlDesigner: Fix crash in material browser Task-number: QDS-7191 Change-Id: I9542a227aeb3f462ff3572e9a07a7473f98bfa61 Reviewed-by: Thomas Hartmann --- .../qmldesigner/components/materialbrowser/materialbrowserview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 2d02ba1276..d85e8239c1 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -107,6 +107,9 @@ void MaterialBrowserView::modelAttached(Model *model) void MaterialBrowserView::refreshModel(bool updateImages) { + if (!model() || !model()->nodeInstanceView()) + return; + ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); QList materials; -- cgit v1.2.1 From ee40ed19e55a47dd109d1b7f4faf9a44ed97fc0f Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 22 Jun 2022 12:26:03 +0300 Subject: Doc: Update timeline documentation - Added a task topic for binding a timeline to a property. - Added topic on adding multilpe timelines. - Some changes to focus more on the task rather than function. - Other minor updates. Task-number: QDS-6879 Change-Id: Ibd99785d6a9ee70fc10b8e1395ef8aaf0e186ddc Reviewed-by: Mahmoud Badri Reviewed-by: Leena Miettinen --- .../images/timeline-bind-animation-state.png | Bin 0 -> 4262 bytes .../images/timeline-insert-keyframe.png | Bin 0 -> 8974 bytes .../images/timeline-per-property-recording.png | Bin 0 -> 6041 bytes .../images/timeline-settings-dialog-second.png | Bin 0 -> 16649 bytes .../images/timeline-settings-dialog.png | Bin 0 -> 14019 bytes .../images/timeline-settings-property-binding.png | Bin 0 -> 14993 bytes doc/qtdesignstudio/images/timeline-states.png | Bin 0 -> 12233 bytes .../qtquick-component-context-menu.qdocinc | 2 +- .../src/views/qtquick-timeline-view.qdoc | 14 +- doc/qtdesignstudio/src/views/qtquick-timeline.qdoc | 244 +++++++++++++-------- 10 files changed, 164 insertions(+), 96 deletions(-) create mode 100644 doc/qtdesignstudio/images/timeline-bind-animation-state.png create mode 100644 doc/qtdesignstudio/images/timeline-insert-keyframe.png create mode 100644 doc/qtdesignstudio/images/timeline-per-property-recording.png create mode 100644 doc/qtdesignstudio/images/timeline-settings-dialog-second.png create mode 100644 doc/qtdesignstudio/images/timeline-settings-dialog.png create mode 100644 doc/qtdesignstudio/images/timeline-settings-property-binding.png create mode 100644 doc/qtdesignstudio/images/timeline-states.png diff --git a/doc/qtdesignstudio/images/timeline-bind-animation-state.png b/doc/qtdesignstudio/images/timeline-bind-animation-state.png new file mode 100644 index 0000000000..7e65c85a30 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-bind-animation-state.png differ diff --git a/doc/qtdesignstudio/images/timeline-insert-keyframe.png b/doc/qtdesignstudio/images/timeline-insert-keyframe.png new file mode 100644 index 0000000000..c46a711806 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-insert-keyframe.png differ diff --git a/doc/qtdesignstudio/images/timeline-per-property-recording.png b/doc/qtdesignstudio/images/timeline-per-property-recording.png new file mode 100644 index 0000000000..7daa337aa1 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-per-property-recording.png differ diff --git a/doc/qtdesignstudio/images/timeline-settings-dialog-second.png b/doc/qtdesignstudio/images/timeline-settings-dialog-second.png new file mode 100644 index 0000000000..03cd0be355 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-settings-dialog-second.png differ diff --git a/doc/qtdesignstudio/images/timeline-settings-dialog.png b/doc/qtdesignstudio/images/timeline-settings-dialog.png new file mode 100644 index 0000000000..aa910e67f6 Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-settings-dialog.png differ diff --git a/doc/qtdesignstudio/images/timeline-settings-property-binding.png b/doc/qtdesignstudio/images/timeline-settings-property-binding.png new file mode 100644 index 0000000000..a774bcd84a Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-settings-property-binding.png differ diff --git a/doc/qtdesignstudio/images/timeline-states.png b/doc/qtdesignstudio/images/timeline-states.png new file mode 100644 index 0000000000..a1dc73e51e Binary files /dev/null and b/doc/qtdesignstudio/images/timeline-states.png differ diff --git a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc index af83a8e918..a8f1a172f2 100644 --- a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc +++ b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc @@ -60,7 +60,7 @@ \li \l{Lists and Other Data Models} \row \li Timeline - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \if defined(qtdesignstudio) \row \li Event List diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc index 9c6b729631..3245b28b59 100644 --- a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc @@ -38,9 +38,9 @@ \image studio-timeline-empty.png "Empty Timeline view" Select the \inlineimage icons/plus.png - (\uicontrol {Add Timeline}) button to \l{Creating Timelines} - {create a timeline} and specify settings for it in the - \uicontrol {Timeline Settings} dialog. + (\uicontrol {Add Timeline}) button to + \l{Creating a Timeline}{create a timeline} and specify settings for it in + the \uicontrol {Timeline Settings} dialog. \image studio-timeline-settings.png "Timeline Settings dialog" @@ -124,11 +124,11 @@ \li \inlineimage icons/animation.png \li Opens the \uicontrol {Timeline Settings} dialog for editing timeline settings. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li Timeline ID \li Displays the ID of the current timeline. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li \inlineimage icons/to_first_frame.png \li \uicontrol {To Start (Home)} moves to the first frame on the @@ -170,7 +170,7 @@ \li Specifies the first frame of the timeline. Negative values are allowed. The difference between the start frame and the end frame determines the duration of the animation. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li \inlineimage icons/zoom_small.png \li \uicontrol {Zoom Out} (\key Ctrl+-) zooms out of the view. @@ -189,7 +189,7 @@ the start frame and the end frame determines the duration of the animation, so if the start frame is 0, the end frame equals the duration. - \li \l{Creating Timelines} + \li \l{Creating a Timeline} \row \li State Name \li Displays the name of the current state. diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc index fc088945ca..e5d938a470 100644 --- a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc @@ -30,18 +30,19 @@ \title Creating Timeline Animations - You can create timeline and keyframe based animations for linear + You can create timelines and keyframe-based animations for linear interpolation through intermediate values at specified keyframes instead of immediately changing to the target value. - \section1 Creating Timelines + You can also bind the timeline to a property value of a component such as + a slider and control the animation this way. - You specify settings for the timeline and for running the animation in the - \uicontrol {Timeline Settings} dialog. The \uicontrol Animation radio button - is selected for a timeline animation and the \uicontrol {Expression binding} - radio button for a \l{Setting Bindings}{property animation}. + \section1 Creating an Animation - \image studio-timeline-settings.png "Timeline Settings dialog" + To create an animation, whether it's a keyframe animation or an animation + bound to a property value, you first need to create a timeline. + + \section2 Creating a Timeline To create a timeline to animate a UI component: @@ -50,95 +51,97 @@ (\uicontrol {Add Timeline}) button to specify settings for the timeline and running the animation in the \uicontrol {Timeline Settings} dialog. - \li In the \uicontrol {Timeline ID} field, enter an ID that describes - the animated component. - \li In the \uicontrol {Start frame} field, set the first frame of the - timeline. Negative values are allowed. - \li In the \uicontrol {End frame} field, set the last frame of the - timeline. - \li In the \uicontrol {Animation ID} field, enter an ID for the - animation. - \li Select the \uicontrol {Running in Base State} check box to run the - animation when the base state is applied. Deselect the check box - if you want to run the animation when some other state is applied. - For more information, see \l{Binding Animations to States}. - \li In the \uicontrol {Start frame} field, set the first frame of the - animation. - \li In the \uicontrol {End frame} field, set the last frame of the - animation. - \li In the \uicontrol {Duration} field, set the length of the - animation from the start frame to the end frame. If you set a - shorter duration than the number of frames, frames are left out - from the end of the animation when viewing it. - \li Select the \uicontrol Continuous check box to loop the animation - indefinitely. - \li In the \uicontrol Loops field, select the number of times to run - the animation as a loop. The default number of loops is one, which - means that you must restart the animation to see it again - \li Select the \uicontrol {Ping pong} check box to play the animation - backwards back to the beginning when it reaches the end. - \li In the \uicontrol Finished field, select the state - to apply when the animation finishes. + \li On the \uicontrol {Timeline Settings} tab: + \list + \li In the \uicontrol {Timeline ID} field, enter an id that + describes the timeline. + \li In the \uicontrol {Start frame} field, set the first frame + of the timeline. Negative values are allowed. + \li In the \uicontrol {End frame} field, set the last frame + of the timeline. + \image timeline-settings-dialog.png + \endlist + \li On the \uicontrol {Animation Settings} tab: + \list + \li In the \uicontrol {Animation ID} field, enter an ID for the + animation. + \li Optional. Select the \uicontrol {Running in Base State} + check box to run the animation when the base state is applied. + Clear the check box to run the animation when some other state + is applied. For more information, see + \l{Binding Animations to States}. + \li In the \uicontrol {Start frame} field, set the first frame + of the animation. + \li In the \uicontrol {End frame} field, set the last frame of + the animation. + \li In the \uicontrol {Duration} field, set the length of the + animation in milliseconds. + \li Optional. Select the \uicontrol Continuous check box to + loop the animation indefinitely. + \li Optional. In the \uicontrol Loops field, set the number of + times to run the animation. The default number of + loops is one, which means that you must restart the animation + to see it again. + \li Optional. Select the \uicontrol {Ping pong} check box to + play the animation backwards back to the beginning when it + reaches the end. + \li Optional. In the \uicontrol Finished field, select the state + to transition to when the animation finishes. + \endlist \li Select \uicontrol Close to close the dialog and save the settings. \endlist - To create additional timelines, select the \inlineimage icons/plus.png - (\uicontrol {Add Timeline}) button next to the - \uicontrol {Timeline Settings} tab. - - To specify settings for running timeline animations, select the - \inlineimage icons/plus.png - (\uicontrol {Add Animation}) button next to the - \uicontrol {Animation Settings} tab. For example, you could create - settings for running a part of the timeline animation between specified - frames or for running the animation backwards from the last frame to the - first. + Now, with the settings set for the timeline and the animation, you + set the keyframes for the properties to animate. - To modify the settings, select the \inlineimage icons/animation.png - (\uicontrol {Timeline Settings (S)}) button on the \l{Timeline Toolbar} - {toolbar} (or press \key S) in the \l Timeline view. - - \section2 Binding Animations to States + \section3 Creating Additional Timelines - The table at the bottom of the \uicontrol {Timeline Settings} dialog lists - the available states. Double-click the values in the \uicontrol Timeline - and \uicontrol Animation column to bind the states to animations. In the - \uicontrol {Fixed Frame} column, you can bind the states that don't have - animations to fixed frames. + You can create more than one timeline. The purpose of several timelines is + to use different timelines in different states. - \section1 Managing Keyframes + To create a timeline for a second state: - To animate components in the \l Timeline view, move to a frame - on the timeline and specify changes in the values of a property. \QC - automatically adds keyframes between two keyframes and sets their values - evenly to create an appearance of movement or transformation. + \list 1 + \li In \uicontrol {Timeline}, open the \uicontrol {Timeline Settings} + dialog. + \li Next to the \uicontrol {Timeline Settings} tab, select + \inlineimage icons/plus.png + . This creates another timeline. + \li In the table below the \uicontrol {Animation Settings} tab, set the + Timeline for the state where you want to use it. + \image timeline-settings-dialog-second.png + \endlist + To set the keyframe values for the timeline you created, first select the + state in \uicontrol {States} and the timeline is available in + \uicontrol{Timelines}. - \image studio-timeline-with-tracks.png "Timeline view" + \image timeline-states.png \section2 Setting Keyframe Values - You can insert keyframes for all the properties of all the components that - you want to animate first, and then record the changes in their values by - selecting the \inlineimage icons/local_record_keyframes.png - (\uicontrol {Per Property Recording}) button for one property at a time. - For example, you can hide and show components by turning their visibility - off and on or by setting their opacity to 0 or 1. + When you create a timeline, \QDS creates one animation for the timeline. + You can create as many animations for a timeline as you want. For example, + you can create animations to run just a small section of the timeline or to + run the timeline backwards. - You can also select the \uicontrol {Auto Key (K)} button (or press \key K) - to record changes in property values, but you need to be more careful about - which property values you are changing to avoid surprises. + To animate components in the \l Timeline view, you set keyframe values for + the property to animate. \QDS automatically adds keyframes between two + keyframes and sets their values evenly to create, for example, movement or + transformation. - To record the changes of property values: + To set keyframe values for a component property: \list 1 \li In the \l Navigator view, select the component to animate. \li In the \l Properties view, select \inlineimage icons/action-icon.png (\uicontrol Actions) > \uicontrol {Insert Keyframe} for the property that you want to animate. + \image timeline-insert-keyframe.png \li In the \l Timeline view, select the \uicontrol {Per Property Recording} button to start recording property changes. - \li Check that the playhead is in frame 0 and enter the value of the + \image timeline-per-property-recording.png + \li Ensure that the playhead is in frame 0 and enter the value of the property in the field next to the property name on the timeline. Press \key Enter to save the value. \li Move the playhead to another frame on the timeline and specify @@ -148,11 +151,67 @@ \uicontrol {Per Property Recording} again to stop recording. \endlist + \section2 Binding a Timeline to a Property + + When you bind a timeline to a component property, the animation's + current frame is controlled by the value of the property. + + In this example, you bind the timeline to a slider component. + + With a timeline created and keyframe values set: + + \list 1 + \li From \uicontrol {Components}, drag a slider to + \uicontrol {Form Editor} or \uicontrol {Navigator}. + \li In \uicontrol {Navigator}, select \e slider and in + \uicontrol {Properties}, set: + \list + \li \uicontrol To to 1000. + \note The \uicontrol From and \uicontrol To values of the slider + should match the \uicontrol {Start Frame} and + \uicontrol {End Frame} values of the timeline if you want to + control the complete animation with the slider. + \endlist + \li In the \uicontrol {Timeline Settings} dialog, select + \inlineimage icons/minus.png + next to the \uicontrol {Animation Settings} tab to delete the + animation. If you have several animations, delete all. + \li In \uicontrol {Expression binding}, enter \c {slider.value}. + \image timeline-settings-property-binding.png + \endlist + + \section2 Binding Animations to States + + You can bind animations to states, this means that the animation will run + when you enter the state. + + To bind an animation to a state: + \list 1 + \li In the table at the bottom of the \uicontrol {Timeline Settings} + dialog lists: + \list + \li Double-click the value in the \uicontrol Timeline field and select + the timeline with the animation you want to bind to the state. + \li Double-click the value in the \uicontrol Animation field and + select the animation you want to bind to the state. + \image timeline-bind-animation-state.png + \endlist + \endlist + To bind a state to a certain keyframe in an animation without running the + animation, set the keyframe in the \uicontrol{Fixed Frame} field. + + \section1 Managing Keyframes + + \image studio-timeline-with-tracks.png "Timeline view" + + \section2 Editing Keyframes + To remove all the changes you recorded for a property, right-click the property name on the timeline and select \uicontrol {Remove Property}. To add keyframes to the keyframe track of a component at the current - position of the playhead, select \uicontrol {Add Keyframes at Current Frame}. + position of the playhead, right-click the component name on the timeline and + select \uicontrol {Add Keyframes at Current Frame}. Keyframes are marked on the timeline by using \l{keyframe_marker}{markers} of different colors and shapes, depending on whether they are active or @@ -162,7 +221,7 @@ \section2 Editing Keyframe Values To fine-tune the value of a keyframe, double-click a keyframe marker or - select \uicontrol {Edit Keyframe} in the context menu. + right-click it and select \uicontrol {Edit Keyframe} in the context menu. The \uicontrol {Edit Keyframe} dialog displays the name of the property you are animating and its current value at the frame specified in the @@ -173,27 +232,36 @@ \section2 Copying Keyframes You can copy the keyframes from the keyframe track for a component and - paste them to the keyframe track of another component. To copy all - keyframes from one track to another one, first right-click the component ID - and select \uicontrol {Copy All Keyframes} in the context menu. - Then right-click the other component ID, and select - \uicontrol {Paste Keyframes} in the context menu. + paste them to the keyframe track of another component. + + To copy all keyframes from one track to another one: + \list 1 + \li Right-click the component ID and select + \uicontrol {Copy All Keyframes} in the context menu. + \li Right-click the other component ID, and select + \uicontrol {Paste Keyframes} in the context menu. + \endlist \section2 Deleting Keyframes - To delete the selected keyframe, select \uicontrol {Delete Keyframe} in the - context menu. + To delete a keyframe, right-click it and select \uicontrol {Delete Keyframe} + in the context menu. - To delete all keyframes from the selected component, select + To delete all keyframes from the selected component, right-click the + component name in \uicontrol {Timeline} and select \uicontrol {Delete All Keyframes} in the context menu. \section1 Viewing the Animation - You can view the animation on the canvas by moving the playhead along the - timeline. + To preview your animation, do one of the following in the + \uicontrol{Timeline} view: + \list + \li Drag the playhead along the timeline. + \li Select \inlineimage icons/start_playback.png + button or press \key Space. + \endlist - To preview the animation, select the \uicontrol {Play (Space)} - button or press \key Space. To preview the whole UI, select the + To preview the whole UI, select the \inlineimage icons/live_preview.png (\uicontrol {Show Live Preview}) button on the canvas toolbar or press \key {Alt+P}. -- cgit v1.2.1 From 234958a47a6edcd17bae255411a5b0f0bbaea6c7 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 27 Jun 2022 14:31:59 +0300 Subject: QmlDesigner: Enable drag-n-drop a material to a model in Navigator Fixes: QDS-6694 Change-Id: I2fb32052559b1d459cc8025e9f30368b0189e8ab Reviewed-by: Miikka Heikkinen Reviewed-by: Reviewed-by: Thomas Hartmann --- .../materialBrowserQmlSource/MaterialItem.qml | 7 +++-- .../materialbrowser/materialbrowserwidget.cpp | 28 ++++++++++++++++++++ .../materialbrowser/materialbrowserwidget.h | 4 +++ .../navigator/choosefrompropertylistdialog.cpp | 5 ++++ .../components/navigator/navigatortreemodel.cpp | 30 ++++++++++++++++++++++ .../components/navigator/navigatortreemodel.h | 1 + .../components/navigator/navigatorview.cpp | 9 +++++++ src/plugins/qmldesigner/qmldesignerconstants.h | 1 + 8 files changed, 83 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml index 4eeb120b27..640383d4e1 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml @@ -72,9 +72,12 @@ Rectangle { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: (mouse) => { + onPressed: (mouse) => { materialBrowserModel.selectMaterial(index) - if (mouse.button === Qt.RightButton) + + if (mouse.button === Qt.LeftButton) + rootView.startDragMaterial(index, mapToGlobal(mouse.x, mouse.y)) + else if (mouse.button === Qt.RightButton) root.showContextMenu() } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp index 156add5d2d..3982d53454 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,27 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event) if (event->type() == QEvent::FocusOut) { if (obj == m_quickWidget.data()) QMetaObject::invokeMethod(m_quickWidget->rootObject(), "closeContextMenu"); + } else if (event->type() == QMouseEvent::MouseMove) { + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + QTC_ASSERT(document, return false); + Model *model = document->currentModel(); + QTC_ASSERT(model, return false); + + if (m_materialToDrag.isValid()) { + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + QByteArray data; + QMimeData *mimeData = new QMimeData; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_materialToDrag.internalId(); + mimeData->setData(Constants::MIME_TYPE_MATERIAL, data); + mimeData->removeFormat("text/plain"); + + model->startDrag(mimeData, m_previewImageProvider->requestPixmap( + QString::number(m_materialToDrag.internalId()), nullptr, {128, 128})); + m_materialToDrag = {}; + } + } } return QObject::eventFilter(obj, event); @@ -166,6 +188,12 @@ void MaterialBrowserWidget::handleSearchfilterChanged(const QString &filterText) } } +void MaterialBrowserWidget::startDragMaterial(int index, const QPointF &mousePos) +{ + m_materialToDrag = m_materialBrowserModel->materialAt(index); + m_dragStartPoint = mousePos.toPoint(); +} + QString MaterialBrowserWidget::qmlSourcesPath() { #ifdef SHARE_QML_PATH diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h index f5f737007e..30f9d05b50 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h @@ -69,6 +69,7 @@ public: void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); + Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos); QQuickWidget *quickWidget() const; @@ -86,6 +87,9 @@ private: PreviewImageProvider *m_previewImageProvider = nullptr; QString m_filterText; + + ModelNode m_materialToDrag; + QPoint m_dragStartPoint; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp index 00987711c5..178f79e18a 100644 --- a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp +++ b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp @@ -56,6 +56,8 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i // ParticleAbstractShape3D // -> ParticleEmitter3D // -> Attractor3D + // Material + // -> Model const TypeName textureType = "QtQuick3D.Texture"; if (insertInfo.isSubclassOf(textureType)) { @@ -104,6 +106,9 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i if (parentInfo.isSubclassOf("QtQuick3D.Particles3D.ParticleEmitter3D") || parentInfo.isSubclassOf("QtQuick3D.Particles3D.Attractor3D")) propertyList.append("shape"); + } else if (insertInfo.isSubclassOf("QtQuick3D.Material")) { + if (parentInfo.isSubclassOf("QtQuick3D.Particles3D.Model")) + propertyList.append("materials"); } } diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 38c32f65cd..d347854f00 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -464,6 +464,7 @@ QStringList NavigatorTreeModel::mimeTypes() const { const static QStringList types({Constants::MIME_TYPE_MODELNODE_LIST, Constants::MIME_TYPE_ITEM_LIBRARY_INFO, + Constants::MIME_TYPE_MATERIAL, Constants::MIME_TYPE_ASSETS}); return types; @@ -559,6 +560,8 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, if (dropModelIndex.model() == this) { if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) { handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex); + } else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + handleMaterialDrop(mimeData, rowNumber, dropModelIndex); } else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) { const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(','); NodeAbstractProperty targetProperty; @@ -779,6 +782,33 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in } } +void NavigatorTreeModel::handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex) +{ + QTC_ASSERT(m_view, return); + + const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0); + int targetRowNumber = rowNumber; + NodeAbstractProperty targetProperty; + + bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber, "materials"); + if (!foundTarget) + return; + + ModelNode targetNode = targetProperty.parentModelNode(); + if (!targetNode.isSubclassOf("QtQuick3D.Model")) + return; + + QByteArray data = mimeData->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = m_view->modelNodeForInternalId(internalId); + + m_view->executeInTransaction(__FUNCTION__, [&] { + m_view->assignMaterialTo3dModel(targetNode, matNode); + }); +} + ModelNode NavigatorTreeModel::handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty, const QModelIndex &rowModelIndex, diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 9652981607..153491bfc1 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -115,6 +115,7 @@ private: int targetIndex, bool executeInTransaction = true); void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); + void handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); ModelNode handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty, const QModelIndex &rowModelIndex, bool &outMoveNodesAfter); ModelNode handleItemLibraryFontDrop(const QString &fontFamily, NodeAbstractProperty targetProperty, diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index 495982c6fc..f8d5c884fb 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -276,6 +276,15 @@ void NavigatorView::dragStarted(QMimeData *mimeData) m_widget->setDragType(itemLibraryEntry.typeName()); m_widget->update(); + } else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) { + QByteArray data = mimeData->data(Constants::MIME_TYPE_MATERIAL); + QDataStream stream(data); + qint32 internalId; + stream >> internalId; + ModelNode matNode = modelNodeForInternalId(internalId); + + m_widget->setDragType(matNode.metaInfo().typeName()); + m_widget->update(); } } diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index b2ed51cd87..486faeaa26 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -92,6 +92,7 @@ const char MATERIAL_LIB_ID[] = "__materialLibrary__"; const char MIME_TYPE_ITEM_LIBRARY_INFO[] = "application/vnd.qtdesignstudio.itemlibraryinfo"; const char MIME_TYPE_ASSETS[] = "application/vnd.qtdesignstudio.assets"; +const char MIME_TYPE_MATERIAL[] = "application/vnd.qtdesignstudio.material"; const char MIME_TYPE_ASSET_IMAGE[] = "application/vnd.qtdesignstudio.asset.image"; const char MIME_TYPE_ASSET_FONT[] = "application/vnd.qtdesignstudio.asset.font"; const char MIME_TYPE_ASSET_SHADER[] = "application/vnd.qtdesignstudio.asset.shader"; -- cgit v1.2.1