forked from qt-creator/qt-creator
QmlDesigner: Implement content library view
Fixes: QDS-8058 Fixes: QDS-8059 Change-Id: I1adfdc7ac15141e010467813ec6e673060269241 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -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("<b>Content Library</b> is disabled inside a material component.")
|
||||||
|
else if (!materialsModel.hasQuick3DImport)
|
||||||
|
qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,5 @@
|
|||||||
/****************************************************************************
|
// 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
|
||||||
** 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 QtQuick 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
@@ -45,8 +23,8 @@ Item {
|
|||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
|
||||||
onPressed: (mouse) => {
|
onPressed: (mouse) => {
|
||||||
if (mouse.button === Qt.LeftButton && !materialBrowserBundleModel.importerRunning)
|
if (mouse.button === Qt.LeftButton && !materialsModel.importerRunning)
|
||||||
rootView.startDragBundleMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
|
rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
|
||||||
else if (mouse.button === Qt.RightButton)
|
else if (mouse.button === Qt.RightButton)
|
||||||
root.showContextMenu()
|
root.showContextMenu()
|
||||||
}
|
}
|
||||||
@@ -102,10 +80,10 @@ Item {
|
|||||||
pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4)
|
pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4)
|
||||||
anchors.right: img.right
|
anchors.right: img.right
|
||||||
anchors.bottom: img.bottom
|
anchors.bottom: img.bottom
|
||||||
enabled: !materialBrowserBundleModel.importerRunning
|
enabled: !materialsModel.importerRunning
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
materialBrowserBundleModel.addToProject(modelData)
|
materialsModel.addToProject(modelData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,5 @@
|
|||||||
/****************************************************************************
|
// 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
|
||||||
** 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
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
@@ -69,7 +47,7 @@ Dialog {
|
|||||||
text: qsTr("Remove")
|
text: qsTr("Remove")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
materialBrowserBundleModel.removeFromProject(root.targetBundleMaterial)
|
materialsModel.removeFromProject(root.targetBundleMaterial)
|
||||||
root.accept()
|
root.accept()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,13 +19,12 @@ Item {
|
|||||||
function closeContextMenu()
|
function closeContextMenu()
|
||||||
{
|
{
|
||||||
ctxMenu.close()
|
ctxMenu.close()
|
||||||
ctxMenuBundle.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from C++ to refresh a preview material after it changes
|
// Called from C++ to refresh a preview material after it changes
|
||||||
function refreshPreview(idx)
|
function refreshPreview(idx)
|
||||||
{
|
{
|
||||||
var item = gridRepeater.itemAt(idx);
|
var item = materialRepeater.itemAt(idx);
|
||||||
if (item)
|
if (item)
|
||||||
item.refreshPreview();
|
item.refreshPreview();
|
||||||
}
|
}
|
||||||
@@ -44,12 +43,14 @@ Item {
|
|||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
|
|
||||||
onClicked: (mouse) => {
|
onClicked: (mouse) => {
|
||||||
// root context-menu works only for user materials
|
if (materialBrowserModel.hasMaterialRoot || !materialBrowserModel.hasQuick3DImport)
|
||||||
var userMatsSecBottom = mapFromItem(userMaterialsSection, 0, userMaterialsSection.y).y
|
return;
|
||||||
+ userMaterialsSection.height;
|
|
||||||
|
var matsSecBottom = mapFromItem(materialsSection, 0, materialsSection.y).y
|
||||||
|
+ materialsSection.height;
|
||||||
|
|
||||||
if (!materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport
|
if (!materialBrowserModel.hasMaterialRoot && materialBrowserModel.hasQuick3DImport
|
||||||
&& (!materialBrowserBundleModel.matBundleExists || mouse.y < userMatsSecBottom)) {
|
&& mouse.y < matsSecBottom) {
|
||||||
ctxMenu.popupMenu()
|
ctxMenu.popupMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,7 +64,7 @@ Item {
|
|||||||
if (root.currMaterialItem)
|
if (root.currMaterialItem)
|
||||||
root.currMaterialItem.commitRename();
|
root.currMaterialItem.commitRename();
|
||||||
|
|
||||||
root.currMaterialItem = gridRepeater.itemAt(materialBrowserModel.selectedIndex);
|
root.currMaterialItem = materialRepeater.itemAt(materialBrowserModel.selectedIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,19 +72,6 @@ Item {
|
|||||||
id: ctxMenu
|
id: ctxMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialBundleContextMenu {
|
|
||||||
id: ctxMenuBundle
|
|
||||||
|
|
||||||
onUnimport: (bundleMat) => {
|
|
||||||
unimportBundleMaterialDialog.targetBundleMaterial = bundleMat
|
|
||||||
unimportBundleMaterialDialog.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UnimportBundleMaterialDialog {
|
|
||||||
id: unimportBundleMaterialDialog
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: col
|
id: col
|
||||||
y: 5
|
y: 5
|
||||||
@@ -100,19 +88,6 @@ Item {
|
|||||||
|
|
||||||
onSearchChanged: (searchText) => {
|
onSearchChanged: (searchText) => {
|
||||||
rootView.handleSearchFilterChanged(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
|
height: root.height - searchBox.height
|
||||||
clip: true
|
clip: true
|
||||||
visible: materialBrowserModel.hasQuick3DImport && !materialBrowserModel.hasMaterialRoot
|
visible: materialBrowserModel.hasQuick3DImport && !materialBrowserModel.hasMaterialRoot
|
||||||
interactive: !ctxMenu.opened && !ctxMenuBundle.opened
|
interactive: !ctxMenu.opened
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Section {
|
Section {
|
||||||
id: userMaterialsSection
|
id: materialsSection
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
caption: qsTr("Materials")
|
caption: qsTr("Materials")
|
||||||
hideHeader: !materialBrowserBundleModel.matBundleExists
|
|
||||||
dropEnabled: true
|
dropEnabled: true
|
||||||
|
|
||||||
onDropEnter: (drag) => {
|
onDropEnter: (drag) => {
|
||||||
drag.accepted = rootView.draggedBundleMaterial
|
drag.accepted = drag.formats[0] === "application/vnd.qtdesignstudio.bundlematerial"
|
||||||
userMaterialsSection.highlight = rootView.draggedBundleMaterial
|
materialsSection.highlight = drag.accepted
|
||||||
}
|
}
|
||||||
|
|
||||||
onDropExit: {
|
onDropExit: {
|
||||||
userMaterialsSection.highlight = false
|
materialsSection.highlight = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onDrop: {
|
onDrop: {
|
||||||
userMaterialsSection.highlight = false
|
materialsSection.highlight = false
|
||||||
materialBrowserBundleModel.addToProject(rootView.draggedBundleMaterial)
|
rootView.acceptBundleMaterialDrop()
|
||||||
}
|
}
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
@@ -191,7 +165,7 @@ Item {
|
|||||||
columns: root.width / root.cellWidth
|
columns: root.width / root.cellWidth
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: gridRepeater
|
id: materialRepeater
|
||||||
|
|
||||||
model: materialBrowserModel
|
model: materialBrowserModel
|
||||||
delegate: MaterialItem {
|
delegate: MaterialItem {
|
||||||
@@ -226,62 +200,51 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
id: bundleMaterialsSection
|
id: texturesSection
|
||||||
|
|
||||||
width: root.width
|
width: root.width
|
||||||
caption: qsTr("Material Library")
|
caption: qsTr("Textures")
|
||||||
addTopPadding: noMatchText.visible
|
|
||||||
visible: materialBrowserBundleModel.matBundleExists
|
|
||||||
|
|
||||||
Column {
|
|
||||||
Repeater {
|
|
||||||
id: bundleMaterialsSectionRepeater
|
|
||||||
|
|
||||||
model: materialBrowserBundleModel
|
|
||||||
|
|
||||||
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 {
|
Grid {
|
||||||
width: scrollView.width
|
width: scrollView.width
|
||||||
leftPadding: 5
|
leftPadding: 5
|
||||||
rightPadding: 5
|
rightPadding: 5
|
||||||
bottomPadding: 5
|
bottomPadding: 5
|
||||||
|
spacing: 5
|
||||||
columns: root.width / root.cellWidth
|
columns: root.width / root.cellWidth
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: bundleCategoryMaterials
|
id: texturesRepeater
|
||||||
|
|
||||||
delegate: BundleMaterialItem {
|
model: materialBrowserTexturesModel
|
||||||
|
delegate: TextureItem {
|
||||||
width: root.cellWidth
|
width: root.cellWidth
|
||||||
height: root.cellHeight
|
height: root.cellWidth
|
||||||
|
|
||||||
onShowContextMenu: {
|
onShowContextMenu: {
|
||||||
ctxMenuBundle.popupMenu(modelData)
|
// ctxMenuTexture.popupMenu(this, model) // TODO: implement textures context menu
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: noMatchText
|
|
||||||
text: qsTr("No match found.");
|
text: qsTr("No match found.");
|
||||||
color: StudioTheme.Values.themeTextColor
|
color: StudioTheme.Values.themeTextColor
|
||||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
visible: materialBrowserBundleModel.isEmpty && !searchBox.isEmpty() && !materialBrowserModel.hasMaterialRoot
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,5 @@
|
|||||||
/****************************************************************************
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
**
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.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
|
import QtQuick
|
||||||
import HelperWidgets
|
import HelperWidgets
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ QtObject {
|
|||||||
property real mediumFont: 14
|
property real mediumFont: 14
|
||||||
property real bigFont: 16
|
property real bigFont: 16
|
||||||
property real baseIconFont: 12
|
property real baseIconFont: 12
|
||||||
|
property real mediumIconFont: 18
|
||||||
property real bigIconFont: 26
|
property real bigIconFont: 26
|
||||||
|
|
||||||
property real scaleFactor: 1.0
|
property real scaleFactor: 1.0
|
||||||
@@ -24,6 +25,7 @@ QtObject {
|
|||||||
property real bigFontSize: Math.round(values.bigFont * values.scaleFactor)
|
property real bigFontSize: Math.round(values.bigFont * values.scaleFactor)
|
||||||
property real baseIconFontSize: Math.round(values.baseIconFont * 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 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 bigIconFontSize: Math.round(values.bigIconFont * values.scaleFactor)
|
||||||
|
|
||||||
property real squareComponentWidth: values.height
|
property real squareComponentWidth: values.height
|
||||||
|
|||||||
@@ -912,6 +912,20 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
quick2propertyeditorview.cpp quick2propertyeditorview.h
|
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
|
extend_qtc_plugin(QmlDesigner
|
||||||
SOURCES_PREFIX components/materialeditor
|
SOURCES_PREFIX components/materialeditor
|
||||||
SOURCES
|
SOURCES
|
||||||
@@ -929,10 +943,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
materialbrowserview.cpp materialbrowserview.h
|
materialbrowserview.cpp materialbrowserview.h
|
||||||
materialbrowserwidget.cpp materialbrowserwidget.h
|
materialbrowserwidget.cpp materialbrowserwidget.h
|
||||||
materialbrowsermodel.cpp materialbrowsermodel.h
|
materialbrowsermodel.cpp materialbrowsermodel.h
|
||||||
bundleimporter.cpp bundleimporter.h
|
materialbrowsertexturesmodel.cpp materialbrowsertexturesmodel.h
|
||||||
materialbrowserbundlemodel.cpp materialbrowserbundlemodel.h
|
|
||||||
bundlematerial.cpp bundlematerial.h
|
|
||||||
bundlematerialcategory.cpp bundlematerialcategory.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ void AssetsLibraryWidget::addResources(const QStringList &files)
|
|||||||
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
|
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
|
||||||
if (operation) {
|
if (operation) {
|
||||||
AddFilesResult result = operation(fileNames,
|
AddFilesResult result = operation(fileNames,
|
||||||
document->fileName().parentDir().toString());
|
document->fileName().parentDir().toString(), true);
|
||||||
if (result == AddFilesResult::Failed) {
|
if (result == AddFilesResult::Failed) {
|
||||||
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
|
||||||
tr("Could not add %1 to project.")
|
tr("Could not add %1 to project.")
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ QHash<QString, QStringList> DesignerActionManager::handleExternalAssetsDrop(cons
|
|||||||
for (const QString &category : categories) {
|
for (const QString &category : categories) {
|
||||||
AddResourceOperation operation = categoryOperation.value(category);
|
AddResourceOperation operation = categoryOperation.value(category);
|
||||||
QStringList files = categoryFiles.value(category);
|
QStringList files = categoryFiles.value(category);
|
||||||
AddFilesResult result = operation(files, {});
|
AddFilesResult result = operation(files, {}, true);
|
||||||
if (result == AddFilesResult::Succeeded)
|
if (result == AddFilesResult::Succeeded)
|
||||||
addedCategoryFiles.insert(category, files);
|
addedCategoryFiles.insert(category, files);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,20 +24,20 @@ namespace QmlDesigner {
|
|||||||
|
|
||||||
class DesignerActionManagerView;
|
class DesignerActionManagerView;
|
||||||
|
|
||||||
using AddResourceOperation = std::function<AddFilesResult (const QStringList &, const QString &)>;
|
using AddResourceOperation = std::function<AddFilesResult(const QStringList &, const QString &, bool)>;
|
||||||
using ModelNodePreviewImageOperation = std::function<QVariant (const ModelNode &)>;
|
using ModelNodePreviewImageOperation = std::function<QVariant(const ModelNode &)>;
|
||||||
|
|
||||||
struct AddResourceHandler
|
struct AddResourceHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AddResourceHandler( const QString &_category,
|
AddResourceHandler(const QString &_category,
|
||||||
const QString &_filter,
|
const QString &_filter,
|
||||||
AddResourceOperation _operation,
|
AddResourceOperation _operation,
|
||||||
int _priority = 0)
|
int _priority = 0)
|
||||||
: category(_category)
|
: category(_category)
|
||||||
,filter(_filter)
|
, filter(_filter)
|
||||||
,operation(_operation)
|
, operation(_operation)
|
||||||
,piority(_priority)
|
, piority(_priority)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
if (directory.isEmpty())
|
||||||
return AddFilesResult::Cancelled;
|
return AddFilesResult::Cancelled;
|
||||||
|
|
||||||
@@ -1105,29 +1105,29 @@ static QString getAssetDefaultDirectory(const QString &assetDir, const QString &
|
|||||||
return adjustedDefaultDirectory;
|
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)
|
void createFlowActionArea(const SelectionContext &selectionContext)
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ void addItemToStackedContainer(const SelectionContext &selectionContext);
|
|||||||
void increaseIndexOfStackedContainer(const SelectionContext &selectionContext);
|
void increaseIndexOfStackedContainer(const SelectionContext &selectionContext);
|
||||||
void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext);
|
void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext);
|
||||||
void addTabBarToStackedContainer(const SelectionContext &selectionContext);
|
void addTabBarToStackedContainer(const SelectionContext &selectionContext);
|
||||||
QMLDESIGNERCORE_EXPORT AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory);
|
QMLDESIGNERCORE_EXPORT AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDir, bool showDialog = true);
|
||||||
AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory);
|
AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true);
|
||||||
AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory);
|
AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true);
|
||||||
AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory);
|
AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true);
|
||||||
AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &directory);
|
AddFilesResult addShaderToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true);
|
||||||
AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &directory);
|
AddFilesResult addVideoToProject(const QStringList &fileNames, const QString &directory, bool showDialog = true);
|
||||||
void createFlowActionArea(const SelectionContext &selectionContext);
|
void createFlowActionArea(const SelectionContext &selectionContext);
|
||||||
void addTransition(const SelectionContext &selectionState);
|
void addTransition(const SelectionContext &selectionState);
|
||||||
void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName);
|
void addFlowEffect(const SelectionContext &selectionState, const TypeName &typeName);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <assetslibraryview.h>
|
#include <assetslibraryview.h>
|
||||||
#include <capturingconnectionmanager.h>
|
#include <capturingconnectionmanager.h>
|
||||||
#include <componentaction.h>
|
#include <componentaction.h>
|
||||||
|
#include <contentlibraryview.h>
|
||||||
|
#include <componentaction.h>
|
||||||
#include <componentview.h>
|
#include <componentview.h>
|
||||||
#include <crumblebar.h>
|
#include <crumblebar.h>
|
||||||
#include <debugview.h>
|
#include <debugview.h>
|
||||||
@@ -56,6 +58,7 @@ public:
|
|||||||
? capturingConnectionManager
|
? capturingConnectionManager
|
||||||
: connectionManager,
|
: connectionManager,
|
||||||
externalDependencies)
|
externalDependencies)
|
||||||
|
, contentLibraryView{externalDependencies}
|
||||||
, componentView{externalDependencies}
|
, componentView{externalDependencies}
|
||||||
, edit3DView{externalDependencies}
|
, edit3DView{externalDependencies}
|
||||||
, formEditorView{externalDependencies}
|
, formEditorView{externalDependencies}
|
||||||
@@ -76,6 +79,7 @@ public:
|
|||||||
Internal::DebugView debugView;
|
Internal::DebugView debugView;
|
||||||
DesignerActionManagerView designerActionManagerView;
|
DesignerActionManagerView designerActionManagerView;
|
||||||
NodeInstanceView nodeInstanceView;
|
NodeInstanceView nodeInstanceView;
|
||||||
|
ContentLibraryView contentLibraryView;
|
||||||
ComponentView componentView;
|
ComponentView componentView;
|
||||||
Edit3DView edit3DView;
|
Edit3DView edit3DView;
|
||||||
FormEditorView formEditorView;
|
FormEditorView formEditorView;
|
||||||
@@ -212,6 +216,7 @@ QList<AbstractView *> ViewManager::standardViews() const
|
|||||||
&d->itemLibraryView,
|
&d->itemLibraryView,
|
||||||
&d->navigatorView,
|
&d->navigatorView,
|
||||||
&d->propertyEditorView,
|
&d->propertyEditorView,
|
||||||
|
&d->contentLibraryView,
|
||||||
&d->materialEditorView,
|
&d->materialEditorView,
|
||||||
&d->materialBrowserView,
|
&d->materialBrowserView,
|
||||||
&d->statesEditorView,
|
&d->statesEditorView,
|
||||||
@@ -392,6 +397,7 @@ QList<WidgetInfo> ViewManager::widgetInfos() const
|
|||||||
widgetInfoList.append(d->itemLibraryView.widgetInfo());
|
widgetInfoList.append(d->itemLibraryView.widgetInfo());
|
||||||
widgetInfoList.append(d->navigatorView.widgetInfo());
|
widgetInfoList.append(d->navigatorView.widgetInfo());
|
||||||
widgetInfoList.append(d->propertyEditorView.widgetInfo());
|
widgetInfoList.append(d->propertyEditorView.widgetInfo());
|
||||||
|
widgetInfoList.append(d->contentLibraryView.widgetInfo());
|
||||||
widgetInfoList.append(d->materialEditorView.widgetInfo());
|
widgetInfoList.append(d->materialEditorView.widgetInfo());
|
||||||
widgetInfoList.append(d->materialBrowserView.widgetInfo());
|
widgetInfoList.append(d->materialBrowserView.widgetInfo());
|
||||||
if (useOldStatesEditor())
|
if (useOldStatesEditor())
|
||||||
|
|||||||
@@ -1,29 +1,7 @@
|
|||||||
/****************************************************************************
|
// 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
|
||||||
** 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 "bundleimporter.h"
|
#include "contentlibrarybundleimporter.h"
|
||||||
|
|
||||||
#include "documentmanager.h"
|
#include "documentmanager.h"
|
||||||
#include "import.h"
|
#include "import.h"
|
||||||
@@ -43,7 +21,7 @@ using namespace Utils;
|
|||||||
|
|
||||||
namespace QmlDesigner::Internal {
|
namespace QmlDesigner::Internal {
|
||||||
|
|
||||||
BundleImporter::BundleImporter(const QString &bundleDir,
|
ContentLibraryBundleImporter::ContentLibraryBundleImporter(const QString &bundleDir,
|
||||||
const QString &bundleId,
|
const QString &bundleId,
|
||||||
const QStringList &sharedFiles,
|
const QStringList &sharedFiles,
|
||||||
QObject *parent)
|
QObject *parent)
|
||||||
@@ -53,7 +31,7 @@ BundleImporter::BundleImporter(const QString &bundleDir,
|
|||||||
, m_sharedFiles(sharedFiles)
|
, m_sharedFiles(sharedFiles)
|
||||||
{
|
{
|
||||||
m_importTimer.setInterval(200);
|
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(
|
m_moduleName = QStringLiteral("%1.%2").arg(
|
||||||
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER),
|
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER),
|
||||||
m_bundleId).mid(1); // Chop leading slash
|
m_bundleId).mid(1); // Chop leading slash
|
||||||
@@ -63,7 +41,7 @@ BundleImporter::BundleImporter(const QString &bundleDir,
|
|||||||
// Note that there is also an asynchronous portion to the import, which will only
|
// 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
|
// be done if this method returns success. Once the asynchronous portion of the
|
||||||
// import is completed, importFinished signal will be emitted.
|
// import is completed, importFinished signal will be emitted.
|
||||||
QString BundleImporter::importComponent(const QString &qmlFile,
|
QString ContentLibraryBundleImporter::importComponent(const QString &qmlFile,
|
||||||
const QStringList &files)
|
const QStringList &files)
|
||||||
{
|
{
|
||||||
FilePath bundleImportPath = resolveBundleImportPath();
|
FilePath bundleImportPath = resolveBundleImportPath();
|
||||||
@@ -171,7 +149,7 @@ QString BundleImporter::importComponent(const QString &qmlFile,
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void BundleImporter::handleImportTimer()
|
void ContentLibraryBundleImporter::handleImportTimer()
|
||||||
{
|
{
|
||||||
auto handleFailure = [this]() {
|
auto handleFailure = [this]() {
|
||||||
m_importTimer.stop();
|
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));
|
FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE));
|
||||||
const std::optional<QByteArray> content = assetRefPath.fileContents();
|
const std::optional<QByteArray> content = assetRefPath.fileContents();
|
||||||
@@ -260,7 +238,7 @@ QVariantHash BundleImporter::loadAssetRefMap(const Utils::FilePath &bundlePath)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void BundleImporter::writeAssetRefMap(const Utils::FilePath &bundlePath,
|
void ContentLibraryBundleImporter::writeAssetRefMap(const Utils::FilePath &bundlePath,
|
||||||
const QVariantHash &assetRefMap)
|
const QVariantHash &assetRefMap)
|
||||||
{
|
{
|
||||||
FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE));
|
FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE));
|
||||||
@@ -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();
|
FilePath bundleImportPath = resolveBundleImportPath();
|
||||||
if (bundleImportPath.isEmpty())
|
if (bundleImportPath.isEmpty())
|
||||||
@@ -358,7 +336,7 @@ QString BundleImporter::unimportComponent(const QString &qmlFile)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath BundleImporter::resolveBundleImportPath()
|
FilePath ContentLibraryBundleImporter::resolveBundleImportPath()
|
||||||
{
|
{
|
||||||
FilePath bundleImportPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
|
FilePath bundleImportPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
|
||||||
if (bundleImportPath.isEmpty())
|
if (bundleImportPath.isEmpty())
|
||||||
@@ -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 <utils/filepath.h>
|
||||||
|
|
||||||
|
#include "nodemetainfo.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QVariantHash>
|
||||||
|
|
||||||
|
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<QString, bool> m_pendingTypes; // <type, isImport>
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner::Internal
|
||||||
@@ -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
|
||||||
@@ -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 <QDataStream>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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<ContentLibraryMaterial *> ContentLibraryMaterialsCategory::categoryMaterials() const
|
||||||
|
{
|
||||||
|
return m_categoryMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -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 <QObject>
|
||||||
|
|
||||||
|
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<ContentLibraryMaterial *> 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<ContentLibraryMaterial *> categoryMaterials() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void categoryVisibleChanged();
|
||||||
|
void categoryExpandChanged();
|
||||||
|
void bundleMaterialsModelChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
bool m_visible = true;
|
||||||
|
bool m_expanded = true;
|
||||||
|
|
||||||
|
QList<ContentLibraryMaterial *> m_categoryMaterials;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -1,33 +1,11 @@
|
|||||||
/****************************************************************************
|
// 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
|
||||||
** 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 "materialbrowserbundlemodel.h"
|
#include "contentlibrarymaterialsmodel.h"
|
||||||
|
|
||||||
#include "bundleimporter.h"
|
#include "contentlibrarybundleimporter.h"
|
||||||
#include "bundlematerial.h"
|
#include "contentlibrarymaterial.h"
|
||||||
#include "bundlematerialcategory.h"
|
#include "contentlibrarymaterialscategory.h"
|
||||||
#include "qmldesignerconstants.h"
|
#include "qmldesignerconstants.h"
|
||||||
#include "utils/qtcassert.h"
|
#include "utils/qtcassert.h"
|
||||||
|
|
||||||
@@ -38,18 +16,18 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
MaterialBrowserBundleModel::MaterialBrowserBundleModel(QObject *parent)
|
ContentLibraryMaterialsModel::ContentLibraryMaterialsModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
loadMaterialBundle();
|
loadMaterialBundle();
|
||||||
}
|
}
|
||||||
|
|
||||||
int MaterialBrowserBundleModel::rowCount(const QModelIndex &) const
|
int ContentLibraryMaterialsModel::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return m_bundleCategories.size();
|
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(index.isValid() && index.row() < m_bundleCategories.count(), return {});
|
||||||
QTC_ASSERT(roleNames().contains(role), 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));
|
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))
|
if (!index.isValid() || !roleNames().contains(role))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QByteArray roleName = roleNames().value(role);
|
QByteArray roleName = roleNames().value(role);
|
||||||
BundleMaterialCategory *bundleCategory = m_bundleCategories.at(index.row());
|
ContentLibraryMaterialsCategory *bundleCategory = m_bundleCategories.at(index.row());
|
||||||
QVariant currValue = bundleCategory->property(roleName);
|
QVariant currValue = bundleCategory->property(roleName);
|
||||||
|
|
||||||
if (currValue != value) {
|
if (currValue != value) {
|
||||||
@@ -76,12 +54,12 @@ bool MaterialBrowserBundleModel::setData(const QModelIndex &index, const QVarian
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MaterialBrowserBundleModel::isValidIndex(int idx) const
|
bool ContentLibraryMaterialsModel::isValidIndex(int idx) const
|
||||||
{
|
{
|
||||||
return idx > -1 && idx < rowCount();
|
return idx > -1 && idx < rowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> MaterialBrowserBundleModel::roleNames() const
|
QHash<int, QByteArray> ContentLibraryMaterialsModel::roleNames() const
|
||||||
{
|
{
|
||||||
static const QHash<int, QByteArray> roles {
|
static const QHash<int, QByteArray> roles {
|
||||||
{Qt::UserRole + 1, "bundleCategoryName"},
|
{Qt::UserRole + 1, "bundleCategoryName"},
|
||||||
@@ -92,7 +70,7 @@ QHash<int, QByteArray> MaterialBrowserBundleModel::roleNames() const
|
|||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::loadMaterialBundle()
|
void ContentLibraryMaterialsModel::loadMaterialBundle()
|
||||||
{
|
{
|
||||||
if (m_matBundleLoaded || m_probeMatBundleDir)
|
if (m_matBundleLoaded || m_probeMatBundleDir)
|
||||||
return;
|
return;
|
||||||
@@ -137,7 +115,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
|
|||||||
const QJsonObject catsObj = m_matBundleObj.value("categories").toObject();
|
const QJsonObject catsObj = m_matBundleObj.value("categories").toObject();
|
||||||
const QStringList categories = catsObj.keys();
|
const QStringList categories = catsObj.keys();
|
||||||
for (const QString &cat : categories) {
|
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 QJsonObject matsObj = catsObj.value(cat).toObject();
|
||||||
const QStringList mats = matsObj.keys();
|
const QStringList mats = matsObj.keys();
|
||||||
@@ -156,7 +134,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
|
|||||||
bundleId,
|
bundleId,
|
||||||
qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
|
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);
|
category->addBundleMaterial(bundleMat);
|
||||||
}
|
}
|
||||||
@@ -168,15 +146,17 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
|
|||||||
for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
|
for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
|
||||||
sharedFiles.append(file.toString());
|
sharedFiles.append(file.toString());
|
||||||
|
|
||||||
m_importer = new Internal::BundleImporter(matBundleDir.path(), bundleId, sharedFiles);
|
m_importer = new Internal::ContentLibraryBundleImporter(matBundleDir.path(), bundleId, sharedFiles);
|
||||||
connect(m_importer, &Internal::BundleImporter::importFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
|
connect(m_importer, &Internal::ContentLibraryBundleImporter::importFinished, this,
|
||||||
|
[&](const QmlDesigner::NodeMetaInfo &metaInfo) {
|
||||||
m_importerRunning = false;
|
m_importerRunning = false;
|
||||||
emit importerRunningChanged();
|
emit importerRunningChanged();
|
||||||
if (metaInfo.isValid())
|
if (metaInfo.isValid())
|
||||||
emit bundleMaterialImported(metaInfo);
|
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)
|
Q_UNUSED(metaInfo)
|
||||||
m_importerRunning = false;
|
m_importerRunning = false;
|
||||||
emit importerRunningChanged();
|
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;
|
return m_hasMaterialRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::setHasMaterialRoot(bool b)
|
void ContentLibraryMaterialsModel::setHasMaterialRoot(bool b)
|
||||||
{
|
{
|
||||||
if (m_hasMaterialRoot == b)
|
if (m_hasMaterialRoot == b)
|
||||||
return;
|
return;
|
||||||
@@ -198,17 +192,17 @@ void MaterialBrowserBundleModel::setHasMaterialRoot(bool b)
|
|||||||
emit hasMaterialRootChanged();
|
emit hasMaterialRootChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MaterialBrowserBundleModel::matBundleExists() const
|
bool ContentLibraryMaterialsModel::matBundleExists() const
|
||||||
{
|
{
|
||||||
return m_matBundleLoaded && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;
|
return m_matBundleLoaded && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
Internal::BundleImporter *MaterialBrowserBundleModel::bundleImporter() const
|
Internal::ContentLibraryBundleImporter *ContentLibraryMaterialsModel::bundleImporter() const
|
||||||
{
|
{
|
||||||
return m_importer;
|
return m_importer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::setSearchText(const QString &searchText)
|
void ContentLibraryMaterialsModel::setSearchText(const QString &searchText)
|
||||||
{
|
{
|
||||||
QString lowerSearchText = searchText.toLower();
|
QString lowerSearchText = searchText.toLower();
|
||||||
|
|
||||||
@@ -220,7 +214,7 @@ void MaterialBrowserBundleModel::setSearchText(const QString &searchText)
|
|||||||
bool anyCatVisible = false;
|
bool anyCatVisible = false;
|
||||||
bool catVisibilityChanged = 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);
|
catVisibilityChanged |= cat->filter(m_searchText);
|
||||||
anyCatVisible |= cat->visible();
|
anyCatVisible |= cat->visible();
|
||||||
}
|
}
|
||||||
@@ -234,17 +228,17 @@ void MaterialBrowserBundleModel::setSearchText(const QString &searchText)
|
|||||||
resetModel();
|
resetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::updateImportedState(const QStringList &importedMats)
|
void ContentLibraryMaterialsModel::updateImportedState(const QStringList &importedMats)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
for (BundleMaterialCategory *cat : std::as_const(m_bundleCategories))
|
for (ContentLibraryMaterialsCategory *cat : std::as_const(m_bundleCategories))
|
||||||
changed |= cat->updateImportedState(importedMats);
|
changed |= cat->updateImportedState(importedMats);
|
||||||
|
|
||||||
if (changed)
|
if (changed)
|
||||||
resetModel();
|
resetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::setQuick3DImportVersion(int major, int minor)
|
void ContentLibraryMaterialsModel::setQuick3DImportVersion(int major, int minor)
|
||||||
{
|
{
|
||||||
bool bundleExisted = matBundleExists();
|
bool bundleExisted = matBundleExists();
|
||||||
|
|
||||||
@@ -255,18 +249,18 @@ void MaterialBrowserBundleModel::setQuick3DImportVersion(int major, int minor)
|
|||||||
emit matBundleExistsChanged();
|
emit matBundleExistsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::resetModel()
|
void ContentLibraryMaterialsModel::resetModel()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::applyToSelected(BundleMaterial *mat, bool add)
|
void ContentLibraryMaterialsModel::applyToSelected(ContentLibraryMaterial *mat, bool add)
|
||||||
{
|
{
|
||||||
emit applyToSelectedTriggered(mat, add);
|
emit applyToSelectedTriggered(mat, add);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserBundleModel::addToProject(BundleMaterial *mat)
|
void ContentLibraryMaterialsModel::addToProject(ContentLibraryMaterial *mat)
|
||||||
{
|
{
|
||||||
QString err = m_importer->importComponent(mat->qml(), mat->files());
|
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());
|
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
|
} // namespace QmlDesigner
|
||||||
@@ -1,58 +1,35 @@
|
|||||||
/****************************************************************************
|
// 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
|
||||||
** 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
|
#pragma once
|
||||||
|
|
||||||
#include <modelnode.h>
|
#include "nodemetainfo.h"
|
||||||
#include <qmlobjectnode.h>
|
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
|
||||||
#include <QPointer>
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class BundleMaterial;
|
class ContentLibraryMaterial;
|
||||||
class BundleMaterialCategory;
|
class ContentLibraryMaterialsCategory;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class BundleImporter;
|
class ContentLibraryBundleImporter;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MaterialBrowserBundleModel : public QAbstractListModel
|
class ContentLibraryMaterialsModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
|
Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
|
||||||
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
|
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 hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged)
|
||||||
Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged)
|
Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MaterialBrowserBundleModel(QObject *parent = nullptr);
|
ContentLibraryMaterialsModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
@@ -64,25 +41,32 @@ public:
|
|||||||
|
|
||||||
void setQuick3DImportVersion(int major, int minor);
|
void setQuick3DImportVersion(int major, int minor);
|
||||||
|
|
||||||
|
bool hasQuick3DImport() const;
|
||||||
|
void setHasQuick3DImport(bool b);
|
||||||
|
|
||||||
bool hasMaterialRoot() const;
|
bool hasMaterialRoot() const;
|
||||||
void setHasMaterialRoot(bool b);
|
void setHasMaterialRoot(bool b);
|
||||||
|
|
||||||
bool matBundleExists() const;
|
bool matBundleExists() const;
|
||||||
|
|
||||||
Internal::BundleImporter *bundleImporter() const;
|
bool hasModelSelection() const;
|
||||||
|
void setHasModelSelection(bool b);
|
||||||
|
|
||||||
void resetModel();
|
void resetModel();
|
||||||
|
|
||||||
Q_INVOKABLE void applyToSelected(QmlDesigner::BundleMaterial *mat, bool add = false);
|
Internal::ContentLibraryBundleImporter *bundleImporter() const;
|
||||||
Q_INVOKABLE void addToProject(QmlDesigner::BundleMaterial *mat);
|
|
||||||
Q_INVOKABLE void removeFromProject(QmlDesigner::BundleMaterial *mat);
|
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:
|
signals:
|
||||||
void isEmptyChanged();
|
void isEmptyChanged();
|
||||||
void hasQuick3DImportChanged();
|
void hasQuick3DImportChanged();
|
||||||
|
void hasModelSelectionChanged();
|
||||||
void hasMaterialRootChanged();
|
void hasMaterialRootChanged();
|
||||||
void materialVisibleChanged();
|
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 bundleMaterialImported(const QmlDesigner::NodeMetaInfo &metaInfo);
|
||||||
void bundleMaterialAboutToUnimport(const QmlDesigner::TypeName &type);
|
void bundleMaterialAboutToUnimport(const QmlDesigner::TypeName &type);
|
||||||
void bundleMaterialUnimported(const QmlDesigner::NodeMetaInfo &metaInfo);
|
void bundleMaterialUnimported(const QmlDesigner::NodeMetaInfo &metaInfo);
|
||||||
@@ -94,13 +78,15 @@ private:
|
|||||||
bool isValidIndex(int idx) const;
|
bool isValidIndex(int idx) const;
|
||||||
|
|
||||||
QString m_searchText;
|
QString m_searchText;
|
||||||
QList<BundleMaterialCategory *> m_bundleCategories;
|
QList<ContentLibraryMaterialsCategory *> m_bundleCategories;
|
||||||
QJsonObject m_matBundleObj;
|
QJsonObject m_matBundleObj;
|
||||||
Internal::BundleImporter *m_importer = nullptr;
|
Internal::ContentLibraryBundleImporter *m_importer = nullptr;
|
||||||
|
|
||||||
bool m_isEmpty = true;
|
bool m_isEmpty = true;
|
||||||
bool m_hasMaterialRoot = false;
|
bool m_hasMaterialRoot = false;
|
||||||
|
bool m_hasQuick3DImport = false;
|
||||||
bool m_matBundleLoaded = false;
|
bool m_matBundleLoaded = false;
|
||||||
|
bool m_hasModelSelection = false;
|
||||||
bool m_probeMatBundleDir = false;
|
bool m_probeMatBundleDir = false;
|
||||||
bool m_importerRunning = false;
|
bool m_importerRunning = false;
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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 <QObject>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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 <QFileInfo>
|
||||||
|
|
||||||
|
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<ContentLibraryTexture *> ContentLibraryTexturesCategory::categoryTextures() const
|
||||||
|
{
|
||||||
|
return m_categoryTextures;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -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 <QObject>
|
||||||
|
|
||||||
|
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<ContentLibraryTexture *> 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<ContentLibraryTexture *> categoryTextures() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void categoryVisibleChanged();
|
||||||
|
void categoryExpandChanged();
|
||||||
|
void bundleTexturesModelChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
bool m_visible = true;
|
||||||
|
bool m_expanded = true;
|
||||||
|
|
||||||
|
QList<ContentLibraryTexture *> m_categoryTextures;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -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 <QCoreApplication>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
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<int, QByteArray> ContentLibraryTexturesModel::roleNames() const
|
||||||
|
{
|
||||||
|
static const QHash<int, QByteArray> 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
|
||||||
@@ -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 <QAbstractListModel>
|
||||||
|
|
||||||
|
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<int, QByteArray> 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<ContentLibraryTexturesCategory *> 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
|
||||||
@@ -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 <coreplugin/messagebox.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
|
#ifndef QMLDESIGNER_TEST
|
||||||
|
#include <projectexplorer/kit.h>
|
||||||
|
#include <projectexplorer/session.h>
|
||||||
|
#include <projectexplorer/target.h>
|
||||||
|
#include <qtsupport/baseqtversion.h>
|
||||||
|
#include <qtsupport/qtkitinformation.h>
|
||||||
|
#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<Import> &addedImports, const QList<Import> &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<ModelNode> &selectedNodeList,
|
||||||
|
const QList<ModelNode> &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<ModelNode> &nodeList, const QList<QVariant> &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 <ModelNode> matLibNodes = matLib.directSubModelNodes();
|
||||||
|
for (const ModelNode &mat : matLibNodes) {
|
||||||
|
if (mat.isValid() && mat.type() == type) {
|
||||||
|
bool isDefault = true;
|
||||||
|
const QList<AbstractProperty> 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
|
||||||
@@ -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 <QObject>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
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<Import> &addedImports, const QList<Import> &removedImports) override;
|
||||||
|
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
|
||||||
|
const QList<ModelNode> &lastSelectedNodeList) override;
|
||||||
|
void customNotification(const AbstractView *view, const QString &identifier,
|
||||||
|
const QList<ModelNode> &nodeList, const QList<QVariant> &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<ContentLibraryWidget> m_widget;
|
||||||
|
QList<ModelNode> m_bundleMaterialTargets;
|
||||||
|
QList<ModelNode> m_selectedModels; // selected 3D model nodes
|
||||||
|
ContentLibraryMaterial *m_draggedBundleMaterial = nullptr;
|
||||||
|
bool m_bundleMaterialAddToSelected = false;
|
||||||
|
bool m_hasQuick3DImport = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -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 <coreplugin/icore.h>
|
||||||
|
#include <qmldesignerconstants.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
|
||||||
|
#include <theme.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QQmlContext>
|
||||||
|
#include <QQuickWidget>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
#include <QQuickItem>
|
||||||
|
#include <QShortcut>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
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<QMouseEvent *>(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<QMouseEvent *>(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<QToolButton *> 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<ContentLibraryMaterialsModel> ContentLibraryWidget::materialsModel() const
|
||||||
|
{
|
||||||
|
return m_materialsModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -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 <QFrame>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
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<QToolButton *> createToolBarWidgets();
|
||||||
|
|
||||||
|
static QString qmlSourcesPath();
|
||||||
|
void clearSearchFilter();
|
||||||
|
|
||||||
|
Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
|
||||||
|
|
||||||
|
void setMaterialsModel(QPointer<ContentLibraryMaterialsModel> newMaterialsModel);
|
||||||
|
|
||||||
|
QPointer<ContentLibraryMaterialsModel> 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<QQuickWidget> m_quickWidget;
|
||||||
|
QPointer<ContentLibraryMaterialsModel> m_materialsModel;
|
||||||
|
QPointer<ContentLibraryTexturesModel> m_texturesModel;
|
||||||
|
QPointer<ContentLibraryTexturesModel> 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
|
||||||
@@ -286,7 +286,7 @@ void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (m_nodeAtPosReqType == NodeAtPosReqType::BundleMaterialDrop) {
|
} else if (m_nodeAtPosReqType == NodeAtPosReqType::BundleMaterialDrop) {
|
||||||
emitCustomNotification("drop_bundle_material", {modelNode}); // To MaterialBrowserView
|
emitCustomNotification("drop_bundle_material", {modelNode}); // To ContentLibraryView
|
||||||
}
|
}
|
||||||
m_nodeAtPosReqType = NodeAtPosReqType::None;
|
m_nodeAtPosReqType = NodeAtPosReqType::None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,8 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap)
|
|||||||
m_importableExtensions3DMap = extMap;
|
m_importableExtensions3DMap = extMap;
|
||||||
|
|
||||||
AddResourceOperation import3DModelOperation = [this](const QStringList &fileNames,
|
AddResourceOperation import3DModelOperation = [this](const QStringList &fileNames,
|
||||||
const QString &defaultDir) -> AddFilesResult {
|
const QString &defaultDir,
|
||||||
|
bool showDialog) -> AddFilesResult {
|
||||||
auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir,
|
auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir,
|
||||||
m_importableExtensions3DMap,
|
m_importableExtensions3DMap,
|
||||||
m_importOptions3DMap, {}, {},
|
m_importOptions3DMap, {}, {},
|
||||||
|
|||||||
@@ -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 <utils/filepath.h>
|
|
||||||
|
|
||||||
#include "nodemetainfo.h"
|
|
||||||
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QVariantHash>
|
|
||||||
|
|
||||||
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<QString, bool> m_pendingTypes; // <type, isImport>
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner::Internal
|
|
||||||
@@ -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
|
|
||||||
@@ -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 <QDataStream>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -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<BundleMaterial *> BundleMaterialCategory::categoryMaterials() const
|
|
||||||
{
|
|
||||||
return m_categoryMaterials;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
||||||
@@ -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 <QObject>
|
|
||||||
|
|
||||||
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<BundleMaterial *> 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<BundleMaterial *> categoryMaterials() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void categoryVisibleChanged();
|
|
||||||
void categoryExpandChanged();
|
|
||||||
void bundleMaterialsModelChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_name;
|
|
||||||
bool m_visible = true;
|
|
||||||
bool m_expanded = true;
|
|
||||||
|
|
||||||
QList<BundleMaterial *> m_categoryMaterials;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
|
||||||
@@ -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 <bindingproperty.h>
|
||||||
|
#include <designmodewidget.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <qmlobjectnode.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
#include <qmltimelinekeyframegroup.h>
|
||||||
|
#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<int, QByteArray> MaterialBrowserTexturesModel::roleNames() const
|
||||||
|
{
|
||||||
|
static const QHash<int, QByteArray> roles {
|
||||||
|
{Qt::UserRole + 1, "textureSource"},
|
||||||
|
{Qt::UserRole + 2, "textureVisible"},
|
||||||
|
{Qt::UserRole + 3, "hasDynamicProperties"}
|
||||||
|
};
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ModelNode> 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<ModelNode> &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
|
||||||
@@ -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 <modelnode.h>
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
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<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
void setSearchText(const QString &searchText);
|
||||||
|
|
||||||
|
QList<ModelNode> textures() const;
|
||||||
|
void setTextures(const QList<ModelNode> &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<ModelNode> m_textureList;
|
||||||
|
ModelNode m_copiedMaterial;
|
||||||
|
QHash<qint32, int> m_textureIndexHash; // internalId -> index
|
||||||
|
|
||||||
|
int m_selectedIndex = 0;
|
||||||
|
bool m_isEmpty = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -4,11 +4,9 @@
|
|||||||
#include "materialbrowserview.h"
|
#include "materialbrowserview.h"
|
||||||
|
|
||||||
#include "bindingproperty.h"
|
#include "bindingproperty.h"
|
||||||
#include "bundlematerial.h"
|
|
||||||
#include "bundleimporter.h"
|
|
||||||
#include "materialbrowsermodel.h"
|
|
||||||
#include "materialbrowserwidget.h"
|
#include "materialbrowserwidget.h"
|
||||||
#include "materialbrowserbundlemodel.h"
|
#include "materialbrowsermodel.h"
|
||||||
|
#include "materialbrowsertexturesmodel.h"
|
||||||
#include "nodeabstractproperty.h"
|
#include "nodeabstractproperty.h"
|
||||||
#include "nodemetainfo.h"
|
#include "nodemetainfo.h"
|
||||||
#include "qmlobjectnode.h"
|
#include "qmlobjectnode.h"
|
||||||
@@ -22,14 +20,6 @@
|
|||||||
#include <qmldesignerconstants.h>
|
#include <qmldesignerconstants.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
#ifndef QMLDESIGNER_TEST
|
|
||||||
#include <projectexplorer/kit.h>
|
|
||||||
#include <projectexplorer/session.h>
|
|
||||||
#include <projectexplorer/target.h>
|
|
||||||
#include <qtsupport/baseqtversion.h>
|
|
||||||
#include <qtsupport/qtkitinformation.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@@ -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(),
|
return createWidgetInfo(m_widget.data(),
|
||||||
@@ -200,77 +148,6 @@ WidgetInfo MaterialBrowserView::widgetInfo()
|
|||||||
tr("Material Browser"));
|
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)
|
void MaterialBrowserView::modelAttached(Model *model)
|
||||||
{
|
{
|
||||||
AbstractView::modelAttached(model);
|
AbstractView::modelAttached(model);
|
||||||
@@ -280,9 +157,6 @@ void MaterialBrowserView::modelAttached(Model *model)
|
|||||||
rootModelNode().metaInfo().isQtQuick3DMaterial());
|
rootModelNode().metaInfo().isQtQuick3DMaterial());
|
||||||
m_hasQuick3DImport = model->hasImport("QtQuick3D");
|
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
|
// Project load is already very busy and may even trigger puppet reset, so let's wait a moment
|
||||||
// before refreshing the model
|
// before refreshing the model
|
||||||
QTimer::singleShot(1000, model, [this]() {
|
QTimer::singleShot(1000, model, [this]() {
|
||||||
@@ -297,18 +171,22 @@ void MaterialBrowserView::refreshModel(bool updateImages)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
|
ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
|
||||||
QList <ModelNode> materials;
|
QList<ModelNode> materials;
|
||||||
|
QList<ModelNode> textures;
|
||||||
|
|
||||||
if (m_hasQuick3DImport && matLib.isValid()) {
|
if (m_hasQuick3DImport && matLib.isValid()) {
|
||||||
const QList <ModelNode> matLibNodes = matLib.directSubModelNodes();
|
const QList <ModelNode> matLibNodes = matLib.directSubModelNodes();
|
||||||
for (const ModelNode &node : matLibNodes) {
|
for (const ModelNode &node : matLibNodes) {
|
||||||
if (isMaterial(node))
|
if (isMaterial(node))
|
||||||
materials.append(node);
|
materials.append(node);
|
||||||
|
else if (isTexture(node))
|
||||||
|
textures.append(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_widget->clearSearchFilter();
|
m_widget->clearSearchFilter();
|
||||||
m_widget->materialBrowserModel()->setMaterials(materials, m_hasQuick3DImport);
|
m_widget->materialBrowserModel()->setMaterials(materials, m_hasQuick3DImport);
|
||||||
|
m_widget->materialBrowserTexturesModel()->setTextures(textures);
|
||||||
|
|
||||||
if (updateImages) {
|
if (updateImages) {
|
||||||
for (const ModelNode &node : std::as_const(materials))
|
for (const ModelNode &node : std::as_const(materials))
|
||||||
@@ -323,6 +201,14 @@ bool MaterialBrowserView::isMaterial(const ModelNode &node) const
|
|||||||
return node.metaInfo().isQtQuick3DMaterial();
|
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)
|
void MaterialBrowserView::modelAboutToBeDetached(Model *model)
|
||||||
{
|
{
|
||||||
m_widget->materialBrowserModel()->setMaterials({}, m_hasQuick3DImport);
|
m_widget->materialBrowserModel()->setMaterials({}, m_hasQuick3DImport);
|
||||||
@@ -388,7 +274,9 @@ void MaterialBrowserView::nodeReparented(const ModelNode &node,
|
|||||||
const NodeAbstractProperty &oldPropertyParent,
|
const NodeAbstractProperty &oldPropertyParent,
|
||||||
[[maybe_unused]] PropertyChangeFlags propertyChange)
|
[[maybe_unused]] PropertyChangeFlags propertyChange)
|
||||||
{
|
{
|
||||||
if (!isMaterial(node))
|
Q_UNUSED(propertyChange)
|
||||||
|
|
||||||
|
if (!isMaterial(node) && !isTexture(node))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ModelNode newParentNode = newPropertyParent.parentModelNode();
|
ModelNode newParentNode = newPropertyParent.parentModelNode();
|
||||||
@@ -445,82 +333,6 @@ void QmlDesigner::MaterialBrowserView::loadPropertyGroups()
|
|||||||
m_propertyGroupsLoaded = m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath);
|
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<ModelNode> materials = m_widget->materialBrowserModel()->materials();
|
|
||||||
for (const ModelNode &mat : materials) {
|
|
||||||
if (mat.type() == type) {
|
|
||||||
bool isDefault = true;
|
|
||||||
const QList<AbstractProperty> props = mat.properties();
|
|
||||||
for (const AbstractProperty &prop : props) {
|
|
||||||
if (prop.name() != "objectName") {
|
|
||||||
isDefault = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefault)
|
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialBrowserView::requestPreviews()
|
void MaterialBrowserView::requestPreviews()
|
||||||
{
|
{
|
||||||
if (model() && model()->nodeInstanceView()) {
|
if (model() && model()->nodeInstanceView()) {
|
||||||
@@ -535,8 +347,6 @@ void MaterialBrowserView::importsChanged([[maybe_unused]] const QList<Import> &a
|
|||||||
{
|
{
|
||||||
bool hasQuick3DImport = model()->hasImport("QtQuick3D");
|
bool hasQuick3DImport = model()->hasImport("QtQuick3D");
|
||||||
|
|
||||||
updateBundleMaterialsQuick3DVersion();
|
|
||||||
|
|
||||||
if (hasQuick3DImport == m_hasQuick3DImport)
|
if (hasQuick3DImport == m_hasQuick3DImport)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -566,16 +376,6 @@ void MaterialBrowserView::customNotification(const AbstractView *view,
|
|||||||
});
|
});
|
||||||
} else if (identifier == "delete_selected_material") {
|
} else if (identifier == "delete_selected_material") {
|
||||||
m_widget->materialBrowserModel()->deleteSelectedMaterial();
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "abstractview.h"
|
#include "abstractview.h"
|
||||||
#include "nodemetainfo.h"
|
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@@ -12,7 +11,6 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class BundleMaterial;
|
|
||||||
class MaterialBrowserWidget;
|
class MaterialBrowserWidget;
|
||||||
|
|
||||||
class MaterialBrowserView : public AbstractView
|
class MaterialBrowserView : public AbstractView
|
||||||
@@ -48,19 +46,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
void refreshModel(bool updateImages);
|
void refreshModel(bool updateImages);
|
||||||
bool isMaterial(const ModelNode &node) const;
|
bool isMaterial(const ModelNode &node) const;
|
||||||
|
bool isTexture(const ModelNode &node) const;
|
||||||
void loadPropertyGroups();
|
void loadPropertyGroups();
|
||||||
void updateBundleMaterialsImportedState();
|
|
||||||
void updateBundleMaterialsQuick3DVersion();
|
|
||||||
void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const NodeMetaInfo &metaInfo = {});
|
|
||||||
ModelNode getBundleMaterialDefaultInstance(const TypeName &type);
|
|
||||||
void requestPreviews();
|
void requestPreviews();
|
||||||
|
|
||||||
QPointer<MaterialBrowserWidget> m_widget;
|
QPointer<MaterialBrowserWidget> m_widget;
|
||||||
QList<ModelNode> m_bundleMaterialTargets;
|
|
||||||
QList<ModelNode> m_selectedModels; // selected 3D model nodes
|
QList<ModelNode> m_selectedModels; // selected 3D model nodes
|
||||||
BundleMaterial *m_draggedBundleMaterial = nullptr;
|
|
||||||
|
|
||||||
bool m_bundleMaterialAddToSelected = false;
|
|
||||||
bool m_hasQuick3DImport = false;
|
bool m_hasQuick3DImport = false;
|
||||||
bool m_autoSelectModelMaterial = false; // TODO: wire this to some action
|
bool m_autoSelectModelMaterial = false; // TODO: wire this to some action
|
||||||
bool m_puppetResetPending = false;
|
bool m_puppetResetPending = false;
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
#include "materialbrowserwidget.h"
|
#include "materialbrowserwidget.h"
|
||||||
|
|
||||||
#include "bundlematerial.h"
|
|
||||||
#include "materialbrowserbundlemodel.h"
|
|
||||||
#include "materialbrowsermodel.h"
|
#include "materialbrowsermodel.h"
|
||||||
|
#include "materialbrowsertexturesmodel.h"
|
||||||
#include "materialbrowserview.h"
|
#include "materialbrowserview.h"
|
||||||
|
|
||||||
#include <designeractionmanager.h>
|
#include <designeractionmanager.h>
|
||||||
@@ -30,10 +29,10 @@
|
|||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
#include <QQuickImageProvider>
|
#include <QQuickImageProvider>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
|
#include <QQuickWidget>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QTabBar>
|
#include <QTabBar>
|
||||||
#include <QTimer>
|
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
@@ -108,34 +107,9 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event)
|
|||||||
QString::number(m_materialToDrag.internalId()), nullptr, {128, 128}));
|
QString::number(m_materialToDrag.internalId()), nullptr, {128, 128}));
|
||||||
m_materialToDrag = {};
|
m_materialToDrag = {};
|
||||||
}
|
}
|
||||||
} else if (m_bundleMaterialToDrag != nullptr) {
|
|
||||||
QMouseEvent *me = static_cast<QMouseEvent *>(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) {
|
} else if (event->type() == QMouseEvent::MouseButtonRelease) {
|
||||||
m_materialToDrag = {};
|
m_materialToDrag = {};
|
||||||
m_bundleMaterialToDrag = nullptr;
|
|
||||||
|
|
||||||
if (m_draggedBundleMaterial) {
|
|
||||||
m_draggedBundleMaterial = nullptr;
|
|
||||||
emit draggedBundleMaterialChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return QObject::eventFilter(obj, event);
|
return QObject::eventFilter(obj, event);
|
||||||
@@ -144,7 +118,7 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event)
|
|||||||
MaterialBrowserWidget::MaterialBrowserWidget(MaterialBrowserView *view)
|
MaterialBrowserWidget::MaterialBrowserWidget(MaterialBrowserView *view)
|
||||||
: m_materialBrowserView(view)
|
: m_materialBrowserView(view)
|
||||||
, m_materialBrowserModel(new MaterialBrowserModel(this))
|
, m_materialBrowserModel(new MaterialBrowserModel(this))
|
||||||
, m_materialBrowserBundleModel(new MaterialBrowserBundleModel(this))
|
, m_materialBrowserTexturesModel(new MaterialBrowserTexturesModel(this))
|
||||||
, m_quickWidget(new QQuickWidget(this))
|
, m_quickWidget(new QQuickWidget(this))
|
||||||
, m_previewImageProvider(new PreviewImageProvider())
|
, m_previewImageProvider(new PreviewImageProvider())
|
||||||
{
|
{
|
||||||
@@ -163,7 +137,7 @@ MaterialBrowserWidget::MaterialBrowserWidget(MaterialBrowserView *view)
|
|||||||
m_quickWidget->rootContext()->setContextProperties({
|
m_quickWidget->rootContext()->setContextProperties({
|
||||||
{"rootView", QVariant::fromValue(this)},
|
{"rootView", QVariant::fromValue(this)},
|
||||||
{"materialBrowserModel", QVariant::fromValue(m_materialBrowserModel.data())},
|
{"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);
|
m_quickWidget->engine()->addImageProvider("materialBrowser", m_previewImageProvider);
|
||||||
@@ -223,10 +197,9 @@ void MaterialBrowserWidget::startDragMaterial(int index, const QPointF &mousePos
|
|||||||
m_dragStartPoint = mousePos.toPoint();
|
m_dragStartPoint = mousePos.toPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialBrowserWidget::startDragBundleMaterial(QmlDesigner::BundleMaterial *bundleMat, const QPointF &mousePos)
|
void MaterialBrowserWidget::acceptBundleMaterialDrop()
|
||||||
{
|
{
|
||||||
m_bundleMaterialToDrag = bundleMat;
|
m_materialBrowserView->emitCustomNotification("drop_bundle_material", {}, {}); // To ContentLibraryView
|
||||||
m_dragStartPoint = mousePos.toPoint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MaterialBrowserWidget::qmlSourcesPath()
|
QString MaterialBrowserWidget::qmlSourcesPath()
|
||||||
@@ -256,7 +229,6 @@ void MaterialBrowserWidget::reloadQmlSource()
|
|||||||
void MaterialBrowserWidget::updateSearch()
|
void MaterialBrowserWidget::updateSearch()
|
||||||
{
|
{
|
||||||
m_materialBrowserModel->setSearchText(m_filterText);
|
m_materialBrowserModel->setSearchText(m_filterText);
|
||||||
m_materialBrowserBundleModel->setSearchText(m_filterText);
|
|
||||||
m_quickWidget->update();
|
m_quickWidget->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,10 +242,9 @@ QPointer<MaterialBrowserModel> MaterialBrowserWidget::materialBrowserModel() con
|
|||||||
return m_materialBrowserModel;
|
return m_materialBrowserModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointer<MaterialBrowserBundleModel> MaterialBrowserWidget::materialBrowserBundleModel() const
|
QPointer<MaterialBrowserTexturesModel> MaterialBrowserWidget::materialBrowserTexturesModel() const
|
||||||
{
|
{
|
||||||
return m_materialBrowserBundleModel;
|
return m_materialBrowserTexturesModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -11,32 +11,27 @@
|
|||||||
|
|
||||||
#include <QFileIconProvider>
|
#include <QFileIconProvider>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QPointF>
|
|
||||||
#include <QQmlPropertyMap>
|
#include <QQmlPropertyMap>
|
||||||
#include <QQuickWidget>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QToolButton>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QStackedWidget;
|
class QQuickWidget;
|
||||||
|
class QPointF;
|
||||||
class QShortcut;
|
class QShortcut;
|
||||||
|
class QToolButton;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class BundleMaterial;
|
|
||||||
class MaterialBrowserView;
|
class MaterialBrowserView;
|
||||||
class MaterialBrowserModel;
|
class MaterialBrowserModel;
|
||||||
class MaterialBrowserBundleModel;
|
class MaterialBrowserTexturesModel;
|
||||||
class PreviewImageProvider;
|
class PreviewImageProvider;
|
||||||
|
|
||||||
class MaterialBrowserWidget : public QFrame
|
class MaterialBrowserWidget : public QFrame
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(BundleMaterial *draggedBundleMaterial MEMBER m_draggedBundleMaterial NOTIFY draggedBundleMaterialChanged)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MaterialBrowserWidget(MaterialBrowserView *view);
|
MaterialBrowserWidget(MaterialBrowserView *view);
|
||||||
@@ -49,19 +44,15 @@ public:
|
|||||||
void clearSearchFilter();
|
void clearSearchFilter();
|
||||||
|
|
||||||
QPointer<MaterialBrowserModel> materialBrowserModel() const;
|
QPointer<MaterialBrowserModel> materialBrowserModel() const;
|
||||||
QPointer<MaterialBrowserBundleModel> materialBrowserBundleModel() const;
|
QPointer<MaterialBrowserTexturesModel> materialBrowserTexturesModel() const;
|
||||||
void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap);
|
void updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap);
|
||||||
|
|
||||||
Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
|
Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
|
||||||
Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos);
|
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;
|
QQuickWidget *quickWidget() const;
|
||||||
|
|
||||||
signals:
|
|
||||||
void bundleMaterialDragStarted(QmlDesigner::BundleMaterial *bundleMat);
|
|
||||||
void draggedBundleMaterialChanged();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
@@ -71,7 +62,7 @@ private:
|
|||||||
|
|
||||||
QPointer<MaterialBrowserView> m_materialBrowserView;
|
QPointer<MaterialBrowserView> m_materialBrowserView;
|
||||||
QPointer<MaterialBrowserModel> m_materialBrowserModel;
|
QPointer<MaterialBrowserModel> m_materialBrowserModel;
|
||||||
QPointer<MaterialBrowserBundleModel> m_materialBrowserBundleModel;
|
QPointer<MaterialBrowserTexturesModel> m_materialBrowserTexturesModel;
|
||||||
QScopedPointer<QQuickWidget> m_quickWidget;
|
QScopedPointer<QQuickWidget> m_quickWidget;
|
||||||
|
|
||||||
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
|
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
|
||||||
@@ -81,8 +72,6 @@ private:
|
|||||||
QString m_filterText;
|
QString m_filterText;
|
||||||
|
|
||||||
ModelNode m_materialToDrag;
|
ModelNode m_materialToDrag;
|
||||||
BundleMaterial *m_bundleMaterialToDrag = nullptr;
|
|
||||||
BundleMaterial *m_draggedBundleMaterial = nullptr;
|
|
||||||
QPoint m_dragStartPoint;
|
QPoint m_dragStartPoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -544,7 +544,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
|
|||||||
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) {
|
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) {
|
||||||
ModelNode targetNode(modelNodeForIndex(dropModelIndex));
|
ModelNode targetNode(modelNodeForIndex(dropModelIndex));
|
||||||
if (targetNode.isValid())
|
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)) {
|
} else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) {
|
||||||
const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',');
|
const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',');
|
||||||
NodeAbstractProperty targetProperty;
|
NodeAbstractProperty targetProperty;
|
||||||
|
|||||||
@@ -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_ASSETS[] = "application/vnd.qtdesignstudio.assets";
|
||||||
const char MIME_TYPE_MATERIAL[] = "application/vnd.qtdesignstudio.material";
|
const char MIME_TYPE_MATERIAL[] = "application/vnd.qtdesignstudio.material";
|
||||||
const char MIME_TYPE_BUNDLE_MATERIAL[] = "application/vnd.qtdesignstudio.bundlematerial";
|
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_IMAGE[] = "application/vnd.qtdesignstudio.asset.image";
|
||||||
const char MIME_TYPE_ASSET_FONT[] = "application/vnd.qtdesignstudio.asset.font";
|
const char MIME_TYPE_ASSET_FONT[] = "application/vnd.qtdesignstudio.asset.font";
|
||||||
const char MIME_TYPE_ASSET_SHADER[] = "application/vnd.qtdesignstudio.asset.shader";
|
const char MIME_TYPE_ASSET_SHADER[] = "application/vnd.qtdesignstudio.asset.shader";
|
||||||
|
|||||||
Reference in New Issue
Block a user