1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qbrush.h"
41#include "qpixmap.h"
42#include "qbitmap.h"
43#include "qpixmapcache.h"
44#include <qpa/qplatformpixmap.h>
45#include "qdatastream.h"
46#include "qvariant.h"
47#include "qline.h"
48#include "qdebug.h"
49#include <QtCore/qjsondocument.h>
50#include <QtCore/qjsonarray.h>
51#include <QtCore/qcoreapplication.h>
52#include "private/qhexstring_p.h"
53#include <QtCore/qnumeric.h>
54#include <QtCore/qfile.h>
55#include <QtCore/qmutex.h>
56
57QT_BEGIN_NAMESPACE
58
59const uchar *qt_patternForBrush(int brushStyle, bool invert)
60{
61 Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
62 static const uchar pat_tbl[][2][8] = {
63 {
64 /* dense1 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 },
65 /*~dense1 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff },
66 }, {
67 /* dense2 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
68 /*~dense2 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff },
69 }, {
70 /* dense3 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 },
71 /*~dense3 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee },
72 }, {
73 /* dense4 */ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa },
74 /*~dense4 */ { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 },
75 }, {
76 /* dense5 */ { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee },
77 /*~dense5 */ { 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa, 0x11 },
78 }, {
79 /* dense6 */ { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff },
80 /*~dense6 */ { 0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00 },
81 }, {
82 /* dense7 */ { 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff },
83 /*~dense7 */ { 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00 },
84 }, {
85 /* hor */ { 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff },
86 /*~hor */ { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 },
87 }, {
88 /* ver */ { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef },
89 /*~ver */ { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
90 }, {
91 /* cross */ { 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef, 0xef },
92 /*~cross */ { 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0x10 },
93 }, {
94 /* bdiag */ { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe },
95 /*~bdiag */ { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
96 }, {
97 /* fdiag */ { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f },
98 /*~fdiag */ { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 },
99 }, {
100 /* dcross */ { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e },
101 /*~dcross */ { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 },
102 },
103 };
104 return pat_tbl[brushStyle - Qt::Dense1Pattern][invert];
105}
106
107Q_GUI_EXPORT QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
108{
109
110 QPixmap pm;
111 QString key = QLatin1String("$qt-brush$")
112 % HexString<uint>(brushStyle)
113 % QLatin1Char(invert ? '1' : '0');
114 if (!QPixmapCache::find(key, pixmap: &pm)) {
115 pm = QBitmap::fromData(size: QSize(8, 8), bits: qt_patternForBrush(brushStyle, invert),
116 monoFormat: QImage::Format_MonoLSB);
117 QPixmapCache::insert(key, pixmap: pm);
118 }
119
120 return pm;
121}
122
123static void qt_cleanup_brush_pattern_image_cache();
124class QBrushPatternImageCache
125{
126public:
127 QBrushPatternImageCache()
128 : m_initialized(false)
129 {
130 init();
131 }
132
133 void init()
134 {
135 qAddPostRoutine(qt_cleanup_brush_pattern_image_cache);
136 for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
137 int i = style - Qt::Dense1Pattern;
138 m_images[i][0] = QImage(qt_patternForBrush(brushStyle: style, invert: 0), 8, 8, 1, QImage::Format_MonoLSB);
139 m_images[i][1] = QImage(qt_patternForBrush(brushStyle: style, invert: 1), 8, 8, 1, QImage::Format_MonoLSB);
140 }
141 m_initialized = true;
142 }
143
144 QImage getImage(int brushStyle, bool invert) const
145 {
146 Q_ASSERT(brushStyle >= Qt::Dense1Pattern && brushStyle <= Qt::DiagCrossPattern);
147 if (!m_initialized)
148 const_cast<QBrushPatternImageCache*>(this)->init();
149 return m_images[brushStyle - Qt::Dense1Pattern][invert];
150 }
151
152 void cleanup() {
153 for (int style = Qt::Dense1Pattern; style <= Qt::DiagCrossPattern; ++style) {
154 int i = style - Qt::Dense1Pattern;
155 m_images[i][0] = QImage();
156 m_images[i][1] = QImage();
157 }
158 m_initialized = false;
159 }
160
161private:
162 QImage m_images[Qt::DiagCrossPattern - Qt::Dense1Pattern + 1][2];
163 bool m_initialized;
164};
165
166Q_GLOBAL_STATIC(QBrushPatternImageCache, qt_brushPatternImageCache)
167
168static void qt_cleanup_brush_pattern_image_cache()
169{
170 qt_brushPatternImageCache()->cleanup();
171}
172
173Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert)
174{
175 return qt_brushPatternImageCache()->getImage(brushStyle, invert);
176}
177
178struct QTexturedBrushData : public QBrushData
179{
180 QTexturedBrushData() {
181 m_has_pixmap_texture = false;
182 m_pixmap = nullptr;
183 }
184 ~QTexturedBrushData() {
185 delete m_pixmap;
186 }
187
188 void setPixmap(const QPixmap &pm) {
189 delete m_pixmap;
190
191 if (pm.isNull()) {
192 m_pixmap = nullptr;
193 m_has_pixmap_texture = false;
194 } else {
195 m_pixmap = new QPixmap(pm);
196 m_has_pixmap_texture = true;
197 }
198
199 m_image = QImage();
200 }
201
202 void setImage(const QImage &image) {
203 m_image = image;
204 delete m_pixmap;
205 m_pixmap = nullptr;
206 m_has_pixmap_texture = false;
207 }
208
209 QPixmap &pixmap() {
210 if (!m_pixmap) {
211 m_pixmap = new QPixmap(QPixmap::fromImage(image: m_image));
212 }
213 return *m_pixmap;
214 }
215
216 QImage &image() {
217 if (m_image.isNull() && m_pixmap)
218 m_image = m_pixmap->toImage();
219 return m_image;
220 }
221
222 QPixmap *m_pixmap;
223 QImage m_image;
224 bool m_has_pixmap_texture;
225};
226
227// returns true if the brush has a pixmap (or bitmap) set as the
228// brush texture, false otherwise
229bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush)
230{
231 if (brush.style() != Qt::TexturePattern)
232 return false;
233 QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.data());
234 return tx_data->m_has_pixmap_texture;
235}
236
237struct QGradientBrushData : public QBrushData
238{
239 QGradient gradient;
240};
241
242struct QBrushDataPointerDeleter
243{
244 static inline void deleteData(QBrushData *d)
245 {
246 switch (d->style) {
247 case Qt::TexturePattern:
248 delete static_cast<QTexturedBrushData*>(d);
249 break;
250 case Qt::LinearGradientPattern:
251 case Qt::RadialGradientPattern:
252 case Qt::ConicalGradientPattern:
253 delete static_cast<QGradientBrushData*>(d);
254 break;
255 default:
256 delete d;
257 }
258 }
259
260 static inline void cleanup(QBrushData *d)
261 {
262 if (d && !d->ref.deref()) {
263 deleteData(d);
264 }
265 }
266};
267
268/*!
269 \class QBrush
270 \ingroup painting
271 \ingroup shared
272 \inmodule QtGui
273
274 \brief The QBrush class defines the fill pattern of shapes drawn
275 by QPainter.
276
277 A brush has a style, a color, a gradient and a texture.
278
279 The brush style() defines the fill pattern using the
280 Qt::BrushStyle enum. The default brush style is Qt::NoBrush
281 (depending on how you construct a brush). This style tells the
282 painter to not fill shapes. The standard style for filling is
283 Qt::SolidPattern. The style can be set when the brush is created
284 using the appropriate constructor, and in addition the setStyle()
285 function provides means for altering the style once the brush is
286 constructed.
287
288 \image brush-styles.png Brush Styles
289
290 The brush color() defines the color of the fill pattern. The color
291 can either be one of Qt's predefined colors, Qt::GlobalColor, or
292 any other custom QColor. The currently set color can be retrieved
293 and altered using the color() and setColor() functions,
294 respectively.
295
296 The gradient() defines the gradient fill used when the current
297 style is either Qt::LinearGradientPattern,
298 Qt::RadialGradientPattern or Qt::ConicalGradientPattern. Gradient
299 brushes are created by giving a QGradient as a constructor
300 argument when creating the QBrush. Qt provides three different
301 gradients: QLinearGradient, QConicalGradient, and QRadialGradient
302 - all of which inherit QGradient.
303
304 \snippet brush/gradientcreationsnippet.cpp 0
305
306 The texture() defines the pixmap used when the current style is
307 Qt::TexturePattern. You can create a brush with a texture by
308 providing the pixmap when the brush is created or by using
309 setTexture().
310
311 Note that applying setTexture() makes style() ==
312 Qt::TexturePattern, regardless of previous style
313 settings. Also, calling setColor() will not make a difference if
314 the style is a gradient. The same is the case if the style is
315 Qt::TexturePattern style unless the current texture is a QBitmap.
316
317 The isOpaque() function returns \c true if the brush is fully opaque
318 otherwise false. A brush is considered opaque if:
319
320 \list
321 \li The alpha component of the color() is 255.
322 \li Its texture() does not have an alpha channel and is not a QBitmap.
323 \li The colors in the gradient() all have an alpha component that is 255.
324 \endlist
325
326 \table 100%
327 \row
328 \li \inlineimage brush-outline.png Outlines
329 \li
330
331 To specify the style and color of lines and outlines, use the
332 QPainter's \l {QPen}{pen} combined with Qt::PenStyle and
333 Qt::GlobalColor:
334
335 \snippet code/src_gui_painting_qbrush.cpp 0
336
337 Note that, by default, QPainter renders the outline (using the
338 currently set pen) when drawing shapes. Use \l {Qt::NoPen}{\c
339 painter.setPen(Qt::NoPen)} to disable this behavior.
340
341 \endtable
342
343 For more information about painting in general, see the \l{Paint
344 System}.
345
346 \sa Qt::BrushStyle, QPainter, QColor
347*/
348
349class QNullBrushData
350{
351public:
352 QBrushData *brush;
353 QNullBrushData() : brush(new QBrushData)
354 {
355 brush->ref.storeRelaxed(newValue: 1);
356 brush->style = Qt::BrushStyle(0);
357 brush->color = Qt::black;
358 }
359 ~QNullBrushData()
360 {
361 if (!brush->ref.deref())
362 delete brush;
363 brush = nullptr;
364 }
365};
366
367Q_GLOBAL_STATIC(QNullBrushData, nullBrushInstance_holder)
368static QBrushData *nullBrushInstance()
369{
370 return nullBrushInstance_holder()->brush;
371}
372
373static bool qbrush_check_type(Qt::BrushStyle style) {
374 switch (style) {
375 case Qt::TexturePattern:
376 qWarning(msg: "QBrush: Incorrect use of TexturePattern");
377 break;
378 case Qt::LinearGradientPattern:
379 case Qt::RadialGradientPattern:
380 case Qt::ConicalGradientPattern:
381 qWarning(msg: "QBrush: Wrong use of a gradient pattern");
382 break;
383 default:
384 return true;
385 }
386 return false;
387}
388
389/*!
390 \internal
391 Initializes the brush.
392*/
393
394void QBrush::init(const QColor &color, Qt::BrushStyle style)
395{
396 switch(style) {
397 case Qt::NoBrush:
398 d.reset(other: nullBrushInstance());
399 d->ref.ref();
400 if (d->color != color) setColor(color);
401 return;
402 case Qt::TexturePattern:
403 d.reset(other: new QTexturedBrushData);
404 break;
405 case Qt::LinearGradientPattern:
406 case Qt::RadialGradientPattern:
407 case Qt::ConicalGradientPattern:
408 d.reset(other: new QGradientBrushData);
409 break;
410 default:
411 d.reset(other: new QBrushData);
412 break;
413 }
414 d->ref.storeRelaxed(newValue: 1);
415 d->style = style;
416 d->color = color;
417}
418
419/*!
420 Constructs a default black brush with the style Qt::NoBrush
421 (i.e. this brush will not fill shapes).
422*/
423
424QBrush::QBrush()
425 : d(nullBrushInstance())
426{
427 Q_ASSERT(d);
428 d->ref.ref();
429}
430
431/*!
432 Constructs a brush with a black color and a texture set to the
433 given \a pixmap. The style is set to Qt::TexturePattern.
434
435 \sa setTexture()
436*/
437
438QBrush::QBrush(const QPixmap &pixmap)
439{
440 init(color: Qt::black, style: Qt::TexturePattern);
441 setTexture(pixmap);
442}
443
444
445/*!
446 Constructs a brush with a black color and a texture set to the
447 given \a image. The style is set to Qt::TexturePattern.
448
449 \sa setTextureImage()
450*/
451
452QBrush::QBrush(const QImage &image)
453{
454 init(color: Qt::black, style: Qt::TexturePattern);
455 setTextureImage(image);
456}
457
458/*!
459 Constructs a black brush with the given \a style.
460
461 \sa setStyle()
462*/
463
464QBrush::QBrush(Qt::BrushStyle style)
465 : QBrush(QColor(Qt::black), style)
466{
467}
468
469/*!
470 Constructs a brush with the given \a color and \a style.
471
472 \sa setColor(), setStyle()
473*/
474
475QBrush::QBrush(const QColor &color, Qt::BrushStyle style)
476{
477 if (qbrush_check_type(style))
478 init(color, style);
479 else {
480 d.reset(other: nullBrushInstance());
481 d->ref.ref();
482 }
483}
484
485/*!
486 \fn QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
487
488 Constructs a brush with the given \a color and \a style.
489
490 \sa setColor(), setStyle()
491*/
492QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style)
493 : QBrush(QColor(color), style)
494{
495}
496
497/*!
498 Constructs a brush with the given \a color and the custom pattern
499 stored in \a pixmap.
500
501 The style is set to Qt::TexturePattern. The color will only have
502 an effect for QBitmaps.
503
504 \sa setColor(), setTexture()
505*/
506
507QBrush::QBrush(const QColor &color, const QPixmap &pixmap)
508{
509 init(color, style: Qt::TexturePattern);
510 setTexture(pixmap);
511}
512
513/*!
514
515 Constructs a brush with the given \a color and the custom pattern
516 stored in \a pixmap.
517
518 The style is set to Qt::TexturePattern. The color will only have
519 an effect for QBitmaps.
520
521 \sa setColor(), setTexture()
522*/
523QBrush::QBrush(Qt::GlobalColor color, const QPixmap &pixmap)
524{
525 init(color, style: Qt::TexturePattern);
526 setTexture(pixmap);
527}
528
529/*!
530 Constructs a copy of \a other.
531*/
532
533QBrush::QBrush(const QBrush &other)
534 : d(other.d.data())
535{
536 d->ref.ref();
537}
538
539/*!
540 Constructs a brush based on the given \a gradient.
541
542 The brush style is set to the corresponding gradient style (either
543 Qt::LinearGradientPattern, Qt::RadialGradientPattern or
544 Qt::ConicalGradientPattern).
545*/
546QBrush::QBrush(const QGradient &gradient)
547{
548 if (Q_UNLIKELY(gradient.type() == QGradient::NoGradient)) {
549 d.reset(other: nullBrushInstance());
550 d->ref.ref();
551 return;
552 }
553
554 const Qt::BrushStyle enum_table[] = {
555 Qt::LinearGradientPattern,
556 Qt::RadialGradientPattern,
557 Qt::ConicalGradientPattern
558 };
559
560 init(color: QColor(), style: enum_table[gradient.type()]);
561 QGradientBrushData *grad = static_cast<QGradientBrushData *>(d.data());
562 grad->gradient = gradient;
563}
564
565/*!
566 Destroys the brush.
567*/
568
569QBrush::~QBrush()
570{
571}
572
573void QBrush::cleanUp(QBrushData *x)
574{
575 QBrushDataPointerDeleter::deleteData(d: x);
576}
577
578static Q_DECL_CONSTEXPR inline bool use_same_brushdata(Qt::BrushStyle lhs, Qt::BrushStyle rhs)
579{
580 return lhs == rhs // includes Qt::TexturePattern
581 || (lhs >= Qt::NoBrush && lhs <= Qt::DiagCrossPattern && rhs >= Qt::NoBrush && rhs <= Qt::DiagCrossPattern)
582 || (lhs >= Qt::LinearGradientPattern && lhs <= Qt::ConicalGradientPattern && rhs >= Qt::LinearGradientPattern && rhs <= Qt::ConicalGradientPattern)
583 ;
584}
585
586void QBrush::detach(Qt::BrushStyle newStyle)
587{
588 if (use_same_brushdata(lhs: newStyle, rhs: d->style) && d->ref.loadRelaxed() == 1) {
589 d->style = newStyle;
590 return;
591 }
592
593 QScopedPointer<QBrushData, QBrushDataPointerDeleter> x;
594 switch(newStyle) {
595 case Qt::TexturePattern: {
596 QTexturedBrushData *tbd = new QTexturedBrushData;
597 if (d->style == Qt::TexturePattern) {
598 QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
599 if (data->m_has_pixmap_texture)
600 tbd->setPixmap(data->pixmap());
601 else
602 tbd->setImage(data->image());
603 }
604 x.reset(other: tbd);
605 break;
606 }
607 case Qt::LinearGradientPattern:
608 case Qt::RadialGradientPattern:
609 case Qt::ConicalGradientPattern: {
610 QGradientBrushData *gbd = new QGradientBrushData;
611 switch (d->style) {
612 case Qt::LinearGradientPattern:
613 case Qt::RadialGradientPattern:
614 case Qt::ConicalGradientPattern:
615 gbd->gradient =
616 static_cast<QGradientBrushData *>(d.data())->gradient;
617 break;
618 default:
619 break;
620 }
621 x.reset(other: gbd);
622 break;
623 }
624 default:
625 x.reset(other: new QBrushData);
626 break;
627 }
628 x->ref.storeRelaxed(newValue: 1); // must be first lest the QBrushDataPointerDeleter turns into a no-op
629 x->style = newStyle;
630 x->color = d->color;
631 x->transform = d->transform;
632 d.swap(other&: x);
633}
634
635
636/*!
637 \fn QBrush &QBrush::operator=(const QBrush &brush)
638
639 Assigns the given \a brush to \e this brush and returns a
640 reference to \e this brush.
641*/
642
643QBrush &QBrush::operator=(const QBrush &b)
644{
645 if (d == b.d)
646 return *this;
647
648 b.d->ref.ref();
649 d.reset(other: b.d.data());
650 return *this;
651}
652
653/*!
654 \fn QBrush &QBrush::operator=(QBrush &&other)
655
656 Move-assigns \a other to this QBrush instance.
657
658 \since 5.2
659*/
660
661/*!
662 \fn void QBrush::swap(QBrush &other)
663 \since 4.8
664
665 Swaps brush \a other with this brush. This operation is very
666 fast and never fails.
667*/
668
669/*!
670 Returns the brush as a QVariant
671*/
672QBrush::operator QVariant() const
673{
674 return QVariant(QMetaType::QBrush, this);
675}
676
677/*!
678 \fn Qt::BrushStyle QBrush::style() const
679
680 Returns the brush style.
681
682 \sa setStyle()
683*/
684
685/*!
686 Sets the brush style to \a style.
687
688 \sa style()
689*/
690
691void QBrush::setStyle(Qt::BrushStyle style)
692{
693 if (d->style == style)
694 return;
695
696 if (qbrush_check_type(style)) {
697 detach(newStyle: style);
698 d->style = style;
699 }
700}
701
702
703/*!
704 \fn const QColor &QBrush::color() const
705
706 Returns the brush color.
707
708 \sa setColor()
709*/
710
711/*!
712 \fn void QBrush::setColor(const QColor &color)
713
714 Sets the brush color to the given \a color.
715
716 Note that calling setColor() will not make a difference if the
717 style is a gradient. The same is the case if the style is
718 Qt::TexturePattern style unless the current texture is a QBitmap.
719
720 \sa color()
721*/
722
723void QBrush::setColor(const QColor &c)
724{
725 if (d->color == c)
726 return;
727
728 detach(newStyle: d->style);
729 d->color = c;
730}
731
732/*!
733 \fn void QBrush::setColor(Qt::GlobalColor color)
734 \overload
735
736 Sets the brush color to the given \a color.
737*/
738
739/*!
740 \fn QPixmap QBrush::texture() const
741
742 Returns the custom brush pattern, or a null pixmap if no custom brush pattern
743 has been set.
744
745 \sa setTexture()
746*/
747QPixmap QBrush::texture() const
748{
749 return d->style == Qt::TexturePattern
750 ? (static_cast<QTexturedBrushData *>(d.data()))->pixmap()
751 : QPixmap();
752}
753
754/*!
755 Sets the brush pixmap to \a pixmap. The style is set to
756 Qt::TexturePattern.
757
758 The current brush color will only have an effect for monochrome
759 pixmaps, i.e. for QPixmap::depth() == 1 (\l {QBitmap}{QBitmaps}).
760
761 \sa texture()
762*/
763
764void QBrush::setTexture(const QPixmap &pixmap)
765{
766 if (!pixmap.isNull()) {
767 detach(newStyle: Qt::TexturePattern);
768 QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
769 data->setPixmap(pixmap);
770 } else {
771 detach(newStyle: Qt::NoBrush);
772 }
773}
774
775
776/*!
777 \since 4.2
778
779 Returns the custom brush pattern, or a null image if no custom
780 brush pattern has been set.
781
782 If the texture was set as a QPixmap it will be converted to a
783 QImage.
784
785 \sa setTextureImage()
786*/
787
788QImage QBrush::textureImage() const
789{
790 return d->style == Qt::TexturePattern
791 ? (static_cast<QTexturedBrushData *>(d.data()))->image()
792 : QImage();
793}
794
795
796/*!
797 \since 4.2
798
799 Sets the brush image to \a image. The style is set to
800 Qt::TexturePattern.
801
802 Note the current brush color will \e not have any affect on
803 monochrome images, as opposed to calling setTexture() with a
804 QBitmap. If you want to change the color of monochrome image
805 brushes, either convert the image to QBitmap with \c
806 QBitmap::fromImage() and set the resulting QBitmap as a texture,
807 or change the entries in the color table for the image.
808
809 \sa textureImage(), setTexture()
810*/
811
812void QBrush::setTextureImage(const QImage &image)
813{
814 if (!image.isNull()) {
815 detach(newStyle: Qt::TexturePattern);
816 QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
817 data->setImage(image);
818 } else {
819 detach(newStyle: Qt::NoBrush);
820 }
821}
822
823
824/*!
825 Returns the gradient describing this brush.
826*/
827const QGradient *QBrush::gradient() const
828{
829 if (d->style == Qt::LinearGradientPattern
830 || d->style == Qt::RadialGradientPattern
831 || d->style == Qt::ConicalGradientPattern) {
832 return &static_cast<const QGradientBrushData *>(d.data())->gradient;
833 }
834 return nullptr;
835}
836
837Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
838{
839 if (brush.style() == Qt::RadialGradientPattern) {
840 const QGradient *g = brush.gradient();
841 const QRadialGradient *rg = static_cast<const QRadialGradient *>(g);
842
843 if (!qFuzzyIsNull(d: rg->focalRadius()))
844 return true;
845
846 QPointF delta = rg->focalPoint() - rg->center();
847 if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius())
848 return true;
849 }
850
851 return false;
852}
853
854/*!
855 Returns \c true if the brush is fully opaque otherwise false. A brush
856 is considered opaque if:
857
858 \list
859 \li The alpha component of the color() is 255.
860 \li Its texture() does not have an alpha channel and is not a QBitmap.
861 \li The colors in the gradient() all have an alpha component that is 255.
862 \li It is an extended radial gradient.
863 \endlist
864*/
865
866bool QBrush::isOpaque() const
867{
868 bool opaqueColor = d->color.alpha() == 255;
869
870 // Test awfully simple case first
871 if (d->style == Qt::SolidPattern)
872 return opaqueColor;
873
874 if (qt_isExtendedRadialGradient(brush: *this))
875 return false;
876
877 if (d->style == Qt::LinearGradientPattern
878 || d->style == Qt::RadialGradientPattern
879 || d->style == Qt::ConicalGradientPattern) {
880 QGradientStops stops = gradient()->stops();
881 for (int i=0; i<stops.size(); ++i)
882 if (stops.at(i).second.alpha() != 255)
883 return false;
884 return true;
885 } else if (d->style == Qt::TexturePattern) {
886 return qHasPixmapTexture(brush: *this)
887 ? !texture().hasAlphaChannel() && !texture().isQBitmap()
888 : !textureImage().hasAlphaChannel();
889 }
890
891 return false;
892}
893
894
895#if QT_DEPRECATED_SINCE(5, 15)
896/*!
897 \since 4.2
898 \obsolete
899
900 Use setTransform() instead.
901
902 Sets \a matrix as an explicit transformation matrix on the
903 current brush. The brush transformation matrix is merged with
904 QPainter transformation matrix to produce the final result.
905
906 \sa matrix()
907*/
908void QBrush::setMatrix(const QMatrix &matrix)
909{
910 setTransform(QTransform(matrix));
911}
912#endif // QT_DEPRECATED_SINCE(5, 15)
913
914/*!
915 \since 4.3
916
917 Sets \a matrix as an explicit transformation matrix on the
918 current brush. The brush transformation matrix is merged with
919 QPainter transformation matrix to produce the final result.
920
921 \sa transform()
922*/
923void QBrush::setTransform(const QTransform &matrix)
924{
925 detach(newStyle: d->style);
926 d->transform = matrix;
927}
928
929
930#if QT_DEPRECATED_SINCE(5, 15)
931/*!
932 \fn void QBrush::matrix() const
933 \since 4.2
934 \obsolete
935
936 Use transform() instead.
937
938 Returns the current transformation matrix for the brush.
939
940 \sa setMatrix()
941*/
942#endif // QT_DEPRECATED_SINCE(5, 15)
943
944/*!
945 \fn bool QBrush::operator!=(const QBrush &brush) const
946
947 Returns \c true if the brush is different from the given \a brush;
948 otherwise returns \c false.
949
950 Two brushes are different if they have different styles, colors or
951 transforms or different pixmaps or gradients depending on the style.
952
953 \sa operator==()
954*/
955
956/*!
957 \fn bool QBrush::operator==(const QBrush &brush) const
958
959 Returns \c true if the brush is equal to the given \a brush;
960 otherwise returns \c false.
961
962 Two brushes are equal if they have equal styles, colors and
963 transforms and equal pixmaps or gradients depending on the style.
964
965 \sa operator!=()
966*/
967
968bool QBrush::operator==(const QBrush &b) const
969{
970 if (b.d == d)
971 return true;
972 if (b.d->style != d->style || b.d->color != d->color || b.d->transform != d->transform)
973 return false;
974 switch (d->style) {
975 case Qt::TexturePattern:
976 {
977 // Note this produces false negatives if the textures have identical data,
978 // but does not share the same data in memory. Since equality is likely to
979 // be used to avoid iterating over the data for a texture update, this should
980 // still be better than doing an accurate comparison.
981 const QPixmap *us = nullptr, *them = nullptr;
982 qint64 cacheKey1, cacheKey2;
983 if (qHasPixmapTexture(brush: *this)) {
984 us = (static_cast<QTexturedBrushData *>(d.data()))->m_pixmap;
985 cacheKey1 = us->cacheKey();
986 } else
987 cacheKey1 = (static_cast<QTexturedBrushData *>(d.data()))->image().cacheKey();
988
989 if (qHasPixmapTexture(brush: b)) {
990 them = (static_cast<QTexturedBrushData *>(b.d.data()))->m_pixmap;
991 cacheKey2 = them->cacheKey();
992 } else
993 cacheKey2 = (static_cast<QTexturedBrushData *>(b.d.data()))->image().cacheKey();
994
995 if (cacheKey1 != cacheKey2)
996 return false;
997 if (!us == !them) // both images or both pixmaps
998 return true;
999 // Only raster QPixmaps use the same cachekeys as QImages.
1000 if (us && us->handle()->classId() == QPlatformPixmap::RasterClass)
1001 return true;
1002 if (them && them->handle()->classId() == QPlatformPixmap::RasterClass)
1003 return true;
1004 return false;
1005 }
1006 case Qt::LinearGradientPattern:
1007 case Qt::RadialGradientPattern:
1008 case Qt::ConicalGradientPattern:
1009 {
1010 const QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.data());
1011 const QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.data());
1012 return d1->gradient == d2->gradient;
1013 }
1014 default:
1015 return true;
1016 }
1017}
1018
1019#ifndef QT_NO_DEBUG_STREAM
1020/*!
1021 \internal
1022*/
1023QDebug operator<<(QDebug dbg, const QBrush &b)
1024{
1025 static const char BRUSH_STYLES[][24] = {
1026 "NoBrush",
1027 "SolidPattern",
1028 "Dense1Pattern",
1029 "Dense2Pattern",
1030 "Dense3Pattern",
1031 "Dense4Pattern",
1032 "Dense5Pattern",
1033 "Dense6Pattern",
1034 "Dense7Pattern",
1035 "HorPattern",
1036 "VerPattern",
1037 "CrossPattern",
1038 "BDiagPattern",
1039 "FDiagPattern",
1040 "DiagCrossPattern",
1041 "LinearGradientPattern",
1042 "RadialGradientPattern",
1043 "ConicalGradientPattern",
1044 "", "", "", "", "", "",
1045 "TexturePattern" // 24
1046 };
1047
1048 QDebugStateSaver saver(dbg);
1049 dbg.nospace() << "QBrush(" << b.color() << ',' << BRUSH_STYLES[b.style()] << ')';
1050 return dbg;
1051}
1052#endif
1053
1054/*****************************************************************************
1055 QBrush stream functions
1056 *****************************************************************************/
1057#ifndef QT_NO_DATASTREAM
1058/*!
1059 \fn QDataStream &operator<<(QDataStream &stream, const QBrush &brush)
1060 \relates QBrush
1061
1062 Writes the given \a brush to the given \a stream and returns a
1063 reference to the \a stream.
1064
1065 \sa {Serializing Qt Data Types}
1066*/
1067
1068QDataStream &operator<<(QDataStream &s, const QBrush &b)
1069{
1070 quint8 style = (quint8) b.style();
1071 bool gradient_style = false;
1072
1073 if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern
1074 || style == Qt::ConicalGradientPattern)
1075 gradient_style = true;
1076
1077 if (s.version() < QDataStream::Qt_4_0 && gradient_style)
1078 style = Qt::NoBrush;
1079
1080 s << style << b.color();
1081 if (b.style() == Qt::TexturePattern) {
1082 if (s.version() >= QDataStream::Qt_5_5)
1083 s << b.textureImage();
1084 else
1085 s << b.texture();
1086 } else if (s.version() >= QDataStream::Qt_4_0 && gradient_style) {
1087 const QGradient *gradient = b.gradient();
1088 int type_as_int = int(gradient->type());
1089 s << type_as_int;
1090 if (s.version() >= QDataStream::Qt_4_3) {
1091 s << int(gradient->spread());
1092 QGradient::CoordinateMode co_mode = gradient->coordinateMode();
1093 if (s.version() < QDataStream::Qt_5_12 && co_mode == QGradient::ObjectMode)
1094 co_mode = QGradient::ObjectBoundingMode;
1095 s << int(co_mode);
1096 }
1097
1098 if (s.version() >= QDataStream::Qt_4_5)
1099 s << int(gradient->interpolationMode());
1100
1101 if (sizeof(qreal) == sizeof(double)) {
1102 s << gradient->stops();
1103 } else {
1104 // ensure that we write doubles here instead of streaming the stops
1105 // directly; otherwise, platforms that redefine qreal might generate
1106 // data that cannot be read on other platforms.
1107 QVector<QGradientStop> stops = gradient->stops();
1108 s << quint32(stops.size());
1109 for (int i = 0; i < stops.size(); ++i) {
1110 const QGradientStop &stop = stops.at(i);
1111 s << QPair<double, QColor>(double(stop.first), stop.second);
1112 }
1113 }
1114
1115 if (gradient->type() == QGradient::LinearGradient) {
1116 s << static_cast<const QLinearGradient *>(gradient)->start();
1117 s << static_cast<const QLinearGradient *>(gradient)->finalStop();
1118 } else if (gradient->type() == QGradient::RadialGradient) {
1119 s << static_cast<const QRadialGradient *>(gradient)->center();
1120 s << static_cast<const QRadialGradient *>(gradient)->focalPoint();
1121 s << (double) static_cast<const QRadialGradient *>(gradient)->radius();
1122 } else { // type == Conical
1123 s << static_cast<const QConicalGradient *>(gradient)->center();
1124 s << (double) static_cast<const QConicalGradient *>(gradient)->angle();
1125 }
1126 }
1127 if (s.version() >= QDataStream::Qt_4_3)
1128 s << b.transform();
1129 return s;
1130}
1131
1132/*!
1133 \fn QDataStream &operator>>(QDataStream &stream, QBrush &brush)
1134 \relates QBrush
1135
1136 Reads the given \a brush from the given \a stream and returns a
1137 reference to the \a stream.
1138
1139 \sa {Serializing Qt Data Types}
1140*/
1141
1142QDataStream &operator>>(QDataStream &s, QBrush &b)
1143{
1144 quint8 style;
1145 QColor color;
1146 s >> style;
1147 s >> color;
1148 b = QBrush(color);
1149 if (style == Qt::TexturePattern) {
1150 if (s.version() >= QDataStream::Qt_5_5) {
1151 QImage img;
1152 s >> img;
1153 b.setTextureImage(std::move(img));
1154 } else {
1155 QPixmap pm;
1156 s >> pm;
1157 b.setTexture(std::move(pm));
1158 }
1159 } else if (style == Qt::LinearGradientPattern
1160 || style == Qt::RadialGradientPattern
1161 || style == Qt::ConicalGradientPattern) {
1162
1163 int type_as_int;
1164 QGradient::Type type;
1165 QGradientStops stops;
1166 QGradient::CoordinateMode cmode = QGradient::LogicalMode;
1167 QGradient::Spread spread = QGradient::PadSpread;
1168 QGradient::InterpolationMode imode = QGradient::ColorInterpolation;
1169
1170 s >> type_as_int;
1171 type = QGradient::Type(type_as_int);
1172 if (s.version() >= QDataStream::Qt_4_3) {
1173 s >> type_as_int;
1174 spread = QGradient::Spread(type_as_int);
1175 s >> type_as_int;
1176 cmode = QGradient::CoordinateMode(type_as_int);
1177 }
1178
1179 if (s.version() >= QDataStream::Qt_4_5) {
1180 s >> type_as_int;
1181 imode = QGradient::InterpolationMode(type_as_int);
1182 }
1183
1184 if (sizeof(qreal) == sizeof(double)) {
1185 s >> stops;
1186 } else {
1187 quint32 numStops;
1188 double n;
1189 QColor c;
1190
1191 s >> numStops;
1192 stops.reserve(asize: numStops);
1193 for (quint32 i = 0; i < numStops; ++i) {
1194 s >> n >> c;
1195 stops << QPair<qreal, QColor>(n, c);
1196 }
1197 }
1198
1199 if (type == QGradient::LinearGradient) {
1200 QPointF p1, p2;
1201 s >> p1;
1202 s >> p2;
1203 QLinearGradient lg(p1, p2);
1204 lg.setStops(stops);
1205 lg.setSpread(spread);
1206 lg.setCoordinateMode(cmode);
1207 lg.setInterpolationMode(imode);
1208 b = QBrush(lg);
1209 } else if (type == QGradient::RadialGradient) {
1210 QPointF center, focal;
1211 double radius;
1212 s >> center;
1213 s >> focal;
1214 s >> radius;
1215 QRadialGradient rg(center, radius, focal);
1216 rg.setStops(stops);
1217 rg.setSpread(spread);
1218 rg.setCoordinateMode(cmode);
1219 rg.setInterpolationMode(imode);
1220 b = QBrush(rg);
1221 } else { // type == QGradient::ConicalGradient
1222 QPointF center;
1223 double angle;
1224 s >> center;
1225 s >> angle;
1226 QConicalGradient cg(center, angle);
1227 cg.setStops(stops);
1228 cg.setSpread(spread);
1229 cg.setCoordinateMode(cmode);
1230 cg.setInterpolationMode(imode);
1231 b = QBrush(cg);
1232 }
1233 } else {
1234 b = QBrush(color, (Qt::BrushStyle)style);
1235 }
1236 if (s.version() >= QDataStream::Qt_4_3) {
1237 QTransform transform;
1238 s >> transform;
1239 b.setTransform(transform);
1240 }
1241 return s;
1242}
1243#endif // QT_NO_DATASTREAM
1244
1245/*******************************************************************************
1246 * QGradient implementations
1247 */
1248
1249
1250/*!
1251 \class QGradient
1252 \ingroup painting
1253 \ingroup shared
1254 \inmodule QtGui
1255
1256 \brief The QGradient class is used in combination with QBrush to
1257 specify gradient fills.
1258
1259 Qt currently supports three types of gradient fills:
1260
1261 \list
1262 \li \e Linear gradients interpolate colors between start and end points.
1263 \li \e Simple radial gradients interpolate colors between a focal point
1264 and end points on a circle surrounding it.
1265 \li \e Extended radial gradients interpolate colors between a center and
1266 a focal circle.
1267 \li \e Conical gradients interpolate colors around a center point.
1268 \endlist
1269
1270 A gradient's type can be retrieved using the type() function.
1271 Each of the types is represented by a subclass of QGradient:
1272
1273 \table
1274 \header
1275 \li QLinearGradient
1276 \li QRadialGradient
1277 \li QConicalGradient
1278 \row
1279 \li \inlineimage qgradient-linear.png
1280 \li \inlineimage qgradient-radial.png
1281 \li \inlineimage qgradient-conical.png
1282 \endtable
1283
1284 The colors in a gradient are defined using stop points of the
1285 QGradientStop type; i.e., a position and a color. Use the setColorAt()
1286 function to define a single stop point. Alternatively, use the
1287 setStops() function to define several stop points in one go. Note that
1288 the latter function \e replaces the current set of stop points.
1289
1290 It is the gradient's complete set of stop points (accessible
1291 through the stops() function) that describes how the gradient area
1292 should be filled. If no stop points have been specified, a gradient
1293 of black at 0 to white at 1 is used.
1294
1295 A diagonal linear gradient from black at (100, 100) to white at
1296 (200, 200) could be specified like this:
1297
1298 \snippet brush/brush.cpp 0
1299
1300 A gradient can have an arbitrary number of stop points. The
1301 following would create a radial gradient starting with
1302 red in the center, blue and then green on the edges:
1303
1304 \snippet brush/brush.cpp 1
1305
1306 It is possible to repeat or reflect the gradient outside its area
1307 by specifiying the \l {QGradient::Spread}{spread method} using the
1308 setSpread() function. The default is to pad the outside area with
1309 the color at the closest stop point. The currently set \l
1310 {QGradient::Spread}{spread method} can be retrieved using the
1311 spread() function. The QGradient::Spread enum defines three
1312 different methods:
1313
1314 \table
1315 \row
1316 \li \inlineimage qradialgradient-pad.png
1317 \li \inlineimage qradialgradient-repeat.png
1318 \li \inlineimage qradialgradient-reflect.png
1319 \row
1320 \li \l {QGradient::PadSpread}{PadSpread}
1321 \li \l {QGradient::RepeatSpread}{RepeatSpread}
1322 \li \l {QGradient::ReflectSpread}{ReflectSpread}
1323 \endtable
1324
1325 Note that the setSpread() function only has effect for linear and
1326 radial gradients. The reason is that the conical gradient is
1327 closed by definition, i.e. the \e conical gradient fills the
1328 entire circle from 0 - 360 degrees, while the boundary of a radial
1329 or a linear gradient can be specified through its radius or final
1330 stop points, respectively.
1331
1332 The gradient coordinates can be specified in logical coordinates,
1333 relative to device coordinates, or relative to object bounding box coordinates.
1334 The \l {QGradient::CoordinateMode}{coordinate mode} can be set using the
1335 setCoordinateMode() function. The default is LogicalMode, where the
1336 gradient coordinates are specified in the same way as the object
1337 coordinates. To retrieve the currently set \l {QGradient::CoordinateMode}
1338 {coordinate mode} use coordinateMode().
1339
1340
1341 \sa {painting/gradients}{The Gradients Example}, QBrush
1342*/
1343
1344/*!
1345 \internal
1346*/
1347QGradient::QGradient()
1348 : m_type(NoGradient), dummy(nullptr)
1349{
1350}
1351
1352/*!
1353 \enum QGradient::Preset
1354 \since 5.12
1355
1356 This enum specifies a set of predefined presets for QGradient,
1357 based on the gradients from \l {https://webgradients.com/}.
1358
1359 \value WarmFlame
1360 \value NightFade
1361 \value SpringWarmth
1362 \value JuicyPeach
1363 \value YoungPassion
1364 \value LadyLips
1365 \value SunnyMorning
1366 \value RainyAshville
1367 \value FrozenDreams
1368 \value WinterNeva
1369 \value DustyGrass
1370 \value TemptingAzure
1371 \value HeavyRain
1372 \value AmyCrisp
1373 \value MeanFruit
1374 \value DeepBlue
1375 \value RipeMalinka
1376 \value CloudyKnoxville
1377 \value MalibuBeach
1378 \value NewLife
1379 \value TrueSunset
1380 \value MorpheusDen
1381 \value RareWind
1382 \value NearMoon
1383 \value WildApple
1384 \value SaintPetersburg
1385 \value PlumPlate
1386 \value EverlastingSky
1387 \value HappyFisher
1388 \value Blessing
1389 \value SharpeyeEagle
1390 \value LadogaBottom
1391 \value LemonGate
1392 \value ItmeoBranding
1393 \value ZeusMiracle
1394 \value OldHat
1395 \value StarWine
1396 \value HappyAcid
1397 \value AwesomePine
1398 \value NewYork
1399 \value ShyRainbow
1400 \value MixedHopes
1401 \value FlyHigh
1402 \value StrongBliss
1403 \value FreshMilk
1404 \value SnowAgain
1405 \value FebruaryInk
1406 \value KindSteel
1407 \value SoftGrass
1408 \value GrownEarly
1409 \value SharpBlues
1410 \value ShadyWater
1411 \value DirtyBeauty
1412 \value GreatWhale
1413 \value TeenNotebook
1414 \value PoliteRumors
1415 \value SweetPeriod
1416 \value WideMatrix
1417 \value SoftCherish
1418 \value RedSalvation
1419 \value BurningSpring
1420 \value NightParty
1421 \value SkyGlider
1422 \value HeavenPeach
1423 \value PurpleDivision
1424 \value AquaSplash
1425 \value SpikyNaga
1426 \value LoveKiss
1427 \value CleanMirror
1428 \value PremiumDark
1429 \value ColdEvening
1430 \value CochitiLake
1431 \value SummerGames
1432 \value PassionateBed
1433 \value MountainRock
1434 \value DesertHump
1435 \value JungleDay
1436 \value PhoenixStart
1437 \value OctoberSilence
1438 \value FarawayRiver
1439 \value AlchemistLab
1440 \value OverSun
1441 \value PremiumWhite
1442 \value MarsParty
1443 \value EternalConstance
1444 \value JapanBlush
1445 \value SmilingRain
1446 \value CloudyApple
1447 \value BigMango
1448 \value HealthyWater
1449 \value AmourAmour
1450 \value RiskyConcrete
1451 \value StrongStick
1452 \value ViciousStance
1453 \value PaloAlto
1454 \value HappyMemories
1455 \value MidnightBloom
1456 \value Crystalline
1457 \value PartyBliss
1458 \value ConfidentCloud
1459 \value LeCocktail
1460 \value RiverCity
1461 \value FrozenBerry
1462 \value ChildCare
1463 \value FlyingLemon
1464 \value NewRetrowave
1465 \value HiddenJaguar
1466 \value AboveTheSky
1467 \value Nega
1468 \value DenseWater
1469 \value Seashore
1470 \value MarbleWall
1471 \value CheerfulCaramel
1472 \value NightSky
1473 \value MagicLake
1474 \value YoungGrass
1475 \value ColorfulPeach
1476 \value GentleCare
1477 \value PlumBath
1478 \value HappyUnicorn
1479 \value AfricanField
1480 \value SolidStone
1481 \value OrangeJuice
1482 \value GlassWater
1483 \value NorthMiracle
1484 \value FruitBlend
1485 \value MillenniumPine
1486 \value HighFlight
1487 \value MoleHall
1488 \value SpaceShift
1489 \value ForestInei
1490 \value RoyalGarden
1491 \value RichMetal
1492 \value JuicyCake
1493 \value SmartIndigo
1494 \value SandStrike
1495 \value NorseBeauty
1496 \value AquaGuidance
1497 \value SunVeggie
1498 \value SeaLord
1499 \value BlackSea
1500 \value GrassShampoo
1501 \value LandingAircraft
1502 \value WitchDance
1503 \value SleeplessNight
1504 \value AngelCare
1505 \value CrystalRiver
1506 \value SoftLipstick
1507 \value SaltMountain
1508 \value PerfectWhite
1509 \value FreshOasis
1510 \value StrictNovember
1511 \value MorningSalad
1512 \value DeepRelief
1513 \value SeaStrike
1514 \value NightCall
1515 \value SupremeSky
1516 \value LightBlue
1517 \value MindCrawl
1518 \value LilyMeadow
1519 \value SugarLollipop
1520 \value SweetDessert
1521 \value MagicRay
1522 \value TeenParty
1523 \value FrozenHeat
1524 \value GagarinView
1525 \value FabledSunset
1526 \value PerfectBlue
1527*/
1528
1529/*!
1530 \fn QGradient::QGradient(QGradient::Preset preset)
1531 \since 5.12
1532
1533 Constructs a gradient based on a predefined \a preset.
1534
1535 The coordinate mode of the resulting gradient is
1536 QGradient::ObjectMode, allowing the preset
1537 to be applied to arbitrary object sizes.
1538*/
1539QGradient::QGradient(Preset preset)
1540 : QGradient()
1541{
1542 static QHash<int, QGradient> cachedPresets;
1543 static QMutex cacheMutex;
1544 QMutexLocker locker(&cacheMutex);
1545 if (cachedPresets.contains(akey: preset)) {
1546 const QGradient &cachedPreset = cachedPresets.value(akey: preset);
1547 m_type = cachedPreset.m_type;
1548 m_data = cachedPreset.m_data;
1549 m_stops = cachedPreset.m_stops;
1550 m_spread = cachedPreset.m_spread;
1551 dummy = cachedPreset.dummy;
1552 } else {
1553 static QJsonDocument jsonPresets = []() {
1554 QFile webGradients(QLatin1String(":/qgradient/webgradients.binaryjson"));
1555 webGradients.open(flags: QFile::ReadOnly);
1556QT_WARNING_PUSH
1557QT_WARNING_DISABLE_DEPRECATED
1558 return QJsonDocument::fromBinaryData(data: webGradients.readAll());
1559QT_WARNING_POP
1560 }();
1561
1562 const QJsonValue presetData = jsonPresets[preset - 1];
1563 if (!presetData.isObject())
1564 return;
1565
1566 m_type = LinearGradient;
1567 setCoordinateMode(ObjectMode);
1568 setSpread(PadSpread);
1569
1570 const QJsonValue start = presetData[QLatin1String("start")];
1571 const QJsonValue end = presetData[QLatin1String("end")];
1572 m_data.linear.x1 = start[QLatin1String("x")].toDouble();
1573 m_data.linear.y1 = start[QLatin1String("y")].toDouble();
1574 m_data.linear.x2 = end[QLatin1String("x")].toDouble();
1575 m_data.linear.y2 = end[QLatin1String("y")].toDouble();
1576
1577 for (const QJsonValue &stop : presetData[QLatin1String("stops")].toArray()) {
1578 setColorAt(pos: stop[QLatin1String("position")].toDouble(),
1579 color: QColor(QRgb(stop[QLatin1String("color")].toInt())));
1580 }
1581
1582 cachedPresets.insert(akey: preset, avalue: *this);
1583 }
1584}
1585
1586/*!
1587 \internal
1588*/
1589QGradient::~QGradient()
1590{
1591}
1592
1593QT_END_NAMESPACE
1594static void initGradientPresets() { Q_INIT_RESOURCE(qmake_webgradients); }
1595Q_CONSTRUCTOR_FUNCTION(initGradientPresets);
1596QT_BEGIN_NAMESPACE
1597
1598/*!
1599 \enum QGradient::Type
1600
1601 Specifies the type of gradient.
1602
1603 \value LinearGradient Interpolates colors between start and end points
1604 (QLinearGradient).
1605
1606 \value RadialGradient Interpolate colors between a focal point and end
1607 points on a circle surrounding it (QRadialGradient).
1608
1609 \value ConicalGradient Interpolate colors around a center point (QConicalGradient).
1610 \value NoGradient No gradient is used.
1611
1612 \sa type()
1613*/
1614
1615/*!
1616 \enum QGradient::Spread
1617
1618 Specifies how the area outside the gradient area should be
1619 filled.
1620
1621 \value PadSpread The area is filled with the closest stop
1622 color. This is the default.
1623
1624 \value RepeatSpread The gradient is repeated outside the gradient
1625 area.
1626
1627 \value ReflectSpread The gradient is reflected outside the
1628 gradient area.
1629
1630 \sa spread(), setSpread()
1631*/
1632
1633/*!
1634 \fn void QGradient::setSpread(Spread method)
1635
1636 Specifies the spread \a method that should be used for this
1637 gradient.
1638
1639 Note that this function only has effect for linear and radial
1640 gradients.
1641
1642 \sa spread()
1643*/
1644
1645/*!
1646 \fn QGradient::Spread QGradient::spread() const
1647
1648 Returns the spread method use by this gradient. The default is
1649 PadSpread.
1650
1651 \sa setSpread()
1652*/
1653
1654/*!
1655 \fn QGradient::Type QGradient::type() const
1656
1657 Returns the type of gradient.
1658*/
1659
1660/*!
1661 \fn void QGradient::setColorAt(qreal position, const QColor &color)
1662
1663 Creates a stop point at the given \a position with the given \a
1664 color. The given \a position must be in the range 0 to 1.
1665
1666 \sa setStops(), stops()
1667*/
1668
1669void QGradient::setColorAt(qreal pos, const QColor &color)
1670{
1671 if ((pos > 1 || pos < 0) && !qIsNaN(d: pos)) {
1672 qWarning(msg: "QGradient::setColorAt: Color position must be specified in the range 0 to 1");
1673 return;
1674 }
1675
1676 int index = 0;
1677 if (!qIsNaN(d: pos))
1678 while (index < m_stops.size() && m_stops.at(i: index).first < pos) ++index;
1679
1680 if (index < m_stops.size() && m_stops.at(i: index).first == pos)
1681 m_stops[index].second = color;
1682 else
1683 m_stops.insert(i: index, t: QGradientStop(pos, color));
1684}
1685
1686static inline bool ok(QGradientStop stop)
1687{
1688 return stop.first >= 0 && stop.first <= 1; // rejects NaNs
1689}
1690
1691static inline bool ok(const QGradientStops &stops)
1692{
1693 qreal lastPos = -1;
1694 for (const QGradientStop &stop : stops) {
1695 if (Q_UNLIKELY(!ok(stop)))
1696 return false;
1697 const bool sorted = stop.first > lastPos; // rejects duplicates
1698 if (Q_UNLIKELY(!sorted))
1699 return false;
1700 lastPos = stop.first;
1701 }
1702 return true;
1703}
1704
1705/*!
1706 \fn void QGradient::setStops(const QGradientStops &stopPoints)
1707
1708 Replaces the current set of stop points with the given \a
1709 stopPoints. The positions of the points must be in the range 0 to
1710 1, and must be sorted with the lowest point first.
1711
1712 \sa setColorAt(), stops()
1713*/
1714void QGradient::setStops(const QGradientStops &stops)
1715{
1716 // ## Qt 6: consider taking \a stops by value, so we can move into m_stops
1717 if (Q_LIKELY(ok(stops))) {
1718 // fast path for the common case: if everything is ok with the stops, just copy them
1719 m_stops = stops;
1720 return;
1721 }
1722 // otherwise, to keep the pre-5.9 behavior, add them one after another,
1723 // so each stop is checked, invalid ones are skipped, they are added in-order (which may be O(N^2)).
1724 m_stops.clear();
1725 for (int i=0; i<stops.size(); ++i)
1726 setColorAt(pos: stops.at(i).first, color: stops.at(i).second);
1727}
1728
1729
1730/*!
1731 Returns the stop points for this gradient.
1732
1733 If no stop points have been specified, a gradient of black at 0 to white
1734 at 1 is used.
1735
1736 \sa setStops(), setColorAt()
1737*/
1738QGradientStops QGradient::stops() const
1739{
1740 if (m_stops.isEmpty()) {
1741 QGradientStops tmp;
1742 tmp << QGradientStop(0, Qt::black) << QGradientStop(1, Qt::white);
1743 return tmp;
1744 }
1745 return m_stops;
1746}
1747
1748#define Q_DUMMY_ACCESSOR union {void *p; uint i;}; p = dummy;
1749
1750/*!
1751 \enum QGradient::CoordinateMode
1752 \since 4.4
1753
1754 This enum specifies how gradient coordinates map to the paint
1755 device on which the gradient is used.
1756
1757 \value LogicalMode This is the default mode. The gradient coordinates
1758 are specified logical space just like the object coordinates.
1759 \value ObjectMode In this mode the gradient coordinates are
1760 relative to the bounding rectangle of the object being drawn, with
1761 (0,0) in the top left corner, and (1,1) in the bottom right corner
1762 of the object's bounding rectangle. This value was added in Qt
1763 5.12.
1764 \value StretchToDeviceMode In this mode the gradient coordinates
1765 are relative to the bounding rectangle of the paint device,
1766 with (0,0) in the top left corner, and (1,1) in the bottom right
1767 corner of the paint device.
1768 \value ObjectBoundingMode This mode is the same as ObjectMode, except that
1769 the {QBrush::transform()} {brush transform}, if any, is applied relative to
1770 the logical space instead of the object space. This enum value is
1771 deprecated and should not be used in new code.
1772*/
1773
1774/*!
1775 \since 4.4
1776
1777 Returns the coordinate mode of this gradient. The default mode is
1778 LogicalMode.
1779*/
1780QGradient::CoordinateMode QGradient::coordinateMode() const
1781{
1782 Q_DUMMY_ACCESSOR
1783 return CoordinateMode(i & 0x03);
1784}
1785
1786/*!
1787 \since 4.4
1788
1789 Sets the coordinate mode of this gradient to \a mode. The default
1790 mode is LogicalMode.
1791*/
1792void QGradient::setCoordinateMode(CoordinateMode mode)
1793{
1794 Q_DUMMY_ACCESSOR
1795 i &= ~0x03;
1796 i |= uint(mode);
1797 dummy = p;
1798}
1799
1800/*!
1801 \enum QGradient::InterpolationMode
1802 \since 4.5
1803 \internal
1804
1805 \value ComponentInterpolation The color components and the alpha component are
1806 independently linearly interpolated.
1807 \value ColorInterpolation The colors are linearly interpolated in
1808 premultiplied color space.
1809*/
1810
1811/*!
1812 \since 4.5
1813 \internal
1814
1815 Returns the interpolation mode of this gradient. The default mode is
1816 ColorInterpolation.
1817*/
1818QGradient::InterpolationMode QGradient::interpolationMode() const
1819{
1820 Q_DUMMY_ACCESSOR
1821 return InterpolationMode((i >> 2) & 0x01);
1822}
1823
1824/*!
1825 \since 4.5
1826 \internal
1827
1828 Sets the interpolation mode of this gradient to \a mode. The default
1829 mode is ColorInterpolation.
1830*/
1831void QGradient::setInterpolationMode(InterpolationMode mode)
1832{
1833 Q_DUMMY_ACCESSOR
1834 i &= ~(1 << 2);
1835 i |= (uint(mode) << 2);
1836 dummy = p;
1837}
1838
1839/*!
1840 \fn bool QGradient::operator!=(const QGradient &gradient) const
1841 \since 4.2
1842
1843 Returns \c true if the gradient is the same as the other \a gradient
1844 specified; otherwise returns \c false.
1845
1846 \sa operator==()
1847*/
1848
1849/*!
1850 Returns \c true if the gradient is the same as the other \a gradient
1851 specified; otherwise returns \c false.
1852
1853 \sa operator!=()
1854*/
1855bool QGradient::operator==(const QGradient &gradient) const
1856{
1857 if (gradient.m_type != m_type
1858 || gradient.m_spread != m_spread
1859 || gradient.dummy != dummy) return false;
1860
1861 if (m_type == LinearGradient) {
1862 if (m_data.linear.x1 != gradient.m_data.linear.x1
1863 || m_data.linear.y1 != gradient.m_data.linear.y1
1864 || m_data.linear.x2 != gradient.m_data.linear.x2
1865 || m_data.linear.y2 != gradient.m_data.linear.y2)
1866 return false;
1867 } else if (m_type == RadialGradient) {
1868 if (m_data.radial.cx != gradient.m_data.radial.cx
1869 || m_data.radial.cy != gradient.m_data.radial.cy
1870 || m_data.radial.fx != gradient.m_data.radial.fx
1871 || m_data.radial.fy != gradient.m_data.radial.fy
1872 || m_data.radial.cradius != gradient.m_data.radial.cradius)
1873 return false;
1874 } else { // m_type == ConicalGradient
1875 if (m_data.conical.cx != gradient.m_data.conical.cx
1876 || m_data.conical.cy != gradient.m_data.conical.cy
1877 || m_data.conical.angle != gradient.m_data.conical.angle)
1878 return false;
1879 }
1880
1881 return stops() == gradient.stops();
1882}
1883
1884/*!
1885 \class QLinearGradient
1886 \ingroup painting
1887 \inmodule QtGui
1888
1889 \brief The QLinearGradient class is used in combination with QBrush to
1890 specify a linear gradient brush.
1891
1892 Linear gradients interpolate colors between start and end
1893 points. Outside these points the gradient is either padded,
1894 reflected or repeated depending on the currently set \l
1895 {QGradient::Spread}{spread} method:
1896
1897 \table
1898 \row
1899 \li \inlineimage qlineargradient-pad.png
1900 \li \inlineimage qlineargradient-reflect.png
1901 \li \inlineimage qlineargradient-repeat.png
1902 \row
1903 \li \l {QGradient::PadSpread}{PadSpread} (default)
1904 \li \l {QGradient::ReflectSpread}{ReflectSpread}
1905 \li \l {QGradient::RepeatSpread}{RepeatSpread}
1906 \endtable
1907
1908 The colors in a gradient is defined using stop points of the
1909 QGradientStop type, i.e. a position and a color. Use the
1910 QGradient::setColorAt() or the QGradient::setStops() function to
1911 define the stop points. It is the gradient's complete set of stop
1912 points that describes how the gradient area should be filled. If
1913 no stop points have been specified, a gradient of black at 0 to
1914 white at 1 is used.
1915
1916 In addition to the functions inherited from QGradient, the
1917 QLinearGradient class provides the finalStop() function which
1918 returns the final stop point of the gradient, and the start()
1919 function returning the start point of the gradient.
1920
1921 \sa QRadialGradient, QConicalGradient, {painting/gradients}{The
1922 Gradients Example}
1923*/
1924
1925
1926/*!
1927 Constructs a default linear gradient with interpolation area
1928 between (0, 0) and (1, 1).
1929
1930 \sa QGradient::setColorAt(), setStart(), setFinalStop()
1931*/
1932
1933QLinearGradient::QLinearGradient()
1934{
1935 m_type = LinearGradient;
1936 m_spread = PadSpread;
1937 m_data.linear.x1 = 0;
1938 m_data.linear.y1 = 0;
1939 m_data.linear.x2 = 1;
1940 m_data.linear.y2 = 1;
1941}
1942
1943
1944/*!
1945 Constructs a linear gradient with interpolation area between the
1946 given \a start point and \a finalStop.
1947
1948 \note The expected parameter values are in pixels.
1949
1950 \sa QGradient::setColorAt(), QGradient::setStops()
1951*/
1952QLinearGradient::QLinearGradient(const QPointF &start, const QPointF &finalStop)
1953{
1954 m_type = LinearGradient;
1955 m_spread = PadSpread;
1956 m_data.linear.x1 = start.x();
1957 m_data.linear.y1 = start.y();
1958 m_data.linear.x2 = finalStop.x();
1959 m_data.linear.y2 = finalStop.y();
1960}
1961
1962/*!
1963 \fn QLinearGradient::QLinearGradient(qreal x1, qreal y1, qreal x2, qreal y2)
1964
1965 Constructs a linear gradient with interpolation area between (\a
1966 x1, \a y1) and (\a x2, \a y2).
1967
1968 \note The expected parameter values are in pixels.
1969
1970 \sa QGradient::setColorAt(), QGradient::setStops()
1971*/
1972QLinearGradient::QLinearGradient(qreal xStart, qreal yStart, qreal xFinalStop, qreal yFinalStop)
1973 : QLinearGradient(QPointF(xStart, yStart), QPointF(xFinalStop, yFinalStop))
1974{
1975}
1976
1977/*!
1978 \internal
1979*/
1980QLinearGradient::~QLinearGradient()
1981{
1982}
1983
1984/*!
1985 Returns the start point of this linear gradient in logical coordinates.
1986
1987 \sa QGradient::stops()
1988*/
1989
1990QPointF QLinearGradient::start() const
1991{
1992 Q_ASSERT(m_type == LinearGradient);
1993 return QPointF(m_data.linear.x1, m_data.linear.y1);
1994}
1995
1996/*!
1997 \fn void QLinearGradient::setStart(qreal x, qreal y)
1998 \overload
1999 \since 4.2
2000
2001 Sets the start point of this linear gradient in logical
2002 coordinates to \a x, \a y.
2003
2004 \sa start()
2005*/
2006
2007/*!
2008 \since 4.2
2009
2010 Sets the start point of this linear gradient in logical
2011 coordinates to \a start.
2012
2013 \sa start()
2014*/
2015
2016void QLinearGradient::setStart(const QPointF &start)
2017{
2018 Q_ASSERT(m_type == LinearGradient);
2019 m_data.linear.x1 = start.x();
2020 m_data.linear.y1 = start.y();
2021}
2022
2023
2024/*!
2025 \fn void QLinearGradient::setFinalStop(qreal x, qreal y)
2026 \overload
2027 \since 4.2
2028
2029 Sets the final stop point of this linear gradient in logical
2030 coordinates to \a x, \a y.
2031
2032 \sa start()
2033*/
2034
2035/*!
2036 Returns the final stop point of this linear gradient in logical coordinates.
2037
2038 \sa QGradient::stops()
2039*/
2040
2041QPointF QLinearGradient::finalStop() const
2042{
2043 Q_ASSERT(m_type == LinearGradient);
2044 return QPointF(m_data.linear.x2, m_data.linear.y2);
2045}
2046
2047
2048/*!
2049 \since 4.2
2050
2051 Sets the final stop point of this linear gradient in logical
2052 coordinates to \a stop.
2053
2054 \sa finalStop()
2055*/
2056
2057void QLinearGradient::setFinalStop(const QPointF &stop)
2058{
2059 Q_ASSERT(m_type == LinearGradient);
2060 m_data.linear.x2 = stop.x();
2061 m_data.linear.y2 = stop.y();
2062}
2063
2064
2065/*!
2066 \class QRadialGradient
2067 \ingroup painting
2068 \inmodule QtGui
2069
2070 \brief The QRadialGradient class is used in combination with QBrush to
2071 specify a radial gradient brush.
2072
2073 Qt supports both simple and extended radial gradients.
2074
2075 Simple radial gradients interpolate colors between a focal point and end
2076 points on a circle surrounding it. Extended radial gradients interpolate
2077 colors between a focal circle and a center circle. Points outside the cone
2078 defined by the two circles will be transparent. For simple radial gradients
2079 the focal point is adjusted to lie inside the center circle, whereas the
2080 focal point can have any position in an extended radial gradient.
2081
2082 Outside the end points the gradient is either padded, reflected or repeated
2083 depending on the currently set \l {QGradient::Spread}{spread} method:
2084
2085 \table
2086 \row
2087 \li \inlineimage qradialgradient-pad.png
2088 \li \inlineimage qradialgradient-reflect.png
2089 \li \inlineimage qradialgradient-repeat.png
2090 \row
2091 \li \l {QGradient::PadSpread}{PadSpread} (default)
2092 \li \l {QGradient::ReflectSpread}{ReflectSpread}
2093 \li \l {QGradient::RepeatSpread}{RepeatSpread}
2094 \endtable
2095
2096 The colors in a gradient is defined using stop points of the
2097 QGradientStop type, i.e. a position and a color. Use the
2098 QGradient::setColorAt() or the QGradient::setStops() function to
2099 define the stop points. It is the gradient's complete set of stop
2100 points that describes how the gradient area should be filled. If
2101 no stop points have been specified, a gradient of black at 0 to
2102 white at 1 is used.
2103
2104 In addition to the functions inherited from QGradient, the
2105 QRadialGradient class provides the center(), focalPoint() and
2106 radius() functions returning the gradient's center, focal point
2107 and radius respectively.
2108
2109 \sa QLinearGradient, QConicalGradient, {painting/gradients}{The
2110 Gradients Example}
2111*/
2112
2113static QPointF qt_radial_gradient_adapt_focal_point(const QPointF &center,
2114 qreal radius,
2115 const QPointF &focalPoint)
2116{
2117 // We have a one pixel buffer zone to avoid numerical instability on the
2118 // circle border
2119 //### this is hacky because technically we should adjust based on current matrix
2120 const qreal compensated_radius = radius - radius * qreal(0.001);
2121 QLineF line(center, focalPoint);
2122 if (line.length() > (compensated_radius))
2123 line.setLength(compensated_radius);
2124 return line.p2();
2125}
2126
2127/*!
2128 Constructs a simple radial gradient with the given \a center, \a
2129 radius and \a focalPoint.
2130
2131 \note If the given focal point is outside the circle defined by the
2132 \a center point and \a radius, it will be re-adjusted to lie at a point on
2133 the circle where it intersects with the line from \a center to
2134 \a focalPoint.
2135
2136 \sa QGradient::setColorAt(), QGradient::setStops()
2137*/
2138
2139QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPointF &focalPoint)
2140{
2141 m_type = RadialGradient;
2142 m_spread = PadSpread;
2143 m_data.radial.cx = center.x();
2144 m_data.radial.cy = center.y();
2145 m_data.radial.cradius = radius;
2146
2147 QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint);
2148 m_data.radial.fx = adapted_focal.x();
2149 m_data.radial.fy = adapted_focal.y();
2150}
2151
2152/*!
2153 Constructs a simple radial gradient with the given \a center, \a
2154 radius and the focal point in the circle center.
2155
2156 \sa QGradient::setColorAt(), QGradient::setStops()
2157*/
2158QRadialGradient::QRadialGradient(const QPointF &center, qreal radius)
2159{
2160 m_type = RadialGradient;
2161 m_spread = PadSpread;
2162 m_data.radial.cx = center.x();
2163 m_data.radial.cy = center.y();
2164 m_data.radial.cradius = radius;
2165 m_data.radial.fx = center.x();
2166 m_data.radial.fy = center.y();
2167}
2168
2169
2170/*!
2171 Constructs a simple radial gradient with the given center (\a cx, \a cy),
2172 \a radius and focal point (\a fx, \a fy).
2173
2174 \note If the given focal point is outside the circle defined by the
2175 center (\a cx, \a cy) and the \a radius it will be re-adjusted to
2176 the intersection between the line from the center to the focal point
2177 and the circle.
2178
2179 \sa QGradient::setColorAt(), QGradient::setStops()
2180*/
2181
2182QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qreal fy)
2183 : QRadialGradient(QPointF(cx, cy), radius, QPointF(fx, fy))
2184{
2185}
2186
2187/*!
2188 Constructs a simple radial gradient with the center at (\a cx, \a cy) and the
2189 specified \a radius. The focal point lies at the center of the circle.
2190
2191 \sa QGradient::setColorAt(), QGradient::setStops()
2192 */
2193QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius)
2194 : QRadialGradient(QPointF(cx, cy), radius)
2195{
2196}
2197
2198
2199/*!
2200 Constructs a simple radial gradient with the center and focal point at
2201 (0, 0) with a radius of 1.
2202*/
2203QRadialGradient::QRadialGradient()
2204{
2205 m_type = RadialGradient;
2206 m_spread = PadSpread;
2207 m_data.radial.cx = 0;
2208 m_data.radial.cy = 0;
2209 m_data.radial.cradius = 1;
2210 m_data.radial.fx = 0;
2211 m_data.radial.fy = 0;
2212}
2213
2214/*!
2215 \since 4.8
2216
2217 Constructs an extended radial gradient with the given \a center, \a
2218 centerRadius, \a focalPoint, and \a focalRadius.
2219*/
2220QRadialGradient::QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius)
2221{
2222 m_type = RadialGradient;
2223 m_spread = PadSpread;
2224 m_data.radial.cx = center.x();
2225 m_data.radial.cy = center.y();
2226 m_data.radial.cradius = centerRadius;
2227
2228 m_data.radial.fx = focalPoint.x();
2229 m_data.radial.fy = focalPoint.y();
2230 setFocalRadius(focalRadius);
2231}
2232
2233/*!
2234 \since 4.8
2235
2236 Constructs an extended radial gradient with the given center
2237 (\a cx, \a cy), center radius, \a centerRadius, focal point, (\a fx, \a fy),
2238 and focal radius \a focalRadius.
2239*/
2240QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius)
2241{
2242 m_type = RadialGradient;
2243 m_spread = PadSpread;
2244 m_data.radial.cx = cx;
2245 m_data.radial.cy = cy;
2246 m_data.radial.cradius = centerRadius;
2247
2248 m_data.radial.fx = fx;
2249 m_data.radial.fy = fy;
2250 setFocalRadius(focalRadius);
2251}
2252
2253/*!
2254 \internal
2255*/
2256QRadialGradient::~QRadialGradient()
2257{
2258}
2259
2260/*!
2261 Returns the center of this radial gradient in logical coordinates.
2262
2263 \sa QGradient::stops()
2264*/
2265
2266QPointF QRadialGradient::center() const
2267{
2268 Q_ASSERT(m_type == RadialGradient);
2269 return QPointF(m_data.radial.cx, m_data.radial.cy);
2270}
2271
2272/*!
2273 \fn void QRadialGradient::setCenter(qreal x, qreal y)
2274 \overload
2275 \since 4.2
2276
2277 Sets the center of this radial gradient in logical coordinates
2278 to (\a x, \a y).
2279
2280 \sa center()
2281*/
2282
2283/*!
2284 \since 4.2
2285
2286 Sets the center of this radial gradient in logical coordinates
2287 to \a center.
2288
2289 \sa center()
2290*/
2291
2292void QRadialGradient::setCenter(const QPointF &center)
2293{
2294 Q_ASSERT(m_type == RadialGradient);
2295 m_data.radial.cx = center.x();
2296 m_data.radial.cy = center.y();
2297}
2298
2299
2300/*!
2301 Returns the radius of this radial gradient in logical coordinates.
2302
2303 Equivalent to centerRadius()
2304
2305 \sa QGradient::stops()
2306*/
2307
2308qreal QRadialGradient::radius() const
2309{
2310 Q_ASSERT(m_type == RadialGradient);
2311 return m_data.radial.cradius;
2312}
2313
2314
2315/*!
2316 \since 4.2
2317
2318 Sets the radius of this radial gradient in logical coordinates
2319 to \a radius
2320
2321 Equivalent to setCenterRadius()
2322*/
2323void QRadialGradient::setRadius(qreal radius)
2324{
2325 Q_ASSERT(m_type == RadialGradient);
2326 m_data.radial.cradius = radius;
2327}
2328
2329/*!
2330 \since 4.8
2331
2332 Returns the center radius of this radial gradient in logical
2333 coordinates.
2334
2335 \sa QGradient::stops()
2336*/
2337qreal QRadialGradient::centerRadius() const
2338{
2339 Q_ASSERT(m_type == RadialGradient);
2340 return m_data.radial.cradius;
2341}
2342
2343/*!
2344 \since 4.8
2345
2346 Sets the center radius of this radial gradient in logical coordinates
2347 to \a radius
2348*/
2349void QRadialGradient::setCenterRadius(qreal radius)
2350{
2351 Q_ASSERT(m_type == RadialGradient);
2352 m_data.radial.cradius = radius;
2353}
2354
2355/*!
2356 \since 4.8
2357
2358 Returns the focal radius of this radial gradient in logical
2359 coordinates.
2360
2361 \sa QGradient::stops()
2362*/
2363qreal QRadialGradient::focalRadius() const
2364{
2365 Q_ASSERT(m_type == RadialGradient);
2366 Q_DUMMY_ACCESSOR
2367
2368 // mask away low three bits
2369 union { float f; quint32 i; } u;
2370 u.i = i & ~0x07;
2371 return u.f;
2372}
2373
2374/*!
2375 \since 4.8
2376
2377 Sets the focal radius of this radial gradient in logical coordinates
2378 to \a radius
2379*/
2380void QRadialGradient::setFocalRadius(qreal radius)
2381{
2382 Q_ASSERT(m_type == RadialGradient);
2383 Q_DUMMY_ACCESSOR
2384
2385 // Since there's no QGradientData, we only have the dummy void * to
2386 // store additional data in. The three lowest bits are already
2387 // taken, thus we cut the three lowest bits from the significand
2388 // and store the radius as a float.
2389 union { float f; quint32 i; } u;
2390 u.f = float(radius);
2391 // add 0x04 to round up when we drop the three lowest bits
2392 i |= (u.i + 0x04) & ~0x07;
2393 dummy = p;
2394}
2395
2396/*!
2397 Returns the focal point of this radial gradient in logical
2398 coordinates.
2399
2400 \sa QGradient::stops()
2401*/
2402
2403QPointF QRadialGradient::focalPoint() const
2404{
2405 Q_ASSERT(m_type == RadialGradient);
2406 return QPointF(m_data.radial.fx, m_data.radial.fy);
2407}
2408
2409/*!
2410 \fn void QRadialGradient::setFocalPoint(qreal x, qreal y)
2411 \overload
2412 \since 4.2
2413
2414 Sets the focal point of this radial gradient in logical
2415 coordinates to (\a x, \a y).
2416
2417 \sa focalPoint()
2418*/
2419
2420/*!
2421 \since 4.2
2422
2423 Sets the focal point of this radial gradient in logical
2424 coordinates to \a focalPoint.
2425
2426 \sa focalPoint()
2427*/
2428
2429void QRadialGradient::setFocalPoint(const QPointF &focalPoint)
2430{
2431 Q_ASSERT(m_type == RadialGradient);
2432 m_data.radial.fx = focalPoint.x();
2433 m_data.radial.fy = focalPoint.y();
2434}
2435
2436
2437
2438/*!
2439 \class QConicalGradient
2440 \ingroup painting
2441 \inmodule QtGui
2442
2443 \brief The QConicalGradient class is used in combination with QBrush to
2444 specify a conical gradient brush.
2445
2446 Conical gradients interpolate interpolate colors counter-clockwise
2447 around a center point.
2448
2449 \image qconicalgradient.png
2450
2451 The colors in a gradient is defined using stop points of the
2452 QGradientStop type, i.e. a position and a color. Use the
2453 QGradient::setColorAt() or the QGradient::setStops() function to
2454 define the stop points. It is the gradient's complete set of stop
2455 points that describes how the gradient area should be filled. If
2456 no stop points have been specified, a gradient of black at 0 to
2457 white at 1 is used.
2458
2459 In addition to the functions inherited from QGradient, the
2460 QConicalGradient class provides the angle() and center() functions
2461 returning the start angle and center of the gradient.
2462
2463 Note that the setSpread() function has no effect for conical
2464 gradients. The reason is that the conical gradient is closed by
2465 definition, i.e. the conical gradient fills the entire circle from
2466 0 - 360 degrees, while the boundary of a radial or a linear
2467 gradient can be specified through its radius or final stop points,
2468 respectively.
2469
2470 \sa QLinearGradient, QRadialGradient, {painting/gradients}{The
2471 Gradients Example}
2472*/
2473
2474
2475/*!
2476 Constructs a conical gradient with the given \a center, starting
2477 the interpolation at the given \a angle. The \a angle must be
2478 specified in degrees between 0 and 360.
2479
2480 \sa QGradient::setColorAt(), QGradient::setStops()
2481*/
2482
2483QConicalGradient::QConicalGradient(const QPointF &center, qreal angle)
2484{
2485 m_type = ConicalGradient;
2486 m_spread = PadSpread;
2487 m_data.conical.cx = center.x();
2488 m_data.conical.cy = center.y();
2489 m_data.conical.angle = angle;
2490}
2491
2492
2493/*!
2494 Constructs a conical gradient with the given center (\a cx, \a
2495 cy), starting the interpolation at the given \a angle. The angle
2496 must be specified in degrees between 0 and 360.
2497
2498 \sa QGradient::setColorAt(), QGradient::setStops()
2499*/
2500
2501QConicalGradient::QConicalGradient(qreal cx, qreal cy, qreal angle)
2502 : QConicalGradient(QPointF(cx, cy), angle)
2503{
2504}
2505
2506/*!
2507 \internal
2508*/
2509QConicalGradient::~QConicalGradient()
2510{
2511}
2512
2513
2514/*!
2515 Constructs a conical with center at (0, 0) starting the
2516 interpolation at angle 0.
2517
2518 \sa QGradient::setColorAt(), setCenter(), setAngle()
2519*/
2520
2521QConicalGradient::QConicalGradient()
2522{
2523 m_type = ConicalGradient;
2524 m_spread = PadSpread;
2525 m_data.conical.cx = 0;
2526 m_data.conical.cy = 0;
2527 m_data.conical.angle = 0;
2528}
2529
2530
2531/*!
2532 Returns the center of the conical gradient in logical
2533 coordinates.
2534
2535 \sa stops()
2536*/
2537
2538QPointF QConicalGradient::center() const
2539{
2540 Q_ASSERT(m_type == ConicalGradient);
2541 return QPointF(m_data.conical.cx, m_data.conical.cy);
2542}
2543
2544
2545/*!
2546 \fn void QConicalGradient::setCenter(qreal x, qreal y)
2547
2548 \overload
2549
2550 Sets the center of this conical gradient in logical coordinates to
2551 (\a x, \a y).
2552
2553 \sa center()
2554*/
2555
2556/*!
2557 Sets the center of this conical gradient in logical coordinates to
2558 \a center.
2559
2560 \sa center()
2561*/
2562
2563void QConicalGradient::setCenter(const QPointF &center)
2564{
2565 Q_ASSERT(m_type == ConicalGradient);
2566 m_data.conical.cx = center.x();
2567 m_data.conical.cy = center.y();
2568}
2569
2570/*!
2571 Returns the start angle of the conical gradient in logical
2572 coordinates.
2573
2574 \sa stops()
2575*/
2576
2577qreal QConicalGradient::angle() const
2578{
2579 Q_ASSERT(m_type == ConicalGradient);
2580 return m_data.conical.angle;
2581}
2582
2583
2584/*!
2585 \since 4.2
2586
2587 Sets \a angle to be the start angle for this conical gradient in
2588 logical coordinates.
2589
2590 \sa angle()
2591*/
2592
2593void QConicalGradient::setAngle(qreal angle)
2594{
2595 Q_ASSERT(m_type == ConicalGradient);
2596 m_data.conical.angle = angle;
2597}
2598
2599/*!
2600 \typedef QGradientStop
2601 \relates QGradient
2602
2603 Typedef for QPair<\l qreal, QColor>.
2604*/
2605
2606/*!
2607 \typedef QGradientStops
2608 \relates QGradient
2609
2610 Typedef for QVector<QGradientStop>.
2611*/
2612
2613/*!
2614 \typedef QBrush::DataPtr
2615 \internal
2616*/
2617
2618/*!
2619 \fn DataPtr &QBrush::data_ptr()
2620 \internal
2621*/
2622
2623
2624/*!
2625 \fn bool QBrush::isDetached() const
2626 \internal
2627*/
2628
2629/*!
2630 \fn QTransform QBrush::transform() const
2631 \since 4.3
2632
2633 Returns the current transformation matrix for the brush.
2634
2635 \sa setTransform()
2636*/
2637
2638#undef Q_DUMMY_ACCESSOR
2639
2640QT_END_NAMESPACE
2641

source code of qtbase/src/gui/painting/qbrush.cpp