forked from qt-creator/qt-creator
QmlDesigner: Add content library user materials bundle
Fixes: QDS-12389 Change-Id: Icec1b06c57e0eaa4ff444e3143d3cba0803c8dd1 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
@@ -23,6 +23,7 @@ Item {
|
||||
texturesView.closeContextMenu()
|
||||
environmentsView.closeContextMenu()
|
||||
effectsView.closeContextMenu()
|
||||
userView.closeContextMenu()
|
||||
HelperWidgets.Controller.closeContextMenu()
|
||||
}
|
||||
|
||||
@@ -113,10 +114,18 @@ Item {
|
||||
id: tabBar
|
||||
width: parent.width
|
||||
height: StudioTheme.Values.toolbarHeight
|
||||
tabsModel: [{name: qsTr("Materials"), icon: StudioTheme.Constants.material_medium},
|
||||
{name: qsTr("Textures"), icon: StudioTheme.Constants.textures_medium},
|
||||
{name: qsTr("Environments"), icon: StudioTheme.Constants.languageList_medium},
|
||||
{name: qsTr("Effects"), icon: StudioTheme.Constants.effects}]
|
||||
|
||||
Component.onCompleted: {
|
||||
var tabs = [
|
||||
{ name: qsTr("Materials"), icon: StudioTheme.Constants.material_medium },
|
||||
{ name: qsTr("Textures"), icon: StudioTheme.Constants.textures_medium },
|
||||
{ name: qsTr("Environments"), icon: StudioTheme.Constants.languageList_medium },
|
||||
{ name: qsTr("Effects"), icon: StudioTheme.Constants.effects }
|
||||
];
|
||||
if (ContentLibraryBackend.rootView.userBundleEnabled())
|
||||
tabs.push({ name: qsTr("User Assets"), icon: StudioTheme.Constants.effects });
|
||||
tabBar.tabsModel = tabs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,7 +157,8 @@ Item {
|
||||
|
||||
onUnimport: (bundleMat) => {
|
||||
confirmUnimportDialog.targetBundleItem = bundleMat
|
||||
confirmUnimportDialog.targetBundleType = "material"
|
||||
confirmUnimportDialog.targetBundleLabel = "material"
|
||||
confirmUnimportDialog.targetBundleModel = ContentLibraryBackend.materialsModel
|
||||
confirmUnimportDialog.open()
|
||||
}
|
||||
|
||||
@@ -208,7 +218,31 @@ Item {
|
||||
|
||||
onUnimport: (bundleItem) => {
|
||||
confirmUnimportDialog.targetBundleItem = bundleItem
|
||||
confirmUnimportDialog.targetBundleType = "effect"
|
||||
confirmUnimportDialog.targetBundleLabel = "effect"
|
||||
confirmUnimportDialog.targetBundleModel = ContentLibraryBackend.effectsModel
|
||||
confirmUnimportDialog.open()
|
||||
}
|
||||
|
||||
onCountChanged: root.responsiveResize(stackLayout.width, stackLayout.height)
|
||||
}
|
||||
|
||||
ContentLibraryUserView {
|
||||
id: userView
|
||||
|
||||
adsFocus: root.adsFocus
|
||||
width: root.width
|
||||
|
||||
cellWidth: root.thumbnailSize
|
||||
cellHeight: root.thumbnailSize + 20
|
||||
numColumns: root.numColumns
|
||||
hideHorizontalScrollBar: true
|
||||
|
||||
searchBox: searchBox
|
||||
|
||||
onUnimport: (bundleItem) => {
|
||||
confirmUnimportDialog.targetBundleItem = bundleItem
|
||||
confirmUnimportDialog.targetBundleLabel = "material"
|
||||
confirmUnimportDialog.targetBundleModel = ContentLibraryBackend.userModel
|
||||
confirmUnimportDialog.open()
|
||||
}
|
||||
|
||||
|
@@ -12,12 +12,15 @@ import WebFetcher
|
||||
Item {
|
||||
id: root
|
||||
|
||||
signal showContextMenu()
|
||||
|
||||
// Download states: "" (ie default, not downloaded), "unavailable", "downloading", "downloaded",
|
||||
// "failed"
|
||||
property string downloadState: modelData.isDownloaded() ? "downloaded" : ""
|
||||
|
||||
property bool importerRunning: false
|
||||
|
||||
signal showContextMenu()
|
||||
signal addToProject()
|
||||
|
||||
visible: modelData.bundleMaterialVisible
|
||||
|
||||
MouseArea {
|
||||
@@ -29,7 +32,7 @@ Item {
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onPressed: (mouse) => {
|
||||
if (mouse.button === Qt.LeftButton && !materialsModel.importerRunning) {
|
||||
if (mouse.button === Qt.LeftButton && !root.importerRunning) {
|
||||
if (root.downloadState === "downloaded")
|
||||
ContentLibraryBackend.rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
|
||||
} else if (mouse.button === Qt.RightButton && root.downloadState === "downloaded") {
|
||||
@@ -96,12 +99,12 @@ Item {
|
||||
pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4)
|
||||
anchors.right: img.right
|
||||
anchors.bottom: img.bottom
|
||||
enabled: !ContentLibraryBackend.materialsModel.importerRunning
|
||||
enabled: !root.importerRunning
|
||||
visible: root.downloadState === "downloaded"
|
||||
&& (containsMouse || mouseArea.containsMouse)
|
||||
|
||||
onClicked: {
|
||||
ContentLibraryBackend.materialsModel.addToProject(modelData)
|
||||
root.addToProject()
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,8 +15,9 @@ StudioControls.Menu {
|
||||
|
||||
readonly property bool targetAvailable: targetMaterial && !importerRunning
|
||||
|
||||
signal unimport(var bundleMat);
|
||||
signal addToProject(var bundleMat)
|
||||
signal unimport();
|
||||
signal addToProject()
|
||||
signal applyToSelected(bool add)
|
||||
|
||||
function popupMenu(targetMaterial = null)
|
||||
{
|
||||
@@ -29,13 +30,13 @@ StudioControls.Menu {
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Apply to selected (replace)")
|
||||
enabled: root.targetAvailable && root.hasModelSelection
|
||||
onTriggered: materialsModel.applyToSelected(root.targetMaterial, false)
|
||||
onTriggered: root.applyToSelected(false)
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Apply to selected (add)")
|
||||
enabled: root.targetAvailable && root.hasModelSelection
|
||||
onTriggered: materialsModel.applyToSelected(root.targetMaterial, true)
|
||||
onTriggered: root.applyToSelected(true)
|
||||
}
|
||||
|
||||
StudioControls.MenuSeparator {}
|
||||
@@ -45,7 +46,7 @@ StudioControls.Menu {
|
||||
text: qsTr("Add an instance to project")
|
||||
|
||||
onTriggered: {
|
||||
root.addToProject(root.targetMaterial)
|
||||
root.addToProject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +54,6 @@ StudioControls.Menu {
|
||||
enabled: root.targetAvailable && root.targetMaterial.bundleMaterialImported
|
||||
text: qsTr("Remove from project")
|
||||
|
||||
onTriggered: root.unimport(root.targetMaterial)
|
||||
onTriggered: root.unimport()
|
||||
}
|
||||
}
|
||||
|
@@ -27,8 +27,6 @@ HelperWidgets.ScrollView {
|
||||
root.count = c
|
||||
}
|
||||
|
||||
property var currMaterialItem: null
|
||||
property var rootItem: null
|
||||
property var materialsModel: ContentLibraryBackend.materialsModel
|
||||
|
||||
required property var searchBox
|
||||
@@ -51,17 +49,19 @@ HelperWidgets.ScrollView {
|
||||
ContentLibraryMaterialContextMenu {
|
||||
id: ctxMenu
|
||||
|
||||
hasModelSelection: materialsModel.hasModelSelection
|
||||
importerRunning: materialsModel.importerRunning
|
||||
hasModelSelection: root.materialsModel.hasModelSelection
|
||||
importerRunning: root.materialsModel.importerRunning
|
||||
|
||||
onUnimport: (bundleMat) => root.unimport(bundleMat)
|
||||
onAddToProject: (bundleMat) => materialsModel.addToProject(bundleMat)
|
||||
onApplyToSelected: (add) => root.materialsModel.applyToSelected(ctxMenu.targetMaterial, add)
|
||||
|
||||
onUnimport: root.unimport(ctxMenu.targetMaterial)
|
||||
onAddToProject: root.materialsModel.addToProject(ctxMenu.targetMaterial)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: categoryRepeater
|
||||
|
||||
model: materialsModel
|
||||
model: root.materialsModel
|
||||
|
||||
delegate: HelperWidgets.Section {
|
||||
id: section
|
||||
@@ -73,7 +73,7 @@ HelperWidgets.ScrollView {
|
||||
bottomPadding: StudioTheme.Values.sectionPadding
|
||||
|
||||
caption: bundleCategoryName
|
||||
visible: bundleCategoryVisible && !materialsModel.isEmpty
|
||||
visible: bundleCategoryVisible && !root.materialsModel.isEmpty
|
||||
expanded: bundleCategoryExpanded
|
||||
expandOnClick: false
|
||||
category: "ContentLib_Mat"
|
||||
@@ -103,7 +103,10 @@ HelperWidgets.ScrollView {
|
||||
width: root.cellWidth
|
||||
height: root.cellHeight
|
||||
|
||||
importerRunning: root.materialsModel.importerRunning
|
||||
|
||||
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
||||
onAddToProject: root.materialsModel.addToProject(modelData)
|
||||
}
|
||||
|
||||
onCountChanged: root.assignMaxCount()
|
||||
@@ -115,13 +118,13 @@ HelperWidgets.ScrollView {
|
||||
Text {
|
||||
id: infoText
|
||||
text: {
|
||||
if (!materialsModel.matBundleExists)
|
||||
if (!root.materialsModel.matBundleExists)
|
||||
qsTr("No materials available. Make sure you have internet connection.")
|
||||
else if (!ContentLibraryBackend.rootView.isQt6Project)
|
||||
qsTr("<b>Content Library</b> materials are not supported in Qt5 projects.")
|
||||
else if (!ContentLibraryBackend.rootView.hasQuick3DImport)
|
||||
qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
||||
else if (!materialsModel.hasRequiredQuick3DImport)
|
||||
else if (!root.materialsModel.hasRequiredQuick3DImport)
|
||||
qsTr("To use <b>Content Library</b>, version 6.3 or later of the QtQuick3D module is required.")
|
||||
else if (!ContentLibraryBackend.rootView.hasMaterialLibrary)
|
||||
qsTr("<b>Content Library</b> is disabled inside a non-visual component.")
|
||||
@@ -134,7 +137,7 @@ HelperWidgets.ScrollView {
|
||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||
topPadding: 10
|
||||
leftPadding: 10
|
||||
visible: materialsModel.isEmpty
|
||||
visible: root.materialsModel.isEmpty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,9 +27,6 @@ HelperWidgets.ScrollView {
|
||||
root.count = c
|
||||
}
|
||||
|
||||
property var currMaterialItem: null
|
||||
property var rootItem: null
|
||||
|
||||
required property var searchBox
|
||||
required property var model
|
||||
required property string sectionCategory
|
||||
|
@@ -0,0 +1,151 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick
|
||||
import HelperWidgets as HelperWidgets
|
||||
import StudioControls as StudioControls
|
||||
import StudioTheme as StudioTheme
|
||||
import ContentLibraryBackend
|
||||
|
||||
HelperWidgets.ScrollView {
|
||||
id: root
|
||||
|
||||
clip: true
|
||||
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
|
||||
&& !HelperWidgets.Controller.contextMenuOpened
|
||||
|
||||
property real cellWidth: 100
|
||||
property real cellHeight: 120
|
||||
property int numColumns: 4
|
||||
|
||||
property int count: 0
|
||||
function assignMaxCount() {
|
||||
let c = 0
|
||||
for (let i = 0; i < categoryRepeater.count; ++i)
|
||||
c = Math.max(c, categoryRepeater.itemAt(i)?.count ?? 0)
|
||||
|
||||
root.count = c
|
||||
}
|
||||
|
||||
required property var searchBox
|
||||
|
||||
signal unimport(var bundleItem);
|
||||
|
||||
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.expandSection()
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
ContentLibraryMaterialContextMenu {
|
||||
id: ctxMenu
|
||||
|
||||
hasModelSelection: ContentLibraryBackend.userModel.hasModelSelection
|
||||
importerRunning: ContentLibraryBackend.userModel.importerRunning
|
||||
|
||||
onApplyToSelected: (add) => ContentLibraryBackend.userModel.applyToSelected(ctxMenu.targetMaterial, add)
|
||||
|
||||
onUnimport: root.unimport(ctxMenu.targetMaterial)
|
||||
onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenu.targetMaterial)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: categoryRepeater
|
||||
|
||||
model: ContentLibraryBackend.userModel
|
||||
|
||||
delegate: HelperWidgets.Section {
|
||||
id: section
|
||||
|
||||
width: root.width
|
||||
leftPadding: StudioTheme.Values.sectionPadding
|
||||
rightPadding: StudioTheme.Values.sectionPadding
|
||||
topPadding: StudioTheme.Values.sectionPadding
|
||||
bottomPadding: StudioTheme.Values.sectionPadding
|
||||
|
||||
caption: categoryName
|
||||
visible: categoryVisible
|
||||
expanded: categoryExpanded
|
||||
expandOnClick: false
|
||||
category: "ContentLib_User"
|
||||
|
||||
onToggleExpand: categoryExpanded = !categoryExpanded
|
||||
onExpand: categoryExpanded = true
|
||||
onCollapse: categoryExpanded = false
|
||||
|
||||
function expandSection() {
|
||||
categoryExpanded = true
|
||||
}
|
||||
|
||||
property alias count: repeater.count
|
||||
|
||||
onCountChanged: root.assignMaxCount()
|
||||
|
||||
property int numVisibleItem: 1 // initially, the tab is invisible so this will be 0
|
||||
|
||||
Grid {
|
||||
width: section.width - section.leftPadding - section.rightPadding
|
||||
spacing: StudioTheme.Values.sectionGridSpacing
|
||||
columns: root.numColumns
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: categoryItems
|
||||
|
||||
delegate: ContentLibraryMaterial {
|
||||
width: root.cellWidth
|
||||
height: root.cellHeight
|
||||
|
||||
importerRunning: ContentLibraryBackend.userModel.importerRunning
|
||||
|
||||
onShowContextMenu: ctxMenu.popupMenu(modelData)
|
||||
onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData)
|
||||
|
||||
onVisibleChanged: {
|
||||
section.numVisibleItem += visible ? 1 : -1
|
||||
}
|
||||
}
|
||||
|
||||
onCountChanged: root.assignMaxCount()
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("No match found.");
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||
leftPadding: 10
|
||||
visible: !searchBox.isEmpty() && section.numVisibleItem === 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: infoText
|
||||
text: {
|
||||
if (!ContentLibraryBackend.effectsModel.bundleExists)
|
||||
qsTr("User bundle couldn't be found.")
|
||||
else if (!ContentLibraryBackend.rootView.isQt6Project)
|
||||
qsTr("<b>Content Library</b> is not supported in Qt5 projects.")
|
||||
else if (!ContentLibraryBackend.rootView.hasQuick3DImport)
|
||||
qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> view.")
|
||||
else if (!ContentLibraryBackend.rootView.hasMaterialLibrary)
|
||||
qsTr("<b>Content Library</b> is disabled inside a non-visual component.")
|
||||
else
|
||||
""
|
||||
}
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
font.pixelSize: StudioTheme.Values.baseFontSize
|
||||
topPadding: 10
|
||||
leftPadding: 10
|
||||
visible: ContentLibraryBackend.effectsModel.isEmpty
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,24 +12,27 @@ import ContentLibraryBackend
|
||||
StudioControls.Dialog {
|
||||
id: root
|
||||
|
||||
title: qsTr("Bundle material might be in use")
|
||||
property var targetBundleItem
|
||||
property var targetBundleLabel // "effect" or "material"
|
||||
property var targetBundleModel
|
||||
|
||||
title: qsTr("Bundle %1 might be in use").arg(root.targetBundleLabel)
|
||||
anchors.centerIn: parent
|
||||
closePolicy: Popup.CloseOnEscape
|
||||
implicitWidth: 300
|
||||
modal: true
|
||||
|
||||
property var targetBundleType // "effect" or "material"
|
||||
property var targetBundleItem
|
||||
onOpened: warningText.forceActiveFocus()
|
||||
|
||||
contentItem: Column {
|
||||
spacing: 20
|
||||
width: parent.width
|
||||
|
||||
Text {
|
||||
id: folderNotEmpty
|
||||
id: warningText
|
||||
|
||||
text: qsTr("If the %1 you are removing is in use, it might cause the project to malfunction.\n\nAre you sure you want to remove the %1?")
|
||||
.arg(root.targetBundleType)
|
||||
text: qsTr("If the %1 you are removing is in use, it might cause the project to malfunction.\n\nAre you sure you want to remove it?")
|
||||
.arg(root.targetBundleLabel)
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
wrapMode: Text.WordWrap
|
||||
anchors.right: parent.right
|
||||
@@ -49,11 +52,7 @@ StudioControls.Dialog {
|
||||
text: qsTr("Remove")
|
||||
|
||||
onClicked: {
|
||||
if (root.targetBundleType === "material")
|
||||
ContentLibraryBackend.materialsModel.removeFromProject(root.targetBundleItem)
|
||||
else if (root.targetBundleType === "effect")
|
||||
ContentLibraryBackend.effectsModel.removeFromProject(root.targetBundleItem)
|
||||
|
||||
root.targetBundleModel.removeFromProject(root.targetBundleItem)
|
||||
root.accept()
|
||||
}
|
||||
}
|
||||
@@ -64,6 +63,4 @@ StudioControls.Dialog {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onOpened: folderNotEmpty.forceActiveFocus()
|
||||
}
|
||||
|
@@ -826,6 +826,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
contentlibraryeffect.cpp contentlibraryeffect.h
|
||||
contentlibraryeffectscategory.cpp contentlibraryeffectscategory.h
|
||||
contentlibraryeffectsmodel.cpp contentlibraryeffectsmodel.h
|
||||
contentlibraryusermodel.cpp contentlibraryusermodel.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
|
@@ -3,9 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "qmldesignercorelib_global.h"
|
||||
#include "nodeinstanceglobal.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
|
||||
|
@@ -0,0 +1,308 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "contentlibraryusermodel.h"
|
||||
|
||||
#include "contentlibrarybundleimporter.h"
|
||||
#include "contentlibrarymaterial.h"
|
||||
#include "contentlibrarymaterialscategory.h"
|
||||
#include "contentlibrarywidget.h"
|
||||
|
||||
#include <designerpaths.h>
|
||||
#include "qmldesignerconstants.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QQmlEngine>
|
||||
#include <QStandardPaths>
|
||||
#include <QUrl>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
ContentLibraryUserModel::ContentLibraryUserModel(ContentLibraryWidget *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_widget(parent)
|
||||
{
|
||||
m_userCategories = {tr("Materials")/*, tr("Textures"), tr("3D"), tr("Effects"), tr("2D components")*/}; // TODO
|
||||
|
||||
loadUserBundle();
|
||||
}
|
||||
|
||||
int ContentLibraryUserModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return m_userCategories.size();
|
||||
}
|
||||
|
||||
QVariant ContentLibraryUserModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QTC_ASSERT(index.isValid() && index.row() < m_userCategories.size(), return {});
|
||||
QTC_ASSERT(roleNames().contains(role), return {});
|
||||
|
||||
if (role == NameRole)
|
||||
return m_userCategories.at(index.row());
|
||||
|
||||
if (role == ItemsRole) {
|
||||
if (index.row() == 0)
|
||||
return QVariant::fromValue(m_userMaterials);
|
||||
if (index.row() == 1)
|
||||
return QVariant::fromValue(m_userTextures);
|
||||
if (index.row() == 2)
|
||||
return QVariant::fromValue(m_user3DItems);
|
||||
if (index.row() == 3)
|
||||
return QVariant::fromValue(m_userEffects);
|
||||
}
|
||||
|
||||
if (role == VisibleRole)
|
||||
return true; // TODO
|
||||
|
||||
if (role == ExpandedRole)
|
||||
return true; // TODO
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ContentLibraryUserModel::isValidIndex(int idx) const
|
||||
{
|
||||
return idx > -1 && idx < rowCount();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::updateIsEmpty()
|
||||
{
|
||||
bool anyMatVisible = Utils::anyOf(m_userMaterials, [&](ContentLibraryMaterial *mat) {
|
||||
return mat->visible();
|
||||
});
|
||||
|
||||
bool newEmpty = !anyMatVisible || !m_widget->hasMaterialLibrary() || !hasRequiredQuick3DImport();
|
||||
|
||||
if (newEmpty != m_isEmpty) {
|
||||
m_isEmpty = newEmpty;
|
||||
emit isEmptyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ContentLibraryUserModel::roleNames() const
|
||||
{
|
||||
static const QHash<int, QByteArray> roles {
|
||||
{NameRole, "categoryName"},
|
||||
{VisibleRole, "categoryVisible"},
|
||||
{ExpandedRole, "categoryExpanded"},
|
||||
{ItemsRole, "categoryItems"}
|
||||
};
|
||||
return roles;
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::createImporter(const QString &bundlePath, const QString &bundleId,
|
||||
const QStringList &sharedFiles)
|
||||
{
|
||||
m_importer = new Internal::ContentLibraryBundleImporter(bundlePath, bundleId, sharedFiles);
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
connect(m_importer,
|
||||
&Internal::ContentLibraryBundleImporter::importFinished,
|
||||
this,
|
||||
[&](const QmlDesigner::TypeName &typeName) {
|
||||
m_importerRunning = false;
|
||||
emit importerRunningChanged();
|
||||
if (typeName.size())
|
||||
emit bundleMaterialImported(typeName);
|
||||
});
|
||||
#else
|
||||
connect(m_importer,
|
||||
&Internal::ContentLibraryBundleImporter::importFinished,
|
||||
this,
|
||||
[&](const QmlDesigner::NodeMetaInfo &metaInfo) {
|
||||
m_importerRunning = false;
|
||||
emit importerRunningChanged();
|
||||
if (metaInfo.isValid())
|
||||
emit bundleMaterialImported(metaInfo);
|
||||
});
|
||||
#endif
|
||||
|
||||
connect(m_importer, &Internal::ContentLibraryBundleImporter::unimportFinished, this,
|
||||
[&](const QmlDesigner::NodeMetaInfo &metaInfo) {
|
||||
Q_UNUSED(metaInfo)
|
||||
m_importerRunning = false;
|
||||
emit importerRunningChanged();
|
||||
emit bundleMaterialUnimported(metaInfo);
|
||||
});
|
||||
|
||||
resetModel();
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::loadUserBundle()
|
||||
{
|
||||
if (m_matBundleExists)
|
||||
return;
|
||||
|
||||
QDir bundleDir{Paths::bundlesPathSetting() + "/User/materials"};
|
||||
|
||||
if (m_bundleObj.isEmpty()) {
|
||||
QFile matsJsonFile(bundleDir.filePath("user_materials_bundle.json"));
|
||||
|
||||
if (!matsJsonFile.open(QIODevice::ReadOnly)) {
|
||||
qWarning("Couldn't open user_materials_bundle.json");
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument matBundleJsonDoc = QJsonDocument::fromJson(matsJsonFile.readAll());
|
||||
if (matBundleJsonDoc.isNull()) {
|
||||
qWarning("Invalid user_materials_bundle.json file");
|
||||
return;
|
||||
} else {
|
||||
m_bundleObj = matBundleJsonDoc.object();
|
||||
}
|
||||
}
|
||||
|
||||
QString bundleId = m_bundleObj.value("id").toString();
|
||||
|
||||
// parse materials
|
||||
const QJsonObject matsObj = m_bundleObj.value("materials").toObject();
|
||||
const QStringList materialNames = matsObj.keys();
|
||||
for (const QString &matName : materialNames) {
|
||||
const QJsonObject matObj = matsObj.value(matName).toObject();
|
||||
|
||||
QStringList files;
|
||||
const QJsonArray assetsArr = matObj.value("files").toArray();
|
||||
for (const auto /*QJson{Const,}ValueRef*/ &asset : assetsArr)
|
||||
files.append(asset.toString());
|
||||
|
||||
QUrl icon = QUrl::fromLocalFile(bundleDir.filePath(matObj.value("icon").toString()));
|
||||
QString qml = matObj.value("qml").toString();
|
||||
|
||||
TypeName type = QLatin1String("%1.%2.%3").arg(
|
||||
QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1),
|
||||
bundleId,
|
||||
qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
|
||||
|
||||
auto userMat = new ContentLibraryMaterial(this, matName, qml, type, icon, files,
|
||||
bundleDir.path(), "");
|
||||
|
||||
m_userMaterials.append(userMat);
|
||||
}
|
||||
|
||||
QStringList sharedFiles;
|
||||
const QJsonArray sharedFilesArr = m_bundleObj.value("sharedFiles").toArray();
|
||||
for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
|
||||
sharedFiles.append(file.toString());
|
||||
|
||||
createImporter(bundleDir.path(), bundleId, sharedFiles);
|
||||
|
||||
m_matBundleExists = true;
|
||||
emit matBundleExistsChanged();
|
||||
}
|
||||
|
||||
bool ContentLibraryUserModel::hasRequiredQuick3DImport() const
|
||||
{
|
||||
return m_widget->hasQuick3DImport() && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;
|
||||
}
|
||||
|
||||
bool ContentLibraryUserModel::matBundleExists() const
|
||||
{
|
||||
return m_matBundleExists;
|
||||
}
|
||||
|
||||
Internal::ContentLibraryBundleImporter *ContentLibraryUserModel::bundleImporter() const
|
||||
{
|
||||
return m_importer;
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::setSearchText(const QString &searchText)
|
||||
{
|
||||
QString lowerSearchText = searchText.toLower();
|
||||
|
||||
if (m_searchText == lowerSearchText)
|
||||
return;
|
||||
|
||||
m_searchText = lowerSearchText;
|
||||
|
||||
for (ContentLibraryMaterial *mat : std::as_const(m_userMaterials))
|
||||
mat->filter(m_searchText);
|
||||
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::updateImportedState(const QStringList &importedMats)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
for (ContentLibraryMaterial *mat : std::as_const(m_userMaterials))
|
||||
changed |= mat->setImported(importedMats.contains(mat->qml().chopped(4)));
|
||||
|
||||
if (changed)
|
||||
resetModel();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::setQuick3DImportVersion(int major, int minor)
|
||||
{
|
||||
bool oldRequiredImport = hasRequiredQuick3DImport();
|
||||
|
||||
m_quick3dMajorVersion = major;
|
||||
m_quick3dMinorVersion = minor;
|
||||
|
||||
bool newRequiredImport = hasRequiredQuick3DImport();
|
||||
|
||||
if (oldRequiredImport == newRequiredImport)
|
||||
return;
|
||||
|
||||
emit hasRequiredQuick3DImportChanged();
|
||||
|
||||
updateIsEmpty();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::resetModel()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::applyToSelected(ContentLibraryMaterial *mat, bool add)
|
||||
{
|
||||
emit applyToSelectedTriggered(mat, add);
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::addToProject(ContentLibraryMaterial *mat)
|
||||
{
|
||||
QString err = m_importer->importComponent(mat->qml(), mat->files());
|
||||
|
||||
if (err.isEmpty()) {
|
||||
m_importerRunning = true;
|
||||
emit importerRunningChanged();
|
||||
} else {
|
||||
qWarning() << __FUNCTION__ << err;
|
||||
}
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::removeFromProject(ContentLibraryMaterial *mat)
|
||||
{
|
||||
emit bundleMaterialAboutToUnimport(mat->type());
|
||||
|
||||
QString err = m_importer->unimportComponent(mat->qml());
|
||||
|
||||
if (err.isEmpty()) {
|
||||
m_importerRunning = true;
|
||||
emit importerRunningChanged();
|
||||
} else {
|
||||
qWarning() << __FUNCTION__ << err;
|
||||
}
|
||||
}
|
||||
|
||||
bool ContentLibraryUserModel::hasModelSelection() const
|
||||
{
|
||||
return m_hasModelSelection;
|
||||
}
|
||||
|
||||
void ContentLibraryUserModel::setHasModelSelection(bool b)
|
||||
{
|
||||
if (b == m_hasModelSelection)
|
||||
return;
|
||||
|
||||
m_hasModelSelection = b;
|
||||
emit hasModelSelectionChanged();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -0,0 +1,118 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nodemetainfo.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ContentLibraryEffect;
|
||||
class ContentLibraryMaterial;
|
||||
class ContentLibraryTexture;
|
||||
class ContentLibraryWidget;
|
||||
|
||||
namespace Internal {
|
||||
class ContentLibraryBundleImporter;
|
||||
}
|
||||
|
||||
class ContentLibraryUserModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
|
||||
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
|
||||
Q_PROPERTY(bool hasRequiredQuick3DImport READ hasRequiredQuick3DImport NOTIFY hasRequiredQuick3DImportChanged)
|
||||
Q_PROPERTY(bool hasModelSelection READ hasModelSelection NOTIFY hasModelSelectionChanged)
|
||||
Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryMaterial *> userMaterials MEMBER m_userMaterials NOTIFY userMaterialsChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryTexture *> userTextures MEMBER m_userTextures NOTIFY userTexturesChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryEffect *> user3DItems MEMBER m_user3DItems NOTIFY user3DItemsChanged)
|
||||
Q_PROPERTY(QList<ContentLibraryEffect *> userEffects MEMBER m_userEffects NOTIFY userEffectsChanged)
|
||||
|
||||
public:
|
||||
ContentLibraryUserModel(ContentLibraryWidget *parent = nullptr);
|
||||
|
||||
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);
|
||||
void updateImportedState(const QStringList &importedMats);
|
||||
|
||||
void setQuick3DImportVersion(int major, int minor);
|
||||
|
||||
bool hasRequiredQuick3DImport() const;
|
||||
|
||||
bool matBundleExists() const;
|
||||
|
||||
bool hasModelSelection() const;
|
||||
void setHasModelSelection(bool b);
|
||||
|
||||
void resetModel();
|
||||
void updateIsEmpty();
|
||||
|
||||
Internal::ContentLibraryBundleImporter *bundleImporter() const;
|
||||
|
||||
Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
|
||||
Q_INVOKABLE void addToProject(QmlDesigner::ContentLibraryMaterial *mat);
|
||||
Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryMaterial *mat);
|
||||
|
||||
signals:
|
||||
void isEmptyChanged();
|
||||
void hasRequiredQuick3DImportChanged();
|
||||
void hasModelSelectionChanged();
|
||||
void userMaterialsChanged();
|
||||
void userTexturesChanged();
|
||||
void user3DItemsChanged();
|
||||
void userEffectsChanged();
|
||||
|
||||
void applyToSelectedTriggered(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
|
||||
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
void bundleMaterialImported(const QmlDesigner::TypeName &typeName);
|
||||
#else
|
||||
void bundleMaterialImported(const QmlDesigner::NodeMetaInfo &metaInfo);
|
||||
#endif
|
||||
void bundleMaterialAboutToUnimport(const QmlDesigner::TypeName &type);
|
||||
void bundleMaterialUnimported(const QmlDesigner::NodeMetaInfo &metaInfo);
|
||||
void importerRunningChanged();
|
||||
void matBundleExistsChanged();
|
||||
|
||||
private:
|
||||
void loadUserBundle();
|
||||
bool isValidIndex(int idx) const;
|
||||
void createImporter(const QString &bundlePath, const QString &bundleId,
|
||||
const QStringList &sharedFiles);
|
||||
|
||||
ContentLibraryWidget *m_widget = nullptr;
|
||||
QString m_searchText;
|
||||
|
||||
QList<ContentLibraryMaterial *> m_userMaterials;
|
||||
QList<ContentLibraryTexture *> m_userTextures;
|
||||
QList<ContentLibraryEffect *> m_userEffects;
|
||||
QList<ContentLibraryEffect *> m_user3DItems;
|
||||
QStringList m_userCategories;
|
||||
|
||||
QJsonObject m_bundleObj;
|
||||
Internal::ContentLibraryBundleImporter *m_importer = nullptr;
|
||||
|
||||
bool m_isEmpty = true;
|
||||
bool m_matBundleExists = false;
|
||||
bool m_hasModelSelection = false;
|
||||
bool m_importerRunning = false;
|
||||
|
||||
int m_quick3dMajorVersion = -1;
|
||||
int m_quick3dMinorVersion = -1;
|
||||
|
||||
QString m_importerBundlePath;
|
||||
QString m_importerBundleId;
|
||||
QStringList m_importerSharedFiles;
|
||||
|
||||
enum Roles { NameRole = Qt::UserRole + 1, VisibleRole, ExpandedRole, ItemsRole };
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
@@ -10,6 +10,7 @@
|
||||
#include "contentlibrarymaterialsmodel.h"
|
||||
#include "contentlibrarytexture.h"
|
||||
#include "contentlibrarytexturesmodel.h"
|
||||
#include "contentlibraryusermodel.h"
|
||||
#include "contentlibrarywidget.h"
|
||||
#include "externaldependenciesinterface.h"
|
||||
#include "nodelistproperty.h"
|
||||
@@ -204,6 +205,8 @@ WidgetInfo ContentLibraryView::widgetInfo()
|
||||
|
||||
connect(effectsModel, &ContentLibraryEffectsModel::bundleItemUnimported, this,
|
||||
&ContentLibraryView::updateBundleEffectsImportedState);
|
||||
|
||||
connectUserBundle();
|
||||
}
|
||||
|
||||
return createWidgetInfo(m_widget.data(),
|
||||
@@ -213,6 +216,64 @@ WidgetInfo ContentLibraryView::widgetInfo()
|
||||
tr("Content Library"));
|
||||
}
|
||||
|
||||
void ContentLibraryView::connectUserBundle()
|
||||
{
|
||||
ContentLibraryUserModel *userModel = m_widget->userModel().data();
|
||||
|
||||
connect(userModel,
|
||||
&ContentLibraryUserModel::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->userModel()->addToProject(bundleMat);
|
||||
});
|
||||
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
connect(userModel,
|
||||
&ContentLibraryUserModel::bundleMaterialImported,
|
||||
this,
|
||||
[&](const QmlDesigner::TypeName &typeName) {
|
||||
applyBundleMaterialToDropTarget({}, typeName);
|
||||
updateBundleUserMaterialsImportedState();
|
||||
});
|
||||
#else
|
||||
connect(userModel,
|
||||
&ContentLibraryUserModel::bundleMaterialImported,
|
||||
this,
|
||||
[&](const QmlDesigner::NodeMetaInfo &metaInfo) {
|
||||
applyBundleMaterialToDropTarget({}, metaInfo);
|
||||
updateBundleUserMaterialsImportedState();
|
||||
});
|
||||
#endif
|
||||
|
||||
connect(userModel, &ContentLibraryUserModel::bundleMaterialAboutToUnimport, this,
|
||||
[&] (const QmlDesigner::TypeName &type) {
|
||||
// delete instances of the bundle material that is about to be unimported
|
||||
executeInTransaction("ContentLibraryView::connectUserModel", [&] {
|
||||
ModelNode matLib = Utils3D::materialLibraryNode(this);
|
||||
if (!matLib.isValid())
|
||||
return;
|
||||
|
||||
Utils::reverseForeach(matLib.directSubModelNodes(), [&](const ModelNode &mat) {
|
||||
if (mat.isValid() && mat.type() == type)
|
||||
QmlObjectNode(mat).destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
connect(userModel, &ContentLibraryUserModel::bundleMaterialUnimported, this,
|
||||
&ContentLibraryView::updateBundleUserMaterialsImportedState);
|
||||
}
|
||||
|
||||
void ContentLibraryView::modelAttached(Model *model)
|
||||
{
|
||||
AbstractView::modelAttached(model);
|
||||
@@ -276,6 +337,7 @@ void ContentLibraryView::selectedNodesChanged(const QList<ModelNode> &selectedNo
|
||||
});
|
||||
|
||||
m_widget->materialsModel()->setHasModelSelection(!m_selectedModels.isEmpty());
|
||||
m_widget->userModel()->setHasModelSelection(!m_selectedModels.isEmpty());
|
||||
}
|
||||
|
||||
void ContentLibraryView::customNotification(const AbstractView *view,
|
||||
@@ -548,6 +610,25 @@ void ContentLibraryView::updateBundleMaterialsImportedState()
|
||||
m_widget->materialsModel()->updateImportedState(importedBundleMats);
|
||||
}
|
||||
|
||||
void ContentLibraryView::updateBundleUserMaterialsImportedState()
|
||||
{
|
||||
using namespace Utils;
|
||||
|
||||
if (!m_widget->userModel()->bundleImporter())
|
||||
return;
|
||||
|
||||
QStringList importedBundleMats;
|
||||
|
||||
FilePath bundlePath = m_widget->userModel()->bundleImporter()->resolveBundleImportPath();
|
||||
|
||||
if (bundlePath.exists()) {
|
||||
importedBundleMats = transform(bundlePath.dirEntries({{"*.qml"}, QDir::Files}),
|
||||
[](const FilePath &f) { return f.fileName().chopped(4); });
|
||||
}
|
||||
|
||||
m_widget->userModel()->updateImportedState(importedBundleMats);
|
||||
}
|
||||
|
||||
void ContentLibraryView::updateBundleEffectsImportedState()
|
||||
{
|
||||
using namespace Utils;
|
||||
|
@@ -46,8 +46,10 @@ public:
|
||||
const QVariant &data) override;
|
||||
|
||||
private:
|
||||
void connectUserBundle();
|
||||
void active3DSceneChanged(qint32 sceneId);
|
||||
void updateBundleMaterialsImportedState();
|
||||
void updateBundleUserMaterialsImportedState();
|
||||
void updateBundleEffectsImportedState();
|
||||
void updateBundlesQuick3DVersion();
|
||||
#ifdef QDS_USE_PROJECTSTORAGE
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "contentlibrarytexture.h"
|
||||
#include "contentlibrarytexturesmodel.h"
|
||||
#include "contentlibraryiconprovider.h"
|
||||
#include "contentlibraryusermodel.h"
|
||||
|
||||
#include "utils/filedownloader.h"
|
||||
#include "utils/fileextractor.h"
|
||||
@@ -126,6 +127,7 @@ ContentLibraryWidget::ContentLibraryWidget()
|
||||
, m_texturesModel(new ContentLibraryTexturesModel("Textures", this))
|
||||
, m_environmentsModel(new ContentLibraryTexturesModel("Environments", this))
|
||||
, m_effectsModel(new ContentLibraryEffectsModel(this))
|
||||
, m_userModel(new ContentLibraryUserModel(this))
|
||||
{
|
||||
qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
|
||||
qmlRegisterType<QmlDesigner::FileExtractor>("WebFetcher", 1, 0, "FileExtractor");
|
||||
@@ -177,7 +179,8 @@ ContentLibraryWidget::ContentLibraryWidget()
|
||||
{"materialsModel", QVariant::fromValue(m_materialsModel.data())},
|
||||
{"texturesModel", QVariant::fromValue(m_texturesModel.data())},
|
||||
{"environmentsModel", QVariant::fromValue(m_environmentsModel.data())},
|
||||
{"effectsModel", QVariant::fromValue(m_effectsModel.data())}});
|
||||
{"effectsModel", QVariant::fromValue(m_effectsModel.data())},
|
||||
{"userModel", QVariant::fromValue(m_userModel.data())}});
|
||||
|
||||
reloadQmlSource();
|
||||
}
|
||||
@@ -601,6 +604,12 @@ void ContentLibraryWidget::markTextureUpdated(const QString &textureKey)
|
||||
m_environmentsModel->markTextureHasNoUpdates(subcategory, textureKey);
|
||||
}
|
||||
|
||||
bool ContentLibraryWidget::userBundleEnabled() const
|
||||
{
|
||||
// TODO: this method is to be removed after user bundle implementation is complete
|
||||
return Core::ICore::settings()->value("QML/Designer/UseExperimentalFeatures45", false).toBool();
|
||||
}
|
||||
|
||||
QSize ContentLibraryWidget::sizeHint() const
|
||||
{
|
||||
return {420, 420};
|
||||
@@ -715,6 +724,7 @@ void ContentLibraryWidget::updateSearch()
|
||||
m_effectsModel->setSearchText(m_filterText);
|
||||
m_texturesModel->setSearchText(m_filterText);
|
||||
m_environmentsModel->setSearchText(m_filterText);
|
||||
m_userModel->setSearchText(m_filterText);
|
||||
m_quickWidget->update();
|
||||
}
|
||||
|
||||
@@ -821,4 +831,9 @@ QPointer<ContentLibraryEffectsModel> ContentLibraryWidget::effectsModel() const
|
||||
return m_effectsModel;
|
||||
}
|
||||
|
||||
QPointer<ContentLibraryUserModel> ContentLibraryWidget::userModel() const
|
||||
{
|
||||
return m_userModel;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -24,6 +24,7 @@ class ContentLibraryMaterial;
|
||||
class ContentLibraryMaterialsModel;
|
||||
class ContentLibraryTexture;
|
||||
class ContentLibraryTexturesModel;
|
||||
class ContentLibraryUserModel;
|
||||
|
||||
class ContentLibraryWidget : public QFrame
|
||||
{
|
||||
@@ -65,6 +66,7 @@ public:
|
||||
QPointer<ContentLibraryTexturesModel> texturesModel() const;
|
||||
QPointer<ContentLibraryTexturesModel> environmentsModel() const;
|
||||
QPointer<ContentLibraryEffectsModel> effectsModel() const;
|
||||
QPointer<ContentLibraryUserModel> userModel() const;
|
||||
|
||||
Q_INVOKABLE void startDragEffect(QmlDesigner::ContentLibraryEffect *eff, const QPointF &mousePos);
|
||||
Q_INVOKABLE void startDragMaterial(QmlDesigner::ContentLibraryMaterial *mat, const QPointF &mousePos);
|
||||
@@ -74,6 +76,7 @@ public:
|
||||
Q_INVOKABLE void addLightProbe(QmlDesigner::ContentLibraryTexture *tex);
|
||||
Q_INVOKABLE void updateSceneEnvState();
|
||||
Q_INVOKABLE void markTextureUpdated(const QString &textureKey);
|
||||
Q_INVOKABLE bool userBundleEnabled() const;
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
@@ -112,6 +115,7 @@ private:
|
||||
QPointer<ContentLibraryTexturesModel> m_texturesModel;
|
||||
QPointer<ContentLibraryTexturesModel> m_environmentsModel;
|
||||
QPointer<ContentLibraryEffectsModel> m_effectsModel;
|
||||
QPointer<ContentLibraryUserModel> m_userModel;
|
||||
|
||||
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
|
||||
|
||||
|
Reference in New Issue
Block a user