// 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 Qt.labs.qmlmodels
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
import ContentLibraryBackend
HelperWidgets.ScrollView {
id: root
clip: true
interactive: !ctxMenuItem.opened && !ctxMenuTexture.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);
signal removeFromContentLib(var bundleItem);
function closeContextMenu() {
ctxMenuItem.close()
ctxMenuTexture.close()
}
function expandVisibleSections() {
for (let i = 0; i < categoryRepeater.count; ++i) {
let cat = categoryRepeater.itemAt(i)
if (cat.visible && !cat.expanded)
cat.expandSection()
}
}
Column {
ContentLibraryItemContextMenu {
id: ctxMenuItem
enableRemove: true
onApplyToSelected: (add) => ContentLibraryBackend.userModel.applyToSelected(ctxMenuItem.targetItem, add)
onUnimport: root.unimport(ctxMenuItem.targetItem)
onAddToProject: ContentLibraryBackend.userModel.addToProject(ctxMenuItem.targetItem)
onRemoveFromContentLib: root.removeFromContentLib(ctxMenuItem.targetItem)
}
ContentLibraryTextureContextMenu {
id: ctxMenuTexture
enableRemove: true
hasSceneEnv: ContentLibraryBackend.texturesModel.hasSceneEnv
}
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
category: "ContentLib_User"
function expandSection() {
section.expanded = 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: DelegateChooser {
role: "itemType"
DelegateChoice {
roleValue: "material"
ContentLibraryMaterial {
width: root.cellWidth
height: root.cellHeight
onShowContextMenu: ctxMenuItem.popupMenu(modelData)
onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData)
onVisibleChanged: {
section.numVisibleItem += visible ? 1 : -1
}
}
}
DelegateChoice {
roleValue: "texture"
delegate: ContentLibraryTexture {
width: root.cellWidth
height: root.cellWidth // for textures use a square size since there is no name row
onShowContextMenu: ctxMenuTexture.popupMenu(modelData)
}
}
DelegateChoice {
roleValue: "item"
delegate: ContentLibraryItem {
width: root.cellWidth
height: root.cellHeight
onShowContextMenu: ctxMenuItem.popupMenu(modelData)
}
}
}
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("Content Library is not supported in Qt5 projects.")
else if (!ContentLibraryBackend.rootView.hasQuick3DImport)
qsTr("To use Content Library, first add the QtQuick3D module in the Components view.")
else if (!ContentLibraryBackend.rootView.hasMaterialLibrary)
qsTr("Content Library 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
}
}
}