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