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 | |
16 | class QPainter; |
17 | class QPoint; |
18 | class QPointF; |
19 | class QRect; |
20 | class QRectF; |
21 | class QSize; |
22 | class QSizeF; |
23 | class QMatrix; |
24 | |
25 | /** |
26 | * The KSvg namespace. |
27 | */ |
28 | namespace KSvg |
29 | { |
30 | class FrameSvgPrivate; |
31 | class 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 | **/ |
45 | class 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 | |
56 | public: |
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, }; |
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 | , |
114 | , |
115 | , |
116 | , |
117 | , |
118 | , |
119 | , |
120 | |
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 | |
498 | Q_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 | |
552 | private: |
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 | |