QmlDesigner: Show and edit texture name instead of ID in MaterialBrowser

Task-number: QDS-13024
Change-Id: I7cb223caf1577942fc273004f0e08df5569c2af0
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Ali Kianian
2024-06-25 12:49:52 +03:00
parent 576e3b7acd
commit da1c00ca64
6 changed files with 105 additions and 51 deletions

View File

@@ -23,7 +23,7 @@ TextInput {
selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
// allow only alphanumeric characters, underscores, no space at start, and 1 space between words // allow only alphanumeric characters, underscores, no space at start, and 1 space between words
validator: RegExpValidator { regExp: /^(\w+\s)*\w+$/ } validator: RegularExpressionValidator { regularExpression: /^(\w+\s)*\w+$/ }
signal renamed(string newName) signal renamed(string newName)
signal clicked() signal clicked()

View File

@@ -16,7 +16,7 @@ Item {
signal showContextMenu() signal showContextMenu()
function forceFinishEditing() { function forceFinishEditing() {
txtId.commitRename() txtName.commitRename()
} }
MouseArea { MouseArea {
@@ -76,16 +76,14 @@ Item {
} }
MaterialBrowserItemName { MaterialBrowserItemName {
id: txtId id: txtName
text: textureId text: textureName
width: img.width width: img.width
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
validator: RegularExpressionValidator { regularExpression: /(^$|^[a-z_]\w*$)/ } onRenamed: (newName) => {
MaterialBrowserBackend.materialBrowserTexturesModel.setTextureName(index, newName);
onRenamed: (newId) => {
MaterialBrowserBackend.materialBrowserTexturesModel.setTextureId(index, newId);
mouseArea.forceActiveFocus() mouseArea.forceActiveFocus()
} }

View File

@@ -34,30 +34,30 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role)
QTC_ASSERT(index.isValid() && index.row() < m_textureList.size(), return {}); QTC_ASSERT(index.isValid() && index.row() < m_textureList.size(), return {});
QTC_ASSERT(roleNames().contains(role), return {}); QTC_ASSERT(roleNames().contains(role), return {});
if (role == RoleTexSource) { switch (role) {
case RoleTexVisible:
return isVisible(index.row());
case RoleTexHasDynamicProps:
return !m_textureList.at(index.row()).dynamicProperties().isEmpty();
case RoleTexInternalId:
return m_textureList.at(index.row()).internalId();
case RoleTexName:
return m_textureList.at(index.row()).variantProperty("objectName").value();
case RoleTexSource: {
QString source = QmlObjectNode(m_textureList.at(index.row())).modelValue("source").toString(); QString source = QmlObjectNode(m_textureList.at(index.row())).modelValue("source").toString();
if (source.isEmpty()) if (source.isEmpty())
return {}; return {};
if (Utils::FilePath::fromString(source).isAbsolutePath()) if (Utils::FilePath::fromString(source).isAbsolutePath())
return QVariant(source); return QVariant(source);
return QVariant(QmlDesignerPlugin::instance()->documentManager().currentDesignDocument() return QVariant(QmlDesignerPlugin::instance()
->fileName().absolutePath().pathAppended(source).cleanPath().toString()); ->documentManager()
} .currentDesignDocument()
->fileName()
if (role == RoleTexVisible) .absolutePath()
return isVisible(index.row()); .pathAppended(source)
.toFSPathString());
if (role == RoleTexHasDynamicProps) };
return !m_textureList.at(index.row()).dynamicProperties().isEmpty(); case RoleTexToolTip: {
if (role == RoleTexInternalId)
return m_textureList.at(index.row()).internalId();
if (role == RoleTexId) {
return m_textureList.at(index.row()).id();
}
if (role == RoleTexToolTip) {
QString source = data(index, RoleTexSource).toString(); // absolute path QString source = data(index, RoleTexSource).toString(); // absolute path
if (source.isEmpty()) if (source.isEmpty())
return tr("Texture has no source image."); return tr("Texture has no source image.");
@@ -68,11 +68,13 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role)
if (info.isEmpty()) if (info.isEmpty())
return tr("Texture has no data."); return tr("Texture has no data.");
QString textName = data(index, RoleTexName).toString();
QString sourceRelative = QmlObjectNode(texNode).modelValue("source").toString(); QString sourceRelative = QmlObjectNode(texNode).modelValue("source").toString();
return QLatin1String("%1\n%2\n%3").arg(texNode.id(), sourceRelative, info); return QLatin1String("%1 (%2)\n%3\n%4").arg(textName, texNode.id(), sourceRelative, info);
};
default:
return {};
} }
return {};
} }
bool MaterialBrowserTexturesModel::isVisible(int idx) const bool MaterialBrowserTexturesModel::isVisible(int idx) const
@@ -91,13 +93,13 @@ bool MaterialBrowserTexturesModel::isValidIndex(int idx) const
QHash<int, QByteArray> MaterialBrowserTexturesModel::roleNames() const QHash<int, QByteArray> MaterialBrowserTexturesModel::roleNames() const
{ {
static const QHash<int, QByteArray> roles { static const QHash<int, QByteArray> roles{
{RoleTexHasDynamicProps, "hasDynamicProperties"}, {RoleTexHasDynamicProps, "hasDynamicProperties"},
{RoleTexInternalId, "textureInternalId"}, {RoleTexInternalId, "textureInternalId"},
{RoleTexId, "textureId"}, {RoleTexName, "textureName"},
{RoleTexSource, "textureSource"}, {RoleTexSource, "textureSource"},
{RoleTexToolTip, "textureToolTip"}, {RoleTexToolTip, "textureToolTip"},
{RoleTexVisible, "textureVisible"} {RoleTexVisible, "textureVisible"},
}; };
return roles; return roles;
} }
@@ -210,7 +212,14 @@ void MaterialBrowserTexturesModel::updateTextureId(const ModelNode &texture)
{ {
int idx = textureIndex(texture); int idx = textureIndex(texture);
if (idx != -1) if (idx != -1)
emit dataChanged(index(idx, 0), index(idx, 0), {RoleTexId, RoleTexSource, RoleTexToolTip}); emit dataChanged(index(idx, 0), index(idx, 0), {RoleTexToolTip});
}
void MaterialBrowserTexturesModel::updateTextureName(const ModelNode &texture)
{
int idx = textureIndex(texture);
if (idx != -1)
emit dataChanged(index(idx, 0), index(idx, 0), {RoleTexName, RoleTexToolTip});
} }
void MaterialBrowserTexturesModel::updateAllTexturesSources() void MaterialBrowserTexturesModel::updateAllTexturesSources()
@@ -311,7 +320,7 @@ void MaterialBrowserTexturesModel::deleteTexture(int idx)
} }
} }
void MaterialBrowserTexturesModel::setTextureId(int idx, const QString &newId) void MaterialBrowserTexturesModel::setTextureName(int idx, const QString &newName)
{ {
if (!isValidIndex(idx)) if (!isValidIndex(idx))
return; return;
@@ -320,14 +329,17 @@ void MaterialBrowserTexturesModel::setTextureId(int idx, const QString &newId)
if (!node.isValid()) if (!node.isValid())
return; return;
if (node.id() != newId) { VariantProperty objectNameProperty = node.variantProperty("objectName");
QString nodeId; QString oldName = objectNameProperty.value().toString();
if (!newId.isEmpty()) {
const auto model = m_view->model(); if (oldName != newName) {
QTC_ASSERT(model, return); const Model *model = m_view->model();
nodeId = model->generateNewId(newId); QTC_ASSERT(model, return);
}
node.setIdWithRefactoring(nodeId); m_view->executeInTransaction(__FUNCTION__, [&] {
node.setIdWithRefactoring(model->generateNewId(newName, "texture"));
objectNameProperty.setValue(newName);
});
} }
} }

