From d5a7f25e608acdd1efd6c76554d7144f70454f02 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 26 Oct 2022 19:57:41 +0300 Subject: [PATCH] QmlDesigner: Implement content library view Fixes: QDS-8058 Fixes: QDS-8059 Change-Id: I1adfdc7ac15141e010467813ec6e673060269241 Reviewed-by: Miikka Heikkinen --- .../ContentLibrary.qml | 121 ++++++ .../ContentLibraryMaterial.qml} | 34 +- .../ContentLibraryMaterialContextMenu.qml | 52 +++ .../ContentLibraryMaterialsView.qml | 91 +++++ .../ContentLibraryTabBar.qml | 33 ++ .../ContentLibraryTabButton.qml | 58 +++ .../ContentLibraryTexture.qml | 34 ++ .../ContentLibraryTextureContextMenu.qml | 39 ++ .../ContentLibraryTexturesView.qml | 92 +++++ .../UnimportBundleMaterialDialog.qml | 28 +- .../MaterialBrowser.qml | 139 +++---- .../MaterialBrowserContextMenu.qml | 26 +- .../MaterialBundleContextMenu.qml | 74 ---- .../materialBrowserQmlSource/TextureItem.qml | 34 ++ .../imports/StudioTheme/Values.qml | 2 + src/plugins/qmldesigner/CMakeLists.txt | 19 +- .../assetslibrary/assetslibrarywidget.cpp | 2 +- .../componentcore/designeractionmanager.cpp | 2 +- .../componentcore/designeractionmanager.h | 18 +- .../componentcore/modelnodeoperations.cpp | 24 +- .../componentcore/modelnodeoperations.h | 12 +- .../components/componentcore/viewmanager.cpp | 6 + .../contentlibrarybundleimporter.cpp} | 54 +-- .../contentlibrarybundleimporter.h | 57 +++ .../contentlibrary/contentlibrarymaterial.cpp | 67 ++++ .../contentlibrary/contentlibrarymaterial.h | 57 +++ .../contentlibrarymaterialscategory.cpp | 63 ++++ .../contentlibrarymaterialscategory.h | 47 +++ .../contentlibrarymaterialsmodel.cpp} | 116 +++--- .../contentlibrarymaterialsmodel.h} | 66 ++-- .../contentlibrary/contentlibrarytexture.cpp | 33 ++ .../contentlibrary/contentlibrarytexture.h | 37 ++ .../contentlibrarytexturescategory.cpp | 56 +++ .../contentlibrarytexturescategory.h | 50 +++ .../contentlibrarytexturesmodel.cpp | 185 +++++++++ .../contentlibrarytexturesmodel.h | 74 ++++ .../contentlibrary/contentlibraryview.cpp | 354 ++++++++++++++++++ .../contentlibrary/contentlibraryview.h | 53 +++ .../contentlibrary/contentlibrarywidget.cpp | 238 ++++++++++++ .../contentlibrary/contentlibrarywidget.h | 76 ++++ .../components/edit3d/edit3dview.cpp | 2 +- .../itemlibrary/itemlibraryview.cpp | 3 +- .../materialbrowser/bundleimporter.h | 79 ---- .../materialbrowser/bundlematerial.cpp | 89 ----- .../materialbrowser/bundlematerial.h | 79 ---- .../bundlematerialcategory.cpp | 85 ----- .../materialbrowser/bundlematerialcategory.h | 69 ---- .../materialbrowsertexturesmodel.cpp | 219 +++++++++++ .../materialbrowsertexturesmodel.h | 63 ++++ .../materialbrowser/materialbrowserview.cpp | 236 +----------- .../materialbrowser/materialbrowserview.h | 10 +- .../materialbrowser/materialbrowserwidget.cpp | 45 +-- .../materialbrowser/materialbrowserwidget.h | 25 +- .../navigator/navigatortreemodel.cpp | 2 +- .../qmldesigner/qmldesignerconstants.h | 1 + 55 files changed, 2540 insertions(+), 1090 deletions(-) create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml rename share/qtcreator/qmldesigner/{materialBrowserQmlSource/BundleMaterialItem.qml => contentLibraryQmlSource/ContentLibraryMaterial.qml} (66%) create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml create mode 100644 share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml rename share/qtcreator/qmldesigner/{materialBrowserQmlSource => contentLibraryQmlSource}/UnimportBundleMaterialDialog.qml (53%) delete mode 100644 share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBundleContextMenu.qml create mode 100644 share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml rename src/plugins/qmldesigner/components/{materialbrowser/bundleimporter.cpp => contentlibrary/contentlibrarybundleimporter.cpp} (86%) create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.cpp create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.h rename src/plugins/qmldesigner/components/{materialbrowser/materialbrowserbundlemodel.cpp => contentlibrary/contentlibrarymaterialsmodel.cpp} (64%) rename src/plugins/qmldesigner/components/{materialbrowser/materialbrowserbundlemodel.h => contentlibrary/contentlibrarymaterialsmodel.h} (50%) create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp create mode 100644 src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h delete mode 100644 src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h delete mode 100644 src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp delete mode 100644 src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h delete mode 100644 src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp delete mode 100644 src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h create mode 100644 src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp create mode 100644 src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml new file mode 100644 index 00000000000..bbe9641419e --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml @@ -0,0 +1,121 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuickDesignerTheme +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme + +Item { + id: root + + // Called also from C++ to close context menu on focus out + function closeContextMenu() + { + materialsView.closeContextMenu() + texturesView.closeContextMenu() + environmentsView.closeContextMenu() + } + + // Called from C++ + function clearSearchFilter() + { + searchBox.clear(); + } + + Column { + id: col + y: 5 + spacing: 5 + + StudioControls.SearchBox { + id: searchBox + + width: root.width + enabled: !materialsModel.hasMaterialRoot && materialsModel.hasQuick3DImport + + onSearchChanged: (searchText) => { + rootView.handleSearchFilterChanged(searchText) + + // make sure categories with matches are expanded + materialsView.expandVisibleSections() + } + } + + Text { + // TODO: only disable the materials section, textures should be available + text: { + if (materialsModel.hasMaterialRoot) + qsTr("Content Library is disabled inside a material component.") + else if (!materialsModel.hasQuick3DImport) + qsTr("To use Content Library, first add the QtQuick3D module in the Components view.") + else + "" + } + + textFormat: Text.RichText + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.mediumFontSize + topPadding: 30 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + width: root.width + visible: text !== "" + } + + UnimportBundleMaterialDialog { + id: confirmUnimportDialog + } + + ContentLibraryTabBar { + id: tabBar + + visible: materialsModel.hasQuick3DImport + // TODO: update icons + tabsModel: [{name: qsTr("Materials"), icon: StudioTheme.Constants.gradient}, + {name: qsTr("Textures"), icon: StudioTheme.Constants.materialPreviewEnvironment}, + {name: qsTr("Environments"), icon: StudioTheme.Constants.translationSelectLanguages}] + } + + StackLayout { + width: root.width + height: root.height - y + currentIndex: tabBar.currIndex + visible: materialsModel.hasQuick3DImport + + ContentLibraryMaterialsView { + id: materialsView + + width: root.width + + searchBox: searchBox + + onUnimport: (bundleMat) => { + unimportBundleMaterialDialog.targetBundleMaterial = bundleMat + unimportBundleMaterialDialog.open() + } + } + + ContentLibraryTexturesView { + id: texturesView + + width: root.width + model: texturesModel + + searchBox: searchBox + } + + ContentLibraryTexturesView { + id: environmentsView + + width: root.width + model: environmentsModel + + searchBox: searchBox + } + } + } +} diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml similarity index 66% rename from share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml rename to share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml index 59541f47d39..4d6377359ce 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml @@ -1,27 +1,5 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 import QtQuick 2.15 import QtQuick.Layouts 1.15 @@ -45,8 +23,8 @@ Item { acceptedButtons: Qt.LeftButton | Qt.RightButton onPressed: (mouse) => { - if (mouse.button === Qt.LeftButton && !materialBrowserBundleModel.importerRunning) - rootView.startDragBundleMaterial(modelData, mapToGlobal(mouse.x, mouse.y)) + if (mouse.button === Qt.LeftButton && !materialsModel.importerRunning) + rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y)) else if (mouse.button === Qt.RightButton) root.showContextMenu() } @@ -102,10 +80,10 @@ Item { pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4) anchors.right: img.right anchors.bottom: img.bottom - enabled: !materialBrowserBundleModel.importerRunning + enabled: !materialsModel.importerRunning onClicked: { - materialBrowserBundleModel.addToProject(modelData) + materialsModel.addToProject(modelData) } } } diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml new file mode 100644 index 00000000000..a85699e6dc3 --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml @@ -0,0 +1,52 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick 2.15 +import HelperWidgets 2.0 +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +StudioControls.Menu { + id: root + + property var targetMaterial: null + signal unimport(var bundleMat); + + function popupMenu(targetMaterial = null) + { + this.targetMaterial = targetMaterial + popup() + } + + closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside + + StudioControls.MenuItem { + text: qsTr("Apply to selected (replace)") + enabled: root.targetMaterial && materialsModel.hasModelSelection + onTriggered: materialsModel.applyToSelected(root.targetMaterial, false) + } + + StudioControls.MenuItem { + text: qsTr("Apply to selected (add)") + enabled: root.targetMaterial && materialsModel.hasModelSelection + onTriggered: materialsModel.applyToSelected(root.targetMaterial, true) + } + + StudioControls.MenuSeparator {} + + StudioControls.MenuItem { + enabled: !materialsModel.importerRunning + text: qsTr("Add an instance to project") + + onTriggered: { + materialsModel.addToProject(root.targetMaterial) + } + } + + StudioControls.MenuItem { + enabled: !materialsModel.importerRunning && root.targetMaterial && root.targetMaterial.bundleMaterialImported + text: qsTr("Remove from project") + + onTriggered: root.unimport(root.targetMaterial); + } +} diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml new file mode 100644 index 00000000000..589e0250b5e --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml @@ -0,0 +1,91 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme + +HelperWidgets.ScrollView { + id: root + + clip: true + + readonly property int cellWidth: 100 + readonly property int cellHeight: 120 + + property var currMaterialItem: null + property var rootItem: null + + required property var searchBox + + signal unimport(var bundleMat); + + function closeContextMenu() + { + ctxMenu.close() + } + + function expandVisibleSections() + { + for (let i = 0; i < categoryRepeater.count; ++i) { + let cat = categoryRepeater.itemAt(i) + if (cat.visible && !cat.expanded) + cat.expanded = true + } + } + + Column { + ContentLibraryMaterialContextMenu { + id: ctxMenu + + onUnimport: (bundleMat) => root.unimport(bundleMat) + } + + Repeater { + id: categoryRepeater + + model: materialsModel + + delegate: HelperWidgets.Section { + width: root.width + caption: bundleCategoryName + addTopPadding: false + sectionBackgroundColor: "transparent" + visible: bundleCategoryVisible + expanded: bundleCategoryExpanded + expandOnClick: false + onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded + + Grid { + width: root.width + leftPadding: 5 + rightPadding: 5 + bottomPadding: 5 + columns: root.width / root.cellWidth + + Repeater { + model: bundleCategoryMaterials + + delegate: ContentLibraryMaterial { + width: root.cellWidth + height: root.cellHeight + + onShowContextMenu: ctxMenu.popupMenu(modelData) + } + } + } + } + } + + Text { + id: noMatchText + text: qsTr("No match found."); + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.baseFontSize + topPadding: 10 + leftPadding: 10 + visible: materialsModel.isEmpty && !searchBox.isEmpty() && !materialsModel.hasMaterialRoot + } + } +} diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml new file mode 100644 index 00000000000..024271d1a23 --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml @@ -0,0 +1,33 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import StudioTheme as StudioTheme + +Rectangle { + id: root + + width: parent.width + height: 50 + color: StudioTheme.Values.themeSectionHeadBackground + + property int currIndex: 0 + property alias tabsModel: repeater.model + + Row { + spacing: 1 + + Repeater { + id: repeater + + ContentLibraryTabButton { + height: root.height + + name: modelData.name + icon: modelData.icon + selected: root.currIndex === index + onClicked: root.currIndex = index + } + } + } +} diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml new file mode 100644 index 00000000000..cd31f2579d2 --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml @@ -0,0 +1,58 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import StudioTheme as StudioTheme + +Rectangle { + id: root + + signal clicked() + + property alias icon: icon.text + property alias name: name.text + property bool selected: false + + width: 100 + height: 100 + color: root.selected ? StudioTheme.Values.themePanelBackground + : mouseArea.containsMouse ? Qt.lighter(StudioTheme.Values.themeSectionHeadBackground, 1.3) + : StudioTheme.Values.themeSectionHeadBackground + + Text { + id: icon + + color: root.selected ? StudioTheme.Values.themeInteraction : StudioTheme.Values.themeTextColor + + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.mediumIconFontSize + anchors.horizontalCenter: parent.horizontalCenter + y: 8 + } + + Text { + id: name + + font.weight: Font.DemiBold + font.pixelSize: StudioTheme.Values.baseFontSize + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 6 + + color: root.selected ? StudioTheme.Values.themeInteraction : StudioTheme.Values.themeTextColor + } + + Rectangle { // strip + width: root.width + height: 4 + color: root.selected ? StudioTheme.Values.themeInteraction : "transparent" + anchors.bottom: parent.bottom + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: root.clicked() + } +} diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml new file mode 100644 index 00000000000..d6c24d4b2af --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml @@ -0,0 +1,34 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtQuickDesignerTheme 1.0 +import HelperWidgets 2.0 +import QtQuick.Controls + +import StudioTheme 1.0 as StudioTheme + +Image { + id: root + + source: modelData.textureIcon + visible: modelData.textureVisible + cache: false + + signal showContextMenu() + + MouseArea { + id: mouseArea + + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onPressed: (mouse) => { + if (mouse.button === Qt.LeftButton) + rootView.startDragTexture(modelData, mapToGlobal(mouse.x, mouse.y)) + else if (mouse.button === Qt.RightButton) + root.showContextMenu() + } + } +} diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml new file mode 100644 index 00000000000..373b2108084 --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml @@ -0,0 +1,39 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick 2.15 +import HelperWidgets 2.0 +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +StudioControls.Menu { + id: root + + property var targetTexture: null + + function popupMenu(targetTexture = null) + { + this.targetTexture = targetTexture + popup() + } + + closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside + + StudioControls.MenuItem { + text: qsTr("Add image") + enabled: root.targetTexture + onTriggered: rootView.addImage(root.targetTexture) + } + + StudioControls.MenuItem { + text: qsTr("Add texture") + enabled: root.targetTexture + onTriggered: rootView.addTexture(root.targetTexture) + } + + StudioControls.MenuItem { + text: qsTr("Add scene environment") + enabled: root.targetTexture + onTriggered: rootView.addEnv(root.targetTexture) + } +} diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml new file mode 100644 index 00000000000..469a4170e20 --- /dev/null +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml @@ -0,0 +1,92 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme + +HelperWidgets.ScrollView { + id: root + + clip: true + + readonly property int cellWidth: 100 + readonly property int cellHeight: 100 + + property var currMaterialItem: null + property var rootItem: null + + required property var searchBox + required property var model + + signal unimport(var bundleMat); + + function closeContextMenu() + { + ctxMenu.close() + } + + function expandVisibleSections() + { + for (let i = 0; i < categoryRepeater.count; ++i) { + let cat = categoryRepeater.itemAt(i) + if (cat.visible && !cat.expanded) + cat.expanded = true + } + } + Column { + ContentLibraryTextureContextMenu { + id: ctxMenu + + // TODO + } + + Repeater { + id: categoryRepeater + + model: root.model + + delegate: HelperWidgets.Section { + width: root.width + caption: bundleCategoryName + addTopPadding: false + sectionBackgroundColor: "transparent" + visible: bundleCategoryVisible + expanded: bundleCategoryExpanded + expandOnClick: false + onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded + + Grid { + width: root.width + leftPadding: 5 + rightPadding: 5 + bottomPadding: 5 + spacing: 5 + columns: root.width / root.cellWidth + + Repeater { + model: bundleCategoryTextures + + delegate: ContentLibraryTexture { + width: root.cellWidth + height: root.cellHeight + + onShowContextMenu: ctxMenu.popupMenu(modelData) + } + } + } + } + } + + Text { + id: noMatchText + text: qsTr("No match found."); + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.baseFontSize + topPadding: 10 + leftPadding: 10 + visible: root.model.isEmpty && !searchBox.isEmpty() && !root.model.hasMaterialRoot + } + } +} diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/UnimportBundleMaterialDialog.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml similarity index 53% rename from share/qtcreator/qmldesigner/materialBrowserQmlSource/UnimportBundleMaterialDialog.qml rename to share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml index 82708467a8a..1c887ca317f 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/UnimportBundleMaterialDialog.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml @@ -1,27 +1,5 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 import QtQuick import QtQuick.Controls @@ -69,7 +47,7 @@ Dialog { text: qsTr("Remove") onClicked: { - materialBrowserBundleModel.removeFromProject(root.targetBundleMaterial) + materialsModel.removeFromProject(root.targetBundleMaterial) root.accept() } } diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml index 2b921374ae6..9edc5019769 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml @@ -19,13 +19,12 @@ Item { function closeContextMenu() { ctxMenu.close() - ctxMenuBundle.close() } // Called from C++ to refresh a preview material after it changes function refreshPreview(idx) { - var item = gridRepeater.itemAt(idx); + var item = materialRepeater.itemAt(idx); if (item) item.refreshPreview(); } @@ -44,12 +43,14 @@ Item { acceptedButtons: Qt.RightButton onClicked: (mouse) => { - // root context-menu works only for user materials - var userMatsSecBottom = mapFromItem(userMaterialsSection, 0, userMaterialsSection.y).y - + userMaterialsSection.height; + if (materialBrowserModel.hasMaterialRoot || !materialBrowserModel.hasQuick3DImport) + return; + + var matsSecBottom = mapFromItem(materialsSection, 0, materialsSection.y).y + + materialsSection.height; if (!materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport - && (!materialBrowserBundleModel.matBundleExists || mouse.y < userMatsSecBottom)) { + && mouse.y < matsSecBottom) { ctxMenu.popupMenu() } } @@ -63,7 +64,7 @@ Item { if (root.currMaterialItem) root.currMaterialItem.commitRename(); - root.currMaterialItem = gridRepeater.itemAt(materialBrowserModel.selectedIndex); + root.currMaterialItem = materialRepeater.itemAt(materialBrowserModel.selectedIndex); } } @@ -71,19 +72,6 @@ Item { id: ctxMenu } - MaterialBundleContextMenu { - id: ctxMenuBundle - - onUnimport: (bundleMat) => { - unimportBundleMaterialDialog.targetBundleMaterial = bundleMat - unimportBundleMaterialDialog.open() - } - } - - UnimportBundleMaterialDialog { - id: unimportBundleMaterialDialog - } - Column { id: col y: 5 @@ -100,19 +88,6 @@ Item { onSearchChanged: (searchText) => { rootView.handleSearchFilterChanged(searchText) - - // make sure searched categories that have matches are expanded - if (!materialBrowserModel.isEmpty && !userMaterialsSection.expanded) - userMaterialsSection.expanded = true - - if (!materialBrowserBundleModel.isEmpty && !bundleMaterialsSection.expanded) - bundleMaterialsSection.expanded = true - - for (let i = 0; i < bundleMaterialsSectionRepeater.count; ++i) { - let sec = bundleMaterialsSectionRepeater.itemAt(i) - if (sec.visible && !sec.expanded) - sec.expanded = true - } } } @@ -156,29 +131,28 @@ Item { height: root.height - searchBox.height clip: true visible: materialBrowserModel.hasQuick3DImport && !materialBrowserModel.hasMaterialRoot - interactive: !ctxMenu.opened && !ctxMenuBundle.opened + interactive: !ctxMenu.opened Column { Section { - id: userMaterialsSection + id: materialsSection width: root.width caption: qsTr("Materials") - hideHeader: !materialBrowserBundleModel.matBundleExists dropEnabled: true onDropEnter: (drag) => { - drag.accepted = rootView.draggedBundleMaterial - userMaterialsSection.highlight = rootView.draggedBundleMaterial + drag.accepted = drag.formats[0] === "application/vnd.qtdesignstudio.bundlematerial" + materialsSection.highlight = drag.accepted } onDropExit: { - userMaterialsSection.highlight = false + materialsSection.highlight = false } onDrop: { - userMaterialsSection.highlight = false - materialBrowserBundleModel.addToProject(rootView.draggedBundleMaterial) + materialsSection.highlight = false + rootView.acceptBundleMaterialDrop() } Grid { @@ -191,7 +165,7 @@ Item { columns: root.width / root.cellWidth Repeater { - id: gridRepeater + id: materialRepeater model: materialBrowserModel delegate: MaterialItem { @@ -226,62 +200,51 @@ Item { } Section { - id: bundleMaterialsSection + id: texturesSection width: root.width - caption: qsTr("Material Library") - addTopPadding: noMatchText.visible - visible: materialBrowserBundleModel.matBundleExists + caption: qsTr("Textures") + + Grid { + width: scrollView.width + leftPadding: 5 + rightPadding: 5 + bottomPadding: 5 + spacing: 5 + columns: root.width / root.cellWidth - Column { Repeater { - id: bundleMaterialsSectionRepeater + id: texturesRepeater - model: materialBrowserBundleModel + model: materialBrowserTexturesModel + delegate: TextureItem { + width: root.cellWidth + height: root.cellWidth - delegate: Section { - width: root.width - caption: bundleCategoryName - addTopPadding: false - sectionBackgroundColor: "transparent" - visible: bundleCategoryVisible - expanded: bundleCategoryExpanded - expandOnClick: false - onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded - onExpand: bundleCategoryExpanded = true - onCollapse: bundleCategoryExpanded = false - - Grid { - width: scrollView.width - leftPadding: 5 - rightPadding: 5 - bottomPadding: 5 - columns: root.width / root.cellWidth - - Repeater { - model: bundleCategoryMaterials - - delegate: BundleMaterialItem { - width: root.cellWidth - height: root.cellHeight - - onShowContextMenu: { - ctxMenuBundle.popupMenu(modelData) - } - } - } + onShowContextMenu: { +// ctxMenuTexture.popupMenu(this, model) // TODO: implement textures context menu } } } + } - Text { - id: noMatchText - text: qsTr("No match found."); - color: StudioTheme.Values.themeTextColor - font.pixelSize: StudioTheme.Values.baseFontSize - leftPadding: 10 - visible: materialBrowserBundleModel.isEmpty && !searchBox.isEmpty() && !materialBrowserModel.hasMaterialRoot - } + Text { + text: qsTr("No match found."); + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.baseFontSize + leftPadding: 10 + visible: materialBrowserModel.isEmpty && !searchBox.isEmpty() && !materialBrowserModel.hasMaterialRoot + } + + Text { + text:qsTr("There are no texture in this project.") + visible: materialBrowserTexturesModel.isEmpty && searchBox.isEmpty() + textFormat: Text.RichText + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.mediumFontSize + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + width: root.width } } } diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml index 796bcab6ebd..25e271c1c4e 100644 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml @@ -1,27 +1,5 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0 import QtQuick import HelperWidgets diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBundleContextMenu.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBundleContextMenu.qml deleted file mode 100644 index eb698d69932..00000000000 --- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBundleContextMenu.qml +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -import QtQuick 2.15 -import HelperWidgets 2.0 -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme - -StudioControls.Menu { - id: root - - property var targetMaterial: null - signal unimport(var bundleMat); - - function popupMenu(targetMaterial = null) - { - this.targetMaterial = targetMaterial - popup() - } - - closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside - - StudioControls.MenuItem { - text: qsTr("Apply to selected (replace)") - enabled: root.targetMaterial && materialBrowserModel.hasModelSelection - onTriggered: materialBrowserBundleModel.applyToSelected(root.targetMaterial, false) - } - - StudioControls.MenuItem { - text: qsTr("Apply to selected (add)") - enabled: root.targetMaterial && materialBrowserModel.hasModelSelection - onTriggered: materialBrowserBundleModel.applyToSelected(root.targetMaterial, true) - } - - StudioControls.MenuSeparator {} - - StudioControls.MenuItem { - enabled: !materialBrowserBundleModel.importerRunning - text: qsTr("Add an instance to project") - - onTriggered: { - materialBrowserBundleModel.addToProject(root.targetMaterial) - } - } - - StudioControls.MenuItem { - enabled: !materialBrowserBundleModel.importerRunning && root.targetMaterial.bundleMaterialImported - text: qsTr("Remove from project") - - onTriggered: root.unimport(root.targetMaterial); - } -} diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml new file mode 100644 index 00000000000..e208ed1ec52 --- /dev/null +++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml @@ -0,0 +1,34 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Layouts +import QtQuickDesignerTheme +import HelperWidgets +import StudioTheme as StudioTheme + +Image { + id: root + + source: textureSource + sourceSize.width: root.width + sourceSize.height: root.height + visible: textureVisible + cache: false + + signal showContextMenu() + + MouseArea { + id: mouseArea + + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onPressed: (mouse) => { + if (mouse.button === Qt.LeftButton) + rootView.startDragTexture(modelData, mapToGlobal(mouse.x, mouse.y)) + else if (mouse.button === Qt.RightButton) + root.showContextMenu() + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml index 2355f33281c..536c8adc6a4 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml @@ -13,6 +13,7 @@ QtObject { property real mediumFont: 14 property real bigFont: 16 property real baseIconFont: 12 + property real mediumIconFont: 18 property real bigIconFont: 26 property real scaleFactor: 1.0 @@ -24,6 +25,7 @@ QtObject { property real bigFontSize: Math.round(values.bigFont * values.scaleFactor) property real baseIconFontSize: Math.round(values.baseIconFont * values.scaleFactor) property real myIconFontSize: values.baseIconFontSize; // TODO: rename all refs to myIconFontSize -> baseIconFontSize then remove myIconFontSize + property real mediumIconFontSize: Math.round(values.mediumIconFont * values.scaleFactor) property real bigIconFontSize: Math.round(values.bigIconFont * values.scaleFactor) property real squareComponentWidth: values.height diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index fdfde219199..279bcbf4c61 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -912,6 +912,20 @@ extend_qtc_plugin(QmlDesigner quick2propertyeditorview.cpp quick2propertyeditorview.h ) +extend_qtc_plugin(QmlDesigner + SOURCES_PREFIX components/contentlibrary + SOURCES + contentlibrarybundleimporter.cpp contentlibrarybundleimporter.h + contentlibraryview.cpp contentlibraryview.h + contentlibrarywidget.cpp contentlibrarywidget.h + contentlibrarytexturesmodel.cpp contentlibrarytexturesmodel.h + contentlibrarytexturescategory.cpp contentlibrarytexturescategory.h + contentlibrarytexture.cpp contentlibrarytexture.h + contentlibrarymaterialsmodel.cpp contentlibrarymaterialsmodel.h + contentlibrarymaterialscategory.cpp contentlibrarymaterialscategory.h + contentlibrarymaterial.cpp contentlibrarymaterial.h +) + extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/materialeditor SOURCES @@ -929,10 +943,7 @@ extend_qtc_plugin(QmlDesigner materialbrowserview.cpp materialbrowserview.h materialbrowserwidget.cpp materialbrowserwidget.h materialbrowsermodel.cpp materialbrowsermodel.h - bundleimporter.cpp bundleimporter.h - materialbrowserbundlemodel.cpp materialbrowserbundlemodel.h - bundlematerial.cpp bundlematerial.h - bundlematerialcategory.cpp bundlematerialcategory.h + materialbrowsertexturesmodel.cpp materialbrowsertexturesmodel.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 44f1c2e747b..c7493a64bb6 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -448,7 +448,7 @@ void AssetsLibraryWidget::addResources(const QStringList &files) QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category); if (operation) { AddFilesResult result = operation(fileNames, - document->fileName().parentDir().toString()); + document->fileName().parentDir().toString(), true); if (result == AddFilesResult::Failed) { Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.") diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 9216635e260..bb60e2a1c9d 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -276,7 +276,7 @@ QHash DesignerActionManager::handleExternalAssetsDrop(cons for (const QString &category : categories) { AddResourceOperation operation = categoryOperation.value(category); QStringList files = categoryFiles.value(category); - AddFilesResult result = operation(files, {}); + AddFilesResult result = operation(files, {}, true); if (result == AddFilesResult::Succeeded) addedCategoryFiles.insert(category, files); } diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h index 099174865fe..928d136a02e 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -24,20 +24,20 @@ namespace QmlDesigner { class DesignerActionManagerView; -using AddResourceOperation = std::function; -using ModelNodePreviewImageOperation = std::function; +using AddResourceOperation = std::function; +using ModelNodePreviewImageOperation = std::function; struct AddResourceHandler { public: - AddResourceHandler( const QString &_category, - const QString &_filter, - AddResourceOperation _operation, - int _priority = 0) + AddResourceHandler(const QString &_category, + const QString &_filter, + AddResourceOperation _operation, + int _priority = 0) : category(_category) - ,filter(_filter) - ,operation(_operation) - ,piority(_priority) + , filter(_filter) + , operation(_operation) + , piority(_priority) { } diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 34b257fe12c..78118e8f8bb 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1034,9 +1034,9 @@ void addTabBarToStackedContainer(const SelectionContext &selectionContext) } -AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog) { - QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory); + QString directory = showDialog ? AddImagesDialog::getDirectory(fileNames, defaultDir) : defaultDir; if (directory.isEmpty()) return AddFilesResult::Cancelled; @@ -1105,29 +1105,29 @@ static QString getAssetDefaultDirectory(const QString &assetDir, const QString & return adjustedDefaultDirectory; } -AddFilesResult addFontToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addFontToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog) { - return addFilesToProject(fileNames, getAssetDefaultDirectory("fonts", defaultDirectory)); + return addFilesToProject(fileNames, getAssetDefaultDirectory("fonts", defaultDir), showDialog); } -AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog) { - return addFilesToProject(fileNames, getAssetDefaultDirectory("sounds", defaultDirectory)); + return addFilesToProject(fileNames, getAssetDefaultDirectory("sounds", defaultDir), showDialog); } -AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog) { - return addFilesToProject(fileNames, getAssetDefaultDirectory("shaders", defaultDirectory)); + return addFilesToProject(fileNames, getAssetDefaultDirectory("shaders", defaultDir), showDialog); } -AddFilesResult addImageToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addImageToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog) { - return addFilesToProject(fileNames, getAssetDefaultDirectory("images", defaultDirectory)); + return addFilesToProject(fileNames, getAssetDefaultDirectory("images", defaultDir), showDialog); } -AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &defaultDirectory) +AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog) { - return addFilesToProject(fileNames, getAssetDefaultDirectory("videos", defaultDirectory)); + return addFilesToProject(fileNames, getAssetDefaultDirectory("videos", defaultDir), showDialog); } void createFlowActionArea(const SelectionContext &selectionContext) diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 8156203a7ca..6ea503bc846 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -57,12 +57,12 @@ void addItemToStackedContainer(const SelectionContext &selectionContext); void increaseIndexOfStackedContainer(const SelectionContext &selectionContext); void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext); void addTabBarToStackedContainer(const SelectionContext &selectionContext); -QMLDESIGNERCORE_EXPORT AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory); -AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory); -AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory); -AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory); -AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &directory); -AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &directory); +QMLDESIGNERCORE_EXPORT AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog = true); +AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true); +AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true); +AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true); +AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true); +AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true); void createFlowActionArea(const SelectionContext &selectionContext); void addTransition(const SelectionContext &selectionState); void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName); diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp index fc56a37f86f..5a06b2b1e83 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -56,6 +58,7 @@ public: ? capturingConnectionManager : connectionManager, externalDependencies) + , contentLibraryView{externalDependencies} , componentView{externalDependencies} , edit3DView{externalDependencies} , formEditorView{externalDependencies} @@ -76,6 +79,7 @@ public: Internal::DebugView debugView; DesignerActionManagerView designerActionManagerView; NodeInstanceView nodeInstanceView; + ContentLibraryView contentLibraryView; ComponentView componentView; Edit3DView edit3DView; FormEditorView formEditorView; @@ -212,6 +216,7 @@ QList ViewManager::standardViews() const &d->itemLibraryView, &d->navigatorView, &d->propertyEditorView, + &d->contentLibraryView, &d->materialEditorView, &d->materialBrowserView, &d->statesEditorView, @@ -392,6 +397,7 @@ QList ViewManager::widgetInfos() const widgetInfoList.append(d->itemLibraryView.widgetInfo()); widgetInfoList.append(d->navigatorView.widgetInfo()); widgetInfoList.append(d->propertyEditorView.widgetInfo()); + widgetInfoList.append(d->contentLibraryView.widgetInfo()); widgetInfoList.append(d->materialEditorView.widgetInfo()); widgetInfoList.append(d->materialBrowserView.widgetInfo()); if (useOldStatesEditor()) diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp similarity index 86% rename from src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp rename to src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp index 24e3d3e1108..086ce32379a 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp @@ -1,29 +1,7 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 -#include "bundleimporter.h" +#include "contentlibrarybundleimporter.h" #include "documentmanager.h" #include "import.h" @@ -43,17 +21,17 @@ using namespace Utils; namespace QmlDesigner::Internal { -BundleImporter::BundleImporter(const QString &bundleDir, - const QString &bundleId, - const QStringList &sharedFiles, - QObject *parent) +ContentLibraryBundleImporter::ContentLibraryBundleImporter(const QString &bundleDir, + const QString &bundleId, + const QStringList &sharedFiles, + QObject *parent) : QObject(parent) , m_bundleDir(FilePath::fromString(bundleDir)) , m_bundleId(bundleId) , m_sharedFiles(sharedFiles) { m_importTimer.setInterval(200); - connect(&m_importTimer, &QTimer::timeout, this, &BundleImporter::handleImportTimer); + connect(&m_importTimer, &QTimer::timeout, this, &ContentLibraryBundleImporter::handleImportTimer); m_moduleName = QStringLiteral("%1.%2").arg( QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER), m_bundleId).mid(1); // Chop leading slash @@ -63,8 +41,8 @@ BundleImporter::BundleImporter(const QString &bundleDir, // Note that there is also an asynchronous portion to the import, which will only // be done if this method returns success. Once the asynchronous portion of the // import is completed, importFinished signal will be emitted. -QString BundleImporter::importComponent(const QString &qmlFile, - const QStringList &files) +QString ContentLibraryBundleImporter::importComponent(const QString &qmlFile, + const QStringList &files) { FilePath bundleImportPath = resolveBundleImportPath(); if (bundleImportPath.isEmpty()) @@ -171,7 +149,7 @@ QString BundleImporter::importComponent(const QString &qmlFile, return {}; } -void BundleImporter::handleImportTimer() +void ContentLibraryBundleImporter::handleImportTimer() { auto handleFailure = [this]() { m_importTimer.stop(); @@ -243,7 +221,7 @@ void BundleImporter::handleImportTimer() } } -QVariantHash BundleImporter::loadAssetRefMap(const Utils::FilePath &bundlePath) +QVariantHash ContentLibraryBundleImporter::loadAssetRefMap(const Utils::FilePath &bundlePath) { FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE)); const std::optional content = assetRefPath.fileContents(); @@ -260,8 +238,8 @@ QVariantHash BundleImporter::loadAssetRefMap(const Utils::FilePath &bundlePath) return {}; } -void BundleImporter::writeAssetRefMap(const Utils::FilePath &bundlePath, - const QVariantHash &assetRefMap) +void ContentLibraryBundleImporter::writeAssetRefMap(const Utils::FilePath &bundlePath, + const QVariantHash &assetRefMap) { FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE)); QJsonObject jsonObj = QJsonObject::fromVariantHash(assetRefMap); @@ -271,7 +249,7 @@ void BundleImporter::writeAssetRefMap(const Utils::FilePath &bundlePath, } } -QString BundleImporter::unimportComponent(const QString &qmlFile) +QString ContentLibraryBundleImporter::unimportComponent(const QString &qmlFile) { FilePath bundleImportPath = resolveBundleImportPath(); if (bundleImportPath.isEmpty()) @@ -358,7 +336,7 @@ QString BundleImporter::unimportComponent(const QString &qmlFile) return {}; } -FilePath BundleImporter::resolveBundleImportPath() +FilePath ContentLibraryBundleImporter::resolveBundleImportPath() { FilePath bundleImportPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath(); if (bundleImportPath.isEmpty()) diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h new file mode 100644 index 00000000000..4da431319db --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h @@ -0,0 +1,57 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include "nodemetainfo.h" + +#include +#include + +QT_BEGIN_NAMESPACE +QT_END_NAMESPACE + +namespace QmlDesigner::Internal { + +class ContentLibraryBundleImporter : public QObject +{ + Q_OBJECT + +public: + ContentLibraryBundleImporter(const QString &bundleDir, + const QString &bundleId, + const QStringList &sharedFiles, + QObject *parent = nullptr); + ~ContentLibraryBundleImporter() = default; + + QString importComponent(const QString &qmlFile, + const QStringList &files); + QString unimportComponent(const QString &qmlFile); + Utils::FilePath resolveBundleImportPath(); + +signals: + // The metaInfo parameter will be invalid if an error was encountered during + // asynchronous part of the import. In this case all remaining pending imports have been + // terminated, and will not receive separate importFinished notifications. + void importFinished(const QmlDesigner::NodeMetaInfo &metaInfo); + void unimportFinished(const QmlDesigner::NodeMetaInfo &metaInfo); + +private: + void handleImportTimer(); + QVariantHash loadAssetRefMap(const Utils::FilePath &bundlePath); + void writeAssetRefMap(const Utils::FilePath &bundlePath, const QVariantHash &assetRefMap); + + Utils::FilePath m_bundleDir; + QString m_bundleId; + QString m_moduleName; + QStringList m_sharedFiles; + QTimer m_importTimer; + int m_importTimerCount = 0; + bool m_importAddPending = false; + bool m_fullReset = false; + QHash m_pendingTypes; // +}; + +} // namespace QmlDesigner::Internal diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp new file mode 100644 index 00000000000..8f034d7a08d --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "contentlibrarymaterial.h" + +namespace QmlDesigner { + +ContentLibraryMaterial::ContentLibraryMaterial(QObject *parent, + const QString &name, + const QString &qml, + const TypeName &type, + const QUrl &icon, + const QStringList &files) + : QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files) {} + +bool ContentLibraryMaterial::filter(const QString &searchText) +{ + if (m_visible != m_name.contains(searchText, Qt::CaseInsensitive)) { + m_visible = !m_visible; + emit materialVisibleChanged(); + } + + return m_visible; +} + +QUrl ContentLibraryMaterial::icon() const +{ + return m_icon; +} + +QString ContentLibraryMaterial::qml() const +{ + return m_qml; +} + +TypeName ContentLibraryMaterial::type() const +{ + return m_type; +} + +QStringList ContentLibraryMaterial::files() const +{ + return m_files; +} + +bool ContentLibraryMaterial::visible() const +{ + return m_visible; +} + +bool ContentLibraryMaterial::setImported(bool imported) +{ + if (m_imported != imported) { + m_imported = imported; + emit materialImportedChanged(); + return true; + } + + return false; +} + +bool ContentLibraryMaterial::imported() const +{ + return m_imported; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h new file mode 100644 index 00000000000..5d156809583 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h @@ -0,0 +1,57 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "qmldesignercorelib_global.h" + +#include +#include +#include + +namespace QmlDesigner { + +class ContentLibraryMaterial : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString bundleMaterialName MEMBER m_name CONSTANT) + Q_PROPERTY(QUrl bundleMaterialIcon MEMBER m_icon CONSTANT) + Q_PROPERTY(bool bundleMaterialVisible MEMBER m_visible NOTIFY materialVisibleChanged) + Q_PROPERTY(bool bundleMaterialImported READ imported WRITE setImported NOTIFY materialImportedChanged) + +public: + ContentLibraryMaterial(QObject *parent, + const QString &name, + const QString &qml, + const TypeName &type, + const QUrl &icon, + const QStringList &files); + + bool filter(const QString &searchText); + + QUrl icon() const; + QString qml() const; + TypeName type() const; + QStringList files() const; + bool visible() const; + + bool setImported(bool imported); + bool imported() const; + +signals: + void materialVisibleChanged(); + void materialImportedChanged(); + +private: + QString m_name; + QString m_qml; + TypeName m_type; + QUrl m_icon; + QStringList m_files; + + bool m_visible = true; + bool m_imported = false; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.cpp new file mode 100644 index 00000000000..17465f6b31b --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.cpp @@ -0,0 +1,63 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "contentlibrarymaterialscategory.h" + +#include "contentlibrarymaterial.h" + +namespace QmlDesigner { + +ContentLibraryMaterialsCategory::ContentLibraryMaterialsCategory(QObject *parent, const QString &name) + : QObject(parent), m_name(name) {} + +void ContentLibraryMaterialsCategory::addBundleMaterial(ContentLibraryMaterial *bundleMat) +{ + m_categoryMaterials.append(bundleMat); +} + +bool ContentLibraryMaterialsCategory::updateImportedState(const QStringList &importedMats) +{ + bool changed = false; + + for (ContentLibraryMaterial *mat : std::as_const(m_categoryMaterials)) + changed |= mat->setImported(importedMats.contains(mat->qml().chopped(4))); + + return changed; +} + +bool ContentLibraryMaterialsCategory::filter(const QString &searchText) +{ + bool visible = false; + for (ContentLibraryMaterial *mat : std::as_const(m_categoryMaterials)) + visible |= mat->filter(searchText); + + if (visible != m_visible) { + m_visible = visible; + emit categoryVisibleChanged(); + return true; + } + + return false; +} + +QString ContentLibraryMaterialsCategory::name() const +{ + return m_name; +} + +bool ContentLibraryMaterialsCategory::visible() const +{ + return m_visible; +} + +bool ContentLibraryMaterialsCategory::expanded() const +{ + return m_expanded; +} + +QList ContentLibraryMaterialsCategory::categoryMaterials() const +{ + return m_categoryMaterials; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.h new file mode 100644 index 00000000000..8010270b25a --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialscategory.h @@ -0,0 +1,47 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace QmlDesigner { + +class ContentLibraryMaterial; + +class ContentLibraryMaterialsCategory : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString bundleCategoryName MEMBER m_name CONSTANT) + Q_PROPERTY(bool bundleCategoryVisible MEMBER m_visible NOTIFY categoryVisibleChanged) + Q_PROPERTY(bool bundleCategoryExpanded MEMBER m_expanded NOTIFY categoryExpandChanged) + Q_PROPERTY(QList bundleCategoryMaterials MEMBER m_categoryMaterials + NOTIFY bundleMaterialsModelChanged) + +public: + ContentLibraryMaterialsCategory(QObject *parent, const QString &name); + + void addBundleMaterial(ContentLibraryMaterial *bundleMat); + bool updateImportedState(const QStringList &importedMats); + bool filter(const QString &searchText); + + QString name() const; + bool visible() const; + bool expanded() const; + QList categoryMaterials() const; + +signals: + void categoryVisibleChanged(); + void categoryExpandChanged(); + void bundleMaterialsModelChanged(); + +private: + QString m_name; + bool m_visible = true; + bool m_expanded = true; + + QList m_categoryMaterials; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp similarity index 64% rename from src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp rename to src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp index 7cb2a39c0d1..92be78f016b 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp @@ -1,33 +1,11 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 -#include "materialbrowserbundlemodel.h" +#include "contentlibrarymaterialsmodel.h" -#include "bundleimporter.h" -#include "bundlematerial.h" -#include "bundlematerialcategory.h" +#include "contentlibrarybundleimporter.h" +#include "contentlibrarymaterial.h" +#include "contentlibrarymaterialscategory.h" #include "qmldesignerconstants.h" #include "utils/qtcassert.h" @@ -38,18 +16,18 @@ namespace QmlDesigner { -MaterialBrowserBundleModel::MaterialBrowserBundleModel(QObject *parent) +ContentLibraryMaterialsModel::ContentLibraryMaterialsModel(QObject *parent) : QAbstractListModel(parent) { loadMaterialBundle(); } -int MaterialBrowserBundleModel::rowCount(const QModelIndex &) const +int ContentLibraryMaterialsModel::rowCount(const QModelIndex &) const { return m_bundleCategories.size(); } -QVariant MaterialBrowserBundleModel::data(const QModelIndex &index, int role) const +QVariant ContentLibraryMaterialsModel::data(const QModelIndex &index, int role) const { QTC_ASSERT(index.isValid() && index.row() < m_bundleCategories.count(), return {}); QTC_ASSERT(roleNames().contains(role), return {}); @@ -57,13 +35,13 @@ QVariant MaterialBrowserBundleModel::data(const QModelIndex &index, int role) co return m_bundleCategories.at(index.row())->property(roleNames().value(role)); } -bool MaterialBrowserBundleModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool ContentLibraryMaterialsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || !roleNames().contains(role)) return false; QByteArray roleName = roleNames().value(role); - BundleMaterialCategory *bundleCategory = m_bundleCategories.at(index.row()); + ContentLibraryMaterialsCategory *bundleCategory = m_bundleCategories.at(index.row()); QVariant currValue = bundleCategory->property(roleName); if (currValue != value) { @@ -76,12 +54,12 @@ bool MaterialBrowserBundleModel::setData(const QModelIndex &index, const QVarian return false; } -bool MaterialBrowserBundleModel::isValidIndex(int idx) const +bool ContentLibraryMaterialsModel::isValidIndex(int idx) const { return idx > -1 && idx < rowCount(); } -QHash MaterialBrowserBundleModel::roleNames() const +QHash ContentLibraryMaterialsModel::roleNames() const { static const QHash roles { {Qt::UserRole + 1, "bundleCategoryName"}, @@ -92,7 +70,7 @@ QHash MaterialBrowserBundleModel::roleNames() const return roles; } -void MaterialBrowserBundleModel::loadMaterialBundle() +void ContentLibraryMaterialsModel::loadMaterialBundle() { if (m_matBundleLoaded || m_probeMatBundleDir) return; @@ -137,7 +115,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle() const QJsonObject catsObj = m_matBundleObj.value("categories").toObject(); const QStringList categories = catsObj.keys(); for (const QString &cat : categories) { - auto category = new BundleMaterialCategory(this, cat); + auto category = new ContentLibraryMaterialsCategory(this, cat); const QJsonObject matsObj = catsObj.value(cat).toObject(); const QStringList mats = matsObj.keys(); @@ -156,7 +134,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle() bundleId, qml.chopped(4)).toLatin1(); // chopped(4): remove .qml - auto bundleMat = new BundleMaterial(category, mat, qml, type, icon, files); + auto bundleMat = new ContentLibraryMaterial(category, mat, qml, type, icon, files); category->addBundleMaterial(bundleMat); } @@ -168,15 +146,17 @@ void MaterialBrowserBundleModel::loadMaterialBundle() for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr) sharedFiles.append(file.toString()); - m_importer = new Internal::BundleImporter(matBundleDir.path(), bundleId, sharedFiles); - connect(m_importer, &Internal::BundleImporter::importFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) { + m_importer = new Internal::ContentLibraryBundleImporter(matBundleDir.path(), bundleId, sharedFiles); + connect(m_importer, &Internal::ContentLibraryBundleImporter::importFinished, this, + [&](const QmlDesigner::NodeMetaInfo &metaInfo) { m_importerRunning = false; emit importerRunningChanged(); if (metaInfo.isValid()) emit bundleMaterialImported(metaInfo); }); - connect(m_importer, &Internal::BundleImporter::unimportFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) { + connect(m_importer, &Internal::ContentLibraryBundleImporter::unimportFinished, this, + [&](const QmlDesigner::NodeMetaInfo &metaInfo) { Q_UNUSED(metaInfo) m_importerRunning = false; emit importerRunningChanged(); @@ -184,12 +164,26 @@ void MaterialBrowserBundleModel::loadMaterialBundle() }); } -bool MaterialBrowserBundleModel::hasMaterialRoot() const +bool ContentLibraryMaterialsModel::hasQuick3DImport() const +{ + return m_hasQuick3DImport; +} + +void ContentLibraryMaterialsModel::setHasQuick3DImport(bool b) +{ + if (b == m_hasQuick3DImport) + return; + + m_hasQuick3DImport = b; + emit hasQuick3DImportChanged(); +} + +bool ContentLibraryMaterialsModel::hasMaterialRoot() const { return m_hasMaterialRoot; } -void MaterialBrowserBundleModel::setHasMaterialRoot(bool b) +void ContentLibraryMaterialsModel::setHasMaterialRoot(bool b) { if (m_hasMaterialRoot == b) return; @@ -198,17 +192,17 @@ void MaterialBrowserBundleModel::setHasMaterialRoot(bool b) emit hasMaterialRootChanged(); } -bool MaterialBrowserBundleModel::matBundleExists() const +bool ContentLibraryMaterialsModel::matBundleExists() const { return m_matBundleLoaded && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3; } -Internal::BundleImporter *MaterialBrowserBundleModel::bundleImporter() const +Internal::ContentLibraryBundleImporter *ContentLibraryMaterialsModel::bundleImporter() const { return m_importer; } -void MaterialBrowserBundleModel::setSearchText(const QString &searchText) +void ContentLibraryMaterialsModel::setSearchText(const QString &searchText) { QString lowerSearchText = searchText.toLower(); @@ -220,7 +214,7 @@ void MaterialBrowserBundleModel::setSearchText(const QString &searchText) bool anyCatVisible = false; bool catVisibilityChanged = false; - for (BundleMaterialCategory *cat : std::as_const(m_bundleCategories)) { + for (ContentLibraryMaterialsCategory *cat : std::as_const(m_bundleCategories)) { catVisibilityChanged |= cat->filter(m_searchText); anyCatVisible |= cat->visible(); } @@ -234,17 +228,17 @@ void MaterialBrowserBundleModel::setSearchText(const QString &searchText) resetModel(); } -void MaterialBrowserBundleModel::updateImportedState(const QStringList &importedMats) +void ContentLibraryMaterialsModel::updateImportedState(const QStringList &importedMats) { bool changed = false; - for (BundleMaterialCategory *cat : std::as_const(m_bundleCategories)) + for (ContentLibraryMaterialsCategory *cat : std::as_const(m_bundleCategories)) changed |= cat->updateImportedState(importedMats); if (changed) resetModel(); } -void MaterialBrowserBundleModel::setQuick3DImportVersion(int major, int minor) +void ContentLibraryMaterialsModel::setQuick3DImportVersion(int major, int minor) { bool bundleExisted = matBundleExists(); @@ -255,18 +249,18 @@ void MaterialBrowserBundleModel::setQuick3DImportVersion(int major, int minor) emit matBundleExistsChanged(); } -void MaterialBrowserBundleModel::resetModel() +void ContentLibraryMaterialsModel::resetModel() { beginResetModel(); endResetModel(); } -void MaterialBrowserBundleModel::applyToSelected(BundleMaterial *mat, bool add) +void ContentLibraryMaterialsModel::applyToSelected(ContentLibraryMaterial *mat, bool add) { emit applyToSelectedTriggered(mat, add); } -void MaterialBrowserBundleModel::addToProject(BundleMaterial *mat) +void ContentLibraryMaterialsModel::addToProject(ContentLibraryMaterial *mat) { QString err = m_importer->importComponent(mat->qml(), mat->files()); @@ -278,7 +272,7 @@ void MaterialBrowserBundleModel::addToProject(BundleMaterial *mat) } } -void MaterialBrowserBundleModel::removeFromProject(BundleMaterial *mat) +void ContentLibraryMaterialsModel::removeFromProject(ContentLibraryMaterial *mat) { emit bundleMaterialAboutToUnimport(mat->type()); @@ -292,4 +286,18 @@ void MaterialBrowserBundleModel::removeFromProject(BundleMaterial *mat) } } +bool ContentLibraryMaterialsModel::hasModelSelection() const +{ + return m_hasModelSelection; +} + +void ContentLibraryMaterialsModel::setHasModelSelection(bool b) +{ + if (b == m_hasModelSelection) + return; + + m_hasModelSelection = b; + emit hasModelSelectionChanged(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h similarity index 50% rename from src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h rename to src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h index beb445422e7..9fe76cd25df 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h @@ -1,58 +1,35 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #pragma once -#include -#include +#include "nodemetainfo.h" #include #include -#include -#include namespace QmlDesigner { -class BundleMaterial; -class BundleMaterialCategory; +class ContentLibraryMaterial; +class ContentLibraryMaterialsCategory; namespace Internal { -class BundleImporter; +class ContentLibraryBundleImporter; } -class MaterialBrowserBundleModel : public QAbstractListModel +class ContentLibraryMaterialsModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged) Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) + Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged) + Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged) Q_PROPERTY(bool hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged) Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged) public: - MaterialBrowserBundleModel(QObject *parent = nullptr); + ContentLibraryMaterialsModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -64,25 +41,32 @@ public: void setQuick3DImportVersion(int major, int minor); + bool hasQuick3DImport() const; + void setHasQuick3DImport(bool b); + bool hasMaterialRoot() const; void setHasMaterialRoot(bool b); bool matBundleExists() const; - Internal::BundleImporter *bundleImporter() const; + bool hasModelSelection() const; + void setHasModelSelection(bool b); void resetModel(); - Q_INVOKABLE void applyToSelected(QmlDesigner::BundleMaterial *mat, bool add = false); - Q_INVOKABLE void addToProject(QmlDesigner::BundleMaterial *mat); - Q_INVOKABLE void removeFromProject(QmlDesigner::BundleMaterial *mat); + Internal::ContentLibraryBundleImporter *bundleImporter() const; + + Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false); + Q_INVOKABLE void addToProject(QmlDesigner::ContentLibraryMaterial *mat); + Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryMaterial *mat); signals: void isEmptyChanged(); void hasQuick3DImportChanged(); + void hasModelSelectionChanged(); void hasMaterialRootChanged(); void materialVisibleChanged(); - void applyToSelectedTriggered(QmlDesigner::BundleMaterial *mat, bool add = false); + void applyToSelectedTriggered(QmlDesigner::ContentLibraryMaterial *mat, bool add = false); void bundleMaterialImported(const QmlDesigner::NodeMetaInfo &metaInfo); void bundleMaterialAboutToUnimport(const QmlDesigner::TypeName &type); void bundleMaterialUnimported(const QmlDesigner::NodeMetaInfo &metaInfo); @@ -94,13 +78,15 @@ private: bool isValidIndex(int idx) const; QString m_searchText; - QList m_bundleCategories; + QList m_bundleCategories; QJsonObject m_matBundleObj; - Internal::BundleImporter *m_importer = nullptr; + Internal::ContentLibraryBundleImporter *m_importer = nullptr; bool m_isEmpty = true; bool m_hasMaterialRoot = false; + bool m_hasQuick3DImport = false; bool m_matBundleLoaded = false; + bool m_hasModelSelection = false; bool m_probeMatBundleDir = false; bool m_importerRunning = false; diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp new file mode 100644 index 00000000000..288e04aaff6 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp @@ -0,0 +1,33 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "contentlibrarytexture.h" + +namespace QmlDesigner { + +ContentLibraryTexture::ContentLibraryTexture(QObject *parent, const QString &path, const QUrl &icon) + : QObject(parent) + , m_path(path) + , m_icon(icon) {} + +bool ContentLibraryTexture::filter(const QString &searchText) +{ + if (m_visible != m_path.contains(searchText, Qt::CaseInsensitive)) { + m_visible = !m_visible; + emit textureVisibleChanged(); + } + + return m_visible; +} + +QUrl ContentLibraryTexture::icon() const +{ + return m_icon; +} + +QString ContentLibraryTexture::path() const +{ + return m_path; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h new file mode 100644 index 00000000000..88d50158325 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h @@ -0,0 +1,37 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace QmlDesigner { + +class ContentLibraryTexture : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString texturePath MEMBER m_path CONSTANT) + Q_PROPERTY(QUrl textureIcon MEMBER m_icon CONSTANT) + Q_PROPERTY(bool textureVisible MEMBER m_visible NOTIFY textureVisibleChanged) + +public: + ContentLibraryTexture(QObject *parent, const QString &path, const QUrl &icon); + + bool filter(const QString &searchText); + + QUrl icon() const; + QString path() const; + +signals: + void textureVisibleChanged(); + +private: + QString m_path; + QUrl m_icon; + + bool m_visible = true; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp new file mode 100644 index 00000000000..56468364e67 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "contentlibrarytexturescategory.h" + +#include "contentlibrarytexture.h" + +#include + +namespace QmlDesigner { + +ContentLibraryTexturesCategory::ContentLibraryTexturesCategory(QObject *parent, const QString &name) + : QObject(parent), m_name(name) {} + +void ContentLibraryTexturesCategory::addTexture(const QFileInfo &tex) +{ + QUrl icon = QUrl::fromLocalFile(tex.path() + "/icon/" + tex.baseName() + ".png"); + m_categoryTextures.append(new ContentLibraryTexture(this, tex.filePath(), icon)); +} + +bool ContentLibraryTexturesCategory::filter(const QString &searchText) +{ + bool visible = false; + for (ContentLibraryTexture *tex : std::as_const(m_categoryTextures)) + visible |= tex->filter(searchText); + + if (visible != m_visible) { + m_visible = visible; + emit categoryVisibleChanged(); + return true; + } + + return false; +} + +QString ContentLibraryTexturesCategory::name() const +{ + return m_name; +} + +bool ContentLibraryTexturesCategory::visible() const +{ + return m_visible; +} + +bool ContentLibraryTexturesCategory::expanded() const +{ + return m_expanded; +} + +QList ContentLibraryTexturesCategory::categoryTextures() const +{ + return m_categoryTextures; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h new file mode 100644 index 00000000000..1e0055d28cd --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h @@ -0,0 +1,50 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +QT_BEGIN_NAMESPACE +class QFileInfo; +QT_END_NAMESPACE + +namespace QmlDesigner { + +class ContentLibraryTexture; + +class ContentLibraryTexturesCategory : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString bundleCategoryName MEMBER m_name CONSTANT) + Q_PROPERTY(bool bundleCategoryVisible MEMBER m_visible NOTIFY categoryVisibleChanged) + Q_PROPERTY(bool bundleCategoryExpanded MEMBER m_expanded NOTIFY categoryExpandChanged) + Q_PROPERTY(QList bundleCategoryTextures MEMBER m_categoryTextures + NOTIFY bundleTexturesModelChanged) + +public: + ContentLibraryTexturesCategory(QObject *parent, const QString &name); + + void addTexture(const QFileInfo &tex); + bool filter(const QString &searchText); + + QString name() const; + bool visible() const; + bool expanded() const; + QList categoryTextures() const; + +signals: + void categoryVisibleChanged(); + void categoryExpandChanged(); + void bundleTexturesModelChanged(); + +private: + QString m_name; + bool m_visible = true; + bool m_expanded = true; + + QList m_categoryTextures; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp new file mode 100644 index 00000000000..38c9522879b --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp @@ -0,0 +1,185 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "contentlibrarytexturesmodel.h" + +#include "contentlibrarytexturescategory.h" +#include "utils/qtcassert.h" + +#include +#include +#include +#include + +namespace QmlDesigner { + +ContentLibraryTexturesModel::ContentLibraryTexturesModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +int ContentLibraryTexturesModel::rowCount(const QModelIndex &) const +{ + return m_bundleCategories.size(); +} + +QVariant ContentLibraryTexturesModel::data(const QModelIndex &index, int role) const +{ + QTC_ASSERT(index.isValid() && index.row() < m_bundleCategories.count(), return {}); + QTC_ASSERT(roleNames().contains(role), return {}); + + return m_bundleCategories.at(index.row())->property(roleNames().value(role)); +} + +bool ContentLibraryTexturesModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || !roleNames().contains(role)) + return false; + + QByteArray roleName = roleNames().value(role); + ContentLibraryTexturesCategory *bundleCategory = m_bundleCategories.at(index.row()); + QVariant currValue = bundleCategory->property(roleName); + + if (currValue != value) { + bundleCategory->setProperty(roleName, value); + + emit dataChanged(index, index, {role}); + return true; + } + + return false; +} + +bool ContentLibraryTexturesModel::isValidIndex(int idx) const +{ + return idx > -1 && idx < rowCount(); +} + +QHash ContentLibraryTexturesModel::roleNames() const +{ + static const QHash roles { + {Qt::UserRole + 1, "bundleCategoryName"}, + {Qt::UserRole + 2, "bundleCategoryVisible"}, + {Qt::UserRole + 3, "bundleCategoryExpanded"}, + {Qt::UserRole + 4, "bundleCategoryTextures"} + }; + return roles; +} + +void ContentLibraryTexturesModel::loadTextureBundle(const QString &bundlePath) +{ + QDir bundleDir = QDir(bundlePath); + if (!bundleDir.exists()) { + qWarning() << __FUNCTION__ << "textures bundle folder doesn't exist." << bundlePath; + return; + } + + if (m_texBundleLoaded) + return; + + const QFileInfoList dirs = bundleDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QFileInfo &dir : dirs) { + auto category = new ContentLibraryTexturesCategory(this, dir.fileName()); + const QFileInfoList texFiles = QDir(dir.filePath()).entryInfoList(QDir::Files); + for (const QFileInfo &tex : texFiles) + category->addTexture(tex); + m_bundleCategories.append(category); + } +} + +bool ContentLibraryTexturesModel::hasQuick3DImport() const +{ + return m_hasQuick3DImport; +} + +void ContentLibraryTexturesModel::setHasQuick3DImport(bool b) +{ + if (b == m_hasQuick3DImport) + return; + + m_hasQuick3DImport = b; + emit hasQuick3DImportChanged(); +} + +bool ContentLibraryTexturesModel::hasMaterialRoot() const +{ + return m_hasMaterialRoot; +} + +void ContentLibraryTexturesModel::setHasMaterialRoot(bool b) +{ + if (m_hasMaterialRoot == b) + return; + + m_hasMaterialRoot = b; + emit hasMaterialRootChanged(); +} + +bool ContentLibraryTexturesModel::matBundleExists() const +{ + return m_texBundleLoaded && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3; +} + +void ContentLibraryTexturesModel::setSearchText(const QString &searchText) +{ + QString lowerSearchText = searchText.toLower(); + + if (m_searchText == lowerSearchText) + return; + + m_searchText = lowerSearchText; + + bool anyCatVisible = false; + bool catVisibilityChanged = false; + + for (ContentLibraryTexturesCategory *cat : std::as_const(m_bundleCategories)) { + catVisibilityChanged |= cat->filter(m_searchText); + anyCatVisible |= cat->visible(); + } + + if (anyCatVisible == m_isEmpty) { + m_isEmpty = !anyCatVisible; + emit isEmptyChanged(); + } + + if (catVisibilityChanged) + resetModel(); +} + +void ContentLibraryTexturesModel::setQuick3DImportVersion(int major, int minor) +{ + bool bundleExisted = matBundleExists(); + + m_quick3dMajorVersion = major; + m_quick3dMinorVersion = minor; + + if (bundleExisted != matBundleExists()) + emit matBundleExistsChanged(); +} + +void ContentLibraryTexturesModel::resetModel() +{ + beginResetModel(); + endResetModel(); +} + +void ContentLibraryTexturesModel::addToProject(const QString &mat) +{ + // TODO: import asset +} + +bool ContentLibraryTexturesModel::hasModelSelection() const +{ + return m_hasModelSelection; +} + +void ContentLibraryTexturesModel::setHasModelSelection(bool b) +{ + if (b == m_hasModelSelection) + return; + + m_hasModelSelection = b; + emit hasModelSelectionChanged(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h new file mode 100644 index 00000000000..8009dd3ff80 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h @@ -0,0 +1,74 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace QmlDesigner { + +class ContentLibraryTexturesCategory; + +class ContentLibraryTexturesModel : public QAbstractListModel +{ + Q_OBJECT + + Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged) + Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) + Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged) + Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged) + Q_PROPERTY(bool hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged) + +public: + ContentLibraryTexturesModel(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + QHash roleNames() const override; + + void setSearchText(const QString &searchText); + + void setQuick3DImportVersion(int major, int minor); + + bool hasQuick3DImport() const; + void setHasQuick3DImport(bool b); + + bool hasMaterialRoot() const; + void setHasMaterialRoot(bool b); + + bool matBundleExists() const; + + bool hasModelSelection() const; + void setHasModelSelection(bool b); + + void resetModel(); + void loadTextureBundle(const QString &bundlePath); + + Q_INVOKABLE void addToProject(const QString &mat); + +signals: + void isEmptyChanged(); + void hasQuick3DImportChanged(); + void hasModelSelectionChanged(); + void hasMaterialRootChanged(); + void materialVisibleChanged(); + void matBundleExistsChanged(); + +private: + bool isValidIndex(int idx) const; + + QString m_searchText; + QList m_bundleCategories; + + bool m_isEmpty = true; + bool m_hasMaterialRoot = false; + bool m_hasQuick3DImport = false; + bool m_texBundleLoaded = false; + bool m_hasModelSelection = false; + + int m_quick3dMajorVersion = -1; + int m_quick3dMinorVersion = -1; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp new file mode 100644 index 00000000000..fe035cee345 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -0,0 +1,354 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "contentlibraryview.h" + +#include "contentlibrarybundleimporter.h" +#include "contentlibrarywidget.h" +#include "contentlibrarymaterial.h" +#include "contentlibrarymaterialsmodel.h" +#include "modelnodeoperations.h" +#include "nodelistproperty.h" +#include "qmlobjectnode.h" +#include "variantproperty.h" + +#include +#include + +#ifndef QMLDESIGNER_TEST +#include +#include +#include +#include +#include +#endif + +namespace QmlDesigner { + +ContentLibraryView::ContentLibraryView(ExternalDependenciesInterface &externalDependencies) + : AbstractView(externalDependencies) +{} + +ContentLibraryView::~ContentLibraryView() +{} + +bool ContentLibraryView::hasWidget() const +{ + return true; +} + +WidgetInfo ContentLibraryView::widgetInfo() +{ + if (m_widget.isNull()) { + m_widget = new ContentLibraryWidget(); + + connect(m_widget, &ContentLibraryWidget::bundleMaterialDragStarted, this, + [&] (QmlDesigner::ContentLibraryMaterial *mat) { + m_draggedBundleMaterial = mat; + }); + connect(m_widget, &ContentLibraryWidget::addTextureRequested, this, + [&] (const QString texPath, ContentLibraryWidget::AddTextureMode mode) { + AddFilesResult result = ModelNodeOperations::addImageToProject({texPath}, "images", false); + + if (result == AddFilesResult::Failed) { + Core::AsynchronousMessageBox::warning(tr("Failed to Add Texture"), + tr("Could not add %1 to project.").arg(texPath)); + return; + } + + if (mode == ContentLibraryWidget::AddTextureMode::Texture) { + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid()) + return; + + NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.Texture"); + ModelNode newTexNode = createModelNode("QtQuick3D.Texture", metaInfo.majorVersion(), + metaInfo.minorVersion()); + newTexNode.validId(); + VariantProperty sourceProp = newTexNode.variantProperty("source"); + sourceProp.setValue(QLatin1String("images/%1").arg(texPath.split('/').last())); + matLib.defaultNodeListProperty().reparentHere(newTexNode); + } else if (mode == ContentLibraryWidget::AddTextureMode::Environment) { + // TODO: assign as env + } + }); + + ContentLibraryMaterialsModel *materialsModel = m_widget->materialsModel().data(); + + connect(materialsModel, &ContentLibraryMaterialsModel::applyToSelectedTriggered, this, + [&] (ContentLibraryMaterial *bundleMat, bool add) { + if (m_selectedModels.isEmpty()) + return; + + m_bundleMaterialTargets = m_selectedModels; + m_bundleMaterialAddToSelected = add; + + ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type()); + if (defaultMat.isValid()) + applyBundleMaterialToDropTarget(defaultMat); + else + m_widget->materialsModel()->addToProject(bundleMat); + }); + + connect(materialsModel, &ContentLibraryMaterialsModel::bundleMaterialImported, this, + [&] (const QmlDesigner::NodeMetaInfo &metaInfo) { + applyBundleMaterialToDropTarget({}, metaInfo); + updateBundleMaterialsImportedState(); + }); + + connect(materialsModel, &ContentLibraryMaterialsModel::bundleMaterialAboutToUnimport, this, + [&] (const QmlDesigner::TypeName &type) { + // delete instances of the bundle material that is about to be unimported + executeInTransaction("MaterialBrowserView::widgetInfo", [&] { + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid()) + return; + + Utils::reverseForeach(matLib.directSubModelNodes(), [&](const ModelNode &mat) { + if (mat.isValid() && mat.type() == type) + QmlObjectNode(mat).destroy(); + }); + }); + }); + + connect(materialsModel, &ContentLibraryMaterialsModel::bundleMaterialUnimported, this, + &ContentLibraryView::updateBundleMaterialsImportedState); + } + + return createWidgetInfo(m_widget.data(), + "ContentLibrary", + WidgetInfo::LeftPane, + 0, + tr("Content Library")); +} + +void ContentLibraryView::modelAttached(Model *model) +{ + AbstractView::modelAttached(model); + + m_hasQuick3DImport = model->hasImport("QtQuick3D"); + + m_widget->materialsModel()->setHasMaterialRoot(rootModelNode().metaInfo().isQtQuick3DMaterial()); + m_widget->materialsModel()->setHasQuick3DImport(m_hasQuick3DImport); + + updateBundleMaterialsQuick3DVersion(); + updateBundleMaterialsImportedState(); +} + +void ContentLibraryView::modelAboutToBeDetached(Model *model) +{ + + AbstractView::modelAboutToBeDetached(model); +} + +void ContentLibraryView::importsChanged(const QList &addedImports, const QList &removedImports) +{ + Q_UNUSED(addedImports) + Q_UNUSED(removedImports) + + updateBundleMaterialsQuick3DVersion(); + + bool hasQuick3DImport = model()->hasImport("QtQuick3D"); + + if (hasQuick3DImport == m_hasQuick3DImport) + return; + + m_hasQuick3DImport = hasQuick3DImport; + m_widget->materialsModel()->setHasQuick3DImport(m_hasQuick3DImport); +} + +void ContentLibraryView::selectedNodesChanged(const QList &selectedNodeList, + const QList &lastSelectedNodeList) +{ + Q_UNUSED(lastSelectedNodeList) + + m_selectedModels = Utils::filtered(selectedNodeList, [](const ModelNode &node) { + return node.metaInfo().isQtQuick3DModel(); + }); + + m_widget->materialsModel()->setHasModelSelection(!m_selectedModels.isEmpty()); +} + +void ContentLibraryView::customNotification(const AbstractView *view, const QString &identifier, + const QList &nodeList, const QList &data) +{ + Q_UNUSED(data) + + if (view == this) + return; + + if (identifier == "drop_bundle_material") { + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid()) + return; + + m_bundleMaterialTargets = nodeList; + + ModelNode defaultMat = getBundleMaterialDefaultInstance(m_draggedBundleMaterial->type()); + if (defaultMat.isValid()) { + if (m_bundleMaterialTargets.isEmpty()) // if no drop target, create a duplicate material + createMaterial(defaultMat.metaInfo()); + else + applyBundleMaterialToDropTarget(defaultMat); + } else { + m_widget->materialsModel()->addToProject(m_draggedBundleMaterial); + } + + m_draggedBundleMaterial = nullptr; + } +} + +void ContentLibraryView::applyBundleMaterialToDropTarget(const ModelNode &bundleMat, + const NodeMetaInfo &metaInfo) +{ + if (!bundleMat.isValid() && !metaInfo.isValid()) + return; + + executeInTransaction("MaterialBrowserView::applyBundleMaterialToDropTarget", [&] { + ModelNode newMatNode = metaInfo.isValid() ? createMaterial(metaInfo) : bundleMat; + + // TODO: unify this logic as it exist elsewhere also + auto expToList = [](const QString &exp) { + QString copy = exp; + copy = copy.remove("[").remove("]"); + + QStringList tmp = copy.split(',', Qt::SkipEmptyParts); + for (QString &str : tmp) + str = str.trimmed(); + + return tmp; + }; + + auto listToExp = [](QStringList &stringList) { + if (stringList.size() > 1) + return QString("[" + stringList.join(",") + "]"); + + if (stringList.size() == 1) + return stringList.first(); + + return QString(); + }; + + for (const ModelNode &target : std::as_const(m_bundleMaterialTargets)) { + if (target.isValid() && target.metaInfo().isQtQuick3DModel()) { + QmlObjectNode qmlObjNode(target); + if (m_bundleMaterialAddToSelected) { + QStringList matList = expToList(qmlObjNode.expression("materials")); + matList.append(newMatNode.id()); + QString updatedExp = listToExp(matList); + qmlObjNode.setBindingProperty("materials", updatedExp); + } else { + qmlObjNode.setBindingProperty("materials", newMatNode.id()); + } + } + + m_bundleMaterialTargets = {}; + m_bundleMaterialAddToSelected = false; + } + }); +} + +ModelNode ContentLibraryView::getBundleMaterialDefaultInstance(const TypeName &type) +{ + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid()) + return {}; + + const QList matLibNodes = matLib.directSubModelNodes(); + for (const ModelNode &mat : matLibNodes) { + if (mat.isValid() && mat.type() == type) { + bool isDefault = true; + const QList props = mat.properties(); + for (const AbstractProperty &prop : props) { + if (prop.name() != "objectName") { + isDefault = false; + break; + } + } + + if (isDefault) + return mat; + } + } + + return {}; +} + +ModelNode ContentLibraryView::createMaterial(const NodeMetaInfo &metaInfo) +{ + ModelNode matLib = materialLibraryNode(); + if (!matLib.isValid() || !metaInfo.isValid()) + return {}; + + ModelNode newMatNode = createModelNode(metaInfo.typeName(), metaInfo.majorVersion(), + metaInfo.minorVersion()); + matLib.defaultNodeListProperty().reparentHere(newMatNode); + + static QRegularExpression rgx("([A-Z])([a-z]*)"); + QString newName = QString::fromLatin1(metaInfo.simplifiedTypeName()).replace(rgx, " \\1\\2").trimmed(); + if (newName.endsWith(" Material")) + newName.chop(9); // remove trailing " Material" + QString newId = model()->generateIdFromName(newName, "material"); + newMatNode.setIdWithRefactoring(newId); + + VariantProperty objNameProp = newMatNode.variantProperty("objectName"); + objNameProp.setValue(newName); + + return newMatNode; +} + +void ContentLibraryView::updateBundleMaterialsImportedState() +{ + using namespace Utils; + + if (!m_widget->materialsModel()->bundleImporter()) + return; + + QStringList importedBundleMats; + + FilePath materialBundlePath = m_widget->materialsModel()->bundleImporter()->resolveBundleImportPath(); + + if (materialBundlePath.exists()) { + importedBundleMats = transform(materialBundlePath.dirEntries({{"*.qml"}, QDir::Files}), + [](const FilePath &f) { return f.fileName().chopped(4); }); + } + + m_widget->materialsModel()->updateImportedState(importedBundleMats); +} + +void ContentLibraryView::updateBundleMaterialsQuick3DVersion() +{ + bool hasImport = false; + int major = -1; + int minor = -1; + const QString url {"QtQuick3D"}; + const auto imports = model()->imports(); + for (const auto &import : imports) { + if (import.url() == url) { + hasImport = true; + const int importMajor = import.majorVersion(); + if (major < importMajor) { + minor = -1; + major = importMajor; + } + if (major == importMajor) + minor = qMax(minor, import.minorVersion()); + } + } +#ifndef QMLDESIGNER_TEST + if (hasImport && major == -1) { + // Import without specifying version, so we take the kit version + auto target = ProjectExplorer::SessionManager::startupTarget(); + if (target) { + QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); + if (qtVersion) { + major = qtVersion->qtVersion().majorVersion(); + minor = qtVersion->qtVersion().minorVersion(); + } + } + } +#endif + m_widget->materialsModel()->setQuick3DImportVersion(major, minor); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h new file mode 100644 index 00000000000..8ece6a76d05 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h @@ -0,0 +1,53 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "abstractview.h" +#include "nodemetainfo.h" + +#include +#include + +namespace QmlDesigner { + +class ContentLibraryMaterial; +class ContentLibraryWidget; +class Model; + +class ContentLibraryView : public AbstractView +{ + Q_OBJECT + +public: + ContentLibraryView(ExternalDependenciesInterface &externalDependencies); + ~ContentLibraryView() override; + + bool hasWidget() const override; + WidgetInfo widgetInfo() override; + + // AbstractView + void modelAttached(Model *model) override; + void modelAboutToBeDetached(Model *model) override; + void importsChanged(const QList &addedImports, const QList &removedImports) override; + void selectedNodesChanged(const QList &selectedNodeList, + const QList &lastSelectedNodeList) override; + void customNotification(const AbstractView *view, const QString &identifier, + const QList &nodeList, const QList &data) override; + +private: + void updateBundleMaterialsImportedState(); + void updateBundleMaterialsQuick3DVersion(); + void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const NodeMetaInfo &metaInfo = {}); + ModelNode getBundleMaterialDefaultInstance(const TypeName &type); + ModelNode createMaterial(const NodeMetaInfo &metaInfo); + + QPointer m_widget; + QList m_bundleMaterialTargets; + QList m_selectedModels; // selected 3D model nodes + ContentLibraryMaterial *m_draggedBundleMaterial = nullptr; + bool m_bundleMaterialAddToSelected = false; + bool m_hasQuick3DImport = false; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp new file mode 100644 index 00000000000..02d116811eb --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp @@ -0,0 +1,238 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "contentlibrarywidget.h" + +#include "contentlibrarymaterial.h" +#include "contentlibrarymaterialsmodel.h" +#include "contentlibrarytexture.h" +#include "contentlibrarytexturesmodel.h" + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { + +static QString propertyEditorResourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources"; +#endif + return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString(); +} + +bool ContentLibraryWidget::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) { + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20) { + QByteArray data; + QMimeData *mimeData = new QMimeData; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_materialToDrag->type(); + mimeData->setData(Constants::MIME_TYPE_BUNDLE_MATERIAL, data); + mimeData->removeFormat("text/plain"); + + if (!m_draggedMaterial) { + m_draggedMaterial = m_materialToDrag; + emit draggedMaterialChanged(); + } + + emit bundleMaterialDragStarted(m_materialToDrag); + model->startDrag(mimeData, m_materialToDrag->icon().toLocalFile()); + m_materialToDrag = nullptr; + } + } else if (m_textureToDrag) { + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20) { + QByteArray data; + QMimeData *mimeData = new QMimeData; + QDataStream stream(&data, QIODevice::WriteOnly); + stream << m_textureToDrag->path(); + mimeData->setData(Constants::MIME_TYPE_BUNDLE_TEXTURE, data); + mimeData->removeFormat("text/plain"); + + model->startDrag(mimeData, m_textureToDrag->icon().toLocalFile()); + m_textureToDrag = nullptr; + } + } + } else if (event->type() == QMouseEvent::MouseButtonRelease) { + m_materialToDrag = nullptr; + m_textureToDrag = nullptr; + + if (m_draggedMaterial) { + m_draggedMaterial = nullptr; + emit draggedMaterialChanged(); + } + } + + return QObject::eventFilter(obj, event); +} + +ContentLibraryWidget::ContentLibraryWidget() + : m_quickWidget(new QQuickWidget(this)) + , m_materialsModel(new ContentLibraryMaterialsModel(this)) + , m_texturesModel(new ContentLibraryTexturesModel(this)) + , m_environmentsModel(new ContentLibraryTexturesModel(this)) +{ + setWindowTitle(tr("Content Library", "Title of content library widget")); + setMinimumWidth(120); + + m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); + m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); + + QString textureBundlePath = findTextureBundlePath(); + m_texturesModel->loadTextureBundle(textureBundlePath + "/Textures"); + m_environmentsModel->loadTextureBundle(textureBundlePath + "/Environments"); + + m_quickWidget->rootContext()->setContextProperties({ + {"rootView", QVariant::fromValue(this)}, + {"materialsModel", QVariant::fromValue(m_materialsModel.data())}, + {"texturesModel", QVariant::fromValue(m_texturesModel.data())}, + {"environmentsModel", QVariant::fromValue(m_environmentsModel.data())}, + }); + + Theme::setupTheme(m_quickWidget->engine()); + m_quickWidget->installEventFilter(this); + + auto layout = new QVBoxLayout(this); + layout->setContentsMargins({}); + layout->setSpacing(0); + layout->addWidget(m_quickWidget.data()); + + updateSearch(); + + setStyleSheet(Theme::replaceCssColors( + QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); + + m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F11), this); + connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &ContentLibraryWidget::reloadQmlSource); + +// QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_MATERIALBROWSER_TIME); // TODO + + reloadQmlSource(); +} + +QList ContentLibraryWidget::createToolBarWidgets() +{ + return {}; +} + +void ContentLibraryWidget::handleSearchFilterChanged(const QString &filterText) +{ + if (filterText != m_filterText) { + m_filterText = filterText; + updateSearch(); + } +} + +QString ContentLibraryWidget::qmlSourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/contentLibraryQmlSource"; +#endif + return Core::ICore::resourcePath("qmldesigner/contentLibraryQmlSource").toString(); +} + +void ContentLibraryWidget::clearSearchFilter() +{ + QMetaObject::invokeMethod(m_quickWidget->rootObject(), "clearSearchFilter"); +} + +void ContentLibraryWidget::reloadQmlSource() +{ + const QString materialBrowserQmlPath = qmlSourcesPath() + "/ContentLibrary.qml"; + + QTC_ASSERT(QFileInfo::exists(materialBrowserQmlPath), return); + + m_quickWidget->engine()->clearComponentCache(); + m_quickWidget->setSource(QUrl::fromLocalFile(materialBrowserQmlPath)); +} + +void ContentLibraryWidget::updateSearch() +{ + m_materialsModel->setSearchText(m_filterText); + m_texturesModel->setSearchText(m_filterText); + m_environmentsModel->setSearchText(m_filterText); + m_quickWidget->update(); +} + +QString ContentLibraryWidget::findTextureBundlePath() +{ + QDir texBundleDir(qEnvironmentVariable("TEXTURE_BUNDLE_PATH")); + + // search for matBundleDir from exec dir and up + if (texBundleDir.dirName() == ".") { + texBundleDir.setPath(QCoreApplication::applicationDirPath()); + while (!texBundleDir.cd("texture_bundle") && texBundleDir.cdUp()) + ; // do nothing + + if (texBundleDir.dirName() != "texture_bundle") // bundlePathDir not found + return {}; + } + + return texBundleDir.path(); +} + +void ContentLibraryWidget::startDragMaterial(QmlDesigner::ContentLibraryMaterial *mat, + const QPointF &mousePos) +{ + m_materialToDrag = mat; + m_dragStartPoint = mousePos.toPoint(); +} + +void ContentLibraryWidget::startDragTexture(QmlDesigner::ContentLibraryTexture *tex, + const QPointF &mousePos) +{ + m_textureToDrag = tex; + m_dragStartPoint = mousePos.toPoint(); +} + +void ContentLibraryWidget::addImage(ContentLibraryTexture *tex) +{ + emit addTextureRequested(tex->path(), AddTextureMode::Image); +} + +void ContentLibraryWidget::addTexture(ContentLibraryTexture *tex) +{ + emit addTextureRequested(tex->path(), AddTextureMode::Texture); +} + +void ContentLibraryWidget::addEnv(ContentLibraryTexture *tex) +{ + emit addTextureRequested(tex->path(), AddTextureMode::Environment); +} + +QPointer ContentLibraryWidget::materialsModel() const +{ + return m_materialsModel; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h new file mode 100644 index 00000000000..3eb470b7ae3 --- /dev/null +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h @@ -0,0 +1,76 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +QT_BEGIN_NAMESPACE +class QShortcut; +class QToolButton; +class QQuickWidget; +QT_END_NAMESPACE + +namespace QmlDesigner { + +class ContentLibraryTexture; +class ContentLibraryMaterial; +class ContentLibraryTexturesModel; +class ContentLibraryMaterialsModel; + +class ContentLibraryWidget : public QFrame +{ + Q_OBJECT + +public: + ContentLibraryWidget(); + + QList createToolBarWidgets(); + + static QString qmlSourcesPath(); + void clearSearchFilter(); + + Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText); + + void setMaterialsModel(QPointer newMaterialsModel); + + QPointer materialsModel() const; + + Q_INVOKABLE void startDragMaterial(QmlDesigner::ContentLibraryMaterial *mat, const QPointF &mousePos); + Q_INVOKABLE void startDragTexture(QmlDesigner::ContentLibraryTexture *tex, const QPointF &mousePos); + Q_INVOKABLE void addImage(QmlDesigner::ContentLibraryTexture *tex); + Q_INVOKABLE void addTexture(QmlDesigner::ContentLibraryTexture *tex); + Q_INVOKABLE void addEnv(QmlDesigner::ContentLibraryTexture *tex); + + enum class AddTextureMode { Image, Texture, Environment }; + +signals: + void bundleMaterialDragStarted(QmlDesigner::ContentLibraryMaterial *bundleMat); + void draggedMaterialChanged(); + void addTextureRequested(const QString texPath, QmlDesigner::ContentLibraryWidget::AddTextureMode mode); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + void reloadQmlSource(); + void updateSearch(); + QString findTextureBundlePath(); + + QScopedPointer m_quickWidget; + QPointer m_materialsModel; + QPointer m_texturesModel; + QPointer m_environmentsModel; + + QShortcut *m_qmlSourceUpdateShortcut = nullptr; + + QString m_filterText; + + ContentLibraryMaterial *m_materialToDrag = nullptr; + ContentLibraryMaterial *m_draggedMaterial = nullptr; + ContentLibraryTexture *m_textureToDrag = nullptr; + QPoint m_dragStartPoint; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 80fd6aa2b16..c734b0e362c 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -286,7 +286,7 @@ void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos }); } } else if (m_nodeAtPosReqType == NodeAtPosReqType::BundleMaterialDrop) { - emitCustomNotification("drop_bundle_material", {modelNode}); // To MaterialBrowserView + emitCustomNotification("drop_bundle_material", {modelNode}); // To ContentLibraryView } m_nodeAtPosReqType = NodeAtPosReqType::None; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index 7d90020d961..813b021b85d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -146,7 +146,8 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap) m_importableExtensions3DMap = extMap; AddResourceOperation import3DModelOperation = [this](const QStringList &fileNames, - const QString &defaultDir) -> AddFilesResult { + const QString &defaultDir, + bool showDialog) -> AddFilesResult { auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir, m_importableExtensions3DMap, m_importOptions3DMap, {}, {}, diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h b/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h deleted file mode 100644 index 64344915ce1..00000000000 --- a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -#include "nodemetainfo.h" - -#include -#include - -QT_BEGIN_NAMESPACE -QT_END_NAMESPACE - -namespace QmlDesigner::Internal { - -class BundleImporter : public QObject -{ - Q_OBJECT - -public: - BundleImporter(const QString &bundleDir, - const QString &bundleId, - const QStringList &sharedFiles, - QObject *parent = nullptr); - ~BundleImporter() = default; - - QString importComponent(const QString &qmlFile, - const QStringList &files); - QString unimportComponent(const QString &qmlFile); - Utils::FilePath resolveBundleImportPath(); - -signals: - // The metaInfo parameter will be invalid if an error was encountered during - // asynchronous part of the import. In this case all remaining pending imports have been - // terminated, and will not receive separate importFinished notifications. - void importFinished(const QmlDesigner::NodeMetaInfo &metaInfo); - void unimportFinished(const QmlDesigner::NodeMetaInfo &metaInfo); - -private: - void handleImportTimer(); - QVariantHash loadAssetRefMap(const Utils::FilePath &bundlePath); - void writeAssetRefMap(const Utils::FilePath &bundlePath, const QVariantHash &assetRefMap); - - Utils::FilePath m_bundleDir; - QString m_bundleId; - QString m_moduleName; - QStringList m_sharedFiles; - QTimer m_importTimer; - int m_importTimerCount = 0; - bool m_importAddPending = false; - bool m_fullReset = false; - QHash m_pendingTypes; // -}; - -} // namespace QmlDesigner::Internal diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp deleted file mode 100644 index 6cee76475ac..00000000000 --- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** 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 "bundlematerial.h" - -namespace QmlDesigner { - -BundleMaterial::BundleMaterial(QObject *parent, - const QString &name, - const QString &qml, - const TypeName &type, - const QUrl &icon, - const QStringList &files) - : QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files) {} - -bool BundleMaterial::filter(const QString &searchText) -{ - if (m_visible != m_name.contains(searchText, Qt::CaseInsensitive)) { - m_visible = !m_visible; - emit materialVisibleChanged(); - } - - return m_visible; -} - -QUrl BundleMaterial::icon() const -{ - return m_icon; -} - -QString BundleMaterial::qml() const -{ - return m_qml; -} - -TypeName BundleMaterial::type() const -{ - return m_type; -} - -QStringList BundleMaterial::files() const -{ - return m_files; -} - -bool BundleMaterial::visible() const -{ - return m_visible; -} - -bool BundleMaterial::setImported(bool imported) -{ - if (m_imported != imported) { - m_imported = imported; - emit materialImportedChanged(); - return true; - } - - return false; -} - -bool BundleMaterial::imported() const -{ - return m_imported; -} - -} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h deleted file mode 100644 index 64d79aa65ee..00000000000 --- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** 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 "qmldesignercorelib_global.h" - -#include -#include -#include - -namespace QmlDesigner { - -class BundleMaterial : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QString bundleMaterialName MEMBER m_name CONSTANT) - Q_PROPERTY(QUrl bundleMaterialIcon MEMBER m_icon CONSTANT) - Q_PROPERTY(bool bundleMaterialVisible MEMBER m_visible NOTIFY materialVisibleChanged) - Q_PROPERTY(bool bundleMaterialImported READ imported WRITE setImported NOTIFY materialImportedChanged) - -public: - BundleMaterial(QObject *parent, - const QString &name, - const QString &qml, - const TypeName &type, - const QUrl &icon, - const QStringList &files); - - bool filter(const QString &searchText); - - QUrl icon() const; - QString qml() const; - TypeName type() const; - QStringList files() const; - bool visible() const; - - bool setImported(bool imported); - bool imported() const; - -signals: - void materialVisibleChanged(); - void materialImportedChanged(); - -private: - QString m_name; - QString m_qml; - TypeName m_type; - QUrl m_icon; - QStringList m_files; - - bool m_visible = true; - bool m_imported = false; -}; - -} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp b/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp deleted file mode 100644 index 60910abb046..00000000000 --- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** 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 "bundlematerialcategory.h" - -#include "bundlematerial.h" - -namespace QmlDesigner { - -BundleMaterialCategory::BundleMaterialCategory(QObject *parent, const QString &name) - : QObject(parent), m_name(name) {} - -void BundleMaterialCategory::addBundleMaterial(BundleMaterial *bundleMat) -{ - m_categoryMaterials.append(bundleMat); -} - -bool BundleMaterialCategory::updateImportedState(const QStringList &importedMats) -{ - bool changed = false; - - for (BundleMaterial *mat : std::as_const(m_categoryMaterials)) - changed |= mat->setImported(importedMats.contains(mat->qml().chopped(4))); - - return changed; -} - -bool BundleMaterialCategory::filter(const QString &searchText) -{ - bool visible = false; - for (BundleMaterial *mat : std::as_const(m_categoryMaterials)) - visible |= mat->filter(searchText); - - if (visible != m_visible) { - m_visible = visible; - emit categoryVisibleChanged(); - return true; - } - - return false; -} - -QString BundleMaterialCategory::name() const -{ - return m_name; -} - -bool BundleMaterialCategory::visible() const -{ - return m_visible; -} - -bool BundleMaterialCategory::expanded() const -{ - return m_expanded; -} - -QList BundleMaterialCategory::categoryMaterials() const -{ - return m_categoryMaterials; -} - -} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h b/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h deleted file mode 100644 index 14f7ddf654e..00000000000 --- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** 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 - -namespace QmlDesigner { - -class BundleMaterial; - -class BundleMaterialCategory : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QString bundleCategoryName MEMBER m_name CONSTANT) - Q_PROPERTY(bool bundleCategoryVisible MEMBER m_visible NOTIFY categoryVisibleChanged) - Q_PROPERTY(bool bundleCategoryExpanded MEMBER m_expanded NOTIFY categoryExpandChanged) - Q_PROPERTY(QList bundleCategoryMaterials MEMBER m_categoryMaterials - NOTIFY bundleMaterialsModelChanged) - -public: - BundleMaterialCategory(QObject *parent, const QString &name); - - void addBundleMaterial(BundleMaterial *bundleMat); - bool updateImportedState(const QStringList &importedMats); - bool filter(const QString &searchText); - - QString name() const; - bool visible() const; - bool expanded() const; - QList categoryMaterials() const; - -signals: - void categoryVisibleChanged(); - void categoryExpandChanged(); - void bundleMaterialsModelChanged(); - -private: - QString m_name; - bool m_visible = true; - bool m_expanded = true; - - QList m_categoryMaterials; -}; - -} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp new file mode 100644 index 00000000000..b39bdbb1f94 --- /dev/null +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp @@ -0,0 +1,219 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "materialbrowsertexturesmodel.h" + +#include +#include +#include +#include +#include +#include +#include "utils/qtcassert.h" + +namespace QmlDesigner { + +MaterialBrowserTexturesModel::MaterialBrowserTexturesModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +MaterialBrowserTexturesModel::~MaterialBrowserTexturesModel() +{ +} + +int MaterialBrowserTexturesModel::rowCount(const QModelIndex &) const +{ + return m_textureList.count(); +} + +QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role) const +{ + QTC_ASSERT(index.isValid() && index.row() < m_textureList.count(), return {}); + QTC_ASSERT(roleNames().contains(role), return {}); + + QByteArray roleName = roleNames().value(role); + if (roleName == "textureSource") { + QString source = m_textureList.at(index.row()).variantProperty("source").value().toString(); + return QUrl::fromLocalFile(DocumentManager::currentResourcePath().path() + '/' + source); + } + + if (roleName == "textureVisible") + return isTextureVisible(index.row()); + + if (roleName == "hasDynamicProperties") + return !m_textureList.at(index.row()).dynamicProperties().isEmpty(); + + return {}; +} + +bool MaterialBrowserTexturesModel::isTextureVisible(int idx) const +{ + if (!isValidIndex(idx)) + return false; + + return m_searchText.isEmpty() || m_textureList.at(idx).variantProperty("objectName") + .value().toString().contains(m_searchText, Qt::CaseInsensitive); +} + +bool MaterialBrowserTexturesModel::isValidIndex(int idx) const +{ + return idx > -1 && idx < rowCount(); +} + + +QHash MaterialBrowserTexturesModel::roleNames() const +{ + static const QHash roles { + {Qt::UserRole + 1, "textureSource"}, + {Qt::UserRole + 2, "textureVisible"}, + {Qt::UserRole + 3, "hasDynamicProperties"} + }; + return roles; +} + +QList MaterialBrowserTexturesModel::textures() const +{ + return m_textureList; +} + +void MaterialBrowserTexturesModel::setSearchText(const QString &searchText) +{ + QString lowerSearchText = searchText.toLower(); + + if (m_searchText == lowerSearchText) + return; + + m_searchText = lowerSearchText; + + bool isEmpty = false; + + // if selected texture goes invisible, select nearest one + if (!isTextureVisible(m_selectedIndex)) { + int inc = 1; + int incCap = m_textureList.count(); + while (!isEmpty && inc < incCap) { + if (isTextureVisible(m_selectedIndex - inc)) { + selectTexture(m_selectedIndex - inc); + break; + } else if (isTextureVisible(m_selectedIndex + inc)) { + selectTexture(m_selectedIndex + inc); + break; + } + ++inc; + isEmpty = !isValidIndex(m_selectedIndex + inc) + && !isValidIndex(m_selectedIndex - inc); + } + if (!isTextureVisible(m_selectedIndex)) // handles the case of a single item + isEmpty = true; + } + + if (isEmpty != m_isEmpty) { + m_isEmpty = isEmpty; + emit isEmptyChanged(); + } + + resetModel(); +} + +void MaterialBrowserTexturesModel::setTextures(const QList &textures) +{ + m_textureList = textures; + m_textureIndexHash.clear(); + for (int i = 0; i < textures.size(); ++i) + m_textureIndexHash.insert(textures.at(i).internalId(), i); + + bool isEmpty = textures.size() == 0; + if (isEmpty != m_isEmpty) { + m_isEmpty = isEmpty; + emit isEmptyChanged(); + } + + updateSelectedTexture(); + resetModel(); +} + +void MaterialBrowserTexturesModel::removeTexture(const ModelNode &texture) +{ + if (!m_textureIndexHash.contains(texture.internalId())) + return; + + m_textureList.removeOne(texture); + int idx = m_textureIndexHash.value(texture.internalId()); + m_textureIndexHash.remove(texture.internalId()); + + // update index hash + for (int i = idx; i < rowCount(); ++i) + m_textureIndexHash.insert(m_textureList.at(i).internalId(), i); + + resetModel(); + + if (m_textureList.isEmpty()) { + m_isEmpty = true; + emit isEmptyChanged(); + } +} + +void MaterialBrowserTexturesModel::deleteSelectedTexture() +{ + deleteTexture(m_selectedIndex); +} + +void MaterialBrowserTexturesModel::updateSelectedTexture() +{ + selectTexture(m_selectedIndex, true); +} + +int MaterialBrowserTexturesModel::textureIndex(const ModelNode &texture) const +{ + if (m_textureIndexHash.contains(texture.internalId())) + return m_textureIndexHash.value(texture.internalId()); + + return -1; +} + +ModelNode MaterialBrowserTexturesModel::textureAt(int idx) const +{ + if (isValidIndex(idx)) + return m_textureList.at(idx); + + return {}; +} + +void MaterialBrowserTexturesModel::resetModel() +{ + beginResetModel(); + endResetModel(); +} + +void MaterialBrowserTexturesModel::selectTexture(int idx, bool force) +{ + if (m_textureList.size() == 0) { + m_selectedIndex = -1; + emit selectedIndexChanged(m_selectedIndex); + return; + } + + idx = std::max(0, std::min(idx, rowCount() - 1)); + + if (idx != m_selectedIndex || force) { + m_selectedIndex = idx; + emit selectedIndexChanged(idx); + } +} + +void MaterialBrowserTexturesModel::duplicateTexture(int idx) +{ + emit duplicateTextureTriggered(m_textureList.at(idx)); +} + +void MaterialBrowserTexturesModel::deleteTexture(int idx) +{ + if (isValidIndex(idx)) { + ModelNode node = m_textureList[idx]; + if (node.isValid()) + QmlObjectNode(node).destroy(); + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h new file mode 100644 index 00000000000..4b5d1bd55bf --- /dev/null +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h @@ -0,0 +1,63 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#include +#include + +namespace QmlDesigner { + +class MaterialBrowserTexturesModel : public QAbstractListModel +{ + Q_OBJECT + + Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) + Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged) + +public: + MaterialBrowserTexturesModel(QObject *parent = nullptr); + ~MaterialBrowserTexturesModel() override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; + + void setSearchText(const QString &searchText); + + QList textures() const; + void setTextures(const QList &textures); + void removeTexture(const ModelNode &texture); + void deleteSelectedTexture(); + void updateSelectedTexture(); + int textureIndex(const ModelNode &material) const; + ModelNode textureAt(int idx) const; + + void resetModel(); + + Q_INVOKABLE void selectTexture(int idx, bool force = false); + Q_INVOKABLE void duplicateTexture(int idx); + Q_INVOKABLE void deleteTexture(int idx); + +signals: + void isEmptyChanged(); + void materialSectionsChanged(); + void selectedIndexChanged(int idx); + void duplicateTextureTriggered(const QmlDesigner::ModelNode &material); + +private: + bool isTextureVisible(int idx) const; + bool isValidIndex(int idx) const; + + QString m_searchText; + QList m_textureList; + ModelNode m_copiedMaterial; + QHash m_textureIndexHash; // internalId -> index + + int m_selectedIndex = 0; + bool m_isEmpty = true; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 2a7b6833b3e..86d6c69b59f 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -4,11 +4,9 @@ #include "materialbrowserview.h" #include "bindingproperty.h" -#include "bundlematerial.h" -#include "bundleimporter.h" -#include "materialbrowsermodel.h" #include "materialbrowserwidget.h" -#include "materialbrowserbundlemodel.h" +#include "materialbrowsermodel.h" +#include "materialbrowsertexturesmodel.h" #include "nodeabstractproperty.h" #include "nodemetainfo.h" #include "qmlobjectnode.h" @@ -22,14 +20,6 @@ #include #include -#ifndef QMLDESIGNER_TEST -#include -#include -#include -#include -#include -#endif - #include #include #include @@ -149,48 +139,6 @@ WidgetInfo MaterialBrowserView::widgetInfo() } }); }); - - connect(m_widget, &MaterialBrowserWidget::bundleMaterialDragStarted, this, - [&] (QmlDesigner::BundleMaterial *bundleMat) { - m_draggedBundleMaterial = bundleMat; - }); - - MaterialBrowserBundleModel *matBrowserBundleModel = m_widget->materialBrowserBundleModel().data(); - - connect(matBrowserBundleModel, &MaterialBrowserBundleModel::applyToSelectedTriggered, this, - [&] (BundleMaterial *bundleMat, bool add) { - if (m_selectedModels.isEmpty()) - return; - - m_bundleMaterialTargets = m_selectedModels; - m_bundleMaterialAddToSelected = add; - - ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type()); - if (defaultMat.isValid()) - applyBundleMaterialToDropTarget(defaultMat); - else - m_widget->materialBrowserBundleModel()->addToProject(bundleMat); - }); - - connect(matBrowserBundleModel, &MaterialBrowserBundleModel::bundleMaterialImported, this, - [&] (const QmlDesigner::NodeMetaInfo &metaInfo) { - applyBundleMaterialToDropTarget({}, metaInfo); - updateBundleMaterialsImportedState(); - }); - - connect(matBrowserBundleModel, &MaterialBrowserBundleModel::bundleMaterialAboutToUnimport, this, - [&] (const QmlDesigner::TypeName &type) { - // delete instances of the bundle material that is about to be unimported - executeInTransaction("MaterialBrowserView::widgetInfo", [&] { - Utils::reverseForeach(m_widget->materialBrowserModel()->materials(), [&](const ModelNode &mat) { - if (mat.isValid() && mat.type() == type) - QmlObjectNode(mat).destroy(); - }); - }); - }); - - connect(matBrowserBundleModel, &MaterialBrowserBundleModel::bundleMaterialUnimported, this, - &MaterialBrowserView::updateBundleMaterialsImportedState); } return createWidgetInfo(m_widget.data(), @@ -200,77 +148,6 @@ WidgetInfo MaterialBrowserView::widgetInfo() tr("Material Browser")); } -void MaterialBrowserView::applyBundleMaterialToDropTarget(const ModelNode &bundleMat, - const NodeMetaInfo &metaInfo) -{ - if (!bundleMat.isValid() && !metaInfo.isValid()) - return; - - ModelNode matLib = materialLibraryNode(); - if (!matLib.isValid()) - return; - - executeInTransaction("MaterialBrowserView::applyBundleMaterialToDropTarget", [&] { - ModelNode newMatNode; - if (metaInfo.isValid()) { - newMatNode = createModelNode(metaInfo.typeName(), metaInfo.majorVersion(), - metaInfo.minorVersion()); - matLib.defaultNodeListProperty().reparentHere(newMatNode); - - static QRegularExpression rgx("([A-Z])([a-z]*)"); - QString newName = QString::fromLatin1(metaInfo.simplifiedTypeName()).replace(rgx, " \\1\\2").trimmed(); - if (newName.endsWith(" Material")) - newName.chop(9); // remove trailing " Material" - QString newId = model()->generateIdFromName(newName, "material"); - newMatNode.setIdWithRefactoring(newId); - - VariantProperty objNameProp = newMatNode.variantProperty("objectName"); - objNameProp.setValue(newName); - } else { - newMatNode = bundleMat; - } - - // TODO: unify this logic as it exist elsewhere also - auto expToList = [](const QString &exp) { - QString copy = exp; - copy = copy.remove("[").remove("]"); - - QStringList tmp = copy.split(',', Qt::SkipEmptyParts); - for (QString &str : tmp) - str = str.trimmed(); - - return tmp; - }; - - auto listToExp = [](QStringList &stringList) { - if (stringList.size() > 1) - return QString("[" + stringList.join(",") + "]"); - - if (stringList.size() == 1) - return stringList.first(); - - return QString(); - }; - - for (const ModelNode &target : std::as_const(m_bundleMaterialTargets)) { - if (target.isValid() && target.metaInfo().isQtQuick3DModel()) { - QmlObjectNode qmlObjNode(target); - if (m_bundleMaterialAddToSelected) { - QStringList matList = expToList(qmlObjNode.expression("materials")); - matList.append(newMatNode.id()); - QString updatedExp = listToExp(matList); - qmlObjNode.setBindingProperty("materials", updatedExp); - } else { - qmlObjNode.setBindingProperty("materials", newMatNode.id()); - } - } - - m_bundleMaterialTargets = {}; - m_bundleMaterialAddToSelected = false; - } - }); -} - void MaterialBrowserView::modelAttached(Model *model) { AbstractView::modelAttached(model); @@ -280,9 +157,6 @@ void MaterialBrowserView::modelAttached(Model *model) rootModelNode().metaInfo().isQtQuick3DMaterial()); m_hasQuick3DImport = model->hasImport("QtQuick3D"); - updateBundleMaterialsQuick3DVersion(); - updateBundleMaterialsImportedState(); - // 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, model, [this]() { @@ -297,18 +171,22 @@ void MaterialBrowserView::refreshModel(bool updateImages) return; ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID); - QList materials; + QList materials; + QList textures; if (m_hasQuick3DImport && matLib.isValid()) { const QList matLibNodes = matLib.directSubModelNodes(); for (const ModelNode &node : matLibNodes) { if (isMaterial(node)) materials.append(node); + else if (isTexture(node)) + textures.append(node); } } m_widget->clearSearchFilter(); m_widget->materialBrowserModel()->setMaterials(materials, m_hasQuick3DImport); + m_widget->materialBrowserTexturesModel()->setTextures(textures); if (updateImages) { for (const ModelNode &node : std::as_const(materials)) @@ -323,6 +201,14 @@ bool MaterialBrowserView::isMaterial(const ModelNode &node) const return node.metaInfo().isQtQuick3DMaterial(); } +bool MaterialBrowserView::isTexture(const ModelNode &node) const +{ + if (!node.isValid()) + return false; + + return node.metaInfo().isQtQuick3DTexture(); +} + void MaterialBrowserView::modelAboutToBeDetached(Model *model) { m_widget->materialBrowserModel()->setMaterials({}, m_hasQuick3DImport); @@ -388,7 +274,9 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &oldPropertyParent, [[maybe_unused]] PropertyChangeFlags propertyChange) { - if (!isMaterial(node)) + Q_UNUSED(propertyChange) + + if (!isMaterial(node) && !isTexture(node)) return; ModelNode newParentNode = newPropertyParent.parentModelNode(); @@ -445,82 +333,6 @@ void QmlDesigner::MaterialBrowserView::loadPropertyGroups() m_propertyGroupsLoaded = m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath); } -void MaterialBrowserView::updateBundleMaterialsImportedState() -{ - using namespace Utils; - - if (!m_widget->materialBrowserBundleModel()->bundleImporter()) - return; - - QStringList importedBundleMats; - - FilePath materialBundlePath = m_widget->materialBrowserBundleModel()->bundleImporter()->resolveBundleImportPath(); - - if (materialBundlePath.exists()) { - importedBundleMats = transform(materialBundlePath.dirEntries({{"*.qml"}, QDir::Files}), - [](const FilePath &f) { return f.fileName().chopped(4); }); - } - - m_widget->materialBrowserBundleModel()->updateImportedState(importedBundleMats); -} - -void MaterialBrowserView::updateBundleMaterialsQuick3DVersion() -{ - bool hasImport = false; - int major = -1; - int minor = -1; - const QString url {"QtQuick3D"}; - const auto imports = model()->imports(); - for (const auto &import : imports) { - if (import.url() == url) { - hasImport = true; - const int importMajor = import.majorVersion(); - if (major < importMajor) { - minor = -1; - major = importMajor; - } - if (major == importMajor) - minor = qMax(minor, import.minorVersion()); - } - } -#ifndef QMLDESIGNER_TEST - if (hasImport && major == -1) { - // Import without specifying version, so we take the kit version - auto target = ProjectExplorer::SessionManager::startupTarget(); - if (target) { - QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); - if (qtVersion) { - major = qtVersion->qtVersion().majorVersion(); - minor = qtVersion->qtVersion().minorVersion(); - } - } - } -#endif - m_widget->materialBrowserBundleModel()->setQuick3DImportVersion(major, minor); -} - -ModelNode MaterialBrowserView::getBundleMaterialDefaultInstance(const TypeName &type) -{ - const QList materials = m_widget->materialBrowserModel()->materials(); - for (const ModelNode &mat : materials) { - if (mat.type() == type) { - bool isDefault = true; - const QList props = mat.properties(); - for (const AbstractProperty &prop : props) { - if (prop.name() != "objectName") { - isDefault = false; - break; - } - } - - if (isDefault) - return mat; - } - } - - return {}; -} - void MaterialBrowserView::requestPreviews() { if (model() && model()->nodeInstanceView()) { @@ -535,8 +347,6 @@ void MaterialBrowserView::importsChanged([[maybe_unused]] const QList &a { bool hasQuick3DImport = model()->hasImport("QtQuick3D"); - updateBundleMaterialsQuick3DVersion(); - if (hasQuick3DImport == m_hasQuick3DImport) return; @@ -566,16 +376,6 @@ void MaterialBrowserView::customNotification(const AbstractView *view, }); } else if (identifier == "delete_selected_material") { m_widget->materialBrowserModel()->deleteSelectedMaterial(); - } else if (identifier == "drop_bundle_material") { - m_bundleMaterialTargets = nodeList; - - ModelNode defaultMat = getBundleMaterialDefaultInstance(m_draggedBundleMaterial->type()); - if (defaultMat.isValid()) - applyBundleMaterialToDropTarget(defaultMat); - else - m_widget->materialBrowserBundleModel()->addToProject(m_draggedBundleMaterial); - - m_draggedBundleMaterial = nullptr; } } diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h index a8bcf5f2f1f..f59cb2dbbcd 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h @@ -4,7 +4,6 @@ #pragma once #include "abstractview.h" -#include "nodemetainfo.h" #include #include @@ -12,7 +11,6 @@ namespace QmlDesigner { -class BundleMaterial; class MaterialBrowserWidget; class MaterialBrowserView : public AbstractView @@ -48,19 +46,13 @@ public: private: void refreshModel(bool updateImages); bool isMaterial(const ModelNode &node) const; + bool isTexture(const ModelNode &node) const; void loadPropertyGroups(); - void updateBundleMaterialsImportedState(); - void updateBundleMaterialsQuick3DVersion(); - void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const NodeMetaInfo &metaInfo = {}); - ModelNode getBundleMaterialDefaultInstance(const TypeName &type); void requestPreviews(); QPointer m_widget; - QList m_bundleMaterialTargets; QList m_selectedModels; // selected 3D model nodes - BundleMaterial *m_draggedBundleMaterial = nullptr; - bool m_bundleMaterialAddToSelected = false; bool m_hasQuick3DImport = false; bool m_autoSelectModelMaterial = false; // TODO: wire this to some action bool m_puppetResetPending = false; diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp index 4a513d380f3..f51dd57b804 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp @@ -3,9 +3,8 @@ #include "materialbrowserwidget.h" -#include "bundlematerial.h" -#include "materialbrowserbundlemodel.h" #include "materialbrowsermodel.h" +#include "materialbrowsertexturesmodel.h" #include "materialbrowserview.h" #include @@ -30,10 +29,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -108,34 +107,9 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event) QString::number(m_materialToDrag.internalId()), nullptr, {128, 128})); m_materialToDrag = {}; } - } else if (m_bundleMaterialToDrag != nullptr) { - QMouseEvent *me = static_cast(event); - if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20) { - QByteArray data; - QMimeData *mimeData = new QMimeData; - QDataStream stream(&data, QIODevice::WriteOnly); - stream << m_bundleMaterialToDrag->type(); - mimeData->setData(Constants::MIME_TYPE_BUNDLE_MATERIAL, data); - mimeData->removeFormat("text/plain"); - - if (!m_draggedBundleMaterial) { - m_draggedBundleMaterial = m_bundleMaterialToDrag; - emit draggedBundleMaterialChanged(); - } - - emit bundleMaterialDragStarted(m_bundleMaterialToDrag); - model->startDrag(mimeData, m_bundleMaterialToDrag->icon().toLocalFile()); - m_bundleMaterialToDrag = nullptr; - } } } else if (event->type() == QMouseEvent::MouseButtonRelease) { m_materialToDrag = {}; - m_bundleMaterialToDrag = nullptr; - - if (m_draggedBundleMaterial) { - m_draggedBundleMaterial = nullptr; - emit draggedBundleMaterialChanged(); - } } return QObject::eventFilter(obj, event); @@ -144,7 +118,7 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event) MaterialBrowserWidget::MaterialBrowserWidget(MaterialBrowserView *view) : m_materialBrowserView(view) , m_materialBrowserModel(new MaterialBrowserModel(this)) - , m_materialBrowserBundleModel(new MaterialBrowserBundleModel(this)) + , m_materialBrowserTexturesModel(new MaterialBrowserTexturesModel(this)) , m_quickWidget(new QQuickWidget(this)) , m_previewImageProvider(new PreviewImageProvider()) { @@ -163,7 +137,7 @@ MaterialBrowserWidget::MaterialBrowserWidget(MaterialBrowserView *view) m_quickWidget->rootContext()->setContextProperties({ {"rootView", QVariant::fromValue(this)}, {"materialBrowserModel", QVariant::fromValue(m_materialBrowserModel.data())}, - {"materialBrowserBundleModel", QVariant::fromValue(m_materialBrowserBundleModel.data())}, + {"materialBrowserTexturesModel", QVariant::fromValue(m_materialBrowserTexturesModel.data())}, }); m_quickWidget->engine()->addImageProvider("materialBrowser", m_previewImageProvider); @@ -223,10 +197,9 @@ void MaterialBrowserWidget::startDragMaterial(int index, const QPointF &mousePos m_dragStartPoint = mousePos.toPoint(); } -void MaterialBrowserWidget::startDragBundleMaterial(QmlDesigner::BundleMaterial *bundleMat, const QPointF &mousePos) +void MaterialBrowserWidget::acceptBundleMaterialDrop() { - m_bundleMaterialToDrag = bundleMat; - m_dragStartPoint = mousePos.toPoint(); + m_materialBrowserView->emitCustomNotification("drop_bundle_material", {}, {}); // To ContentLibraryView } QString MaterialBrowserWidget::qmlSourcesPath() @@ -256,7 +229,6 @@ void MaterialBrowserWidget::reloadQmlSource() void MaterialBrowserWidget::updateSearch() { m_materialBrowserModel->setSearchText(m_filterText); - m_materialBrowserBundleModel->setSearchText(m_filterText); m_quickWidget->update(); } @@ -270,10 +242,9 @@ QPointer MaterialBrowserWidget::materialBrowserModel() con return m_materialBrowserModel; } -QPointer MaterialBrowserWidget::materialBrowserBundleModel() const +QPointer MaterialBrowserWidget::materialBrowserTexturesModel() const { - return m_materialBrowserBundleModel; + return m_materialBrowserTexturesModel; } - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h index 42739d83c42..af5909b546b 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h @@ -11,32 +11,27 @@ #include #include -#include -#include #include -#include -#include -#include #include QT_BEGIN_NAMESPACE -class QStackedWidget; +class QQuickWidget; +class QPointF; class QShortcut; +class QToolButton; QT_END_NAMESPACE namespace QmlDesigner { -class BundleMaterial; class MaterialBrowserView; class MaterialBrowserModel; -class MaterialBrowserBundleModel; +class MaterialBrowserTexturesModel; class PreviewImageProvider; class MaterialBrowserWidget : public QFrame { Q_OBJECT - Q_PROPERTY(BundleMaterial *draggedBundleMaterial MEMBER m_draggedBundleMaterial NOTIFY draggedBundleMaterialChanged) public: MaterialBrowserWidget(MaterialBrowserView *view); @@ -49,19 +44,15 @@ public: void clearSearchFilter(); QPointer materialBrowserModel() const; - QPointer materialBrowserBundleModel() const; + QPointer materialBrowserTexturesModel() const; void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap); Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText); Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos); - Q_INVOKABLE void startDragBundleMaterial(QmlDesigner::BundleMaterial *bundleMat, const QPointF &mousePos); + Q_INVOKABLE void acceptBundleMaterialDrop(); QQuickWidget *quickWidget() const; -signals: - void bundleMaterialDragStarted(QmlDesigner::BundleMaterial *bundleMat); - void draggedBundleMaterialChanged(); - protected: bool eventFilter(QObject *obj, QEvent *event) override; @@ -71,7 +62,7 @@ private: QPointer m_materialBrowserView; QPointer m_materialBrowserModel; - QPointer m_materialBrowserBundleModel; + QPointer m_materialBrowserTexturesModel; QScopedPointer m_quickWidget; QShortcut *m_qmlSourceUpdateShortcut = nullptr; @@ -81,8 +72,6 @@ private: QString m_filterText; ModelNode m_materialToDrag; - BundleMaterial *m_bundleMaterialToDrag = nullptr; - BundleMaterial *m_draggedBundleMaterial = nullptr; QPoint m_dragStartPoint; }; diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 12d496b2522..a407cf129b3 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -544,7 +544,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, } else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) { ModelNode targetNode(modelNodeForIndex(dropModelIndex)); if (targetNode.isValid()) - m_view->emitCustomNotification("drop_bundle_material", {targetNode}); // To MaterialBrowserView + m_view->emitCustomNotification("drop_bundle_material", {targetNode}); // To ContentLibraryView } else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) { const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(','); NodeAbstractProperty targetProperty; diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 9b5dac8aa9f..6a3a4e0de48 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -76,6 +76,7 @@ const char MIME_TYPE_ITEM_LIBRARY_INFO[] = "application/vnd.qtdesignstudio.iteml const char MIME_TYPE_ASSETS[] = "application/vnd.qtdesignstudio.assets"; const char MIME_TYPE_MATERIAL[] = "application/vnd.qtdesignstudio.material"; const char MIME_TYPE_BUNDLE_MATERIAL[] = "application/vnd.qtdesignstudio.bundlematerial"; +const char MIME_TYPE_BUNDLE_TEXTURE[] = "application/vnd.qtdesignstudio.bundletexture"; 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";