forked from qt-creator/qt-creator
QmlDesigner: Show font, audio, and shader files in assets tab
Icon for font files is a short text using the font in the file. Audio and shader files use system default icons for those types for now. Task-number: QDS-3326 Change-Id: Id3d416857b8abe5d803997956dcf450ac115b179 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -35,9 +35,102 @@
|
|||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QRawFont>
|
||||||
|
#include <QGlyphRun>
|
||||||
|
#include <qmath.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
static const QStringList &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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QStringList &supportedShaderSuffixes()
|
||||||
|
{
|
||||||
|
static const QStringList retList {"frag", "vert",
|
||||||
|
"glsl", "glslv", "glslf",
|
||||||
|
"vsh", "fsh"};
|
||||||
|
return retList;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QStringList &supportedFontSuffixes()
|
||||||
|
{
|
||||||
|
static const QStringList retList {"ttf", "otf"};
|
||||||
|
return retList;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QStringList &supportedAudioSuffixes()
|
||||||
|
{
|
||||||
|
static const QStringList retList {"wav"};
|
||||||
|
return retList;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QPixmap generateFontImage(const QFileInfo &info, const QSize &size)
|
||||||
|
{
|
||||||
|
static QHash<QString, QPixmap> fontImageCache;
|
||||||
|
const QString file = info.absoluteFilePath();
|
||||||
|
const QString key = QStringLiteral("%1@%2@%3").arg(file).arg(size.width()).arg(size.height());
|
||||||
|
if (!fontImageCache.contains(key)) {
|
||||||
|
QPixmap pixmap(size);
|
||||||
|
pixmap.fill(Qt::transparent);
|
||||||
|
qreal pixelSize = size.width() / 2.;
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
QRawFont font(file, pixelSize);
|
||||||
|
if (!font.isValid())
|
||||||
|
return pixmap;
|
||||||
|
QGlyphRun gr;
|
||||||
|
gr.setRawFont(font);
|
||||||
|
QVector<quint32> indices = font.glyphIndexesForString("Abc");
|
||||||
|
if (indices.isEmpty())
|
||||||
|
return pixmap;
|
||||||
|
const QVector<QPointF> advances = font.advancesForGlyphIndexes(indices);
|
||||||
|
QVector<QPointF> positions;
|
||||||
|
QPointF totalAdvance;
|
||||||
|
for (const QPointF &advance : advances) {
|
||||||
|
positions.append(totalAdvance);
|
||||||
|
totalAdvance += advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
gr.setGlyphIndexes(indices);
|
||||||
|
gr.setPositions(positions);
|
||||||
|
QRectF bounds = gr.boundingRect();
|
||||||
|
if (bounds.width() <= 0 || bounds.height() <= 0)
|
||||||
|
return pixmap;
|
||||||
|
|
||||||
|
bounds.moveCenter({size.width() / 2., size.height() / 2.});
|
||||||
|
|
||||||
|
// Bounding rectangle doesn't necessarily contain the entirety of glyphs for some
|
||||||
|
// reason, so also check totalAdvance for overflow.
|
||||||
|
qreal limitX = qMax(bounds.width(), totalAdvance.x());
|
||||||
|
if (size.width() < limitX) {
|
||||||
|
pixelSize = qreal(qFloor(pixelSize * size.width() / limitX));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
qreal limitY = qMax(bounds.height(), totalAdvance.y());
|
||||||
|
if (size.height() < limitY) {
|
||||||
|
pixelSize = qreal(qFloor(pixelSize * size.height() / limitY));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(&pixmap);
|
||||||
|
painter.setPen(Theme::getColor(Theme::DStextColor));
|
||||||
|
painter.drawGlyphRun(bounds.bottomLeft(), gr);
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
fontImageCache[key] = pixmap;
|
||||||
|
}
|
||||||
|
return fontImageCache[key];
|
||||||
|
}
|
||||||
|
|
||||||
class ItemLibraryFileIconProvider : public QFileIconProvider
|
class ItemLibraryFileIconProvider : public QFileIconProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -46,20 +139,21 @@ public:
|
|||||||
QIcon icon( const QFileInfo & info ) const override
|
QIcon icon( const QFileInfo & info ) const override
|
||||||
{
|
{
|
||||||
QIcon icon;
|
QIcon icon;
|
||||||
|
const QString suffix = info.suffix();
|
||||||
|
|
||||||
for (auto iconSize : iconSizes) {
|
for (auto iconSize : iconSizes) {
|
||||||
|
// Provide icon depending on suffix
|
||||||
|
QPixmap pixmap;
|
||||||
|
|
||||||
QPixmap pixmap(info.absoluteFilePath());
|
if (supportedImageSuffixes().contains(suffix))
|
||||||
|
pixmap.load(info.absoluteFilePath());
|
||||||
|
else if (supportedFontSuffixes().contains(suffix))
|
||||||
|
pixmap = generateFontImage(info, iconSize);
|
||||||
|
|
||||||
if (pixmap.isNull())
|
if (pixmap.isNull())
|
||||||
return QFileIconProvider::icon(info);
|
return QFileIconProvider::icon(info);
|
||||||
|
|
||||||
if (pixmap.width() == iconSize.width()
|
if ((pixmap.width() > iconSize.width()) || (pixmap.height() > iconSize.height()))
|
||||||
&& pixmap.height() == iconSize.height())
|
|
||||||
return pixmap;
|
|
||||||
|
|
||||||
if ((pixmap.width() > iconSize.width())
|
|
||||||
|| (pixmap.height() > iconSize.height()))
|
|
||||||
pixmap = pixmap.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
pixmap = pixmap.scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
|
||||||
icon.addPixmap(pixmap);
|
icon.addPixmap(pixmap);
|
||||||
@@ -68,7 +162,8 @@ public:
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QSize> iconSizes = {{256, 196},{128, 96},{64, 64},{32, 32}};
|
// Generated icon sizes should match ItemLibraryResourceView icon sizes
|
||||||
|
QList<QSize> iconSizes = {{192, 192}, {96, 96}, {48, 48}, {32, 32}};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -201,9 +296,15 @@ QModelIndex CustomFileSystemModel::updatePath(const QString &newPath)
|
|||||||
if (searchFilter.contains(QLatin1Char('.'))) {
|
if (searchFilter.contains(QLatin1Char('.'))) {
|
||||||
nameFilterList.append(QString(QStringLiteral("*%1*")).arg(searchFilter));
|
nameFilterList.append(QString(QStringLiteral("*%1*")).arg(searchFilter));
|
||||||
} else {
|
} else {
|
||||||
foreach (const QByteArray &extension, QImageReader::supportedImageFormats()) {
|
const QString filterTemplate("*%1*.%2");
|
||||||
nameFilterList.append(QString(QStringLiteral("*%1*.%2")).arg(searchFilter, QString::fromUtf8(extension)));
|
for (const QString &ext : supportedImageSuffixes())
|
||||||
}
|
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
|
||||||
|
for (const QString &ext : supportedShaderSuffixes())
|
||||||
|
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
|
||||||
|
for (const QString &ext : supportedFontSuffixes())
|
||||||
|
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
|
||||||
|
for (const QString &ext : supportedAudioSuffixes())
|
||||||
|
nameFilterList.append(filterTemplate.arg(searchFilter, ext));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_files.clear();
|
m_files.clear();
|
||||||
|
Reference in New Issue
Block a user