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

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