1 | // Copyright (C) 2020 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | #include "qgraphicssvgitem.h" |
4 | |
5 | #if !defined(QT_NO_GRAPHICSVIEW) |
6 | |
7 | #include "qpainter.h" |
8 | #include "qstyleoption.h" |
9 | #include "qsvgrenderer.h" |
10 | #include "qdebug.h" |
11 | |
12 | #include <QtCore/private/qobject_p.h> |
13 | #include <QtWidgets/private/qgraphicsitem_p.h> |
14 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | class QGraphicsSvgItemPrivate : public QGraphicsItemPrivate |
18 | { |
19 | public: |
20 | Q_DECLARE_PUBLIC(QGraphicsSvgItem) |
21 | |
22 | QGraphicsSvgItemPrivate() |
23 | : renderer(0), shared(false) |
24 | { |
25 | } |
26 | |
27 | void init(QGraphicsItem *parent) |
28 | { |
29 | Q_Q(QGraphicsSvgItem); |
30 | q->setParentItem(parent); |
31 | renderer = new QSvgRenderer(q); |
32 | QObject::connect(sender: renderer, SIGNAL(repaintNeeded()), |
33 | receiver: q, SLOT(_q_repaintItem())); |
34 | q->setCacheMode(mode: QGraphicsItem::DeviceCoordinateCache); |
35 | q->setMaximumCacheSize(QSize(1024, 768)); |
36 | } |
37 | |
38 | void _q_repaintItem() |
39 | { |
40 | q_func()->update(); |
41 | } |
42 | |
43 | inline void updateDefaultSize() |
44 | { |
45 | QRectF bounds; |
46 | if (elemId.isEmpty()) { |
47 | bounds = QRectF(QPointF(0, 0), renderer->defaultSize()); |
48 | } else { |
49 | bounds = renderer->boundsOnElement(id: elemId); |
50 | } |
51 | if (boundingRect.size() != bounds.size()) { |
52 | q_func()->prepareGeometryChange(); |
53 | boundingRect.setSize(bounds.size()); |
54 | } |
55 | } |
56 | |
57 | QSvgRenderer *renderer; |
58 | QRectF boundingRect; |
59 | bool shared; |
60 | QString elemId; |
61 | }; |
62 | |
63 | /*! |
64 | \class QGraphicsSvgItem |
65 | \inmodule QtSvgWidgets |
66 | \ingroup graphicsview-api |
67 | \brief The QGraphicsSvgItem class is a QGraphicsItem that can be used to render |
68 | the contents of SVG files. |
69 | |
70 | \since 4.2 |
71 | |
72 | QGraphicsSvgItem provides a way of rendering SVG files onto QGraphicsView. |
73 | QGraphicsSvgItem can be created by passing the SVG file to be rendered to |
74 | its constructor or by explicit setting a shared QSvgRenderer on it. |
75 | |
76 | Note that setting QSvgRenderer on a QGraphicsSvgItem doesn't make the item take |
77 | ownership of the renderer, therefore if using setSharedRenderer() method one has |
78 | to make sure that the lifetime of the QSvgRenderer object will be at least as long |
79 | as that of the QGraphicsSvgItem. |
80 | |
81 | QGraphicsSvgItem provides a way of rendering only parts of the SVG files via |
82 | the setElementId. If setElementId() method is called, only the SVG element |
83 | (and its children) with the passed id will be renderer. This provides a convenient |
84 | way of selectively rendering large SVG files that contain a number of discrete |
85 | elements. For example the following code renders only jokers from a SVG file |
86 | containing a whole card deck: |
87 | |
88 | \snippet src_svg_qgraphicssvgitem.cpp 0 |
89 | |
90 | Size of the item can be set via direct manipulation of the items |
91 | transformation matrix. |
92 | |
93 | By default the SVG rendering is cached using QGraphicsItem::DeviceCoordinateCache |
94 | mode to speedup the display of items. Caching can be disabled by passing |
95 | QGraphicsItem::NoCache to the QGraphicsItem::setCacheMode() method. |
96 | |
97 | \sa QSvgWidget, {Qt SVG C++ Classes}, QGraphicsItem, QGraphicsView |
98 | */ |
99 | |
100 | /*! |
101 | Constructs a new SVG item with the given \a parent. |
102 | */ |
103 | QGraphicsSvgItem::QGraphicsSvgItem(QGraphicsItem *parent) |
104 | : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0) |
105 | { |
106 | Q_D(QGraphicsSvgItem); |
107 | d->init(parent); |
108 | } |
109 | |
110 | /*! |
111 | Constructs a new item with the given \a parent and loads the contents of the |
112 | SVG file with the specified \a fileName. |
113 | */ |
114 | QGraphicsSvgItem::QGraphicsSvgItem(const QString &fileName, QGraphicsItem *parent) |
115 | : QGraphicsObject(*new QGraphicsSvgItemPrivate(), 0) |
116 | { |
117 | Q_D(QGraphicsSvgItem); |
118 | d->init(parent); |
119 | d->renderer->load(filename: fileName); |
120 | d->updateDefaultSize(); |
121 | } |
122 | |
123 | /*! |
124 | Returns the currently use QSvgRenderer. |
125 | */ |
126 | QSvgRenderer *QGraphicsSvgItem::renderer() const |
127 | { |
128 | return d_func()->renderer; |
129 | } |
130 | |
131 | |
132 | /*! |
133 | Returns the bounding rectangle of this item. |
134 | */ |
135 | QRectF QGraphicsSvgItem::boundingRect() const |
136 | { |
137 | Q_D(const QGraphicsSvgItem); |
138 | return d->boundingRect; |
139 | } |
140 | |
141 | // from qgraphicsitem.cpp |
142 | void Q_WIDGETS_EXPORT qt_graphicsItem_highlightSelected(QGraphicsItem *item, QPainter *painter, |
143 | const QStyleOptionGraphicsItem *option); |
144 | |
145 | /*! |
146 | \reimp |
147 | */ |
148 | void QGraphicsSvgItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, |
149 | QWidget *widget) |
150 | { |
151 | // Q_UNUSED(option); |
152 | Q_UNUSED(widget); |
153 | |
154 | Q_D(QGraphicsSvgItem); |
155 | if (!d->renderer->isValid()) |
156 | return; |
157 | |
158 | if (d->elemId.isEmpty()) |
159 | d->renderer->render(p: painter, bounds: d->boundingRect); |
160 | else |
161 | d->renderer->render(p: painter, elementId: d->elemId, bounds: d->boundingRect); |
162 | |
163 | if (option->state & QStyle::State_Selected) |
164 | qt_graphicsItem_highlightSelected(item: this, painter, option); |
165 | } |
166 | |
167 | /*! |
168 | \reimp |
169 | */ |
170 | int QGraphicsSvgItem::type() const |
171 | { |
172 | return Type; |
173 | } |
174 | |
175 | /*! |
176 | \property QGraphicsSvgItem::maximumCacheSize |
177 | \since 4.6 |
178 | |
179 | This property holds the maximum size of the device coordinate cache |
180 | for this item. |
181 | */ |
182 | |
183 | /*! |
184 | Sets the maximum device coordinate cache size of the item to \a size. |
185 | If the item is cached using QGraphicsItem::DeviceCoordinateCache mode, |
186 | caching is bypassed if the extension of the item in device coordinates |
187 | is larger than \a size. |
188 | |
189 | The cache corresponds to the QPixmap which is used to cache the |
190 | results of the rendering. |
191 | Use QPixmapCache::setCacheLimit() to set limitations on the whole cache |
192 | and use setMaximumCacheSize() when setting cache size for individual |
193 | items. |
194 | |
195 | \sa QGraphicsItem::cacheMode() |
196 | */ |
197 | void QGraphicsSvgItem::setMaximumCacheSize(const QSize &size) |
198 | { |
199 | QGraphicsItem::d_ptr->setExtra(type: QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize, value: size); |
200 | update(); |
201 | } |
202 | |
203 | /*! |
204 | Returns the current maximum size of the device coordinate cache for this item. |
205 | If the item is cached using QGraphicsItem::DeviceCoordinateCache mode, |
206 | caching is bypassed if the extension of the item in device coordinates |
207 | is larger than the maximum size. |
208 | |
209 | The default maximum cache size is 1024x768. |
210 | QPixmapCache::cacheLimit() gives the |
211 | cumulative bounds of the whole cache, whereas maximumCacheSize() refers |
212 | to a maximum cache size for this particular item. |
213 | |
214 | \sa QGraphicsItem::cacheMode() |
215 | */ |
216 | QSize QGraphicsSvgItem::maximumCacheSize() const |
217 | { |
218 | return QGraphicsItem::d_ptr->extra(type: QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize(); |
219 | } |
220 | |
221 | /*! |
222 | \property QGraphicsSvgItem::elementId |
223 | \since 4.6 |
224 | |
225 | This property holds the element's XML ID. |
226 | */ |
227 | |
228 | /*! |
229 | Sets the XML ID of the element to \a id. |
230 | */ |
231 | void QGraphicsSvgItem::setElementId(const QString &id) |
232 | { |
233 | Q_D(QGraphicsSvgItem); |
234 | d->elemId = id; |
235 | d->updateDefaultSize(); |
236 | update(); |
237 | } |
238 | |
239 | /*! |
240 | Returns the XML ID the element that is currently |
241 | being rendered. Returns an empty string if the whole |
242 | file is being rendered. |
243 | */ |
244 | QString QGraphicsSvgItem::elementId() const |
245 | { |
246 | Q_D(const QGraphicsSvgItem); |
247 | return d->elemId; |
248 | } |
249 | |
250 | /*! |
251 | Sets \a renderer to be a shared QSvgRenderer on the item. By |
252 | using this method one can share the same QSvgRenderer on a number |
253 | of items. This means that the SVG file will be parsed only once. |
254 | QSvgRenderer passed to this method has to exist for as long as |
255 | this item is used. |
256 | */ |
257 | void QGraphicsSvgItem::setSharedRenderer(QSvgRenderer *renderer) |
258 | { |
259 | Q_D(QGraphicsSvgItem); |
260 | if (!d->shared) |
261 | delete d->renderer; |
262 | |
263 | d->renderer = renderer; |
264 | d->shared = true; |
265 | |
266 | d->updateDefaultSize(); |
267 | |
268 | update(); |
269 | } |
270 | |
271 | /*! |
272 | \deprecated |
273 | |
274 | Use QGraphicsItem::setCacheMode() instead. Passing true to this function is equivalent |
275 | to QGraphicsItem::setCacheMode(QGraphicsItem::DeviceCoordinateCache). |
276 | */ |
277 | void QGraphicsSvgItem::setCachingEnabled(bool caching) |
278 | { |
279 | setCacheMode(mode: caching ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache); |
280 | } |
281 | |
282 | /*! |
283 | \deprecated |
284 | |
285 | Use QGraphicsItem::cacheMode() instead. |
286 | */ |
287 | bool QGraphicsSvgItem::isCachingEnabled() const |
288 | { |
289 | return cacheMode() != QGraphicsItem::NoCache; |
290 | } |
291 | |
292 | QT_END_NAMESPACE |
293 | |
294 | #include "moc_qgraphicssvgitem.cpp" |
295 | |
296 | #endif // QT_NO_GRAPHICSVIEW |
297 | |