File indexing completed on 2024-04-14 03:53:48

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