File indexing completed on 2023-10-01 04:11:46

0001 /*
0002     SPDX-FileCopyrightText: 2006-2007 Aaron Seigo <aseigo@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef PLASMA_SVG_H
0008 #define PLASMA_SVG_H
0009 
0010 #include <QObject>
0011 #include <QPixmap>
0012 
0013 #include <plasma/plasma_export.h>
0014 #include <plasma/theme.h>
0015 
0016 class QPainter;
0017 class QPoint;
0018 class QPointF;
0019 class QRect;
0020 class QRectF;
0021 class QSize;
0022 class QSizeF;
0023 class QMatrix;
0024 
0025 namespace Plasma
0026 {
0027 class FrameSvgPrivate;
0028 class SvgPrivate;
0029 
0030 /**
0031  * @class Svg plasma/svg.h <Plasma/Svg>
0032  *
0033  * @short A theme aware image-centric SVG class
0034  *
0035  * Plasma::Svg provides a class for rendering SVG images to a QPainter in a
0036  * convenient manner. Unless an absolute path to a file is provided, it loads
0037  * the SVG document using Plasma::Theme. It also provides a number of internal
0038  * optimizations to help lower the cost of painting SVGs, such as caching.
0039  *
0040  * @see Plasma::FrameSvg
0041  **/
0042 class PLASMA_EXPORT Svg : public QObject
0043 {
0044     Q_OBJECT
0045     Q_PROPERTY(QSize size READ size WRITE resize NOTIFY sizeChanged)
0046     Q_PROPERTY(bool multipleImages READ containsMultipleImages WRITE setContainsMultipleImages)
0047     Q_PROPERTY(QString imagePath READ imagePath WRITE setImagePath NOTIFY imagePathChanged)
0048     Q_PROPERTY(bool usingRenderingCache READ isUsingRenderingCache WRITE setUsingRenderingCache)
0049     Q_PROPERTY(bool fromCurrentTheme READ fromCurrentTheme NOTIFY fromCurrentThemeChanged)
0050     Q_PROPERTY(Plasma::Theme::ColorGroup colorGroup READ colorGroup WRITE setColorGroup NOTIFY colorGroupChanged)
0051     Q_PROPERTY(Plasma::Svg::Status status READ status WRITE setStatus NOTIFY statusChanged)
0052 
0053 public:
0054     enum Status {
0055         Normal = 0,
0056         Selected,
0057         Inactive,
0058     };
0059     Q_ENUM(Status)
0060 
0061     /**
0062      * Constructs an SVG object that implicitly shares and caches rendering.
0063      *
0064      * Unlike QSvgRenderer, which this class uses internally,
0065      * Plasma::Svg represents an image generated from an SVG. As such, it
0066      * has a related size and transform matrix (the latter being provided
0067      * by the painter used to paint the image).
0068      *
0069      * The size is initialized to be the SVG's native size.
0070      *
0071      * @param parent options QObject to parent this to
0072      *
0073      * @related Plasma::Theme
0074      */
0075     explicit Svg(QObject *parent = nullptr);
0076     ~Svg() override;
0077 
0078     /**
0079      * Set the device pixel ratio for the Svg. This is the ratio between
0080      * image pixels and device-independent pixels.
0081      * The Svg will produce pixmaps scaled by devicePixelRatio, but all the sizes and element
0082      * rects will not be altered.
0083      * The default value is 1.0 and the scale will be done rounded to the floor integer
0084      * Setting it to something more, will make all the elements of this svg appear bigger.
0085      */
0086     void setDevicePixelRatio(qreal ratio);
0087 
0088     /**
0089      * @return the device pixel ratio for this Svg.
0090      */
0091     qreal devicePixelRatio();
0092 
0093     /**
0094      * Setting a scale factor greater than one it will result in final images scaled by it.
0095      * Unlike devicePixelRatio, every size and element rect will be scaled accordingly.
0096      * @return how much to scale the rendered image.
0097      */
0098     qreal scaleFactor() const;
0099 
0100     /**
0101      * Setting a scale factor greater than one it will result in final images scaled by it.
0102      * Unlike devicePixelRatio, every size and element rect will be scaled accordingly.
0103      * The default value is 1.0 and the scale will be done rounded to the floor integer.
0104      * @param how much to scale the Svg
0105      */
0106     void setScaleFactor(qreal factor);
0107 
0108     /**
0109      * Set a color group for the Svg.
0110      * if the Svg uses stylesheets and has elements
0111      * that are either TextColor or BackgroundColor class,
0112      * make them use ButtonTextColor/ButtonBackgroundColor
0113      * or ViewTextColor/ViewBackgroundColor
0114      */
0115     void setColorGroup(Plasma::Theme::ColorGroup group);
0116 
0117     /**
0118      * @return the color group for this Svg
0119      */
0120     Plasma::Theme::ColorGroup colorGroup() const;
0121 
0122     /**
0123      * Returns a pixmap of the SVG represented by this object.
0124      *
0125      * The size of the pixmap will be the size of this Svg object (size())
0126      * if containsMultipleImages is @c true; otherwise, it will be the
0127      * size of the requested element after the whole SVG has been scaled
0128      * to size().
0129      *
0130      * @param elementId  the ID string of the element to render, or an empty
0131      *                 string for the whole SVG (the default)
0132      * @return a QPixmap of the rendered SVG
0133      */
0134     Q_INVOKABLE QPixmap pixmap(const QString &elementID = QString());
0135 
0136     /**
0137      * Returns an image of the SVG represented by this object.
0138      *
0139      * The size of the image will be the size of this Svg object (size())
0140      * if containsMultipleImages is @c true; otherwise, it will be the
0141      * size of the requested element after the whole SVG has been scaled
0142      * to size().
0143      *
0144      * @param elementId  the ID string of the element to render, or an empty
0145      *                 string for the whole SVG (the default)
0146      * @return a QPixmap of the rendered SVG
0147      */
0148     Q_INVOKABLE QImage image(const QSize &size, const QString &elementID = QString());
0149 
0150     /**
0151      * Paints all or part of the SVG represented by this object
0152      *
0153      * The size of the painted area will be the size of this Svg object
0154      * (size()) if containsMultipleImages is @c true; otherwise, it will
0155      * be the size of the requested element after the whole SVG has been
0156      * scaled to size().
0157      *
0158      * @param painter    the QPainter to use
0159      * @param point      the position to start drawing; the entire svg will be
0160      *                 drawn starting at this point.
0161      * @param elementId  the ID string of the element to render, or an empty
0162      *                 string for the whole SVG (the default)
0163      */
0164     Q_INVOKABLE void paint(QPainter *painter, const QPointF &point, const QString &elementID = QString());
0165 
0166     /**
0167      * Paints all or part of the SVG represented by this object
0168      *
0169      * The size of the painted area will be the size of this Svg object
0170      * (size()) if containsMultipleImages is @c true; otherwise, it will
0171      * be the size of the requested element after the whole SVG has been
0172      * scaled to size().
0173      *
0174      * @param painter    the QPainter to use
0175      * @param x          the horizontal coordinate to start painting from
0176      * @param y          the vertical coordinate to start painting from
0177      * @param elementId  the ID string of the element to render, or an empty
0178      *                 string for the whole SVG (the default)
0179      */
0180     Q_INVOKABLE void paint(QPainter *painter, int x, int y, const QString &elementID = QString());
0181 
0182     /**
0183      * Paints all or part of the SVG represented by this object
0184      *
0185      * @param painter    the QPainter to use
0186      * @param rect       the rect to draw into; if smaller than the current size
0187      *                 the drawing is starting at this point.
0188      * @param elementId  the ID string of the element to render, or an empty
0189      *                 string for the whole SVG (the default)
0190      */
0191     Q_INVOKABLE void paint(QPainter *painter, const QRectF &rect, const QString &elementID = QString());
0192 
0193     /**
0194      * Paints all or part of the SVG represented by this object
0195      *
0196      * @param painter    the QPainter to use
0197      * @param x          the horizontal coordinate to start painting from
0198      * @param y          the vertical coordinate to start painting from
0199      * @param width      the width of the element to draw
0200      * @param height     the height of the element do draw
0201      * @param elementId  the ID string of the element to render, or an empty
0202      *                 string for the whole SVG (the default)
0203      */
0204     Q_INVOKABLE void paint(QPainter *painter, int x, int y, int width, int height, const QString &elementID = QString());
0205 
0206     /**
0207      * The size of the SVG.
0208      *
0209      * If the SVG has been resized with resize(), that size will be
0210      * returned; otherwise, the natural size of the SVG will be returned.
0211      *
0212      * If containsMultipleImages is @c true, each element of the SVG
0213      * will be rendered at this size by default.
0214      *
0215      * @return the current size of the SVG
0216      **/
0217     QSize size() const;
0218 
0219     /**
0220      * Resizes the rendered image.
0221      *
0222      * Rendering will actually take place on the next call to paint.
0223      *
0224      * If containsMultipleImages is @c true, each element of the SVG
0225      * will be rendered at this size by default; otherwise, the entire
0226      * image will be scaled to this size and each element will be
0227      * scaled appropriately.
0228      *
0229      * @param width   the new width
0230      * @param height  the new height
0231      **/
0232     Q_INVOKABLE void resize(qreal width, qreal height);
0233 
0234     /**
0235      * Resizes the rendered image.
0236      *
0237      * Rendering will actually take place on the next call to paint.
0238      *
0239      * If containsMultipleImages is @c true, each element of the SVG
0240      * will be rendered at this size by default; otherwise, the entire
0241      * image will be scaled to this size and each element will be
0242      * scaled appropriately.
0243      *
0244      * @param size  the new size of the image
0245      **/
0246     Q_INVOKABLE void resize(const QSizeF &size);
0247 
0248     /**
0249      * Resizes the rendered image to the natural size of the SVG.
0250      *
0251      * Rendering will actually take place on the next call to paint.
0252      **/
0253     Q_INVOKABLE void resize();
0254 
0255     /**
0256      * Find the size of a given element.
0257      *
0258      * This is the size of the element with ID @p elementId after the SVG
0259      * has been scaled (see resize()).  Note that this is unaffected by
0260      * the containsMultipleImages property.
0261      *
0262      * @param elementId  the id of the element to check
0263      * @return the size of a given element, given the current size of the SVG
0264      **/
0265     Q_INVOKABLE QSize elementSize(const QString &elementId) const;
0266 
0267     QSize elementSize(QStringView elementId) const;
0268 
0269     /**
0270      * The bounding rect of a given element.
0271      *
0272      * This is the bounding rect of the element with ID @p elementId after
0273      * the SVG has been scaled (see resize()).  Note that this is
0274      * unaffected by the containsMultipleImages property.
0275      *
0276      * @param elementId  the id of the element to check
0277      * @return  the current rect of a given element, given the current size of the SVG
0278      **/
0279     Q_INVOKABLE QRectF elementRect(const QString &elementId) const;
0280 
0281     QRectF elementRect(QStringView elementId) const;
0282 
0283     /**
0284      * Check whether an element exists in the loaded SVG.
0285      *
0286      * @param elementId  the id of the element to check for
0287      * @return @c true if the element is defined in the SVG, otherwise @c false
0288      **/
0289     Q_INVOKABLE bool hasElement(const QString &elementId) const;
0290 
0291     bool hasElement(QStringView elementId) const;
0292 
0293     /**
0294      * Check whether this object is backed by a valid SVG file.
0295      *
0296      * This method can be expensive as it causes disk access.
0297      *
0298      * @return @c true if the SVG file exists and the document is valid,
0299      *         otherwise @c false.
0300      **/
0301     Q_INVOKABLE bool isValid() const;
0302 
0303     /**
0304      * Set whether the SVG contains a single image or multiple ones.
0305      *
0306      * If this is set to @c true, the SVG will be treated as a
0307      * collection of related images, rather than a consistent
0308      * drawing.
0309      *
0310      * In particular, when individual elements are rendered, this
0311      * affects whether the elements are resized to size() by default.
0312      * See paint() and pixmap().
0313      *
0314      * @param multiple true if the svg contains multiple images
0315      */
0316     void setContainsMultipleImages(bool multiple);
0317 
0318     /**
0319      * Whether the SVG contains multiple images.
0320      *
0321      * If this is @c true, the SVG will be treated as a
0322      * collection of related images, rather than a consistent
0323      * drawing.
0324      *
0325      * @return @c true if the SVG will be treated as containing
0326      *         multiple images, @c false if it will be treated
0327      *         as a coherent image.
0328      */
0329     bool containsMultipleImages() const;
0330 
0331     /**
0332      * Set the SVG file to render.
0333      *
0334      * Relative paths are looked for in the current Plasma theme,
0335      * and should not include the file extension (.svg and .svgz
0336      * files will be searched for).  See Theme::imagePath().
0337      *
0338      * If the parent object of this Svg is a Plasma::Applet,
0339      * relative paths will be searched for in the applet's package
0340      * first.
0341      *
0342      * @param svgFilePath  either an absolute path to an SVG file, or
0343      *                   an image name
0344      */
0345     virtual void setImagePath(const QString &svgFilePath);
0346 
0347     /**
0348      * The SVG file to render.
0349      *
0350      * If this SVG is themed, this will be a relative path, and will not
0351      * include a file extension.
0352      *
0353      * @return  either an absolute path to an SVG file, or an image name
0354      * @see Theme::imagePath()
0355      */
0356     QString imagePath() const;
0357 
0358     /**
0359      * Sets whether or not to cache the results of rendering to pixmaps.
0360      *
0361      * If the SVG is resized and re-rendered often (and does not keep using the
0362      * same small set of pixmap dimensions), then it may be less efficient to do
0363      * disk caching.  A good example might be a progress meter that uses an Svg
0364      * object to paint itself: the meter will be changing often enough, with
0365      * enough unpredictability and without re-use of the previous pixmaps to
0366      * not get a gain from caching.
0367      *
0368      * Most Svg objects should use the caching feature, however.
0369      * Therefore, the default is to use the render cache.
0370      *
0371      * @param useCache true to cache rendered pixmaps
0372      * @since 4.3
0373      */
0374     void setUsingRenderingCache(bool useCache);
0375 
0376     /**
0377      * Whether the rendering cache is being used.
0378      *
0379      * @return @c true if the Svg object is using caching for rendering results
0380      * @since 4.3
0381      */
0382     bool isUsingRenderingCache() const;
0383 
0384     /**
0385      * Whether the current theme has this Svg, without any fallback
0386      * to the default theme involved
0387      *
0388      * @return true if the svg is loaded from the current theme
0389      * @see Theme::currentThemeHasImage
0390      */
0391     bool fromCurrentTheme() const;
0392 
0393     /**
0394      * Sets whether the Svg uses the global system theme for its colors or
0395      * the Plasma theme. Default is False.
0396      *
0397      * @since 5.16
0398      */
0399     void setUseSystemColors(bool system);
0400 
0401     /**
0402      * @returns True if colors from the system theme are used.
0403      *           Default is False
0404      * @since 5.16
0405      */
0406     bool useSystemColors() const;
0407 
0408     /**
0409      * Sets the Plasma::Theme to use with this Svg object.
0410      *
0411      * By default, Svg objects use Plasma::Theme::default().
0412      *
0413      * This determines how relative image paths are interpreted.
0414      *
0415      * @param theme  the theme object to use
0416      * @since 4.3
0417      */
0418     void setTheme(Plasma::Theme *theme);
0419 
0420     /**
0421      * The Plasma::Theme used by this Svg object.
0422      *
0423      * This determines how relative image paths are interpreted.
0424      *
0425      * @return  the theme used by this Svg
0426      */
0427     Theme *theme() const;
0428 
0429     /**
0430      * Sets the image in a selected status.
0431      * Svgs can be colored with system color themes, if the status is selected,
0432      * the TextColor will become HighlightedText color and BackgroundColor
0433      * will become HighlightColor, making the svg graphics (for instance an icon)
0434      * will look correct together selected text
0435      * Supported statuses as of 5.23 are Normal and Selected
0436      * @since 5.23
0437      */
0438     void setStatus(Svg::Status status);
0439 
0440     /**
0441      * @return the status of the Svg
0442      * @since 5.23
0443      */
0444     Svg::Status status() const;
0445 
0446 Q_SIGNALS:
0447     /**
0448      * Emitted whenever the SVG data has changed in such a way that a repaint is required.
0449      * Any usage of an Svg object that does the painting itself must connect to this signal
0450      * and respond by updating the painting. Note that connected to Theme::themeChanged is
0451      * incorrect in such a use case as the Svg itself may not be updated yet nor may theme
0452      * change be the only case when a repaint is needed. Also note that classes or QML code
0453      * which take Svg objects as parameters for their own painting all respond to this signal
0454      * so that in those cases manually responding to the signal is unnecessary; ONLY when
0455      * direct, manual painting with an Svg object is done in application code is this signal
0456      * used.
0457      */
0458     void repaintNeeded();
0459 
0460     /**
0461      * Emitted whenever the size of the Svg is changed. @see resize()
0462      */
0463     void sizeChanged();
0464 
0465     /**
0466      * Emitted whenever the image path of the Svg is changed.
0467      */
0468     void imagePathChanged();
0469 
0470     /**
0471      * Emitted whenever the color hint has changed.
0472      */
0473     void colorHintChanged();
0474 
0475     /**
0476      * Emitted whenever the color group has changed.
0477      */
0478     void colorGroupChanged();
0479 
0480     /**
0481      * Emitted when fromCurrentTheme() value has changed
0482      */
0483     void fromCurrentThemeChanged(bool fromCurrentTheme);
0484 
0485     /**
0486      * Emitted when the status changes
0487      * @since 5.23
0488      */
0489     void statusChanged(Plasma::Svg::Status status);
0490 
0491 private:
0492     SvgPrivate *const d;
0493     bool eventFilter(QObject *watched, QEvent *event) override;
0494 
0495     Q_PRIVATE_SLOT(d, void themeChanged())
0496     Q_PRIVATE_SLOT(d, void colorsChanged())
0497 
0498     friend class SvgPrivate;
0499     friend class FrameSvgPrivate;
0500     friend class FrameSvg;
0501 };
0502 
0503 } // Plasma namespace
0504 
0505 #endif // multiple inclusion guard