View File

@@ -39,6 +39,7 @@ public:
void updateSelectedTexture(); void updateSelectedTexture();
void updateTextureSource(const ModelNode &texture); void updateTextureSource(const ModelNode &texture);
void updateTextureId(const ModelNode &texture); void updateTextureId(const ModelNode &texture);
void updateTextureName(const ModelNode &texture);
void updateAllTexturesSources(); void updateAllTexturesSources();
int textureIndex(const ModelNode &texture) const; int textureIndex(const ModelNode &texture) const;
ModelNode textureAt(int idx) const; ModelNode textureAt(int idx) const;
@@ -58,7 +59,7 @@ public:
Q_INVOKABLE void addNewTexture(); Q_INVOKABLE void addNewTexture();
Q_INVOKABLE void duplicateTexture(int idx); Q_INVOKABLE void duplicateTexture(int idx);
Q_INVOKABLE void deleteTexture(int idx); Q_INVOKABLE void deleteTexture(int idx);
Q_INVOKABLE void setTextureId(int idx, const QString &newId); Q_INVOKABLE void setTextureName(int idx, const QString &newName);
Q_INVOKABLE void applyToSelectedMaterial(qint64 internalId); Q_INVOKABLE void applyToSelectedMaterial(qint64 internalId);
Q_INVOKABLE void applyToSelectedModel(qint64 internalId); Q_INVOKABLE void applyToSelectedModel(qint64 internalId);
Q_INVOKABLE void openTextureEditor(); Q_INVOKABLE void openTextureEditor();
@@ -97,7 +98,7 @@ private:
enum { enum {
RoleTexHasDynamicProps = Qt::UserRole + 1, RoleTexHasDynamicProps = Qt::UserRole + 1,
RoleTexInternalId, RoleTexInternalId,
RoleTexId, RoleTexName,
RoleTexSource, RoleTexSource,
RoleTexToolTip, RoleTexToolTip,
RoleTexVisible RoleTexVisible

View File

@@ -290,11 +290,15 @@ void MaterialBrowserView::updatePropertyList(const QList<T> &propertyList)
m_widget->materialBrowserModel()->updateMaterialName(node); m_widget->materialBrowserModel()->updateMaterialName(node);
else else
m_previewRequests << node; m_previewRequests << node;
} else if (property.name() == "source") { } else if (isTexture(node)) {
QmlObjectNode selectedTex = m_widget->materialBrowserTexturesModel()->selectedTexture(); QmlObjectNode selectedTex = m_widget->materialBrowserTexturesModel()->selectedTexture();
if (isTexture(node)) if (property.name() == "source")
m_widget->materialBrowserTexturesModel()->updateTextureSource(node); m_widget->materialBrowserTexturesModel()->updateTextureSource(node);
else if (selectedTex.propertyChangeForCurrentState() == node) else if (property.name() == "objectName")
m_widget->materialBrowserTexturesModel()->updateTextureName(node);
} else {
QmlObjectNode selectedTex = m_widget->materialBrowserTexturesModel()->selectedTexture();
if (property.name() == "source" && selectedTex.propertyChangeForCurrentState() == node)
m_widget->materialBrowserTexturesModel()->updateTextureSource(selectedTex); m_widget->materialBrowserTexturesModel()->updateTextureSource(selectedTex);
} }
} }

