File indexing completed on 2024-04-28 15:27:44

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #pragma once
0008 
0009 #include <QQuickItem>
0010 #include <memory>
0011 
0012 class PaintedRectangleItem;
0013 
0014 /**
0015  * @brief Grouped property for rectangle border.
0016  *
0017  * Example usage:
0018  * @include shadowedrectangle.qml
0019  */
0020 class BorderGroup : public QObject
0021 {
0022     Q_OBJECT
0023     /**
0024      * @brief This property holds the border's width in pixels.
0025      *
0026      * default: ``0``px
0027      */
0028     Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY changed)
0029     /**
0030      * @brief This property holds the border's color.
0031      *
0032      * Full RGBA colors are supported.
0033      *
0034      * default: ``Qt::black``
0035      */
0036     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
0037 
0038 public:
0039     explicit BorderGroup(QObject *parent = nullptr);
0040 
0041     qreal width() const;
0042     void setWidth(qreal newWidth);
0043 
0044     QColor color() const;
0045     void setColor(const QColor &newColor);
0046 
0047     Q_SIGNAL void changed();
0048 
0049     inline bool isEnabled() const
0050     {
0051         return !qFuzzyIsNull(m_width);
0052     }
0053 
0054 private:
0055     qreal m_width = 0.0;
0056     QColor m_color = Qt::black;
0057 };
0058 
0059 /**
0060  * @brief Grouped property for the rectangle's shadow.
0061  */
0062 class ShadowGroup : public QObject
0063 {
0064     Q_OBJECT
0065     /**
0066      * @brief This property holds the shadow's approximate size in pixels.
0067      * @note The actual shadow size can be less than this value due to falloff.
0068      *
0069      * default: ``0``px
0070      */
0071     Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY changed)
0072     /**
0073      * @brief This property holds the shadow's offset in pixels on the X axis.
0074      *
0075      * default: ``0``px
0076      */
0077     Q_PROPERTY(qreal xOffset READ xOffset WRITE setXOffset NOTIFY changed)
0078     /**
0079      * @brief This property holds the shadow's offset in pixels on the Y axis.
0080      *
0081      * default: ``0``px
0082      */
0083     Q_PROPERTY(qreal yOffset READ yOffset WRITE setYOffset NOTIFY changed)
0084     /**
0085      * @brief This property holds the shadow's color.
0086      *
0087      * Full RGBA colors are supported.
0088      *
0089      * default: ``Qt::black``
0090      */
0091     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed)
0092 
0093 public:
0094     explicit ShadowGroup(QObject *parent = nullptr);
0095 
0096     qreal size() const;
0097     void setSize(qreal newSize);
0098 
0099     qreal xOffset() const;
0100     void setXOffset(qreal newXOffset);
0101 
0102     qreal yOffset() const;
0103     void setYOffset(qreal newYOffset);
0104 
0105     QColor color() const;
0106     void setColor(const QColor &newShadowColor);
0107 
0108     Q_SIGNAL void changed();
0109 
0110 private:
0111     qreal m_size = 0.0;
0112     qreal m_xOffset = 0.0;
0113     qreal m_yOffset = 0.0;
0114     QColor m_color = Qt::black;
0115 };
0116 
0117 /**
0118  * @brief Grouped property for corner radius.
0119  */
0120 class CornersGroup : public QObject
0121 {
0122     Q_OBJECT
0123     /**
0124      * @brief This property holds the top-left corner's radius in pixels.
0125      *
0126      * Setting this to ``-1`` indicates that the value should be ignored.
0127      * 
0128      * default: ``-1``px
0129      */
0130     Q_PROPERTY(qreal topLeftRadius READ topLeft WRITE setTopLeft NOTIFY changed)
0131 
0132     /**
0133      * @brief This property holds the top-right corner's radius in pixels.
0134      *
0135      * Setting this to ``-1`` indicates that the value should be ignored.
0136      * 
0137      * default: ``-1``px
0138      */
0139     Q_PROPERTY(qreal topRightRadius READ topRight WRITE setTopRight NOTIFY changed)
0140 
0141     /**
0142      * @brief This property holds the bottom-left corner's radius in pixels.
0143      *
0144      * Setting this to ``-1`` indicates that the value should be ignored.
0145      * 
0146      * default: ``-1``px
0147      */
0148     Q_PROPERTY(qreal bottomLeftRadius READ bottomLeft WRITE setBottomLeft NOTIFY changed)
0149 
0150     /**
0151      * @brief This property holds the bottom-right corner's radius in pixels.
0152      *
0153      * Setting this to ``-1`` indicates that the value should be ignored.
0154      * 
0155      * default: ``-1``px
0156      */
0157     Q_PROPERTY(qreal bottomRightRadius READ bottomRight WRITE setBottomRight NOTIFY changed)
0158 
0159 public:
0160     explicit CornersGroup(QObject *parent = nullptr);
0161 
0162     qreal topLeft() const;
0163     void setTopLeft(qreal newTopLeft);
0164 
0165     qreal topRight() const;
0166     void setTopRight(qreal newTopRight);
0167 
0168     qreal bottomLeft() const;
0169     void setBottomLeft(qreal newBottomLeft);
0170 
0171     qreal bottomRight() const;
0172     void setBottomRight(qreal newBottomRight);
0173 
0174     Q_SIGNAL void changed();
0175 
0176     QVector4D toVector4D(float all) const;
0177 
0178 private:
0179     float m_topLeft = -1.0;
0180     float m_topRight = -1.0;
0181     float m_bottomLeft = -1.0;
0182     float m_bottomRight = -1.0;
0183 };
0184 
0185 /**
0186  * @brief A rectangle with a shadow behind it.
0187  *
0188  * This item will render a rectangle, with a shadow below it. The rendering is done
0189  * using distance fields, which provide greatly improved performance. The shadow is
0190  * rendered outside of the item's bounds, so the item's width and height are the
0191  * rectangle's width and height.
0192  *
0193  * @since KDE Frameworks 5.69
0194  * @since org.kde.kirigami 2.12
0195  */
0196 class ShadowedRectangle : public QQuickItem
0197 {
0198     Q_OBJECT
0199     /**
0200      * @brief This property holds the radii of the rectangle's corners.
0201      *
0202      * This is the amount of rounding to apply to all of the rectangle's
0203      * corners, in pixels. Each corner can have a different radius.
0204      *
0205      * default: ``0``
0206      *
0207      * @see ::corners
0208      */
0209     Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
0210 
0211     /**
0212      * @brief This property holds the rectangle's color.
0213      *
0214      * Full RGBA colors are supported.
0215      *
0216      * default: ``Qt::white``
0217      */
0218     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
0219 
0220     /**
0221      * @brief This property holds the border's grouped property.
0222      *
0223      * Example usage:
0224      * @code
0225      * Kirigami.ShadowedRectangle {
0226      *     border.width: 2
0227      *     border.color: Kirigami.Theme.textColor
0228      * }
0229      * @endcode
0230      * @see kirigami::BorderGroup
0231      */
0232     Q_PROPERTY(BorderGroup *border READ border CONSTANT)
0233 
0234     /**
0235      * @brief This property holds the shadow's grouped property.
0236      *
0237      * Example usage:
0238      * @code
0239      * Kirigami.ShadowedRectangle {
0240      *     shadow.size: 20
0241      *     shadow.xOffset: 5
0242      *     shadow.yOffset: 5
0243      * }
0244      * @endcode
0245      *
0246      * @see kirigami::ShadowGroup
0247      */
0248     Q_PROPERTY(ShadowGroup *shadow READ shadow CONSTANT)
0249 
0250     /**
0251      * @brief This property holds the corners grouped property
0252      *
0253      * Note that the values from this group override \property radius for the
0254      * corner they affect.
0255      *
0256      * Example usage:
0257      * @code
0258      * Kirigami.ShadowedRectangle {
0259      *     corners.topLeftRadius: 4
0260      *     corners.topRightRadius: 5
0261      *     corners.bottomLeftRadius: 2
0262      *     corners.bottomRightRadius: 10
0263      * @endcode
0264      *
0265      * @see kirigami::CornersGroup
0266      */
0267     Q_PROPERTY(CornersGroup *corners READ corners CONSTANT)
0268 
0269     /**
0270      * @brief This property holds the rectangle's render mode.
0271      *
0272      * default: ``RenderType.Auto``
0273      *
0274      * @see ::RenderType
0275      */
0276     Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType CONSTANT)
0277 
0278     /**
0279      * @brief This property specifies whether software rendering is being used.
0280      *
0281      * default: ``false``
0282      */
0283     Q_PROPERTY(bool softwareRendering READ isSoftwareRendering NOTIFY softwareRenderingChanged)
0284 
0285 public:
0286     ShadowedRectangle(QQuickItem *parent = nullptr);
0287     ~ShadowedRectangle() override;
0288 
0289     /**
0290      * @brief Available rendering types for ShadowedRectangle.
0291      */
0292     enum RenderType {
0293 
0294         /**
0295          * @brief Automatically determine the optimal rendering type.
0296          *
0297          * This will use the highest rendering quality possible, falling back to
0298          * lower quality if the hardware doesn't support it. It will use software
0299          * rendering if the QtQuick scene graph is set to use software rendering.
0300          */
0301         Auto,
0302 
0303         /**
0304          * @brief Use the highest rendering quality possible, even if the hardware might
0305          * not be able to handle it normally.
0306          */
0307         HighQuality,
0308 
0309         /**
0310          * @brief Use the lowest rendering quality, even if the hardware could handle
0311          * higher quality rendering.
0312          *
0313          * This might result in certain effects being omitted, like shadows.
0314          */
0315         LowQuality,
0316 
0317         /**
0318          * @brief Always use software rendering for this rectangle.
0319          *
0320          * Software rendering is intended as a fallback when the QtQuick scene
0321          * graph is configured to use software rendering. It will result in
0322          * a number of missing features, like shadows and multiple corner radii.
0323          */
0324         Software
0325     };
0326     Q_ENUM(RenderType)
0327 
0328     BorderGroup *border() const;
0329     ShadowGroup *shadow() const;
0330     CornersGroup *corners() const;
0331 
0332     qreal radius() const;
0333     void setRadius(qreal newRadius);
0334     Q_SIGNAL void radiusChanged();
0335 
0336     QColor color() const;
0337     void setColor(const QColor &newColor);
0338     Q_SIGNAL void colorChanged();
0339 
0340     RenderType renderType() const;
0341     void setRenderType(RenderType renderType);
0342     Q_SIGNAL void renderTypeChanged();
0343 
0344     void componentComplete() override;
0345 
0346     bool isSoftwareRendering() const;
0347 
0348 Q_SIGNALS:
0349     void softwareRenderingChanged();
0350 
0351 protected:
0352     PaintedRectangleItem *softwareItem() const;
0353     void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override;
0354     QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) override;
0355 
0356 private:
0357     void checkSoftwareItem();
0358     const std::unique_ptr<BorderGroup> m_border;
0359     const std::unique_ptr<ShadowGroup> m_shadow;
0360     const std::unique_ptr<CornersGroup> m_corners;
0361     qreal m_radius = 0.0;
0362     QColor m_color = Qt::white;
0363     RenderType m_renderType = RenderType::Auto;
0364     PaintedRectangleItem *m_softwareItem = nullptr;
0365 };