QmlDesigner: Extract asset type stuff from the AssetsLibraryModel

This is in preparation for the task that will show metadata of assets.
The functions for checking the asset type have little to nothing to do
with the model. This change will also clean up the code a bit.

Task-number: QDS-8177
Change-Id: Ibab28f5b63228f626f517a59e2442d2718c2fc07
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Samuel Ghinet
2022-12-15 19:26:49 +02:00
parent e7b4ccf608
commit 4a5359cb86
9 changed files with 272 additions and 130 deletions

View File

@@ -20,6 +20,7 @@ add_qtc_library(QmlDesignerUtils STATIC
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/utils PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/utils
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/utils SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/utils
SOURCES SOURCES
asset.cpp asset.h
designersettings.cpp designersettings.h designersettings.cpp designersettings.h
hdrimage.cpp hdrimage.h hdrimage.cpp hdrimage.h
imageutils.cpp imageutils.h imageutils.cpp imageutils.h

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "assetslibraryiconprovider.h" #include "assetslibraryiconprovider.h"
#include "assetslibrarymodel.h" #include "asset.h"
#include "modelnodeoperations.h" #include "modelnodeoperations.h"
#include <theme.h> #include <theme.h>
@@ -57,24 +57,25 @@ QPixmap AssetsLibraryIconProvider::generateFontIcons(const QString &filePath, co
QPixmap AssetsLibraryIconProvider::fetchPixmap(const QString &id, const QSize &requestedSize) const QPixmap AssetsLibraryIconProvider::fetchPixmap(const QString &id, const QSize &requestedSize) const
{ {
const QString suffix = "*." + id.split('.').last().toLower(); Asset asset(id);
if (id == "browse") { if (id == "browse") {
return Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/browse.png"); return Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/browse.png");
} else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) { } else if (asset.isFont()) {
return generateFontIcons(id, requestedSize); return generateFontIcons(id, requestedSize);
} else if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { } else if (asset.isImage()) {
return Utils::StyleHelper::dpiSpecificImageFile(id); return Utils::StyleHelper::dpiSpecificImageFile(id);
} else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { } else if (asset.isTexture3D()) {
return HdrImage{id}.toPixmap(); return HdrImage{id}.toPixmap();
} else { } else {
QString type; QString type;
if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) if (asset.isShader())
type = "shader"; type = "shader";
else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) else if (asset.isAudio())
type = "sound"; type = "sound";
else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) else if (asset.isVideo())
type = "video"; type = "video";
else if (AssetsLibraryModel::supportedEffectMakerSuffixes().contains(suffix)) else if (asset.isEffect())
type = QmlDesigner::ModelNodeOperations::getEffectIcon(id); type = QmlDesigner::ModelNodeOperations::getEffectIcon(id);
QString pathTemplate = QString(":/AssetsLibrary/images/asset_%1%2.png").arg(type); QString pathTemplate = QString(":/AssetsLibrary/images/asset_%1%2.png").arg(type);

View File

@@ -1,13 +1,13 @@
// Copyright (C) 2021 The Qt Company Ltd. // 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 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include <QCheckBox> #include <QCheckBox>
#include <QFileInfo> #include <QFileInfo>
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QImageReader>
#include <QMessageBox> #include <QMessageBox>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include "asset.h"
#include "assetslibrarymodel.h" #include "assetslibrarymodel.h"
#include <modelnodeoperations.h> #include <modelnodeoperations.h>
@@ -158,9 +158,7 @@ bool AssetsLibraryModel::deleteFolderRecursively(const QModelIndex &folderIndex)
bool AssetsLibraryModel::allFilePathsAreImages(const QStringList &filePaths) const bool AssetsLibraryModel::allFilePathsAreImages(const QStringList &filePaths) const
{ {
return Utils::allOf(filePaths, [](const QString &path) { return Utils::allOf(filePaths, [](const QString &path) {
const QString suffix = "*." + path.split('.').last().toLower(); return Asset(path).isImage();
return AssetsLibraryModel::supportedImageSuffixes().contains(suffix);
}); });
} }
@@ -299,7 +297,7 @@ void AssetsLibraryModel::setRootPath(const QString &newPath)
m_rootPath = newPath; m_rootPath = newPath;
m_sourceFsModel->setRootPath(newPath); m_sourceFsModel->setRootPath(newPath);
m_sourceFsModel->setNameFilters(supportedSuffixes().values()); m_sourceFsModel->setNameFilters(Asset::supportedSuffixes().values());
m_sourceFsModel->setNameFilterDisables(false); m_sourceFsModel->setNameFilterDisables(false);
endResetModel(); endResetModel();
@@ -374,80 +372,4 @@ QString AssetsLibraryModel::parentDirPath(const QString &path) const
return filePath(parentIdx); return filePath(parentIdx);
} }
const QStringList &AssetsLibraryModel::supportedImageSuffixes()
{
static QStringList retList;
if (retList.isEmpty()) {
const QList<QByteArray> suffixes = QImageReader::supportedImageFormats();
for (const QByteArray &suffix : suffixes)
retList.append("*." + QString::fromUtf8(suffix));
}
return retList;
}
const QStringList &AssetsLibraryModel::supportedFragmentShaderSuffixes()
{
static const QStringList retList {"*.frag", "*.glsl", "*.glslf", "*.fsh"};
return retList;
}
const QStringList &AssetsLibraryModel::supportedShaderSuffixes()
{
static const QStringList retList {"*.frag", "*.vert",
"*.glsl", "*.glslv", "*.glslf",
"*.vsh", "*.fsh"};
return retList;
}
const QStringList &AssetsLibraryModel::supportedFontSuffixes()
{
static const QStringList retList {"*.ttf", "*.otf"};
return retList;
}
const QStringList &AssetsLibraryModel::supportedAudioSuffixes()
{
static const QStringList retList {"*.wav", "*.mp3"};
return retList;
}
const QStringList &AssetsLibraryModel::supportedVideoSuffixes()
{
static const QStringList retList {"*.mp4"};
return retList;
}
const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes()
{
// These are file types only supported by 3D textures
static QStringList retList {"*.hdr", "*.ktx"};
return retList;
}
const QStringList &AssetsLibraryModel::supportedEffectMakerSuffixes()
{
// These are file types only supported by Effect Maker
static QStringList retList {"*.qep"};
return retList;
}
const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
{
static QSet<QString> allSuffixes;
if (allSuffixes.isEmpty()) {
auto insertSuffixes = [](const QStringList &suffixes) {
for (const auto &suffix : suffixes)
allSuffixes.insert(suffix);
};
insertSuffixes(supportedImageSuffixes());
insertSuffixes(supportedShaderSuffixes());
insertSuffixes(supportedFontSuffixes());
insertSuffixes(supportedAudioSuffixes());
insertSuffixes(supportedVideoSuffixes());
insertSuffixes(supportedTexture3DSuffixes());
insertSuffixes(supportedEffectMakerSuffixes());
}
return allSuffixes;
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -1,14 +1,14 @@
// Copyright (C) 2021 The Qt Company Ltd. // 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 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once #pragma once
#include <QFileInfo>
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QFileInfo>
#include <utils/qtcassert.h>
#include <utils/filesystemwatcher.h> #include <utils/filesystemwatcher.h>
#include <utils/qtcassert.h>
namespace QmlDesigner { namespace QmlDesigner {
@@ -60,16 +60,6 @@ public:
bool haveFiles() const { return m_haveFiles; } bool haveFiles() const { return m_haveFiles; }
static const QStringList &supportedImageSuffixes();
static const QStringList &supportedFragmentShaderSuffixes();
static const QStringList &supportedShaderSuffixes();
static const QStringList &supportedFontSuffixes();
static const QStringList &supportedAudioSuffixes();
static const QStringList &supportedVideoSuffixes();
static const QStringList &supportedTexture3DSuffixes();
static const QStringList &supportedEffectMakerSuffixes();
static const QSet<QString> &supportedSuffixes();
signals: signals:
void directoryLoaded(const QString &path); void directoryLoaded(const QString &path);
void rootPathChanged(); void rootPathChanged();

View File

@@ -3,8 +3,9 @@
#include "assetslibrarywidget.h" #include "assetslibrarywidget.h"
#include "assetslibrarymodel.h" #include "asset.h"
#include "assetslibraryiconprovider.h" #include "assetslibraryiconprovider.h"
#include "assetslibrarymodel.h"
#include <theme.h> #include <theme.h>
@@ -229,7 +230,7 @@ QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
QSet<QString> suffixes; QSet<QString> suffixes;
for (const AddResourceHandler &handler : handlers) { for (const AddResourceHandler &handler : handlers) {
if (AssetsLibraryModel::supportedSuffixes().contains(handler.filter) != complex) if (Asset(handler.filter).isSupported() != complex)
suffixes.insert(handler.filter); suffixes.insert(handler.filter);
} }
@@ -290,32 +291,32 @@ void AssetsLibraryWidget::startDragAsset(const QStringList &assetPaths, const QP
QPair<QString, QByteArray> AssetsLibraryWidget::getAssetTypeAndData(const QString &assetPath) QPair<QString, QByteArray> AssetsLibraryWidget::getAssetTypeAndData(const QString &assetPath)
{ {
QString suffix = "*." + assetPath.split('.').last().toLower(); Asset asset(assetPath);
if (!suffix.isEmpty()) { if (asset.hasSuffix()) {
if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { if (asset.isImage()) {
// Data: Image format (suffix) // Data: Image format (suffix)
return {Constants::MIME_TYPE_ASSET_IMAGE, suffix.toUtf8()}; return {Constants::MIME_TYPE_ASSET_IMAGE, asset.suffix().toUtf8()};
} else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) { } else if (asset.isFont()) {
// Data: Font family name // Data: Font family name
QRawFont font(assetPath, 10); QRawFont font(assetPath, 10);
QString fontFamily = font.isValid() ? font.familyName() : ""; QString fontFamily = font.isValid() ? font.familyName() : "";
return {Constants::MIME_TYPE_ASSET_FONT, fontFamily.toUtf8()}; return {Constants::MIME_TYPE_ASSET_FONT, fontFamily.toUtf8()};
} else if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) { } else if (asset.isShader()) {
// Data: shader type, frament (f) or vertex (v) // Data: shader type, frament (f) or vertex (v)
return {Constants::MIME_TYPE_ASSET_SHADER, return {Constants::MIME_TYPE_ASSET_SHADER,
AssetsLibraryModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; asset.isFragmentShader() ? "f" : "v"};
} else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) { } else if (asset.isAudio()) {
// No extra data for sounds // No extra data for sounds
return {Constants::MIME_TYPE_ASSET_SOUND, {}}; return {Constants::MIME_TYPE_ASSET_SOUND, {}};
} else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) { } else if (asset.isVideo()) {
// No extra data for videos // No extra data for videos
return {Constants::MIME_TYPE_ASSET_VIDEO, {}}; return {Constants::MIME_TYPE_ASSET_VIDEO, {}};
} else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { } else if (asset.isTexture3D()) {
// Data: Image format (suffix) // Data: Image format (suffix)
return {Constants::MIME_TYPE_ASSET_TEXTURE3D, suffix.toUtf8()}; return {Constants::MIME_TYPE_ASSET_TEXTURE3D, asset.suffix().toUtf8()};
} else if (AssetsLibraryModel::supportedEffectMakerSuffixes().contains(suffix)) { } else if (asset.isEffect()) {
// Data: Effect Maker format (suffix) // Data: Effect Maker format (suffix)
return {Constants::MIME_TYPE_ASSET_EFFECT, suffix.toUtf8()}; return {Constants::MIME_TYPE_ASSET_EFFECT, asset.suffix().toUtf8()};
} }
} }
return {}; return {};

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "propertyeditorimageprovider.h" #include "propertyeditorimageprovider.h"
#include "assetslibrarymodel.h" #include "asset.h"
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <utils/hdrimage.h> #include <utils/hdrimage.h>
@@ -16,12 +16,12 @@ namespace QmlDesigner {
QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QString &id, QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QString &id,
const QSize &requestedSize) const QSize &requestedSize)
{ {
const QString suffix = "*." + id.split('.').last().toLower(); Asset asset(id);
if (suffix == "*.mesh") if (asset.suffix() == "*.mesh")
return m_smallImageCacheProvider.requestImageResponse(id, requestedSize); return m_smallImageCacheProvider.requestImageResponse(id, requestedSize);
if (suffix == "*.builtin") if (asset.suffix() == "*.builtin")
return m_smallImageCacheProvider.requestImageResponse("#" + id.split('.').first(), return m_smallImageCacheProvider.requestImageResponse("#" + id.split('.').first(),
requestedSize); requestedSize);
@@ -29,15 +29,15 @@ QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QSt
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
response.get(), response.get(),
[response = QPointer<QmlDesigner::ImageResponse>(response.get()), suffix, id, requestedSize] { [response = QPointer<QmlDesigner::ImageResponse>(response.get()), asset, requestedSize] {
if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { if (asset.isImage()) {
QImage image = QImage(Utils::StyleHelper::dpiSpecificImageFile(id)); QImage image = QImage(Utils::StyleHelper::dpiSpecificImageFile(asset.id()));
if (!image.isNull()) { if (!image.isNull()) {
response->setImage(image.scaled(requestedSize, Qt::KeepAspectRatio)); response->setImage(image.scaled(requestedSize, Qt::KeepAspectRatio));
return; return;
} }
} else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { } else if (asset.isTexture3D()) {
HdrImage hdr{id}; HdrImage hdr{asset.id()};
if (!hdr.image().isNull()) { if (!hdr.image().isNull()) {
response->setImage(hdr.image().scaled(requestedSize, Qt::KeepAspectRatio)); response->setImage(hdr.image().scaled(requestedSize, Qt::KeepAspectRatio));
return; return;

View File

@@ -0,0 +1,182 @@
// 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 <QImageReader>
#include "asset.h"
namespace QmlDesigner {
Asset::Asset(const QString &filePath)
: m_filePath(filePath)
{
m_suffix = "*." + filePath.split('.').last().toLower();
}
const QStringList &Asset::supportedImageSuffixes()
{
static QStringList retList;
if (retList.isEmpty()) {
const QList<QByteArray> suffixes = QImageReader::supportedImageFormats();
for (const QByteArray &suffix : suffixes)
retList.append("*." + QString::fromUtf8(suffix));
}
return retList;
}
const QStringList &Asset::supportedFragmentShaderSuffixes()
{
static const QStringList retList {"*.frag", "*.glsl", "*.glslf", "*.fsh"};
return retList;
}
const QStringList &Asset::supportedShaderSuffixes()
{
static const QStringList retList {"*.frag", "*.vert",
"*.glsl", "*.glslv", "*.glslf",
"*.vsh", "*.fsh"};
return retList;
}
const QStringList &Asset::supportedFontSuffixes()
{
static const QStringList retList {"*.ttf", "*.otf"};
return retList;
}
const QStringList &Asset::supportedAudioSuffixes()
{
static const QStringList retList {"*.wav", "*.mp3"};
return retList;
}
const QStringList &Asset::supportedVideoSuffixes()
{
static const QStringList retList {"*.mp4"};
return retList;
}
const QStringList &Asset::supportedTexture3DSuffixes()
{
// These are file types only supported by 3D textures
static QStringList retList {"*.hdr", "*.ktx"};
return retList;
}
const QStringList &Asset::supportedEffectMakerSuffixes()
{
// These are file types only supported by Effect Maker
static QStringList retList {"*.qep"};
return retList;
}
const QSet<QString> &Asset::supportedSuffixes()
{
static QSet<QString> allSuffixes;
if (allSuffixes.isEmpty()) {
auto insertSuffixes = [](const QStringList &suffixes) {
for (const auto &suffix : suffixes)
allSuffixes.insert(suffix);
};
insertSuffixes(supportedImageSuffixes());
insertSuffixes(supportedShaderSuffixes());
insertSuffixes(supportedFontSuffixes());
insertSuffixes(supportedAudioSuffixes());
insertSuffixes(supportedVideoSuffixes());
insertSuffixes(supportedTexture3DSuffixes());
insertSuffixes(supportedEffectMakerSuffixes());
}
return allSuffixes;
}
Asset::Type Asset::type() const
{
if (supportedImageSuffixes().contains(m_suffix))
return Asset::Type::Image;
if (supportedFragmentShaderSuffixes().contains(m_suffix))
return Asset::Type::FragmentShader;
if (supportedShaderSuffixes().contains(m_suffix))
return Asset::Type::Shader;
if (supportedFontSuffixes().contains(m_suffix))
return Asset::Type::Font;
if (supportedAudioSuffixes().contains(m_suffix))
return Asset::Type::Audio;
if (supportedVideoSuffixes().contains(m_suffix))
return Asset::Type::Video;
if (supportedTexture3DSuffixes().contains(m_suffix))
return Asset::Type::Texture3D;
if (supportedEffectMakerSuffixes().contains(m_suffix))
return Asset::Type::Effect;
return Asset::Type::Unknown;
}
bool Asset::isImage() const
{
return type() == Asset::Type::Image;
}
bool Asset::isFragmentShader() const
{
return type() == Asset::Type::FragmentShader;
}
bool Asset::isShader() const
{
return type() == Asset::Type::Shader;
}
bool Asset::isFont() const
{
return type() == Asset::Type::Font;
}
bool Asset::isAudio() const
{
return type() == Asset::Type::Audio;
}
bool Asset::isVideo() const
{
return type() == Asset::Type::Video;
}
bool Asset::isTexture3D() const
{
return type() == Asset::Type::Texture3D;
}
bool Asset::isEffect() const
{
return type() == Asset::Type::Effect;
}
const QString Asset::suffix() const
{
return m_suffix;
}
const QString Asset::id() const
{
return m_filePath;
}
bool Asset::isSupported() const
{
return supportedSuffixes().contains(m_filePath);
}
bool Asset::hasSuffix() const
{
return !m_suffix.isEmpty();
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,45 @@
// 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
namespace QmlDesigner {
class Asset
{
public:
enum Type { Unknown, Image, FragmentShader, Font, Audio, Video, Texture3D, Effect, Shader };
Asset(const QString &filePath);
static const QStringList &supportedImageSuffixes();
static const QStringList &supportedFragmentShaderSuffixes();
static const QStringList &supportedShaderSuffixes();
static const QStringList &supportedFontSuffixes();
static const QStringList &supportedAudioSuffixes();
static const QStringList &supportedVideoSuffixes();
static const QStringList &supportedTexture3DSuffixes();
static const QStringList &supportedEffectMakerSuffixes();
static const QSet<QString> &supportedSuffixes();
const QString suffix() const;
const QString id() const;
bool hasSuffix() const;
Type type() const;
bool isImage() const;
bool isFragmentShader() const;
bool isShader() const;
bool isFont() const;
bool isAudio() const;
bool isVideo() const;
bool isTexture3D() const;
bool isEffect() const;
bool isSupported() const;
private:
QString m_filePath;
QString m_suffix;
};
} // namespace QmlDesigner

View File

@@ -921,7 +921,7 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D([[maybe_unu
if (toolStates.contains("syncBackgroundColor")) { if (toolStates.contains("syncBackgroundColor")) {
bool sync = toolStates["syncBackgroundColor"].toBool(); bool sync = toolStates["syncBackgroundColor"].toBool();
if (sync) { if (sync) {
QList<QColor> colors = {helper->sceneEnvironmentColor(sceneId)}; QList<QColor> colors{helper->sceneEnvironmentColor(sceneId)};
View3DActionCommand cmd(View3DActionType::SelectBackgroundColor, View3DActionCommand cmd(View3DActionType::SelectBackgroundColor,
QVariant::fromValue(colors)); QVariant::fromValue(colors));
view3DAction(cmd); view3DAction(cmd);
@@ -2274,7 +2274,7 @@ void Qt5InformationNodeInstanceServer::setSceneEnvironmentColor(const PropertyVa
if (toolStates.contains("syncBackgroundColor")) { if (toolStates.contains("syncBackgroundColor")) {
bool sync = toolStates["syncBackgroundColor"].toBool(); bool sync = toolStates["syncBackgroundColor"].toBool();
QList<QColor> colors = {color}; QList<QColor> colors{color};
if (sync) { if (sync) {
View3DActionCommand cmd(View3DActionType::SelectBackgroundColor, View3DActionCommand cmd(View3DActionType::SelectBackgroundColor,
QVariant::fromValue(colors)); QVariant::fromValue(colors));