| 1 | /* |
| 2 | * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl> |
| 3 | * |
| 4 | * SPDX-License-Identifier: LGPL-2.0-or-later |
| 5 | */ |
| 6 | |
| 7 | #pragma once |
| 8 | |
| 9 | #include <QQuickItem> |
| 10 | #include <memory> |
| 11 | |
| 12 | #include <QQmlEngine> |
| 13 | |
| 14 | class ShaderNode; |
| 15 | |
| 16 | class BorderGroup : public QObject |
| 17 | { |
| 18 | Q_OBJECT |
| 19 | QML_ELEMENT |
| 20 | QML_UNCREATABLE("" ) |
| 21 | |
| 22 | Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY changed FINAL) |
| 23 | |
| 24 | Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed FINAL) |
| 25 | |
| 26 | public: |
| 27 | explicit BorderGroup(QObject *parent = nullptr); |
| 28 | |
| 29 | qreal width() const; |
| 30 | void setWidth(qreal newWidth); |
| 31 | |
| 32 | QColor color() const; |
| 33 | void setColor(const QColor &newColor); |
| 34 | |
| 35 | Q_SIGNAL void changed(); |
| 36 | |
| 37 | inline bool isEnabled() const |
| 38 | { |
| 39 | return !qFuzzyIsNull(d: m_width); |
| 40 | } |
| 41 | |
| 42 | private: |
| 43 | qreal m_width = 0.0; |
| 44 | QColor m_color = Qt::black; |
| 45 | }; |
| 46 | |
| 47 | class ShadowGroup : public QObject |
| 48 | { |
| 49 | Q_OBJECT |
| 50 | QML_ELEMENT |
| 51 | QML_UNCREATABLE("" ) |
| 52 | |
| 53 | Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY changed FINAL) |
| 54 | |
| 55 | Q_PROPERTY(qreal xOffset READ xOffset WRITE setXOffset NOTIFY changed FINAL) |
| 56 | |
| 57 | Q_PROPERTY(qreal yOffset READ yOffset WRITE setYOffset NOTIFY changed FINAL) |
| 58 | |
| 59 | Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed FINAL) |
| 60 | |
| 61 | public: |
| 62 | explicit ShadowGroup(QObject *parent = nullptr); |
| 63 | |
| 64 | qreal size() const; |
| 65 | void setSize(qreal newSize); |
| 66 | |
| 67 | qreal xOffset() const; |
| 68 | void setXOffset(qreal newXOffset); |
| 69 | |
| 70 | qreal yOffset() const; |
| 71 | void setYOffset(qreal newYOffset); |
| 72 | |
| 73 | QColor color() const; |
| 74 | void setColor(const QColor &newShadowColor); |
| 75 | |
| 76 | Q_SIGNAL void changed(); |
| 77 | |
| 78 | private: |
| 79 | qreal m_size = 0.0; |
| 80 | qreal m_xOffset = 0.0; |
| 81 | qreal m_yOffset = 0.0; |
| 82 | QColor m_color = Qt::black; |
| 83 | }; |
| 84 | |
| 85 | class CornersGroup : public QObject |
| 86 | { |
| 87 | Q_OBJECT |
| 88 | QML_ELEMENT |
| 89 | QML_UNCREATABLE("" ) |
| 90 | |
| 91 | Q_PROPERTY(qreal topLeftRadius READ topLeft WRITE setTopLeft NOTIFY changed FINAL) |
| 92 | |
| 93 | Q_PROPERTY(qreal topRightRadius READ topRight WRITE setTopRight NOTIFY changed FINAL) |
| 94 | |
| 95 | Q_PROPERTY(qreal bottomLeftRadius READ bottomLeft WRITE setBottomLeft NOTIFY changed FINAL) |
| 96 | |
| 97 | Q_PROPERTY(qreal bottomRightRadius READ bottomRight WRITE setBottomRight NOTIFY changed FINAL) |
| 98 | |
| 99 | public: |
| 100 | explicit CornersGroup(QObject *parent = nullptr); |
| 101 | |
| 102 | qreal topLeft() const; |
| 103 | void setTopLeft(qreal newTopLeft); |
| 104 | |
| 105 | qreal topRight() const; |
| 106 | void setTopRight(qreal newTopRight); |
| 107 | |
| 108 | qreal bottomLeft() const; |
| 109 | void setBottomLeft(qreal newBottomLeft); |
| 110 | |
| 111 | qreal bottomRight() const; |
| 112 | void setBottomRight(qreal newBottomRight); |
| 113 | |
| 114 | Q_SIGNAL void changed(); |
| 115 | |
| 116 | QVector4D toVector4D(float all) const; |
| 117 | |
| 118 | private: |
| 119 | float m_topLeft = -1.0; |
| 120 | float m_topRight = -1.0; |
| 121 | float m_bottomLeft = -1.0; |
| 122 | float m_bottomRight = -1.0; |
| 123 | }; |
| 124 | |
| 125 | /*! |
| 126 | * \qmltype ShadowedRectangle |
| 127 | * \inqmlmodule org.kde.kirigami.primitives |
| 128 | * |
| 129 | * \brief A rectangle with a shadow behind it. |
| 130 | * |
| 131 | * This item will render a rectangle, with a shadow below it. The rendering is done |
| 132 | * using distance fields, which provide greatly improved performance. The shadow is |
| 133 | * rendered outside of the item's bounds, so the item's width and height are the |
| 134 | * rectangle's width and height. |
| 135 | * |
| 136 | * \since 5.69 |
| 137 | */ |
| 138 | class ShadowedRectangle : public QQuickItem |
| 139 | { |
| 140 | Q_OBJECT |
| 141 | QML_ELEMENT |
| 142 | /*! |
| 143 | * \qmlproperty real ShadowedRectangle::radius |
| 144 | * |
| 145 | * \brief This property holds the radii of the rectangle's corners. |
| 146 | * |
| 147 | * This is the amount of rounding to apply to all of the rectangle's |
| 148 | * corners, in pixels. Each corner can have a different radius. |
| 149 | * |
| 150 | * default: 0 |
| 151 | */ |
| 152 | Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL) |
| 153 | |
| 154 | /*! |
| 155 | * \qmlproperty color ShadowedRectangle::color |
| 156 | * \brief This property holds the rectangle's color. |
| 157 | * |
| 158 | * Full RGBA colors are supported. |
| 159 | * |
| 160 | * default: Qt.white |
| 161 | */ |
| 162 | Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL) |
| 163 | |
| 164 | /*! |
| 165 | * \qmlproperty real ShadowedRectangle::border.width |
| 166 | * \qmlproperty color ShadowedRectangle::border.color |
| 167 | * |
| 168 | * \brief This property holds the border's grouped property. |
| 169 | * |
| 170 | * width: The border's width in pixels. Default: 0 |
| 171 | * |
| 172 | * color: The border's color. Full RGBA colors are supported. Default: Qt.black |
| 173 | * |
| 174 | * Example usage: |
| 175 | * \code |
| 176 | * Kirigami.ShadowedRectangle { |
| 177 | * border.width: 2 |
| 178 | * border.color: Kirigami.Theme.textColor |
| 179 | * } |
| 180 | * \endcode |
| 181 | */ |
| 182 | Q_PROPERTY(BorderGroup *border READ border CONSTANT FINAL) |
| 183 | |
| 184 | /*! |
| 185 | * \qmlproperty real ShadowedRectangle::shadow.size |
| 186 | * \qmlproperty real ShadowedRectangle::shadow.xOffset |
| 187 | * \qmlproperty real ShadowedRectangle::shadow.yOffset |
| 188 | * \qmlproperty color ShadowedRectangle::shadow.color |
| 189 | * |
| 190 | * \brief This property group holds the shadow's properties. |
| 191 | * |
| 192 | * size: The shadow's approximate size in pixels. Note: The actual shadow size can be less than this value due to falloff. Default: 0px |
| 193 | * |
| 194 | * xOffset: The shadow's offset in pixels on the X axis. Default: 0px |
| 195 | * |
| 196 | * yOffset: The shadow's offset in pixels on the Y axis. Default: 0px |
| 197 | * |
| 198 | * color: The shadow's color. Full RGBA colors are supported. Default: Qt.black |
| 199 | * |
| 200 | * Example usage: |
| 201 | * \code |
| 202 | * Kirigami.ShadowedRectangle { |
| 203 | * shadow.size: 20 |
| 204 | * shadow.xOffset: 5 |
| 205 | * shadow.yOffset: 5 |
| 206 | * } |
| 207 | * \endcode |
| 208 | */ |
| 209 | Q_PROPERTY(ShadowGroup *shadow READ shadow CONSTANT FINAL) |
| 210 | |
| 211 | /*! |
| 212 | * \qmlproperty real ShadowedRectangle::corners.topLeftRadius |
| 213 | * \qmlproperty real ShadowedRectangle::corners.topRightRadius |
| 214 | * \qmlproperty real ShadowedRectangle::corners.bottomLeftRadius |
| 215 | * \qmlproperty real ShadowedRectangle::corners.bottomRightRadius |
| 216 | * |
| 217 | * \brief This property holds the corners grouped property |
| 218 | * |
| 219 | * Note that the values from this group override the radius property for the |
| 220 | * corner they affect. |
| 221 | * |
| 222 | * Setting any value to -1 indicates that the value should be ignored. |
| 223 | * |
| 224 | * The default value is -1 |
| 225 | * |
| 226 | * Example usage: |
| 227 | * \code |
| 228 | * Kirigami.ShadowedRectangle { |
| 229 | * corners.topLeftRadius: 4 |
| 230 | * corners.topRightRadius: 5 |
| 231 | * corners.bottomLeftRadius: 2 |
| 232 | * corners.bottomRightRadius: 10 |
| 233 | * \endcode |
| 234 | */ |
| 235 | Q_PROPERTY(CornersGroup *corners READ corners CONSTANT FINAL) |
| 236 | |
| 237 | /*! |
| 238 | * \qmlproperty enumeration ShadowedRectangle::renderType |
| 239 | * |
| 240 | * \brief This property holds the rectangle's render mode. |
| 241 | * |
| 242 | * \qmlenumeratorsfrom ShadowedRectangle::RenderType |
| 243 | * |
| 244 | * default: RenderType.Auto |
| 245 | */ |
| 246 | Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged FINAL) |
| 247 | |
| 248 | /*! |
| 249 | * \qmlproperty bool ShadowedRectangle::softwareRendering |
| 250 | * |
| 251 | * \brief This property tells whether software rendering is being used. |
| 252 | * |
| 253 | * default: false |
| 254 | */ |
| 255 | Q_PROPERTY(bool softwareRendering READ isSoftwareRendering NOTIFY softwareRenderingChanged FINAL) |
| 256 | |
| 257 | public: |
| 258 | ShadowedRectangle(QQuickItem *parent = nullptr); |
| 259 | ~ShadowedRectangle() override; |
| 260 | |
| 261 | /*! |
| 262 | * \brief Available rendering types for ShadowedRectangle. |
| 263 | * |
| 264 | * \value Auto Automatically determine the optimal rendering type. This will use the highest rendering quality possible, falling back to lower quality if |
| 265 | * the hardware doesn't support it. It will use software rendering if the QtQuick scene graph is set to use software rendering. |
| 266 | * \value HighQuality Use the highest rendering quality possible, even if the hardware might not be able to handle it normally. |
| 267 | * \value LowQuality Use the lowest rendering quality, even if the hardware could handle higher quality rendering. This might result in certain effects |
| 268 | * being omitted, like shadows. |
| 269 | * \value Software Always use software rendering for this rectangle. Software rendering is intended as a fallback when the QtQuick scene graph is configured |
| 270 | * to use software rendering. It will result in a number of missing features, like shadows and multiple corner radii. |
| 271 | */ |
| 272 | enum RenderType { |
| 273 | Auto, |
| 274 | HighQuality, |
| 275 | LowQuality, |
| 276 | Software |
| 277 | }; |
| 278 | Q_ENUM(RenderType) |
| 279 | |
| 280 | BorderGroup *border() const; |
| 281 | ShadowGroup *shadow() const; |
| 282 | CornersGroup *corners() const; |
| 283 | |
| 284 | qreal radius() const; |
| 285 | void setRadius(qreal newRadius); |
| 286 | Q_SIGNAL void radiusChanged(); |
| 287 | |
| 288 | QColor color() const; |
| 289 | void setColor(const QColor &newColor); |
| 290 | Q_SIGNAL void colorChanged(); |
| 291 | |
| 292 | RenderType renderType() const; |
| 293 | void setRenderType(RenderType renderType); |
| 294 | Q_SIGNAL void renderTypeChanged(); |
| 295 | |
| 296 | void componentComplete() override; |
| 297 | |
| 298 | Q_SIGNALS: |
| 299 | void softwareRenderingChanged(); |
| 300 | |
| 301 | protected: |
| 302 | bool isSoftwareRendering() const; |
| 303 | bool isLowPowerRendering() const; |
| 304 | |
| 305 | QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) override; |
| 306 | void updateShaderNode(ShaderNode *shaderNode); |
| 307 | |
| 308 | private: |
| 309 | const std::unique_ptr<BorderGroup> m_border; |
| 310 | const std::unique_ptr<ShadowGroup> m_shadow; |
| 311 | const std::unique_ptr<CornersGroup> m_corners; |
| 312 | qreal m_radius = 0.0; |
| 313 | QColor m_color = Qt::white; |
| 314 | RenderType m_renderType = RenderType::Auto; |
| 315 | }; |
| 316 | |