summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Jenssen <tim.jenssen@qt.io>2022-07-01 11:19:21 +0200
committerTim Jenssen <tim.jenssen@qt.io>2022-07-01 09:22:10 +0000
commit56bcad81adb7268773b902ece0fc065d01f3db27 (patch)
treead19b5f8f6bbeeedffcde2549bd83ab0ac0d25d1
parenta920bbf59fb071af2e6bfb306dec07bb8ba94924 (diff)
parent234958a47a6edcd17bae255411a5b0f0bbaea6c7 (diff)
downloadqt-creator-56bcad81adb7268773b902ece0fc065d01f3db27.tar.gz
Merge remote-tracking branch 'origin/7.0' into 8.0
Change-Id: I7cd5d3808007ef739212f4347ba9b16e7b298943
-rw-r--r--doc/qtdesignstudio/images/icons/apply-material.pngbin0 -> 779 bytes
-rw-r--r--doc/qtdesignstudio/images/material-editor-browser.webpbin0 -> 49886 bytes
-rw-r--r--doc/qtdesignstudio/images/materials-remove-material.pngbin0 -> 15142 bytes
-rw-r--r--doc/qtdesignstudio/images/navigator-material-texture.pngbin0 -> 3820 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webpbin0 -> 13236 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-qtquick-3d-material.webpbin0 -> 35562 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-bind-animation-state.pngbin0 -> 4262 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-insert-keyframe.pngbin0 -> 8974 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-per-property-recording.pngbin0 -> 6041 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-settings-dialog-second.pngbin0 -> 16649 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-settings-dialog.pngbin0 -> 14019 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-settings-property-binding.pngbin0 -> 14993 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-states.pngbin0 -> 12233 bytes
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc2
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc1
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc173
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-components-view.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc14
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-timeline.qdoc244
-rw-r--r--doc/qtdesignstudio/src/views/studio-material-editor.qdoc266
-rw-r--r--share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h7
-rw-r--r--share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h1
-rw-r--r--share/qtcreator/qml/qmlpuppet/editor3d_qt5.qrc2
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.pngbin0 -> 2685 bytes
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml18
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt5/HelperGrid.qml1
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml24
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml9
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml4
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt5/SceneView3D.qml1
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml18
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/HelperGrid.qml1
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml23
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml44
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml4
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/SceneView3D.qml1
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp6
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h2
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp3
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp72
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h3
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp17
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp8
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp4
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml8
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml7
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/EmptyMaterialEditorPane.qml5
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml38
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml15
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml210
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml13
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml44
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml17
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml32
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttfbin23272 -> 23512 bytes
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file.qml.tpl5
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/fileForm.ui.qml.tpl33
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.pngbin0 -> 1084 bytes
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.pngbin0 -> 1879 bytes
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/wizard.json132
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-3d/Screen01.ui.qml.tpl14
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl2
-rw-r--r--src/libs/sqlite/sqlitedatabase.cpp4
-rw-r--r--src/plugins/cppeditor/cppeditordocument.cpp2
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt5
-rw-r--r--src/plugins/qmldesigner/assetexporterplugin/assetexporterview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp2
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp9
-rw-r--r--src/plugins/qmldesigner/components/debugview/debugview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.cpp79
-rw-r--r--src/plugins/qmldesigner/components/edit3d/backgroundcolorselection.h13
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp3
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp43
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.cpp99
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.h6
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dviewconfig.h98
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.cpp15
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.h1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp4
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp174
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h16
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp5
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h1
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp48
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h4
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp28
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h4
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp90
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.h3
-rw-r--r--src/plugins/qmldesigner/components/navigator/checkers.pngbin0 -> 80 bytes
-rw-r--r--src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp5
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigator.qrc1
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp102
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.h2
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.cpp9
-rw-r--r--src/plugins/qmldesigner/components/navigator/previewtooltip.cpp14
-rw-r--r--src/plugins/qmldesigner/components/navigator/previewtooltip.ui88
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp81
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h54
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp13
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h8
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp68
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h48
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp13
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h3
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp7
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp51
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h7
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp7
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp90
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp16
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp112
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h70
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp87
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h68
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/timestampprovider.cpp8
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractview.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/rewriterview.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/viewmanager.h3
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp44
-rw-r--r--src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp6
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractview.cpp109
-rw-r--r--src/plugins/qmldesigner/designercore/model/model.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp30
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.h7
-rw-r--r--src/plugins/qmldesigner/designercore/model/viewmanager.cpp7
-rw-r--r--src/plugins/qmldesigner/designersettings.cpp2
-rw-r--r--src/plugins/qmldesigner/designersettings.h2
-rw-r--r--src/plugins/qmldesigner/dynamiclicensecheck.h19
-rw-r--r--src/plugins/qmldesigner/qmldesignerconstants.h2
-rw-r--r--src/plugins/qmldesigner/qmldesignercore.cmake2
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp3
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.qbs7
-rw-r--r--src/plugins/qmldesigner/qmldesignerprojectmanager.cpp35
-rw-r--r--src/plugins/qmldesigner/qmldesignerprojectmanager.h1
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.pngbin389 -> 296 bytes
-rw-r--r--src/plugins/qmldesigner/settingspage.cpp2
-rw-r--r--src/plugins/qmldesigner/settingspage.ui17
-rw-r--r--tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp96
-rw-r--r--tests/auto/qml/qmldesigner/coretests/tst_testcore.h1
151 files changed, 2799 insertions, 980 deletions
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
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/apply-material.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/material-editor-browser.webp
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/materials-remove-material.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/navigator-material-texture.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.webp
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-qtquick-3d-material.webp
Binary files differ
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
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-bind-animation-state.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-insert-keyframe.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-per-property-recording.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-settings-dialog-second.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-settings-dialog.png
Binary files 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
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-settings-property-binding.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/timeline-states.png b/doc/qtdesignstudio/images/timeline-states.png
new file mode 100644
index 0000000000..a1dc73e51e
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-states.png
Binary files 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/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/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}.
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.
+
+*/
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<QColor> &edit3dBackgroundColor)
+ const QList<QColor> &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<QColor> 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/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 @@
<file>mockfiles/images/directional@2x.png</file>
<file>mockfiles/images/point.png</file>
<file>mockfiles/images/point@2x.png</file>
- <file>mockfiles/images/floor_tex.png</file>
+ <file>mockfiles/images/static_floor.png</file>
<file>mockfiles/images/spot.png</file>
<file>mockfiles/images/spot@2x.png</file>
<file>mockfiles/qt5/AdjustableArrow.qml</file>
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
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/static_floor.png
Binary files differ
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/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 5c8b9e1cd7..82688bbef5 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);
}
@@ -70,7 +70,7 @@ View3D {
materials: [
DefaultMaterial {
- diffuseColor: "#4aee45"
+ diffuseColor: "#999999"
}
]
}
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/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 1762e3c9a4..ea2e23837f 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);
}
@@ -70,7 +70,7 @@ View3D {
materials: [
DefaultMaterial {
- diffuseColor: "#4aee45"
+ diffuseColor: "#999999"
}
]
}
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/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<QSSGRenderNode *>(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<QQuick3DNode *>(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;
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/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index 5183b5cd8f..0d35121456 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)));
@@ -1012,7 +1024,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
@@ -1023,6 +1035,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<QObject *>();
+ 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.
@@ -1059,6 +1090,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)
@@ -1578,6 +1616,8 @@ void Qt5InformationNodeInstanceServer::add3DViewPorts(const QList<ServerNodeInst
for (const ServerNodeInstance &instance : instanceList) {
if (instance.isSubclassOf("QQuick3DViewport")) {
QObject *obj = instance.internalObject();
+ if (!m_editView3DSetupDone)
+ m_priorityView3DsToRender.append(obj); // Workaround for quick3d bug QTBUG-103316
if (!m_view3Ds.contains(obj)) {
m_view3Ds << obj;
QObject::connect(obj, SIGNAL(widthChanged()), this, SLOT(handleView3DSizeChange()));
@@ -1746,7 +1786,7 @@ QObject *Qt5InformationNodeInstanceServer::find3DSceneRoot(QObject *obj) const
}
void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeInstance> &instanceList,
- const QHash<QString, QVariantMap> &toolStates)
+ const CreateSceneCommand &command)
{
#ifdef QUICK3D_MODULE
if (!m_editView3DData.rootItem)
@@ -1779,6 +1819,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D(true);
});
+ const QHash<QString, QVariantMap> &toolStates = command.edit3dToolStates;
QString lastSceneId;
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
if (helper) {
@@ -1832,11 +1873,23 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
createCameraAndLightGizmos(instanceList);
+ if (!command.edit3dBackgroundColor.isEmpty()) {
+ View3DActionCommand backgroundColorCommand(View3DActionCommand::SelectBackgroundColor,
+ QVariant::fromValue(command.edit3dBackgroundColor));
+ view3DAction(backgroundColorCommand);
+ }
+
+ if (command.edit3dGridColor.isValid()) {
+ View3DActionCommand backgroundColorCommand(View3DActionCommand::SelectGridColor,
+ QVariant::fromValue(command.edit3dGridColor));
+ view3DAction(backgroundColorCommand);
+ }
+
// Queue two renders to make sure icon gizmos update properly
render3DEditView(2);
#else
Q_UNUSED(instanceList)
- Q_UNUSED(toolStates)
+ Q_UNUSED(command)
#endif
}
@@ -1958,7 +2011,7 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
nodeInstanceClient()->componentCompleted(createComponentCompletedCommand(instanceList));
if (ViewConfig::isQuick3DMode()) {
- setup3DEditView(instanceList, command.edit3dToolStates);
+ setup3DEditView(instanceList, command);
updateRotationBlocks(command.auxiliaryChanges);
}
@@ -1967,12 +2020,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<ServerNodeInstance> &childList)
@@ -2237,9 +2284,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..c85a2730c4 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<ServerNodeInstance> &instanceList,
- const QHash<QString, QVariantMap> &toolStates);
+ const CreateSceneCommand &command);
void createCameraAndLightGizmos(const QList<ServerNodeInstance> &instanceList) const;
void add3DViewPorts(const QList<ServerNodeInstance> &instanceList);
void add3DScenes(const QList<ServerNodeInstance> &instanceList);
@@ -165,6 +165,7 @@ private:
QSet<QObject *> m_view3Ds;
QMultiHash<QObject *, QObject *> m_3DSceneMap; // key: scene root, value: node
QObject *m_active3DView = nullptr;
+ QList<QObject *> m_priorityView3DsToRender;
QObject *m_active3DScene = nullptr;
QSet<ServerNodeInstance> m_parentChangedSet;
QList<ServerNodeInstance> m_completedComponentList;
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp
index 32f63a8cd6..3ccd6c60dc 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp
@@ -405,6 +405,7 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item)
QQuickItemPrivate *pItem = QQuickItemPrivate::get(item);
const bool renderEffects = qEnvironmentVariableIsSet("QMLPUPPET_RENDER_EFFECTS");
+ const bool smoothRendering = qEnvironmentVariableIsSet("QMLPUPPET_SMOOTH_RENDERING");
if (renderEffects) {
if (parentEffectItem(item))
@@ -427,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<QQuickItem *> layerChildren;
@@ -470,6 +474,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 +484,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 +495,8 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item)
delete layer;
layer = nullptr;
+
+ renderImage.setDevicePixelRatio(scaleFactor);
});
m_viewData.renderControl->render();
@@ -514,7 +522,6 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item)
if (!isLayerEnabled(pItem))
pItem->derefFromEffectItem(false);
-
#else
Q_UNUSED(item)
#endif
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;
}
}
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/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.<br>Select '<b>+</b>' 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 <b>Material Browser</b>, first add the QtQuick3D module in the <b>Components</b> view.");
+ textFormat: Text.RichText
color: StudioTheme.Values.themeTextColor
font.pixelSize: StudioTheme.Values.mediumFontSize
topPadding: 30
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/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.<br>Select '<b>+</b>' to create one.")
+ : qsTr("To use <b>Material Editor</b>, first add the QtQuick3D module in the <b>Components</b> 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 {
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 {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontComboBox.qml
index 4b5f5caf4a..2f087c3b29 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,45 @@ 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)
+ 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)
+ }
+ }
+
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.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 = root.createFontLoader(fileModel.docPath + "/"
+ + fileModel.model[i].relativeFilePath)
familyNames.push(fontLoader.name)
}
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 {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml
index f6766234d0..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.
@@ -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
@@ -60,6 +63,7 @@ Row {
property ListModel listModel: ListModel {}
+ hasActiveDrag: activeDragSuffix !== "" && root.filter.includes(activeDragSuffix)
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
@@ -69,26 +73,99 @@ 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 !== ""
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
+ }
+ }
}
}
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,20 +227,66 @@ 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 {
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
+ }
+ }
}
}
}
@@ -197,8 +320,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,9 +354,13 @@ 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
+
+ if (!root.backendValue.isBound)
+ root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
+
comboBox.dirty = false
}
@@ -252,11 +380,14 @@ 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
+ if (!root.backendValue.isBound)
+ root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
+
comboBox.dirty = false
}
@@ -273,6 +404,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()
@@ -284,17 +432,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 +457,7 @@ Row {
Connections {
target: fileModel
- function onFullPathModelChanged() {
+ function onModelChanged() {
root.createModel()
comboBox.setCurrentText(comboBox.textValue)
}
@@ -315,6 +468,9 @@ Row {
Component.onCompleted: {
root.createModel()
comboBox.updateTextValue()
+
+ if (!root.backendValue.isBound)
+ root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
}
function indexOf(model, criteria) {
@@ -333,7 +489,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) {
@@ -352,8 +508,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/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 {
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,13 +82,21 @@ 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
&& !checkIndicator.hover && myControl.hover && !myControl.edit
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
@@ -106,6 +105,14 @@ TextInput {
}
},
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
PropertyChanges {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
index 008713a4e1..1c2fa82c14 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
@@ -88,6 +88,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
@@ -469,9 +472,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
@@ -480,6 +485,23 @@ Item {
}
},
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
PropertyChanges {
@@ -587,13 +609,21 @@ 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
&& !checkIndicator.hover && root.hover && !root.edit
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
index 5a3e99d459..cefd1d7d86 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
Binary files differ
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
--- /dev/null
+++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui.png
Binary files 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
--- /dev/null
+++ b/share/qtcreator/qmldesigner/studio_templates/files/qtuiquickform/file_ui@2.png
Binary files 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
+ }
+ ]
+ }
+ ]
+}
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..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
@@ -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
@@ -63,4 +57,12 @@ Rectangle {
diffuseColor: "#4aee45"
}
}
+
+ Text {
+ text: qsTr("Hello %{ProjectName}")
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.topMargin: 100
+ font.family: Constants.font.family
+ }
}
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}"
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;
}
diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp
index 80a8cce0bd..2b01b86c27 100644
--- a/src/plugins/cppeditor/cppeditordocument.cpp
+++ b/src/plugins/cppeditor/cppeditordocument.cpp
@@ -473,7 +473,7 @@ bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, boo
if (!editedRanges.empty()) {
QTextCursor cursor(document());
- cursor.beginEditBlock();
+ cursor.joinPreviousEditBlock();
indenter()->format(editedRanges);
cursor.endEditBlock();
}
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index dc19983f66..ec0eaa6537 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -161,6 +161,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
@@ -305,6 +306,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
@@ -392,7 +394,8 @@ extend_qtc_plugin(QmlDesigner
SOURCES
explicitimagecacheimageprovider.cpp
explicitimagecacheimageprovider.h
-
+ smallimagecacheprovider.cpp
+ smallimagecacheprovider.h
)
extend_qtc_plugin(QmlDesigner
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/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/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/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index fd8d11768e..068e9cf2fd 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -478,19 +478,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<ModelNode> sortedSelectedNodes = selectionContext.selectedModelNodes();
Utils::sort(sortedSelectedNodes, lessThan);
diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp
index 9af8651c44..c32edec724 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());
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 <QColorDialog>
-#include <nodeinstanceview.h>
#include <utils/qtcassert.h>
-#include <view3dactioncommand.h>
-#include <qmldesignerplugin.h>
+
+#include "backgroundcolorselection.h"
+#include "edit3dviewconfig.h"
using namespace QmlDesigner;
-namespace {
-QList<QColor> 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<QList<QString>>();
- QTC_ASSERT(colorNameList.size() == 2, return {});
-
- return {colorNameList[0], colorNameList[1]};
-}
+ if (m_dialog)
+ return;
-void setBackgroundColorConfiguration(const QList<QColor> &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<QColor> &colorConfig)
-{
- QList<QString> 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<QColor> oldColorConfig = readBackgroundColorConfiguration();
+ QList<QColor> 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 <QColorDialog>
+#include <QByteArray>
+#include <view3dactioncommand.h>
+
+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/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<ModelNode> 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/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
index 30f909f159..383af0aa91 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 <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
@@ -42,8 +44,6 @@
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
-#include <backgroundcolorselection.h>
-
#include <QDebug>
#include <QToolButton>
@@ -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<QColor> 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<QColor> colors = {QRgb(0x222222), QRgb(0x999999)};
- auto view = QmlDesignerPlugin::instance()->viewManager().nodeInstanceView();
- View3DActionCommand cmd(View3DActionCommand::SelectBackgroundColor, QVariant::fromValue(colors));
- view->view3DAction(cmd);
-
- QList<QString> 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<Edit3DAction *> 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<Edit3DWidget> m_edit3DWidget;
QVector<Edit3DAction *> m_leftActions;
QVector<Edit3DAction *> 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 <view3dactioncommand.h>
+
+#include <nodeinstanceview.h>
+#include <qmldesignerplugin.h>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+namespace QmlDesigner {
+
+class Edit3DViewConfig
+{
+public:
+ static QList<QColor> load(const char key[])
+ {
+ QVariant var = DesignerSettings::getValue(key);
+
+ if (!var.isValid())
+ return {};
+
+ auto colorNameList = var.value<QStringList>();
+
+ return Utils::transform(colorNameList, [](const QString &colorName) {
+ return QColor{colorName};
+ });
+ }
+
+ static void set(View3DActionCommand::Type type, const QList<QColor> &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<QColor> &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<QColor> &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/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 <rewritingexception.h>
#include "qmldesignerconstants.h"
+#include <utils/qtcassert.h>
+
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QLoggingCategory>
@@ -405,10 +407,23 @@ void DragTool::move(const QPointF &scenePosition, const QList<QGraphicsItem *> &
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<ModelNode> 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<QGraphicsItem *> &itemList);
void createDragNodes(const QMimeData *mimeData, const QPointF &scenePosition, const QList<QGraphicsItem *> &itemList);
void commitTransaction();
+ void handleView3dDrop();
private:
MoveManipulator m_moveManipulator;
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
index 47ce7b6c5b..42ecfc0679 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
@@ -471,7 +471,7 @@ void FormEditorView::documentMessagesChanged(const QList<DocumentMessage> &error
if (!errors.isEmpty() && !model()->rewriterView()->hasIncompleteTypeInformation())
m_formEditorWidget->showErrorMessageBox(errors);
- else
+ else if (rewriterView()->errors().isEmpty())
m_formEditorWidget->hideErrorMessageBox();
checkRootModelNode();
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;
}
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 <utils/algorithm.h>
#include <utils/runextensions.h>
+#include <utils/qtcassert.h>
#include <QApplication>
#include <QDir>
@@ -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<int>(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<int>(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<QString> &preselectedFilesForOverwrite);
bool preParseQuick3DAsset(const QString &file, ParseData &pd,
const QSet<QString> &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<QProcessUniquePointer> m_qmlPuppetProcesses;
- int m_qmlPuppetCount = 0;
- int m_qmlImportFinishedCount = 0;
+ QProcessUniquePointer m_puppetProcess;
int m_importIdCounter = 0;
+ int m_currentImportId = 0;
QHash<int, ParseData> m_parseData;
QString m_progressTitle;
QList<Import> m_requiredImports;
+ QList<int> m_puppetQueue;
};
} // QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index c4c2c7ab3d..e1911036b5 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/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<ModelNode> 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<ModelNode> materials() const;
void setMaterials(const QList<ModelNode> &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 d8c7286411..e232f6cc08 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
@@ -96,11 +96,19 @@ void MaterialBrowserView::modelAttached(Model *model)
m_widget->clearSearchFilter();
m_hasQuick3DImport = model->hasImport("QtQuick3D");
- QTimer::singleShot(0, this, &MaterialBrowserView::refreshModel);
+
+ // 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);
+ });
}
-void MaterialBrowserView::refreshModel()
+void MaterialBrowserView::refreshModel(bool updateImages)
{
+ if (!model() || !model()->nodeInstanceView())
+ return;
+
ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
QList <ModelNode> materials;
@@ -114,8 +122,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
@@ -203,8 +213,12 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node,
bool matRemoved = oldParentNode.isValid() && oldParentNode.id() == Constants::MATERIAL_LIB_ID;
if (matAdded || matRemoved) {
- refreshModel();
-
+ 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);
}
@@ -251,7 +265,9 @@ void MaterialBrowserView::importsChanged(const QList<Import> &addedImports, cons
return;
m_hasQuick3DImport = hasQuick3DImport;
- refreshModel();
+
+ // 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,
@@ -269,4 +285,22 @@ void MaterialBrowserView::customNotification(const AbstractView *view, const QSt
}
}
+void MaterialBrowserView::instancesCompleted(const QVector<ModelNode> &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]() {
+ if (!model() || !model()->nodeInstanceView())
+ return;
+ const QList<ModelNode> materials = m_widget->materialBrowserModel()->materials();
+ for (const ModelNode &node : materials)
+ model()->nodeInstanceView()->previewImageDataForGenericNode(node, {});
+ });
+ break;
+ }
+ }
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
index e140eede13..503986a28e 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
@@ -60,14 +60,16 @@ public:
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
+ void instancesCompleted(const QVector<ModelNode> &completedNodeList) override;
private:
- void refreshModel();
+ void refreshModel(bool updateImages);
bool isMaterial(const ModelNode &node) const;
QPointer<MaterialBrowserWidget> m_widget;
bool m_hasQuick3DImport = false;
bool m_autoSelectModelMaterial = false; // TODO: wire this to some action
+ bool m_puppetResetPending = false;
};
} // namespace QmlDesigner
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 <designermcumanager.h>
#include <documentmanager.h>
#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
#include <utils/algorithm.h>
#include <utils/stylehelper.h>
@@ -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<QMouseEvent *>(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/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
index aad0ea660a..3184c718d9 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
@@ -73,52 +73,21 @@ 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()
+ && model()->rewriterView()->errors().isEmpty()) {
+ executeInTransaction("MaterialEditorView::MaterialEditorView", [this] {
+ ensureMaterialLibraryNode();
+ });
+ m_ensureMatLibTimer.stop();
+ }
+ });
+
m_stackedWidget->setStyleSheet(Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
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<ModelNode> 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 +416,15 @@ void MaterialEditorView::handleToolBarAction(int action)
}
case MaterialEditorContextObject::AddNewMaterial: {
- ensureMaterialLibraryNode();
-
+ if (!model())
+ break;
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;
}
@@ -567,6 +536,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;
@@ -580,8 +554,6 @@ void MaterialEditorView::modelAboutToBeDetached(Model *model)
{
AbstractView::modelAboutToBeDetached(model);
m_qmlBackEnd->materialEditorTransaction()->end();
-
-
}
void MaterialEditorView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
@@ -589,6 +561,7 @@ void MaterialEditorView::propertiesRemoved(const QList<AbstractProperty> &proper
if (noValidSelection())
return;
+ bool changed = false;
for (const AbstractProperty &property : propertyList) {
ModelNode node(property.parentModelNode());
@@ -597,8 +570,11 @@ void MaterialEditorView::propertiesRemoved(const QList<AbstractProperty> &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<VariantProperty> &propertyList, PropertyChangeFlags /*propertyChange*/)
@@ -660,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, {});
}
@@ -707,6 +683,7 @@ void MaterialEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
m_locked = true;
+ bool changed = false;
for (const QPair<ModelNode, PropertyName> &propertyPair : propertyList) {
const ModelNode modelNode = propertyPair.first;
const QmlObjectNode qmlObjectNode(modelNode);
@@ -718,8 +695,11 @@ void MaterialEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
setValue(modelNode, property.name(), qmlObjectNode.instanceValue(property.name()));
else
setValue(modelNode, property.name(), qmlObjectNode.modelValue(property.name()));
+ changed = true;
}
}
+ if (changed)
+ requestPreviewRender();
m_locked = false;
}
@@ -744,6 +724,9 @@ void MaterialEditorView::importsChanged(const QList<Import> &addedImports, const
m_hasQuick3DImport = model()->hasImport("QtQuick3D");
m_qmlBackEnd->contextObject()->setHasQuick3DImport(m_hasQuick3DImport);
+ if (m_hasQuick3DImport)
+ m_ensureMatLibTimer.start(500);
+
resetView();
}
@@ -763,7 +746,8 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
{
QTC_ASSERT(material.isValid(), return);
- ensureMaterialLibraryNode();
+ if (!model())
+ return;
TypeName matType = material.type();
QmlObjectNode sourceMat(material);
@@ -790,7 +774,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
}
- m_materialLibrary.defaultNodeListProperty().reparentHere(duplicateMat);
+ materialLibraryNode().defaultNodeListProperty().reparentHere(duplicateMat);
});
}
@@ -816,11 +800,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<QObject *>();
PropertyEditorValue *propEditorVal = qobject_cast<PropertyEditorValue *>(propEditorValObj);
propEditorVal->setHasActiveDrag(highlight);
@@ -852,7 +841,6 @@ void MaterialEditorView::setValue(const QmlObjectNode &qmlObjectNode, const Prop
{
m_locked = true;
m_qmlBackEnd->setValue(qmlObjectNode, name, value);
- requestPreviewRender();
m_locked = false;
}
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
index 3e8632d26f..ff734ed30b 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,7 @@ private:
bool noValidSelection() const;
ModelNode m_selectedMaterial;
- ModelNode m_materialLibrary;
+ QTimer m_ensureMatLibTimer;
QShortcut *m_updateShortcut = nullptr;
int m_timerId = 0;
QStackedWidget *m_stackedWidget = nullptr;
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
--- /dev/null
+++ b/src/plugins/qmldesigner/components/navigator/checkers.png
Binary files differ
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/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 @@
<file>export_unchecked.png</file>
<file>export_unchecked@2x.png</file>
<file>tooltip_placeholder.png</file>
+ <file>checkers.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index 0a92f81d93..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;
@@ -686,18 +689,20 @@ 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;
+ }
+ m_view->assignMaterialTo3dModel(targetNode, newModelNode);
+ }
+
ChooseFromPropertyListDialog *dialog = ChooseFromPropertyListDialog::createIfNeeded(
targetNode, newModelNode, Core::ICore::dialogParent());
if (dialog) {
@@ -734,28 +739,10 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
if (newModelNode.isSubclassOf("QtQuick3D.View3D")) {
const QList<ModelNode> 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) {
@@ -795,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,
@@ -1089,40 +1103,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<ModelNode> 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..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,
@@ -130,7 +131,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<QPersistentModelIndex> nodesToPersistentIndex(const QList<ModelNode> &modelNodes);
void addImport(const QString &importName);
QList<ModelNode> filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const;
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
index 3adfc91781..cc3934b628 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
@@ -275,6 +275,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/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 <utils/theme/theme.h>
-#include <QtGui/qpixmap.h>
+#include <QPainter>
+#include <QPixmap>
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 @@
<number>6</number>
</property>
<item>
- <widget class="QLabel" name="imageLabel">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>150</width>
- <height>150</height>
- </size>
- </property>
- <property name="frameShape">
- <enum>QFrame::Box</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Plain</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
+ <widget class="QWidget" name="imageContainer" native="true">
+ <widget class="QLabel" name="labelBackground">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>150</width>
+ <height>150</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="imageLabel">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>150</width>
+ <height>150</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>150</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
</widget>
</item>
<item>
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 <model.h>
-#include <utils/algorithm.h>
#include <documentmanager.h>
+#include <utils/algorithm.h>
-#include <QFileDialog>
#include <QDirIterator>
+#include <QFileDialog>
#include <qmlmodelnodeproxy.h>
#include <projectexplorer/project.h>
@@ -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<QObject *>();
- const auto backendObjectCasted =
- qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(modelNodeBackendObject);
+ const auto backendObjectCasted = qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(
+ 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<FileResourcesItem> 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<FileResourcesModel>("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 <QUrl>
#include <QtQml>
+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<FileResourcesItem> 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<FileResourcesItem> 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<FileResourcesItem> m_model;
};
QML_DECLARE_TYPE(FileResourcesModel)
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/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 <hdrimage.h>
+#include <projectexplorer/target.h>
+#include <utils/stylehelper.h>
+
+#include <QMetaObject>
+#include <QQuickImageResponse>
+
+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<QmlDesigner::ImageResponse>(image);
+
+ QMetaObject::invokeMethod(
+ response.get(),
+ [response = QPointer<QmlDesigner::ImageResponse>(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 <QQuickAsyncImageProvider>
+
+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 8026fc7d6f..c3e201bf1d 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/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
index 6ea079b6f1..c68db4c57f 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
@@ -537,6 +538,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 4f3859d00d..fb1be16dc7 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 <qmldesignerconstants.h>
#include <qmltimeline.h>
@@ -70,16 +70,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();
@@ -118,7 +118,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);
@@ -486,7 +486,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);
@@ -852,7 +852,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);
@@ -871,6 +890,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 06e86fd57c..09d6dc7f41 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;
@@ -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);
@@ -119,8 +122,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/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
index 82dcb44d85..09e9b9f05a 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;
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 <QMetaObject>
#include <QQuickImageResponse>
-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<ImageRespose>(m_defaultImage);
+ auto response = std::make_unique<::ImageResponse>(m_defaultImage);
m_cache.requestImage(
id,
- [response = QPointer<ImageRespose>(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<ImageRespose>(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/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/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 <projectexplorer/target.h>
+#include <utils/smallstring.h>
+#include <qtsupport/qtkitinformation.h>
+
+#include <QTemporaryFile>
+
+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<QImage, QImage> 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<QImage, QImage> 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 <asynchronousimagecache.h>
+
+#include <QMetaObject>
+
+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<QmlDesigner::ImageResponse>(m_defaultImage);
+
+ m_cache.requestSmallImage(
+ id,
+ [response = QPointer<QmlDesigner::ImageResponse>(response.get())](const QImage &image) {
+ QMetaObject::invokeMethod(
+ response,
+ [response, image] {
+ if (response)
+ response->setImage(image);
+ },
+ Qt::QueuedConnection);
+ },
+ [response = QPointer<QmlDesigner::ImageResponse>(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 <QQuickAsyncImageProvider>
+#include <QQuickImageResponse>
+
+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 <QDateTime>
#include <QFileInfo>
+#include <limits>
+
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<long long>::max()};
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h
index 23273939b4..890b5c0e9c 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractview.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractview.h
@@ -109,6 +109,8 @@ public:
RewriterTransaction beginRewriterTransaction(const QByteArray &identifier);
+ ModelNode createModelNode(const TypeName &typeName);
+
ModelNode createModelNode(const TypeName &typeName,
int majorVersion,
int minorVersion,
@@ -234,6 +236,10 @@ public:
void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion);
+ void ensureMaterialLibraryNode();
+ ModelNode materialLibraryNode();
+ void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {});
+
NodeInstanceView *nodeInstanceView() const;
RewriterView *rewriterView() const;
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;
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/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index 3555bcdefc..6a7ad61276 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -90,6 +90,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/documentmanager.h>
#include <hdrimage.h>
+#include <edit3d/edit3dviewconfig.h>
#endif
#include <coreplugin/messagemanager.h>
@@ -103,6 +104,7 @@
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
+#include <utils/theme/theme.h>
#include <qtsupport/qtkitinformation.h>
@@ -985,17 +987,6 @@ QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList)
return filteredNodeList;
}
-QList<QColor> readBackgroundColorConfiguration(const QVariant &var)
-{
- if (!var.isValid())
- return {};
-
- auto colorNameList = var.value<QList<QString>>();
- QTC_ASSERT(colorNameList.size() == 2, return {});
-
- return {colorNameList[0], colorNameList[1]};
-}
-
CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
{
QList<ModelNode> nodeList = allModelNodes();
@@ -1150,16 +1141,15 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0))
stateInstanceId = stateNode.internalId();
- QVariant value
+ QColor gridColor;
+ QList<QColor> backgroundColor;
+
#ifndef QMLDESIGNER_TEST
- = QmlDesigner::DesignerSettings::getValue(
- QmlDesigner::DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR);
-#else
- = {};
+ backgroundColor = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_BACKGROUND_COLOR);
+ QList<QColor> gridColorList = Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_GRID_COLOR);
+ if (!gridColorList.isEmpty())
+ gridColor = gridColorList.at(0);
#endif
- QList<QColor> edit3dBackgroundColor;
- if (value.isValid())
- edit3dBackgroundColor = readBackgroundColorConfiguration(value);
return CreateSceneCommand(
instanceContainerList,
@@ -1182,7 +1172,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
m_captureImageMinimumSize,
m_captureImageMaximumSize,
stateInstanceId,
- edit3dBackgroundColor);
+ backgroundColor,
+ gridColor);
}
ClearSceneCommand NodeInstanceView::createClearSceneCommand() const
@@ -1727,7 +1718,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;
@@ -1767,7 +1758,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);
diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
index 38c88a1cee..f2baf9c984 100644
--- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp
@@ -505,6 +505,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/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index b22ba232f9..23c018f7cb 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -31,6 +31,11 @@
#include "nodeinstanceview.h"
#include <qmlstate.h>
#include <qmltimeline.h>
+#include <nodemetainfo.h>
+#include <qmldesignerconstants.h>
+#include <nodelistproperty.h>
+#include <variantproperty.h>
+#include <bindingproperty.h>
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
@@ -85,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,
@@ -803,6 +814,104 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in
m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion);
}
+// 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;
+
+ // 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<ModelNode> materials = rootModelNode().subModelNodesOfType("QtQuick3D.Material");
+ 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);
+ }
+ }
+}
+
+// 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;
+}
+
+// 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();
+
+ if (!matLib.isValid())
+ return;
+
+ ModelNode newMaterialNode;
+
+ if (materialNode.isValid() && materialNode.isSubclassOf("QtQuick3D.Material")) {
+ newMaterialNode = materialNode;
+ } else {
+ const QList<ModelNode> 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())
diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp
index 0e9e8b8a5d..bd92ac643f 100644
--- a/src/plugins/qmldesigner/designercore/model/model.cpp
+++ b/src/plugins/qmldesigner/designercore/model/model.cpp
@@ -1521,7 +1521,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();
}
diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp
index 9dcba56a7f..d89765b5bf 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 6422765ec3..abdba53823 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<RewriteAction *> &actions,
compressImports(actions);
compressRereparentActions(actions);
compressReparentIntoSamePropertyActions(actions);
+ compressReparentIntoNewPropertyActions(actions);
compressPropertyActions(actions);
compressAddEditRemoveNodeActions(actions);
compressAddEditActions(actions, tabSettings);
@@ -152,6 +153,35 @@ void RewriteActionCompressor::compressReparentIntoSamePropertyActions(QList<Rewr
}
}
+void RewriteActionCompressor::compressReparentIntoNewPropertyActions(QList<RewriteAction *> &actions) const
+{
+ QList<RewriteAction *> actionsToRemove;
+
+ QList<RewriteAction *> 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);
+
+ const ModelNode childNode = reparentAction->reparentedNode();
+
+ if (m_positionStore->nodeOffset(childNode) > 0)
+ removeActions.append(new RemoveNodeRewriteAction(childNode));
+ }
+ }
+ }
+
+ for (RewriteAction *action : qAsConst(actionsToRemove)) {
+ actions.removeOne(action);
+ delete action;
+ }
+
+ actions.append(removeActions);
+}
+
void RewriteActionCompressor::compressAddEditRemoveNodeActions(QList<RewriteAction *> &actions) const
{
QList<RewriteAction *> 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<RewriteAction *> &actions, const TextEditor::TabSettings &tabSettings) const;
@@ -42,6 +45,7 @@ private:
void compressRereparentActions(QList<RewriteAction *> &actions) const;
void compressReparentIntoSamePropertyActions(QList<RewriteAction *> &actions) const;
+ void compressReparentIntoNewPropertyActions(QList<RewriteAction *> &actions) const;
void compressAddEditRemoveNodeActions(QList<RewriteAction *> &actions) const;
void compressPropertyActions(QList<RewriteAction *> &actions) const;
void compressAddEditActions(QList<RewriteAction *> &actions, const TextEditor::TabSettings &tabSettings) const;
@@ -49,6 +53,7 @@ private:
private:
PropertyNameList m_propertyOrder;
+ ModelNodePositionStorage *m_positionStore;
};
} // namespace Internal
diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp
index 730bfbb0fb..d1b53b05ae 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<ViewManagerData>(imageCache))
+ViewManager::ViewManager(AsynchronousImageCache &imageCache, AsynchronousImageCache &meshImageCache)
+ : d(std::make_unique<ViewManagerData>(imageCache, meshImageCache))
{
d->formEditorView.setGotoErrorCallback([this](int line, int column) {
d->textEditorView.gotoCursorPosition(line, column);
diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp
index 20083068c1..1b9651d471 100644
--- a/src/plugins/qmldesigner/designersettings.cpp
+++ b/src/plugins/qmldesigner/designersettings.cpp
@@ -82,6 +82,8 @@ 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();
settings->endGroup();
diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h
index 8c249fc65e..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";
@@ -72,6 +73,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<QByteArray, QVariant>
diff --git a/src/plugins/qmldesigner/dynamiclicensecheck.h b/src/plugins/qmldesigner/dynamiclicensecheck.h
index f8362cec94..197f5da415 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
@@ -57,12 +58,28 @@ inline ExtensionSystem::IPlugin *licenseCheckerPlugin()
inline 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
diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h
index 8dc2b94749..486faeaa26 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";
@@ -91,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";
diff --git a/src/plugins/qmldesigner/qmldesignercore.cmake b/src/plugins/qmldesigner/qmldesignercore.cmake
index 51d3d8794b..8795659c69 100644
--- a/src/plugins/qmldesigner/qmldesignercore.cmake
+++ b/src/plugins/qmldesigner/qmldesignercore.cmake
@@ -135,6 +135,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 131bedac04..331c8e7852 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -135,7 +135,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 7b8ef97775..7e7dc7c7af 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.qbs
+++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs
@@ -441,6 +441,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",
@@ -525,6 +529,7 @@ Project {
"debugview/debugviewwidget.ui",
"edit3d/edit3dview.cpp",
"edit3d/edit3dview.h",
+ "edit3d/edit3dviewconfig.h",
"edit3d/backgroundcolorselection.cpp",
"edit3d/backgroundcolorselection.h",
"edit3d/edit3dwidget.cpp",
@@ -736,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..366f1ef04e 100644
--- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
+++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
@@ -51,7 +51,8 @@
#include <imagecache/imagecacheconnectionmanager.h>
#include <imagecache/imagecachegenerator.h>
#include <imagecache/imagecachestorage.h>
-#include <imagecache/timestampproviderinterface.h>
+#include <imagecache/meshimagecachecollector.h>
+#include <imagecache/timestampprovider.h>
#include <coreplugin/icore.h>
@@ -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<Sqlite::Database> 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,9 +139,9 @@ public:
QSize{300, 300},
QSize{1000, 1000},
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
- TimeStampProvider timeStampProvider;
+ PreviewTimeStampProvider timeStampProvider;
AsynchronousImageFactory factory;
- ::ProjectExplorer::Target *activeTarget = nullptr;
+ QPointer<::ProjectExplorer::Target> activeTarget;
};
QmlDesignerProjectManager::QmlDesignerProjectManager()
@@ -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<ImageCacheData>();
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);
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
--- a/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png
+++ b/src/plugins/qmldesigner/qtquickplugin/images/timeline-animation-16px.png
Binary files differ
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 @@
</property>
</widget>
</item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="smoothRendering">
+ <property name="toolTip">
+ <string>Enable Smooth Rendering in Form Editor</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="smoothRenderingLabel">
+ <property name="text">
+ <string>Smooth Rendering:</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
index ac0440b65d..1c0239b542 100644
--- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
+++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
@@ -1152,6 +1152,102 @@ 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(Model::create("QtQuick.Rectangle"));
+
+ QScopedPointer<TestRewriterView> 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<ModelNode> children = rootModelNode.directSubModelNodes();
+
+ ModelNode rectangle = testRewriterView->createModelNode("QtQuick.Rectangle");
+ 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");
+ 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);
+
+ 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()
{
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