1/*
2 SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#ifndef KSVG_SVG_H
8#define KSVG_SVG_H
9
10#include <QObject>
11#include <QPixmap>
12
13#include <ksvg/imageset.h>
14#include <ksvg/ksvg_export.h>
15
16class QPainter;
17class QPoint;
18class QPointF;
19class QRect;
20class QRectF;
21class QSize;
22class QSizeF;
23class QMatrix;
24
25/**
26 * The KSvg namespace.
27 */
28namespace KSvg
29{
30class FrameSvgPrivate;
31class SvgPrivate;
32
33/**
34 * @class Svg ksvg/svg.h <KSvg/Svg>
35 *
36 * @short A theme aware image-centric SVG class
37 *
38 * KSvg::Svg provides a class for rendering SVG images to a QPainter in a
39 * convenient manner. Unless an absolute path to a file is provided, it loads
40 * the SVG document using KSvg::ImageSet. It also provides a number of internal
41 * optimizations to help lower the cost of painting SVGs, such as caching.
42 *
43 * @see KSvg::FrameSvg
44 **/
45class KSVG_EXPORT Svg : public QObject
46{
47 Q_OBJECT
48 Q_PROPERTY(QSizeF size READ size WRITE resize NOTIFY sizeChanged)
49 Q_PROPERTY(bool multipleImages READ containsMultipleImages WRITE setContainsMultipleImages)
50 Q_PROPERTY(QString imagePath READ imagePath WRITE setImagePath NOTIFY imagePathChanged)
51 Q_PROPERTY(bool usingRenderingCache READ isUsingRenderingCache WRITE setUsingRenderingCache)
52 Q_PROPERTY(bool fromCurrentImageSet READ fromCurrentImageSet NOTIFY fromCurrentImageSetChanged)
53 Q_PROPERTY(KSvg::Svg::Status status READ status WRITE setStatus NOTIFY statusChanged)
54 Q_PROPERTY(KSvg::Svg::ColorSet colorSet READ colorSet WRITE setColorSet NOTIFY colorSetChanged)
55
56public:
57 enum Status {
58 Normal = 0,
59 Selected,
60 Inactive,
61 };
62 Q_ENUM(Status)
63
64 // FIXME? Those are copied from KColorScheme because is needed to make it a Q_ENUM
65 enum ColorSet { View, Window, Button, Selection, Tooltip, Complementary, Header };
66 Q_ENUM(ColorSet)
67
68 enum StyleSheetColor {
69 Text,
70 Background,
71 Highlight,
72 HighlightedText,
73 PositiveText,
74 NeutralText,
75 NegativeText,
76
77 ButtonText,
78 ButtonBackground,
79 ButtonHover,
80 ButtonFocus,
81 ButtonHighlightedText,
82 ButtonPositiveText,
83 ButtonNeutralText,
84 ButtonNegativeText,
85
86 ViewText,
87 ViewBackground,
88 ViewHover,
89 ViewFocus,
90 ViewHighlightedText,
91 ViewPositiveText,
92 ViewNeutralText,
93 ViewNegativeText,
94
95 TooltipText,
96 TooltipBackground,
97 TooltipHover,
98 TooltipFocus,
99 TooltipHighlightedText,
100 TooltipPositiveText,
101 TooltipNeutralText,
102 TooltipNegativeText,
103
104 ComplementaryText,
105 ComplementaryBackground,
106 ComplementaryHover,
107 ComplementaryFocus,
108 ComplementaryHighlightedText,
109 ComplementaryPositiveText,
110 ComplementaryNeutralText,
111 ComplementaryNegativeText,
112
113 HeaderText,
114 HeaderBackground,
115 HeaderHover,
116 HeaderFocus,
117 HeaderHighlightedText,
118 HeaderPositiveText,
119 HeaderNeutralText,
120 HeaderNegativeText
121 };
122 Q_ENUM(StyleSheetColor);
123
124 /**
125 * @brief This method constructs an SVG object that implicitly shares and
126 * caches rendering.
127 *
128 * Unlike QSvgRenderer, which this class uses internally,
129 * KSvg::Svg represents an image generated from an SVG. As such, it has a
130 * related size and transform matrix (the latter being provided by the
131 * painter used to paint the image).
132 *
133 * The size is initialized to be the SVG's native size.
134 *
135 * @param parent options QObject to parent this to
136 *
137 * @related KSvg::ImageSet
138 */
139 explicit Svg(QObject *parent = nullptr);
140 ~Svg() override;
141
142 /**
143 * @brief This method sets the device pixel ratio for the Svg.
144 *
145 * This is the ratio between image pixels and device-independent pixels. The
146 * SVG will produce pixmaps scaled by devicePixelRatio, but all the sizes
147 * and element rects will not be altered. The default value is 1.0 and the
148 * scale will be done rounded to the floor integer.
149 *
150 * Setting it to something higher will make all the elements of this SVG
151 * appear bigger.
152 */
153 void setDevicePixelRatio(qreal factor);
154
155 /**
156 * @brief This method returns the device pixel ratio for this Svg.
157 */
158 qreal devicePixelRatio() const;
159
160 /**
161 * @brief This method returns a pixmap of the SVG represented by this
162 * object.
163 *
164 * The size of the pixmap will be the size of this Svg object (size()) if
165 * containsMultipleImages is @c true; otherwise, it will be the size of the
166 * requested element after the whole SVG has been scaled to size().
167 *
168 * @param elementId the ID string of the element to render, or an empty
169 * string for the whole SVG (the default)
170 * @return a QPixmap of the rendered SVG
171 */
172 Q_INVOKABLE QPixmap pixmap(const QString &elementID = QString());
173
174 /**
175 * @brief This method returns an image of the SVG represented by this
176 * object.
177 *
178 * The size of the image will be the size of this Svg object (size()) if
179 * containsMultipleImages is @c true; otherwise, it will be the size of the
180 * requested element after the whole SVG has been scaled to size().
181 *
182 * @param elementId the ID string of the element to render, or an empty
183 * string for the whole SVG (the default)
184 * @return a QPixmap of the rendered SVG
185 */
186 Q_INVOKABLE QImage image(const QSize &size, const QString &elementID = QString());
187
188 /**
189 * @brief This method paints all or part of the SVG represented by this
190 * object.
191 *
192 * The size of the painted area will be the size of this Svg object (size())
193 * if containsMultipleImages is @c true; otherwise, it will be the size of
194 * the requested element after the whole SVG has been scaled to size().
195 *
196 * @param painter the QPainter to use
197 * @param point the position to start drawing; the entire svg will be
198 * drawn starting at this point.
199 * @param elementId the ID string of the element to render, or an empty
200 * string for the whole SVG (the default)
201 */
202 Q_INVOKABLE void paint(QPainter *painter, const QPointF &point, const QString &elementID = QString());
203
204 /**
205 * @brief This method paints all or part of the SVG represented by this
206 * object.
207 *
208 * The size of the painted area will be the size of this Svg object (size())
209 * if containsMultipleImages is @c true; otherwise, it will be the size of
210 * the requested element after the whole SVG has been scaled to size().
211 *
212 * @param painter the QPainter to use
213 * @param x the horizontal coordinate to start painting from
214 * @param y the vertical coordinate to start painting from
215 * @param elementId the ID string of the element to render, or an empty
216 * string for the whole SVG (the default)
217 */
218 Q_INVOKABLE void paint(QPainter *painter, int x, int y, const QString &elementID = QString());
219
220 /**
221 * @brief This method paints all or part of the SVG represented by this
222 * object.
223 *
224 * @param painter the QPainter to use
225 * @param rect the rect to draw into; if smaller than the current size
226 * the drawing is starting at this point.
227 * @param elementId the ID string of the element to render, or an empty
228 * string for the whole SVG (the default)
229 */
230 Q_INVOKABLE void paint(QPainter *painter, const QRectF &rect, const QString &elementID = QString());
231
232 /**
233 * @brief This method paints all or part of the SVG represented by this
234 * object.
235 *
236 * @param painter the QPainter to use
237 * @param x the horizontal coordinate to start painting from
238 * @param y the vertical coordinate to start painting from
239 * @param width the width of the element to draw
240 * @param height the height of the element do draw
241 * @param elementId the ID string of the element to render, or an empty
242 * string for the whole SVG (the default)
243 */
244 Q_INVOKABLE void paint(QPainter *painter, int x, int y, int width, int height, const QString &elementID = QString());
245
246 /**
247 * @brief This method returns the size of the SVG.
248 *
249 * If the SVG has been resized with resize(), that size will be returned;
250 * otherwise, the natural size of the SVG will be returned.
251 *
252 * If containsMultipleImages is @c true, each element of the SVG will be
253 * rendered at this size by default.
254 *
255 * @return the current size of the SVG
256 **/
257 QSizeF size() const;
258
259 /**
260 * @brief This method resizes the rendered image.
261 *
262 * Rendering will actually take place on the next call to paint.
263 *
264 * If containsMultipleImages is @c true, each element of the SVG will be
265 * rendered at this size by default; otherwise, the entire image will be
266 * scaled to this size and each element will be scaled appropriately.
267 *
268 * @param width the new width
269 * @param height the new height
270 **/
271 Q_INVOKABLE void resize(qreal width, qreal height);
272
273 /**
274 * @brief This method resizes the rendered image.
275 *
276 * Rendering will actually take place on the next call to paint.
277 *
278 * If containsMultipleImages is @c true, each element of the SVG will be
279 * rendered at this size by default; otherwise, the entire image will be
280 * scaled to this size and each element will be scaled appropriately.
281 *
282 * @param size the new size of the image
283 **/
284 Q_INVOKABLE void resize(const QSizeF &size);
285
286 /**
287 * @brief This method resizes the rendered image to the natural size of the
288 * SVG.
289 *
290 * Rendering will actually take place on the next call to paint.
291 **/
292 Q_INVOKABLE void resize();
293
294 /**
295 * @brief This method returns the size of a given element.
296 *
297 * This is the size of the element with ID @p elementId after the SVG
298 * has been scaled (see resize()). Note that this is unaffected by
299 * the containsMultipleImages property.
300 *
301 * @param elementId the id of the element to check
302 * @return the size of a given element, given the current size of the SVG
303 **/
304 Q_INVOKABLE QSizeF elementSize(const QString &elementId) const;
305
306 QSizeF elementSize(QStringView elementId) const;
307
308 /**
309 * @brief This method returns the bounding rect of a given element.
310 *
311 * This is the bounding rect of the element with ID @p elementId after the
312 * SVG has been scaled (see resize()). Note that this is unaffected by the
313 * containsMultipleImages property.
314 *
315 * @param elementId the id of the element to check
316 * @return the current rect of a given element, given the current size of the SVG
317 **/
318 Q_INVOKABLE QRectF elementRect(const QString &elementId) const;
319
320 QRectF elementRect(QStringView elementId) const;
321
322 /**
323 * @brief This method checks whether an element exists in the loaded SVG.
324 *
325 * @param elementId the id of the element to check for
326 * @return @c true if the element is defined in the SVG, otherwise @c false
327 **/
328 Q_INVOKABLE bool hasElement(const QString &elementId) const;
329
330 bool hasElement(QStringView elementId) const;
331
332 /**
333 * @brief This method checks whether this object is backed by a valid SVG
334 * file.
335 *
336 * This method can be expensive as it causes disk access.
337 *
338 * @return @c true if the SVG file exists and the document is valid,
339 * otherwise @c false.
340 **/
341 Q_INVOKABLE bool isValid() const;
342
343 /**
344 * @brief This method sets whether the SVG contains a single image or
345 * multiple ones.
346 *
347 * If this is set to @c true, the SVG will be treated as a collection of
348 * related images, rather than a consistent drawing.
349 *
350 * In particular, when individual elements are rendered, this affects
351 * whether the elements are resized to size() by default. See paint() and
352 * pixmap().
353 *
354 * @see ::paint()
355 * @see ::pixmap()
356 *
357 * @param multiple true if the svg contains multiple images
358 */
359 void setContainsMultipleImages(bool multiple);
360
361 /**
362 * @brief This method returns whether the SVG contains multiple images.
363 *
364 * If this is @c true, the SVG will be treated as a collection of related
365 * images, rather than a consistent drawing.
366 *
367 * @return @c true if the SVG will be treated as containing multiple images,
368 * @c false if it will be treated as a coherent image.
369 */
370 bool containsMultipleImages() const;
371
372 /**
373 * @brief This method sets the SVG file to render.
374 *
375 * Relative paths are looked for in the current Svg theme, and should not
376 * include the file extension (.svg and .svgz files will be searched for).
377 * include the file extension; files with the .svg and .svgz extensions will be
378 * found automatically.
379 *
380 * @see ImageSet::imagePath()
381 *
382 * If the parent object of this Svg is a KSvg::Applet, relative paths will
383 * be searched for in the applet's package first.
384 *
385 * @param svgFilePath either an absolute path to an SVG file, or an image
386 * name.
387 */
388 virtual void setImagePath(const QString &svgFilePath);
389
390 /**
391 * @brief This method returns the SVG file to render.
392 *
393 * If this SVG is themed, this will be a relative path, and will not
394 * include a file extension.
395 *
396 * @return either an absolute path to an SVG file, or an image name
397 * @see ImageSet::imagePath()
398 */
399 QString imagePath() const;
400
401 /**
402 * @brief This method sets whether or not to cache the results of rendering
403 * to pixmaps.
404 *
405 * If the SVG is resized and re-rendered often (and does not keep using the
406 * same small set of pixmap dimensions), then it may be less efficient to do
407 * disk caching. A good example might be a progress meter that uses an Svg
408 * object to paint itself: the meter will be changing often enough, with
409 * enough unpredictability and without re-use of the previous pixmaps to
410 * not get a gain from caching.
411 *
412 * Most Svg objects should use the caching feature, however.
413 * Therefore, the default is to use the render cache.
414 *
415 * @param useCache true to cache rendered pixmaps
416 * @since 4.3
417 */
418 void setUsingRenderingCache(bool useCache);
419
420 /**
421 * Whether the rendering cache is being used.
422 *
423 * @brief This method returns whether the Svg object is using caching for
424 * rendering results.
425 *
426 * @since 4.3
427 */
428 bool isUsingRenderingCache() const;
429
430 /**
431 * @brief This method returns whether the current theme has this SVG,
432 * without having to fall back to the default theme.
433 *
434 * @return true if the svg is loaded from the current theme
435 * @see ImageSet::currentImageSetHasImage
436 */
437 bool fromCurrentImageSet() const;
438
439 /**
440 * @brief This method sets the KSvg::ImageSet to use with this Svg object.
441 *
442 * By default, Svg objects use KSvg::ImageSet::default().
443 *
444 * This determines how relative image paths are interpreted.
445 *
446 * @param theme the theme object to use
447 * @since 4.3
448 */
449 void setImageSet(KSvg::ImageSet *theme);
450
451 /**
452 * @brief This method returns the KSvg::ImageSet used by this Svg object.
453 *
454 * This determines how relative image paths are interpreted.
455 *
456 * @return the theme used by this Svg
457 */
458 ImageSet *imageSet() const;
459
460 /**
461 * @brief This method sets the image in a selected status.
462 *
463 * SVGs can be colored with system color themes. If ``status`` is selected,
464 * TextColor will become HighlightedText color, and BackgroundColor will
465 * become HighlightColor. This can be used to make SVG-based graphics such
466 * as symbolic icons look correct together. Supported statuses are Normal
467 * and Selected.
468 * @since 5.23
469 */
470 void setStatus(Svg::Status status);
471
472 /**
473 * @brief This method returns the Svg object's status.
474 * @since 5.23
475 */
476 Svg::Status status() const;
477
478 /**
479 * @brief This method sets a color set for the SVG.
480 * Set a color set for the Svg.
481 * if the Svg uses stylesheets and has elements
482 * that are either TextColor or BackgroundColor class,
483 * make them use ButtonTextColor/ButtonBackgroundColor
484 * or ViewTextColor/ViewBackgroundColor
485 */
486 void setColorSet(ColorSet colorSet);
487
488 /**
489 * @return the color set for this Svg
490 */
491 KSvg::Svg::ColorSet colorSet() const;
492
493 QColor color(StyleSheetColor colorName) const;
494 void setColor(StyleSheetColor colorName, const QColor &color);
495
496 void clearColorOverrides();
497
498Q_SIGNALS:
499 /**
500 * @brief This signal is emitted whenever the SVG data has changed in such a
501 * way that a repaint is required.
502 *
503 * Any usage of an SVG object that does the painting itself must connect to
504 * this signal and respond by updating the painting. Note that connecting to
505 * ImageSet::imageSetChanged is incorrect in such a use case as the SVG
506 * itself may not be updated yet nor may theme change be the only case when
507 * a repaint is needed. Also note that classes or QML code which take Svg
508 * objects as parameters for their own painting all respond to this signal
509 * so that in those cases manually responding to the signal is unnecessary;
510 * ONLY when direct, manual painting with an Svg object is done in
511 * application code is this signal used.
512 */
513 void repaintNeeded();
514
515 /**
516 * @brief This signal is emitted whenever the size has changed.
517 * @see ::resize()
518 */
519 void sizeChanged();
520
521 /**
522 * @brief This signal is emitted whenever the image path has changed.
523 */
524 void imagePathChanged();
525
526 /**
527 * @brief This signal is emitted whenever the color hint has changed.
528 */
529 void colorHintChanged();
530
531 /**
532 * @brief This signal is emitted when the value of fromCurrentImageSet()
533 * has changed.
534 */
535 void fromCurrentImageSetChanged(bool fromCurrentImageSet);
536
537 /**
538 * @brief This signal is emitted when the status has changed.
539 */
540 void statusChanged(KSvg::Svg::Status status);
541
542 /**
543 * @brief This signal is emitted when the color set has changed.
544 */
545 void colorSetChanged(KSvg::Svg::ColorSet colorSet);
546
547 /**
548 * @brief This signal is emitted when the image set has changed.
549 */
550 void imageSetChanged(ImageSet *imageSet);
551
552private:
553 SvgPrivate *const d;
554 bool eventFilter(QObject *watched, QEvent *event) override;
555
556 Q_PRIVATE_SLOT(d, void imageSetChanged())
557 Q_PRIVATE_SLOT(d, void colorsChanged())
558
559 friend class SvgPrivate;
560 friend class FrameSvgPrivate;
561 friend class FrameSvg;
562 friend class ImageSetPrivate;
563};
564
565} // KSvg namespace
566
567#endif // multiple inclusion guard
568

source code of ksvg/src/ksvg/svg.h