View File

@@ -48,6 +48,43 @@
#include <QTimer> #include <QTimer>
#include <QColorDialog> #include <QColorDialog>
using namespace Qt::StringLiterals;
namespace {
QString nameFromId(const QString &id, const QString &defaultName)
{
if (id.isEmpty())
return defaultName;
QString newName = id;
static const QRegularExpression sideUnderscores{R"((?:^_+)|(?:_+$))"};
static const QRegularExpression underscores{R"((?:_+))"};
static const QRegularExpression camelCases{R"((?:[A-Z](?=[a-z]))|(?:(?<=[a-z])[A-Z]))"};
newName.remove(sideUnderscores);
// Insert underscore to camel case edges
QRegularExpressionMatchIterator caseMatch = camelCases.globalMatch(newName);
QStack<int> camelCaseIndexes;
while (caseMatch.hasNext())
camelCaseIndexes.push(caseMatch.next().capturedStart());
while (!camelCaseIndexes.isEmpty())
newName.insert(camelCaseIndexes.pop(), '_');
// Replace underscored joints with space
newName.replace(underscores, " ");
newName = newName.trimmed();
if (newName.isEmpty())
return defaultName;
newName[0] = newName[0].toUpper();
return newName;
}
} // namespace
namespace QmlDesigner { namespace QmlDesigner {
TextureEditorView::TextureEditorView(AsynchronousImageCache &imageCache, TextureEditorView::TextureEditorView(AsynchronousImageCache &imageCache,
@@ -389,6 +426,8 @@ void TextureEditorView::handleToolBarAction(int action)
metaInfo.minorVersion()); metaInfo.minorVersion());
#endif #endif
newTextureNode.ensureIdExists(); newTextureNode.ensureIdExists();
VariantProperty textureName = newTextureNode.variantProperty("objectName");
textureName.setValue(nameFromId(newTextureNode.id(), "Texture"_L1));
matLib.defaultNodeListProperty().reparentHere(newTextureNode); matLib.defaultNodeListProperty().reparentHere(newTextureNode);
}); });
break; break;