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