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

0001 /*
0002     SPDX-FileCopyrightText: 2008 Aaron Seigo <aseigo@kde.org>
0003     SPDX-FileCopyrightText: 2008 Marco Martin <notmart@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef PLASMA_FRAMESVG_H
0009 #define PLASMA_FRAMESVG_H
0010 
0011 #include <QObject>
0012 #include <QPixmap>
0013 
0014 #include <plasma/plasma_export.h>
0015 
0016 #include <plasma/plasma.h>
0017 #include <plasma/svg.h>
0018 
0019 class QPainter;
0020 class QPoint;
0021 class QPointF;
0022 class QRect;
0023 class QRectF;
0024 class QSize;
0025 class QSizeF;
0026 class QMatrix;
0027 
0028 namespace Plasma
0029 {
0030 class FrameSvgPrivate;
0031 
0032 /**
0033  * @class FrameSvg plasma/framesvg.h <Plasma/FrameSvg>
0034  *
0035  * @short Provides an SVG with borders.
0036  *
0037  * When using SVG images for a background of an object that may change
0038  * its aspect ratio, such as a dialog, simply scaling a single image
0039  * may not be enough.
0040  *
0041  * FrameSvg allows SVGs to provide several elements for borders as well
0042  * as a central element, each of which are scaled individually.  These
0043  * elements should be named
0044  *
0045  *  - @c center  - the central element, which will be scaled in both directions
0046  *  - @c top     - the top border; the height is fixed, but it will be scaled
0047  *                 horizontally to the same width as @c center
0048  *  - @c bottom  - the bottom border; scaled in the same way as @c top
0049  *  - @c left    - the left border; the width is fixed, but it will be scaled
0050  *                 vertically to the same height as @c center
0051  *  - @c right   - the right border; scaled in the same way as @c left
0052  *  - @c topleft - fixed size; must be the same height as @c top and the same
0053  *                 width as @c left
0054  *  - @c bottomleft, @c topright, @c bottomright - similar to @c topleft
0055  *
0056  * @c center must exist, but all the others are optional.  @c topleft and
0057  * @c topright will be ignored if @c top does not exist, and similarly for
0058  * @c bottomleft and @c bottomright.
0059  *
0060  * @see Plasma::Svg
0061  **/
0062 class PLASMA_EXPORT FrameSvg : public Svg
0063 {
0064     Q_OBJECT
0065 
0066     Q_PROPERTY(EnabledBorders enabledBorders READ enabledBorders WRITE setEnabledBorders)
0067 
0068 public:
0069     /**
0070      * These flags represents what borders should be drawn
0071      */
0072     enum EnabledBorder {
0073         NoBorder = 0,
0074         TopBorder = 1,
0075         BottomBorder = 2,
0076         LeftBorder = 4,
0077         RightBorder = 8,
0078         AllBorders = TopBorder | BottomBorder | LeftBorder | RightBorder,
0079     };
0080     Q_DECLARE_FLAGS(EnabledBorders, EnabledBorder)
0081     Q_FLAG(EnabledBorders)
0082 
0083     /**
0084      * Constructs a new FrameSvg that paints the proper named subelements
0085      * as borders. It may also be used as a regular Plasma::Svg object
0086      * for direct access to elements in the Svg.
0087      *
0088      * @param parent options QObject to parent this to
0089      *
0090      * @related Plasma::Theme
0091      */
0092     explicit FrameSvg(QObject *parent = nullptr);
0093     ~FrameSvg() override;
0094 
0095     /**
0096      * Loads a new Svg
0097      * @param imagePath the new file
0098      */
0099     Q_INVOKABLE void setImagePath(const QString &path) override;
0100 
0101     /**
0102      * Sets what borders should be painted
0103      * @param flags borders we want to paint
0104      */
0105     void setEnabledBorders(const EnabledBorders borders);
0106 
0107     /**
0108      * Convenience method to get the enabled borders
0109      * @return what borders are painted
0110      */
0111     EnabledBorders enabledBorders() const;
0112 
0113     /**
0114      * Resize the frame maintaining the same border size
0115      * @param size the new size of the frame
0116      */
0117     Q_INVOKABLE void resizeFrame(const QSizeF &size);
0118 
0119     /**
0120      * @returns the size of the frame
0121      */
0122     Q_INVOKABLE QSizeF frameSize() const;
0123 
0124     /**
0125      * Returns the margin size given the margin edge we want
0126      * If the given margin is disabled, it will return 0.
0127      * If you don't care about the margin being on or off, use fixedMarginSize()
0128      * @param edge the margin edge we want, top, bottom, left or right
0129      * @return the margin size
0130      */
0131     Q_INVOKABLE qreal marginSize(const Plasma::Types::MarginEdge edge) const;
0132 
0133     /**
0134      * Convenience method that extracts the size of the four margins
0135      * in the four output parameters
0136      * The disabled margins will be 0.
0137      * If you don't care about the margins being on or off, use getFixedMargins()
0138      * @param left left margin size
0139      * @param top top margin size
0140      * @param right right margin size
0141      * @param bottom bottom margin size
0142      */
0143     Q_INVOKABLE void getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
0144 
0145     /**
0146      * Returns the margin size given the margin edge we want.
0147      * Compared to marginSize(), this doesn't depend whether the margin is enabled or not
0148      * @param edge the margin edge we want, top, bottom, left or right
0149      * @return the margin size
0150      */
0151     Q_INVOKABLE qreal fixedMarginSize(const Plasma::Types::MarginEdge edge) const;
0152 
0153     /**
0154      * Convenience method that extracts the size of the four margins
0155      * in the four output parameters
0156      * Compared to getMargins(), this doesn't depend whether the margins are enabled or not
0157      * @param left left margin size
0158      * @param top top margin size
0159      * @param right right margin size
0160      * @param bottom bottom margin size
0161      */
0162     Q_INVOKABLE void getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
0163 
0164     /**
0165      * Returns the insets margin size given the margin edge we want.
0166      * @param edge the margin edge we want, top, bottom, left or right
0167      * @return the margin size
0168      * @since 5.77
0169      */
0170     Q_INVOKABLE qreal insetSize(const Plasma::Types::MarginEdge edge) const;
0171 
0172     /**
0173      * Convenience method that extracts the size of the four inset margins
0174      * in the four output parameters
0175      * @param left left margin size
0176      * @param top top margin size
0177      * @param right right margin size
0178      * @param bottom bottom margin size
0179      * @since 5.77
0180      */
0181     Q_INVOKABLE void getInset(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
0182 
0183     /**
0184      * @return the rectangle of the center element, taking the margins into account.
0185      */
0186     Q_INVOKABLE QRectF contentsRect() const;
0187 
0188     /**
0189      * Sets the prefix (@see setElementPrefix) to 'north', 'south', 'west' and 'east'
0190      * when the location is TopEdge, BottomEdge, LeftEdge and RightEdge,
0191      * respectively. Clears the prefix in other cases.
0192      *
0193      * The prefix must exist in the SVG document, which means that this can only be
0194      * called successfully after setImagePath is called.
0195      * @param location location in the UI this frame will be drawn
0196      */
0197     Q_INVOKABLE void setElementPrefix(Plasma::Types::Location location);
0198 
0199     /**
0200      * Sets the prefix for the SVG elements to be used for painting. For example,
0201      * if prefix is 'active', then instead of using the 'top' element of the SVG
0202      * file to paint the top border, 'active-top' element will be used. The same
0203      * goes for other SVG elements.
0204      *
0205      * If the elements with prefixes are not present, the default ones are used.
0206      * (for the sake of speed, the test is present only for the 'center' element)
0207      *
0208      * Setting the prefix manually resets the location to Floating.
0209      *
0210      * The prefix must exist in the SVG document, which means that this can only be
0211      * called successfully after setImagePath is called.
0212      *
0213      * @param prefix prefix for the SVG elements that make up the frame
0214      */
0215     Q_INVOKABLE void setElementPrefix(const QString &prefix);
0216 
0217     /**
0218      * @return true if the svg has the necessary elements with the given prefix
0219      * to draw a frame
0220      * @param prefix the given prefix we want to check if drawable (can have trailing '-' since 5.59)
0221      */
0222     Q_INVOKABLE bool hasElementPrefix(const QString &prefix) const;
0223 
0224     /**
0225      * This is an overloaded method provided for convenience equivalent to
0226      * hasElementPrefix("north"), hasElementPrefix("south")
0227      * hasElementPrefix("west") and hasElementPrefix("east")
0228      * @return true if the svg has the necessary elements with the given prefix
0229      * to draw a frame.
0230      * @param location the given prefix we want to check if drawable
0231      */
0232     Q_INVOKABLE bool hasElementPrefix(Plasma::Types::Location location) const;
0233 
0234     /**
0235      * Returns the prefix for SVG elements of the FrameSvg (including a '-' at the end if not empty)
0236      * @return the prefix
0237      * @sa actualPrefix()
0238      */
0239     Q_INVOKABLE QString prefix();
0240 
0241     /**
0242      * Returns a mask that tightly contains the fully opaque areas of the svg
0243      * @return a region of opaque areas
0244      */
0245     Q_INVOKABLE QRegion mask() const;
0246 
0247     /**
0248      * @return a pixmap whose alpha channel is the opacity of the frame. It may be the frame itself or a special frame with the mask- prefix
0249      */
0250     QPixmap alphaMask() const;
0251 
0252     /**
0253      * Sets whether saving all the rendered prefixes in a cache or not
0254      * @param cache if use the cache or not
0255      */
0256     Q_INVOKABLE void setCacheAllRenderedFrames(bool cache);
0257 
0258     /**
0259      * @return if all the different prefixes should be kept in a cache when rendered
0260      */
0261     Q_INVOKABLE bool cacheAllRenderedFrames() const;
0262 
0263     /**
0264      * Deletes the internal cache freeing memory: use this if you want to switch the rendered
0265      * element and you don't plan to switch back to the previous one for a long time and you
0266      * used setUsingRenderingCache(true)
0267      */
0268     Q_INVOKABLE void clearCache();
0269 
0270     /**
0271      * Returns a pixmap of the SVG represented by this object.
0272      *
0273      * @param elelementId the ID string of the element to render, or an empty
0274      *                  string for the whole SVG (the default)
0275      * @return a QPixmap of the rendered SVG
0276      */
0277     Q_INVOKABLE QPixmap framePixmap();
0278 
0279     /**
0280      * Paints the loaded SVG with the elements that represents the border
0281      * @param painter the QPainter to use
0282      * @param target the target rectangle on the paint device
0283      * @param source the portion rectangle of the source image
0284      */
0285     Q_INVOKABLE void paintFrame(QPainter *painter, const QRectF &target, const QRectF &source = QRectF());
0286 
0287     /**
0288      * Paints the loaded SVG with the elements that represents the border
0289      * This is an overloaded member provided for convenience
0290      * @param painter the QPainter to use
0291      * @param pos where to paint the svg
0292      */
0293     Q_INVOKABLE void paintFrame(QPainter *painter, const QPointF &pos = QPointF(0, 0));
0294 
0295     /**
0296      * @returns the prefix that is actually used (including a '-' at the end if not empty)
0297      * @sa prefix()
0298      */
0299     QString actualPrefix() const;
0300 
0301     /**
0302      * @returns true if we are in a transaction of many changes at once
0303      * and we don't want to rebuild the generated graphics for each change yet
0304      * @since 5.31
0305      */
0306     bool isRepaintBlocked() const;
0307 
0308     /**
0309      * If we will do several changes at once in the frame properties,
0310      * such as prefix, enabled borders and size, in order to not regenerate
0311      * the graphics for each change, set this property to true, and set
0312      * it to false again after applying all the changes needed.
0313      * Note that any change will not be visible in the painted frame while this property is set to true.
0314      * @since 5.31
0315      */
0316     void setRepaintBlocked(bool blocked);
0317 
0318     /**
0319      * This will return the minimum height required to correctly draw this
0320      * SVG. 
0321      * @since 5.101
0322      */
0323     Q_INVOKABLE int minimumDrawingHeight();
0324 
0325     /**
0326      * This will return the minimum width required to correctly draw this
0327      * SVG. 
0328      * @since 5.101
0329      */
0330     Q_INVOKABLE int minimumDrawingWidth();
0331 
0332 private:
0333     FrameSvgPrivate *const d;
0334     friend class FrameData;
0335 };
0336 
0337 Q_DECLARE_OPERATORS_FOR_FLAGS(FrameSvg::EnabledBorders)
0338 
0339 } // Plasma namespace
0340 
0341 #endif // multiple inclusion guard