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