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

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