File indexing completed on 2024-06-02 03:59:20

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 KSVG_FRAMESVG_H
0009 #define KSVG_FRAMESVG_H
0010 
0011 #include <QObject>
0012 #include <QPixmap>
0013 
0014 #include <ksvg/ksvg_export.h>
0015 
0016 #include <ksvg/svg.h>
0017 
0018 class QPainter;
0019 class QPoint;
0020 class QPointF;
0021 class QRect;
0022 class QRectF;
0023 class QSize;
0024 class QSizeF;
0025 class QMatrix;
0026 
0027 namespace KSvg
0028 {
0029 class FrameSvgPrivate;
0030 
0031 /**
0032  * @class FrameSvg ksvg/framesvg.h <KSvg/FrameSvg>
0033  *
0034  * @short Provides an SVG with borders.
0035  *
0036  * When using SVG images for a background of an object that may change
0037  * its aspect ratio, such as a dialog, simply scaling a single image
0038  * may not be enough.
0039  *
0040  * FrameSvg allows SVGs to provide several elements for borders as well
0041  * as a central element, each of which are scaled individually. These elements
0042  * should be named:
0043  * * @c center  - the central element, which will be scaled in both directions
0044  * * @c top     - the top border; the height is fixed, but it will be scaled
0045  * horizontally to the same width as @c center
0046  * * @c bottom  - the bottom border; scaled in the same way as @c top
0047  * * @c left    - the left border; the width is fixed, but it will be scaled
0048  * vertically to the same height as @c center
0049  * * @c right   - the right border; scaled in the same way as @c left
0050  * * @c topleft - fixed size; must be the same height as @c top and the same
0051  * width as @c left
0052  * * @c bottomleft, @c topright, @c bottomright - similar to @c topleft
0053  *
0054  * @c center must exist, but all the others are optional.  @c topleft and
0055  * @c topright will be ignored if @c top does not exist, and similarly for
0056  * @c bottomleft and @c bottomright.
0057  *
0058  * @see KSvg::Svg
0059  **/
0060 class KSVG_EXPORT FrameSvg : public Svg
0061 {
0062     Q_OBJECT
0063 
0064     Q_PROPERTY(EnabledBorders enabledBorders READ enabledBorders WRITE setEnabledBorders)
0065 
0066 public:
0067     /**
0068      * @brief This flag enum specifies which borders should be drawn.
0069      */
0070     enum EnabledBorder {
0071         NoBorder = 0,
0072         TopBorder = 1,
0073         BottomBorder = 2,
0074         LeftBorder = 4,
0075         RightBorder = 8,
0076         AllBorders = TopBorder | BottomBorder | LeftBorder | RightBorder,
0077     };
0078     Q_DECLARE_FLAGS(EnabledBorders, EnabledBorder)
0079     Q_FLAG(EnabledBorders)
0080 
0081     // TODO: merge those two?
0082     enum LocationPrefix {
0083         Floating = 0, /**< Free floating.*/
0084         TopEdge, /**< Along the top of the screen*/
0085         BottomEdge, /**< Along the bottom of the screen*/
0086         LeftEdge, /**< Along the left side of the screen */
0087         RightEdge, /**< Along the right side of the screen */
0088     };
0089     Q_ENUM(LocationPrefix)
0090 
0091     enum MarginEdge {
0092         TopMargin = 0, /**< The top margin **/
0093         BottomMargin, /**< The bottom margin **/
0094         LeftMargin, /**< The left margin **/
0095         RightMargin, /**< The right margin **/
0096     };
0097     Q_ENUM(MarginEdge)
0098 
0099     /**
0100      * Constructs a new FrameSvg that paints the proper named subelements
0101      * as borders. It may also be used as a regular KSvg::Svg object
0102      * for direct access to elements in the Svg.
0103      *
0104      * @param parent options QObject to parent this to
0105      *
0106      * @related KSvg::Theme
0107      */
0108     explicit FrameSvg(QObject *parent = nullptr);
0109     ~FrameSvg() override;
0110 
0111     /**
0112      * Loads a new Svg
0113      * @param imagePath the new file
0114      */
0115     Q_INVOKABLE void setImagePath(const QString &path) override;
0116 
0117     /**
0118      * @brief This method sets which borders should be painted.
0119      * @param flags borders we want to paint
0120      *
0121      * @see ::EnabledBorder
0122      * @param borders
0123      */
0124     void setEnabledBorders(const EnabledBorders borders);
0125 
0126     /**
0127      * @brief This is a convenience method to get the enabled borders.
0128      * @return what borders are painted
0129      */
0130     EnabledBorders enabledBorders() const;
0131 
0132     /**
0133      * @brief This method resizes the frame, maintaining the same border size.
0134      * @param size the new size of the frame
0135      */
0136     Q_INVOKABLE void resizeFrame(const QSizeF &size);
0137 
0138     /**
0139      * @returns the size of the frame
0140      */
0141     Q_INVOKABLE QSizeF frameSize() const;
0142 
0143     /**
0144      *
0145      * @brief This method returns the margin size for the given edge.
0146      *
0147      * Note that @c 0 will be returned if the given margin is disabled.
0148      *
0149      * If you don't care about the margin being on or off, use
0150      * ::fixedMarginSize() instead.
0151      *
0152      * @param edge the margin edge we want, top, bottom, left or right
0153      * @return the margin size
0154      */
0155     Q_INVOKABLE qreal marginSize(const FrameSvg::MarginEdge edge) const;
0156 
0157     /**
0158      * @brief This is a convenience method that extracts the size of the four
0159      * margins and saves their size into the passed variables.
0160      *
0161      * If you don't care about the margins being on or off, use
0162      * ::getFixedMargins() instead.
0163      *
0164      * @param left left margin size
0165      * @param top top margin size
0166      * @param right right margin size
0167      * @param bottom bottom margin size
0168      */
0169     Q_INVOKABLE void getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
0170 
0171     /**
0172      * @brief This method returns the margin size for the specified edge.
0173      *
0174      * Compared to ::marginSize(), this does not depend on whether the margin is
0175      * enabled or not.
0176      *
0177      * @param edge the margin edge we want, top, bottom, left or right
0178      * @return the margin size
0179      */
0180     Q_INVOKABLE qreal fixedMarginSize(const FrameSvg::MarginEdge edge) const;
0181 
0182     /**
0183      * @brief This is a convenience method that extracts the size of the four
0184      * margins and saves their size into the passed variables.
0185      *
0186      * Compared to ::getMargins(), this doesn't depend on whether the margins are
0187      * enabled or not.
0188      *
0189      * @param left left margin size
0190      * @param top top margin size
0191      * @param right right margin size
0192      * @param bottom bottom margin size
0193      */
0194     Q_INVOKABLE void getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
0195 
0196     /**
0197      * @brief This method returns the insets margin size for the specified edge.
0198      * @param edge the margin edge we want, top, bottom, left or right
0199      * @return the margin size
0200      * @since 5.77
0201      */
0202     Q_INVOKABLE qreal insetSize(const FrameSvg::MarginEdge edge) const;
0203 
0204     /**
0205      * @brief This is a convenience method that extracts the size of the four
0206      * inset margins and saves their size into the passed variables.
0207      *
0208      * @param left left margin size
0209      * @param top top margin size
0210      * @param right right margin size
0211      * @param bottom bottom margin size
0212      * @since 5.77
0213      */
0214     Q_INVOKABLE void getInset(qreal &left, qreal &top, qreal &right, qreal &bottom) const;
0215 
0216     /**
0217      * @brief This method returns the rectangle of the center element, taking
0218      * the margins into account.
0219      */
0220     Q_INVOKABLE QRectF contentsRect() const;
0221 
0222     /**
0223      * @brief This method sets the prefix (@see setElementPrefix) to 'north',
0224      * 'south', 'west' and 'east' when the location is TopEdge, BottomEdge,
0225      * LeftEdge and RightEdge, respectively. Clears the prefix in other cases.
0226      *
0227      * The prefix must exist in the SVG document, which means that this can only
0228      * be called successfully after setImagePath is called.
0229      *
0230      * @param location location in the UI this frame will be drawn
0231      */
0232     Q_INVOKABLE void setElementPrefix(KSvg::FrameSvg::LocationPrefix location);
0233 
0234     /**
0235      * @brief This method sets the prefix for the SVG elements to be used for
0236      * painting.
0237      *
0238      * For example, if prefix is 'active', then instead of using the 'top'
0239      * element of the SVG file to paint the top border, the 'active-top' element
0240      * will be used. The same goes for other SVG elements.
0241      *
0242      * If the elements with prefixes are not present, the default ones are used.
0243      * (for the sake of speed, the test is present only for the 'center' element)
0244      *
0245      * Setting the prefix manually resets the location to Floating.
0246      *
0247      * The prefix must exist in the SVG document, which means that this can only be
0248      * called successfully after setImagePath is called.
0249      *
0250      * @param prefix prefix for the SVG elements that make up the frame
0251      */
0252     Q_INVOKABLE void setElementPrefix(const QString &prefix);
0253 
0254     /**
0255      * @brief This method returns whether the SVG has the necessary elements
0256      * with the given prefix to draw a frame.
0257      *
0258      * @param prefix the given prefix we want to check if drawable (can have trailing '-' since 5.59)
0259      */
0260     Q_INVOKABLE bool hasElementPrefix(const QString &prefix) const;
0261 
0262     /**
0263      * @brief This is an overloaded method provided for convenience that is
0264      * equivalent to hasElementPrefix("north"), hasElementPrefix("south")
0265      * hasElementPrefix("west") and hasElementPrefix("east").
0266      *
0267      * @return true if the svg has the necessary elements with the given prefix
0268      * to draw a frame.
0269      *
0270      * @param location the given prefix we want to check if drawable
0271      */
0272     Q_INVOKABLE bool hasElementPrefix(KSvg::FrameSvg::LocationPrefix location) const;
0273 
0274     /**
0275      * @brief This method returns the prefix for SVG elements of the FrameSvg
0276      * (including a '-' at the end if not empty).
0277      *
0278      * @return the prefix
0279      * @see actualPrefix()
0280      */
0281     Q_INVOKABLE QString prefix();
0282 
0283     /**
0284      * @brief This method returns a mask that tightly contains the fully opaque
0285      * areas of the SVG.
0286      *
0287      * @return a region of opaque areas
0288      */
0289     Q_INVOKABLE QRegion mask() const;
0290 
0291     /**
0292      * @brief This method returns a pixmap whose alpha channel is the opacity of
0293      * the frame. It may be the frame itself or a special frame with the
0294      * "mask-" prefix.
0295      */
0296     QPixmap alphaMask() const;
0297 
0298     /**
0299      * @brief This method sets whether saving all the rendered prefixes in a
0300      * cache or not.
0301      *
0302      * @param cache whether to use the cache.
0303      */
0304     Q_INVOKABLE void setCacheAllRenderedFrames(bool cache);
0305 
0306     /**
0307      * @brief This method returns whether all the different prefixes should be
0308      * kept in a cache when rendered.
0309      */
0310     Q_INVOKABLE bool cacheAllRenderedFrames() const;
0311 
0312     /**
0313      * @brief This method deletes the internal cache.
0314      *
0315      * Calling this method frees memeory. Use this if you want to switch the
0316      * rendered element and you don't plan to switch back to the previous one
0317      * for a long time.
0318      *
0319      * This only works if setUsingRenderingCache(@c true) has been called.
0320      *
0321      * @see KSvg::Svg::setUsingRenderingCache()
0322      */
0323     Q_INVOKABLE void clearCache();
0324 
0325     /**
0326      * @brief This method returns a pixmap of the SVG represented by this
0327      * object.
0328      *
0329      * @param elelementId the ID string of the element to render, or an empty
0330      * string for the whole SVG (the default).
0331      *
0332      * @return a QPixmap of the rendered SVG
0333      */
0334     Q_INVOKABLE QPixmap framePixmap();
0335 
0336     /**
0337      * @brief This method paints the loaded SVG with the elements that
0338      * represents the border.
0339      *
0340      * @param painter the QPainter to use
0341      * @param target the target rectangle on the paint device
0342      * @param source the portion rectangle of the source image
0343      */
0344     Q_INVOKABLE void paintFrame(QPainter *painter, const QRectF &target, const QRectF &source = QRectF());
0345 
0346     /**
0347      * @brief This method paints the loaded SVG with the elements that
0348      * represents the border.
0349      *
0350      * This is an overloaded member provided for convenience
0351      *
0352      * @param painter the QPainter to use
0353      * @param pos where to paint the svg
0354      */
0355     Q_INVOKABLE void paintFrame(QPainter *painter, const QPointF &pos = QPointF(0, 0));
0356 
0357     /**
0358      * @brief This method returns the prefix that is actually being used
0359      * (including a '-' at the end if not empty).
0360      *
0361      * @see ::prefix()
0362      */
0363     QString actualPrefix() const;
0364 
0365     /**
0366      * @brief This method returns whether we are in a transaction of many
0367      * changes at once.
0368      *
0369      * This is used to restrict rebuilding generated graphics for each change
0370      * made.
0371      *
0372      * @since 5.31
0373      */
0374     bool isRepaintBlocked() const;
0375 
0376     /**
0377      * @brief This method sets whether we should block rebuilding generated
0378      * graphics for each change made.
0379      *
0380      * Setting this to @c true will block rebuilding the generated graphics for
0381      * each change made and will do these changes in blocks instead.
0382      *
0383      * How to use this method:
0384      * When making several changes at once to the frame properties--such as
0385      * prefix, enabled borders, and size--set this property to true to avoid
0386      * regenerating the graphics for each change. Set it to false again after
0387      * applying all required changes.
0388      *
0389      * Note that any change will not be visible in the painted frame while this
0390      * property is set to true.
0391      * @since 5.31
0392      */
0393     void setRepaintBlocked(bool blocked);
0394 
0395     /**
0396      * @brief This method returns the minimum height required to correctly draw
0397      * this SVG.
0398      *
0399      * @since 5.101
0400      */
0401     Q_INVOKABLE int minimumDrawingHeight();
0402 
0403     /**
0404      * @brief This method returns the minimum width required to correctly draw
0405      * this SVG.
0406      *
0407      * @since 5.101
0408      */
0409     Q_INVOKABLE int minimumDrawingWidth();
0410 
0411 private:
0412     FrameSvgPrivate *const d;
0413     friend class FrameData;
0414 };
0415 
0416 Q_DECLARE_OPERATORS_FOR_FLAGS(FrameSvg::EnabledBorders)
0417 
0418 } // KSvg namespace
0419 
0420 #endif // multiple inclusion guard