2022-10-26 19:57:41 +03:00
|
|
|
// 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"
|
|
|
|
|
|
2022-11-24 23:42:26 +02:00
|
|
|
#include "designmodewidget.h"
|
|
|
|
|
#include "qmldesignerplugin.h"
|
|
|
|
|
#include "qmlobjectnode.h"
|
|
|
|
|
#include "variantproperty.h"
|
|
|
|
|
|
|
|
|
|
#include <utils/qtcassert.h>
|
2022-10-26 19:57:41 +03:00
|
|
|
|
|
|
|
|
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") {
|
2022-12-08 13:51:12 +02:00
|
|
|
QString source = QmlObjectNode(m_textureList.at(index.row())).modelValue("source").toString();
|
2022-12-05 14:22:13 +02:00
|
|
|
if (source.isEmpty())
|
|
|
|
|
return {};
|
|
|
|
|
if (Utils::FilePath::fromString(source).isAbsolutePath())
|
|
|
|
|
return QVariant(source);
|
|
|
|
|
return QVariant(QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()
|
|
|
|
|
->fileName().absolutePath().pathAppended(source).cleanPath().toString());
|
2022-10-26 19:57:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (roleName == "textureVisible")
|
|
|
|
|
return isTextureVisible(index.row());
|
|
|
|
|
|
|
|
|
|
if (roleName == "hasDynamicProperties")
|
|
|
|
|
return !m_textureList.at(index.row()).dynamicProperties().isEmpty();
|
|
|
|
|
|
2022-11-17 15:46:11 +02:00
|
|
|
if (roleName == "textureInternalId")
|
|
|
|
|
return m_textureList.at(index.row()).internalId();
|
|
|
|
|
|
2022-10-26 19:57:41 +03:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MaterialBrowserTexturesModel::isTextureVisible(int idx) const
|
|
|
|
|
{
|
|
|
|
|
if (!isValidIndex(idx))
|
|
|
|
|
return false;
|
|
|
|
|
|
2022-11-29 19:35:10 +02:00
|
|
|
return m_searchText.isEmpty() || m_textureList.at(idx).variantProperty("source")
|
2022-10-26 19:57:41 +03:00
|
|
|
.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"},
|
2022-11-17 15:46:11 +02:00
|
|
|
{Qt::UserRole + 3, "hasDynamicProperties"},
|
|
|
|
|
{Qt::UserRole + 4, "textureInternalId"}
|
2022-10-26 19:57:41 +03:00
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
|
|
2022-12-07 18:47:19 +02:00
|
|
|
refreshSearch();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialBrowserTexturesModel::refreshSearch()
|
|
|
|
|
{
|
2022-10-26 19:57:41 +03:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-21 14:17:00 +02:00
|
|
|
void MaterialBrowserTexturesModel::addNewTexture()
|
|
|
|
|
{
|
|
|
|
|
emit addNewTextureTriggered();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 19:57:41 +03:00
|
|
|
void MaterialBrowserTexturesModel::deleteSelectedTexture()
|
|
|
|
|
{
|
|
|
|
|
deleteTexture(m_selectedIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-21 16:45:03 +02:00
|
|
|
void MaterialBrowserTexturesModel::updateTextureSource(const ModelNode &texture)
|
|
|
|
|
{
|
|
|
|
|
int idx = textureIndex(texture);
|
|
|
|
|
if (idx != -1)
|
|
|
|
|
emit dataChanged(index(idx, 0), index(idx, 0), {roleNames().key("textureSource")});
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 13:51:12 +02:00
|
|
|
void MaterialBrowserTexturesModel::updateAllTexturesSources()
|
|
|
|
|
{
|
|
|
|
|
emit dataChanged(index(0, 0), index(rowCount() - 1, 0), {roleNames().key("textureSource")});
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 19:57:41 +03:00
|
|
|
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 {};
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 13:51:12 +02:00
|
|
|
ModelNode MaterialBrowserTexturesModel::selectedTexture() const
|
|
|
|
|
{
|
|
|
|
|
return textureAt(m_selectedIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-17 12:54:19 +02:00
|
|
|
bool MaterialBrowserTexturesModel::hasSingleModelSelection() const
|
|
|
|
|
{
|
|
|
|
|
return m_hasSingleModelSelection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialBrowserTexturesModel::setHasSingleModelSelection(bool b)
|
|
|
|
|
{
|
|
|
|
|
if (b == m_hasSingleModelSelection)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_hasSingleModelSelection = b;
|
|
|
|
|
emit hasSingleModelSelectionChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 15:54:45 +02:00
|
|
|
bool MaterialBrowserTexturesModel::hasSceneEnv() const
|
|
|
|
|
{
|
|
|
|
|
return m_hasSceneEnv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialBrowserTexturesModel::setHasSceneEnv(bool b)
|
|
|
|
|
{
|
|
|
|
|
if (b == m_hasSceneEnv)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_hasSceneEnv = b;
|
|
|
|
|
emit hasSceneEnvChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 19:57:41 +03:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-17 15:46:11 +02:00
|
|
|
void MaterialBrowserTexturesModel::applyToSelectedMaterial(qint64 internalId)
|
|
|
|
|
{
|
|
|
|
|
int idx = m_textureIndexHash.value(internalId);
|
|
|
|
|
if (idx != -1) {
|
|
|
|
|
ModelNode tex = m_textureList.at(idx);
|
|
|
|
|
emit applyToSelectedMaterialTriggered(tex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialBrowserTexturesModel::applyToSelectedModel(qint64 internalId)
|
|
|
|
|
{
|
|
|
|
|
int idx = m_textureIndexHash.value(internalId);
|
|
|
|
|
if (idx != -1) {
|
|
|
|
|
ModelNode tex = m_textureList.at(idx);
|
|
|
|
|
emit applyToSelectedModelTriggered(tex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-24 23:42:26 +02:00
|
|
|
void MaterialBrowserTexturesModel::openTextureEditor()
|
|
|
|
|
{
|
|
|
|
|
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("TextureEditor", true);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 15:54:45 +02:00
|
|
|
void MaterialBrowserTexturesModel::updateSceneEnvState()
|
|
|
|
|
{
|
|
|
|
|
emit updateSceneEnvStateRequested();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MaterialBrowserTexturesModel::applyAsLightProbe(qint64 internalId)
|
|
|
|
|
{
|
|
|
|
|
int idx = m_textureIndexHash.value(internalId);
|
|
|
|
|
if (idx != -1) {
|
|
|
|
|
ModelNode tex = m_textureList.at(idx);
|
|
|
|
|
emit applyAsLightProbeRequested(tex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-26 19:57:41 +03:00
|
|
|
} // namespace QmlDesigner
|