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

source code of kirigami/src/shadowedrectangle.h