1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
|
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qurl.h>
#include "qquickvectorimage_p.h"
#include "qquickvectorimage_p_p.h"
#include <QtQuickVectorImageGenerator/private/qquickitemgenerator_p.h>
#include <QtQuickVectorImageGenerator/private/qquickvectorimageglobal_p.h>
#include <QtCore/qloggingcategory.h>
#include <private/qquicktranslate_p.h>
QT_BEGIN_NAMESPACE
/*!
\qmlmodule QtQuick.VectorImage
\title Qt Quick Vector Image QML Types
\ingroup qmlmodules
\brief Provides QML types for displaying vector image files.
\since 6.8
To use the types in this module, import the module with the following line:
\qml
import QtQuick.VectorImage
\endqml
Qt Quick Vector Image provides support for displaying vector image files in a Qt Quick
scene.
It currently supports the \c SVG file format.
Qt supports multiple options for displaying SVG files. For an overview and comparison of the
different ones, see the documentation of the \l{svgtoqml} tool.
\section1 QML Types
*/
void QQuickVectorImagePrivate::setSource(const QUrl &source)
{
Q_Q(QQuickVectorImage);
if (sourceFile == source)
return;
sourceFile = source;
loadSvg();
emit q->sourceChanged();
}
void QQuickVectorImagePrivate::loadSvg()
{
Q_Q(QQuickVectorImage);
QUrl resolvedUrl = qmlContext(q)->resolvedUrl(sourceFile);
QString localFile = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
if (localFile.isEmpty())
return;
QQuickVectorImagePrivate::Format fileFormat = formatFromFilePath(localFile);
if (fileFormat != QQuickVectorImagePrivate::Format::Svg) {
qCWarning(lcQuickVectorImage) << "Unsupported file format";
return;
}
if (svgItem)
svgItem->deleteLater();
svgItem = new QQuickItem(q);
svgItem->setParentItem(q);
QQuickVectorImageGenerator::GeneratorFlags flags;
if (preferredRendererType == QQuickVectorImage::CurveRenderer)
flags.setFlag(QQuickVectorImageGenerator::CurveRenderer);
QQuickItemGenerator generator(localFile, flags, svgItem, qmlContext(q));
generator.generate();
q->setImplicitWidth(svgItem->width());
q->setImplicitHeight(svgItem->height());
q->updateAnimationProperties();
q->updateSvgItemScale();
q->update();
}
QQuickVectorImagePrivate::Format QQuickVectorImagePrivate::formatFromFilePath(const QString &filePath)
{
Q_UNUSED(filePath)
QQuickVectorImagePrivate::Format res = QQuickVectorImagePrivate::Format::Unknown;
if (filePath.endsWith(QLatin1String(".svg")) || filePath.endsWith(QLatin1String(".svgz"))
|| filePath.endsWith(QLatin1String(".svg.gz"))) {
res = QQuickVectorImagePrivate::Format::Svg;
}
return res;
}
/*!
\qmltype VectorImage
\inqmlmodule QtQuick.VectorImage
\inherits Item
\brief Loads a vector image file and displays it in a Qt Quick scene.
\since 6.8
The VectorImage can be used to load a vector image file and display this as an item in a Qt
Quick scene. It currently supports the \c SVG file format.
\note This complements the approach of loading the vector image file through an \l Image
element: \l Image creates a raster version of the image at the requested size. VectorImage
builds a Qt Quick scene that represents the image. This means the resulting item can be scaled
and rotated without losing quality, and it will typically consume less memory than the
rasterized version.
*/
QQuickVectorImage::QQuickVectorImage(QQuickItem *parent)
: QQuickItem(*(new QQuickVectorImagePrivate), parent)
{
setFlag(QQuickItem::ItemHasContents, true);
QObject::connect(this, &QQuickItem::widthChanged, this, &QQuickVectorImage::updateSvgItemScale);
QObject::connect(this, &QQuickItem::heightChanged, this, &QQuickVectorImage::updateSvgItemScale);
QObject::connect(this, &QQuickVectorImage::fillModeChanged, this, &QQuickVectorImage::updateSvgItemScale);
}
/*!
\qmlproperty url QtQuick.VectorImage::VectorImage::source
This property holds the URL of the vector image file to load.
VectorImage currently only supports the \c SVG file format.
*/
QUrl QQuickVectorImage::source() const
{
Q_D(const QQuickVectorImage);
return d->sourceFile;
}
void QQuickVectorImage::setSource(const QUrl &source)
{
Q_D(QQuickVectorImage);
d->setSource(source);
}
void QQuickVectorImage::updateSvgItemScale()
{
Q_D(QQuickVectorImage);
if (d->svgItem == nullptr
|| qFuzzyIsNull(d->svgItem->width())
|| qFuzzyIsNull(d->svgItem->height())) {
return;
}
auto xformProp = d->svgItem->transform();
QQuickScale *scaleTransform = nullptr;
if (xformProp.count(&xformProp) == 0) {
scaleTransform = new QQuickScale;
scaleTransform->setParent(d->svgItem);
xformProp.append(&xformProp, scaleTransform);
} else {
scaleTransform = qobject_cast<QQuickScale *>(xformProp.at(&xformProp, 0));
}
if (scaleTransform != nullptr) {
qreal xScale = width() / d->svgItem->width();
qreal yScale = height() / d->svgItem->height();
switch (d->fillMode) {
case QQuickVectorImage::NoResize:
xScale = yScale = 1.0;
break;
case QQuickVectorImage::PreserveAspectFit:
xScale = yScale = qMin(xScale, yScale);
break;
case QQuickVectorImage::PreserveAspectCrop:
xScale = yScale = qMax(xScale, yScale);
break;
case QQuickVectorImage::Stretch:
// Already correct
break;
};
scaleTransform->setXScale(xScale);
scaleTransform->setYScale(yScale);
}
}
void QQuickVectorImage::updateAnimationProperties()
{
Q_D(QQuickVectorImage);
if (Q_UNLIKELY(d->svgItem == nullptr || d->svgItem->childItems().isEmpty()))
return;
QQuickItem *childItem = d->svgItem->childItems().first();
if (Q_UNLIKELY(d->animations != nullptr)) {
QObject *animationsInfo = childItem->property("animations").value<QObject*>();
if (Q_UNLIKELY(animationsInfo != nullptr)) {
animationsInfo->setProperty("loops", d->animations->loops());
animationsInfo->setProperty("paused", d->animations->paused());
}
}
}
QQuickVectorImageAnimations *QQuickVectorImage::animations()
{
Q_D(QQuickVectorImage);
if (d->animations == nullptr) {
d->animations = new QQuickVectorImageAnimations;
QQml_setParent_noEvent(d->animations, this);
QObject::connect(d->animations, &QQuickVectorImageAnimations::loopsChanged, this, &QQuickVectorImage::updateAnimationProperties);
QObject::connect(d->animations, &QQuickVectorImageAnimations::pausedChanged, this, &QQuickVectorImage::updateAnimationProperties);
}
return d->animations;
}
/*!
\qmlproperty enumeration QtQuick.VectorImage::VectorImage::fillMode
This property defines what happens if the width and height of the VectorImage differs from
the implicit size of its contents.
\value VectorImage.NoResize The contents are still rendered at the size provided by
the input.
\value VectorImage.Stretch The contents are scaled to match the width and height of
the \c{VectorImage}. (This is the default.)
\value VectorImage.PreserveAspectFit The contents are scaled to fit inside the bounds of the
\c VectorImage, while preserving aspect ratio. The
actual bounding rect of the contents will sometimes be
smaller than the \c VectorImage item.
\value VectorImage.PreserveAspectCrop The contents are scaled to fill the \c VectorImage item,
while preserving the aspect ratio. The actual bounds of
the contents will sometimes be larger than the
\c VectorImage item.
*/
QQuickVectorImage::FillMode QQuickVectorImage::fillMode() const
{
Q_D(const QQuickVectorImage);
return d->fillMode;
}
void QQuickVectorImage::setFillMode(FillMode newFillMode)
{
Q_D(QQuickVectorImage);
if (d->fillMode == newFillMode)
return;
d->fillMode = newFillMode;
emit fillModeChanged();
}
/*!
\qmlproperty enumeration QtQuick.VectorImage::VectorImage::preferredRendererType
Requests a specific backend to use for rendering shapes in the \c VectorImage.
\value VectorImage.GeometryRenderer Equivalent to Shape.GeometryRenderer. This backend flattens
curves and triangulates the result. It will give aliased results unless multi-sampling is
enabled, and curve flattening may be visible when the item is scaled.
\value VectorImage.CurveRenderer Equivalent to Shape.CurveRenderer. With this backend, curves
are rendered on the GPU and anti-aliasing is built in. Will typically give better visual
results, but at some extra cost to performance.
The default is \c{VectorImage.GeometryRenderer}.
*/
QQuickVectorImage::RendererType QQuickVectorImage::preferredRendererType() const
{
Q_D(const QQuickVectorImage);
return d->preferredRendererType;
}
void QQuickVectorImage::setPreferredRendererType(RendererType newPreferredRendererType)
{
Q_D(QQuickVectorImage);
if (d->preferredRendererType == newPreferredRendererType)
return;
d->preferredRendererType = newPreferredRendererType;
d->loadSvg();
emit preferredRendererTypeChanged();
}
/*!
\qmlpropertygroup QtQuick.VectorImage::VectorImage::animations
\qmlproperty bool QtQuick.VectorImage::VectorImage::animations.paused
\qmlproperty int QtQuick.VectorImage::VectorImage::animations.loops
\since 6.10
These properties can be used to control animations in the image, if it contains any.
The \c paused property can be set to true to temporarily pause all animations. When the
property is reset to \c false, the animations will resume where they were. By default this
property is \c false.
The \c loops property defines the number of times the animations in the document will repeat.
By default this property is 1. Any animations that is set to loop indefinitely in the source
image will be unaffected by this property. To make all animations in the document repeat
indefinitely, the \c loops property can be set to \c{Animation.Infinite}.
*/
int QQuickVectorImageAnimations::loops() const
{
return m_loops;
}
void QQuickVectorImageAnimations::setLoops(int loops)
{
if (m_loops == loops)
return;
m_loops = loops;
emit loopsChanged();
}
bool QQuickVectorImageAnimations::paused() const
{
return m_paused;
}
void QQuickVectorImageAnimations::setPaused(bool paused)
{
if (m_paused == paused)
return;
m_paused = paused;
emit pausedChanged();
}
void QQuickVectorImageAnimations::restart()
{
QQuickVectorImage *parentVectorImage = qobject_cast<QQuickVectorImage *>(parent());
if (Q_UNLIKELY(parentVectorImage == nullptr)) {
qCWarning(lcQuickVectorImage) << Q_FUNC_INFO << "Parent is not a VectorImage";
return;
}
QQuickVectorImagePrivate *d = QQuickVectorImagePrivate::get(parentVectorImage);
if (Q_UNLIKELY(d->svgItem == nullptr || d->svgItem->childItems().isEmpty()))
return;
QQuickItem *childItem = d->svgItem->childItems().first();
QObject *animationsInfo = childItem->property("animations").value<QObject*>();
if (Q_UNLIKELY(animationsInfo == nullptr)) {
qCWarning(lcQuickVectorImage) << Q_FUNC_INFO << "Item does not have animations property";
return;
}
QMetaObject::invokeMethod(animationsInfo, "restart");
}
QT_END_NAMESPACE
#include <moc_qquickvectorimage_p.cpp>
|