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