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