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 tools applications 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 "qtgradientwidget.h"
41 #include <QtCore/QMap>
42 #include <QtGui/QImage>
43 #include <QtGui/QPainter>
44 #include <QtWidgets/QScrollBar>
45 #include <QtGui/QMouseEvent>
46 #include <QtGui/QRegion>
47 
48 #ifndef _USE_MATH_DEFINES
49 #define _USE_MATH_DEFINES
50 #endif
51 
52 #include "qmath.h"
53 
54 QT_BEGIN_NAMESPACE
55 
56 class QtGradientWidgetPrivate
57 {
58     QtGradientWidget *q_ptr;
59     Q_DECLARE_PUBLIC(QtGradientWidget)
60 public:
61     QPointF fromViewport(const QPointF &point) const;
62     QPointF toViewport(const QPointF &point) const;
63 //    void setupDrag(QtGradientStop *stop, int x);
64 
65     QPointF checkRange(const QPointF &point) const;
66     QRectF pointRect(const QPointF &point, double size) const;
67 
68     double correctAngle(double angle) const;
69     void setAngleConical(double angle);
70 
71     void paintPoint(QPainter *painter, const QPointF &point, double size) const;
72 
73     double m_handleSize;
74     bool m_backgroundCheckered;
75 
76     QGradientStops m_gradientStops;
77     QGradient::Type m_gradientType;
78     QGradient::Spread m_gradientSpread;
79     QPointF m_startLinear;
80     QPointF m_endLinear;
81     QPointF m_centralRadial;
82     QPointF m_focalRadial;
83     qreal m_radiusRadial;
84     QPointF m_centralConical;
85     qreal m_angleConical;
86 
87     enum Handle {
88         NoHandle,
89         StartLinearHandle,
90         EndLinearHandle,
91         CentralRadialHandle,
92         FocalRadialHandle,
93         RadiusRadialHandle,
94         CentralConicalHandle,
95         AngleConicalHandle
96     };
97 
98     Handle m_dragHandle;
99     QPointF m_dragOffset;
100     //double m_radiusOffset;
101     double m_radiusFactor;
102     double m_dragRadius;
103     double m_angleOffset;
104     double m_dragAngle;
105 };
106 
correctAngle(double angle) const107 double QtGradientWidgetPrivate::correctAngle(double angle) const
108 {
109     double a = angle;
110     while (a >= 360)
111         a -= 360;
112     while (a < 0)
113         a += 360;
114     return a;
115 }
116 
setAngleConical(double angle)117 void QtGradientWidgetPrivate::setAngleConical(double angle)
118 {
119     double a = correctAngle(angle);
120     if (m_angleConical == a)
121         return;
122     m_angleConical = a;
123     emit q_ptr->angleConicalChanged(m_angleConical);
124 }
125 
pointRect(const QPointF & point,double size) const126 QRectF QtGradientWidgetPrivate::pointRect(const QPointF &point, double size) const
127 {
128     return QRectF(point.x() - size / 2, point.y() - size / 2, size, size);
129 }
130 
checkRange(const QPointF & point) const131 QPointF QtGradientWidgetPrivate::checkRange(const QPointF &point) const
132 {
133     QPointF p = point;
134     if (p.x() > 1)
135         p.setX(1);
136     else if (p.x() < 0)
137         p.setX(0);
138     if (p.y() > 1)
139         p.setY(1);
140     else if (p.y() < 0)
141         p.setY(0);
142     return p;
143 }
144 
fromViewport(const QPointF & point) const145 QPointF QtGradientWidgetPrivate::fromViewport(const QPointF &point) const
146 {
147     QSize size = q_ptr->size();
148     return QPointF(point.x() / size.width(), point.y() / size.height());
149 }
150 
toViewport(const QPointF & point) const151 QPointF QtGradientWidgetPrivate::toViewport(const QPointF &point) const
152 {
153     QSize size = q_ptr->size();
154     return QPointF(point.x() * size.width(), point.y() * size.height());
155 }
156 
paintPoint(QPainter * painter,const QPointF & point,double size) const157 void QtGradientWidgetPrivate::paintPoint(QPainter *painter, const QPointF &point, double size) const
158 {
159     QPointF pf = toViewport(point);
160     QRectF rf = pointRect(pf, size);
161 
162     QPen pen;
163     pen.setWidthF(1);
164     QColor alphaZero = Qt::white;
165     alphaZero.setAlpha(0);
166 
167     painter->save();
168     painter->drawEllipse(rf);
169 
170     /*
171     painter->save();
172 
173     QLinearGradient lgV(0, rf.top(), 0, rf.bottom());
174     lgV.setColorAt(0, alphaZero);
175     lgV.setColorAt(0.25, Qt::white);
176     lgV.setColorAt(0.25, Qt::white);
177     lgV.setColorAt(1, alphaZero);
178     pen.setBrush(lgV);
179     painter->setPen(pen);
180 
181     painter->drawLine(QPointF(pf.x(), rf.top()), QPointF(pf.x(), rf.bottom()));
182 
183     QLinearGradient lgH(rf.left(), 0, rf.right(), 0);
184     lgH.setColorAt(0, alphaZero);
185     lgH.setColorAt(0.5, Qt::white);
186     lgH.setColorAt(1, alphaZero);
187     pen.setBrush(lgH);
188     painter->setPen(pen);
189 
190     painter->drawLine(QPointF(rf.left(), pf.y()), QPointF(rf.right(), pf.y()));
191 
192     painter->restore();
193     */
194 
195     painter->restore();
196 }
197 
198 /*
199 void QtGradientWidgetPrivate::setupDrag(QtGradientStop *stop, int x)
200 {
201     m_model->setCurrentStop(stop);
202 
203     int viewportX = qRound(toViewport(stop->position()));
204     m_dragOffset = x - viewportX;
205 
206     const auto stops = m_stops;
207     m_stops.clear();
208     for (QtGradientStop *s : stops) {
209         if (m_model->isSelected(s) || s == stop) {
210             m_dragStops[s] = s->position() - stop->position();
211             m_stops.append(s);
212         } else {
213             m_dragOriginal[s->position()] = s->color();
214         }
215     }
216     for (QtGradientStop *s : stops) {
217         if (!m_model->isSelected(s))
218             m_stops.append(s);
219     }
220     m_stops.removeAll(stop);
221     m_stops.prepend(stop);
222 }
223 */
224 ////////////////////////////
225 
QtGradientWidget(QWidget * parent)226 QtGradientWidget::QtGradientWidget(QWidget *parent)
227     : QWidget(parent), d_ptr(new QtGradientWidgetPrivate)
228 {
229     d_ptr->q_ptr = this;
230     d_ptr->m_backgroundCheckered = true;
231     d_ptr->m_handleSize = 20.0;
232     d_ptr->m_gradientType = QGradient::LinearGradient;
233     d_ptr->m_startLinear = QPointF(0, 0);
234     d_ptr->m_endLinear = QPointF(1, 1);
235     d_ptr->m_centralRadial = QPointF(0.5, 0.5);
236     d_ptr->m_focalRadial = QPointF(0.5, 0.5);
237     d_ptr->m_radiusRadial = 0.5;
238     d_ptr->m_centralConical = QPointF(0.5, 0.5);
239     d_ptr->m_angleConical = 0;
240     d_ptr->m_dragHandle = QtGradientWidgetPrivate::NoHandle;
241 
242     setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
243 }
244 
~QtGradientWidget()245 QtGradientWidget::~QtGradientWidget()
246 {
247 }
248 
sizeHint() const249 QSize QtGradientWidget::sizeHint() const
250 {
251     return QSize(176, 176);
252 }
253 
minimumSizeHint() const254 QSize QtGradientWidget::minimumSizeHint() const
255 {
256     return QSize(128, 128);
257 }
258 
heightForWidth(int w) const259 int QtGradientWidget::heightForWidth(int w) const
260 {
261     return w;
262 }
263 
setBackgroundCheckered(bool checkered)264 void QtGradientWidget::setBackgroundCheckered(bool checkered)
265 {
266     if (d_ptr->m_backgroundCheckered == checkered)
267         return;
268     d_ptr->m_backgroundCheckered = checkered;
269     update();
270 }
271 
isBackgroundCheckered() const272 bool QtGradientWidget::isBackgroundCheckered() const
273 {
274     return d_ptr->m_backgroundCheckered;
275 }
276 
mousePressEvent(QMouseEvent * e)277 void QtGradientWidget::mousePressEvent(QMouseEvent *e)
278 {
279     if (e->button() != Qt::LeftButton)
280         return;
281 
282     QPoint p = e->pos();
283     if (d_ptr->m_gradientType == QGradient::LinearGradient) {
284         QPointF startPoint = d_ptr->toViewport(d_ptr->m_startLinear);
285         double x = p.x() - startPoint.x();
286         double y = p.y() - startPoint.y();
287 
288         if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) {
289             d_ptr->m_dragHandle = QtGradientWidgetPrivate::StartLinearHandle;
290             d_ptr->m_dragOffset = QPointF(x, y);
291             update();
292             return;
293         }
294 
295         QPointF endPoint = d_ptr->toViewport(d_ptr->m_endLinear);
296         x = p.x() - endPoint.x();
297         y = p.y() - endPoint.y();
298 
299         if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) {
300             d_ptr->m_dragHandle = QtGradientWidgetPrivate::EndLinearHandle;
301             d_ptr->m_dragOffset = QPointF(x, y);
302             update();
303             return;
304         }
305     } else if (d_ptr->m_gradientType == QGradient::RadialGradient) {
306         QPointF focalPoint = d_ptr->toViewport(d_ptr->m_focalRadial);
307         double x = p.x() - focalPoint.x();
308         double y = p.y() - focalPoint.y();
309 
310         if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 9) > (x * x + y * y)) {
311             d_ptr->m_dragHandle = QtGradientWidgetPrivate::FocalRadialHandle;
312             d_ptr->m_dragOffset = QPointF(x, y);
313             update();
314             return;
315         }
316 
317         QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralRadial);
318         x = p.x() - centralPoint.x();
319         y = p.y() - centralPoint.y();
320 
321         if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) {
322             d_ptr->m_dragHandle = QtGradientWidgetPrivate::CentralRadialHandle;
323             d_ptr->m_dragOffset = QPointF(x, y);
324             update();
325             return;
326         }
327 
328         QPointF central = d_ptr->toViewport(d_ptr->m_centralRadial);
329         QRectF r = d_ptr->pointRect(central, 2 * d_ptr->m_handleSize / 3);
330         QRectF r1(0, r.y(), size().width(), r.height());
331         QRectF r2(r.x(), 0, r.width(), r.y());
332         QRectF r3(r.x(), r.y() + r.height(), r.width(), size().height() - r.y() - r.height());
333         QPointF pF(p.x(), p.y());
334         if (r1.contains(pF) || r2.contains(pF) || r3.contains(pF)) {
335             x = pF.x() / size().width() - d_ptr->m_centralRadial.x();
336             y = pF.y() / size().height() - d_ptr->m_centralRadial.y();
337             const double clickRadius = hypot(x, y);
338             //d_ptr->m_radiusOffset = d_ptr->m_radiusRadial - clickRadius;
339             d_ptr->m_radiusFactor = d_ptr->m_radiusRadial / clickRadius;
340             if (d_ptr->m_radiusFactor == 0)
341                 d_ptr->m_radiusFactor = 1;
342             d_ptr->m_dragRadius = d_ptr->m_radiusRadial;
343             d_ptr->m_dragHandle = QtGradientWidgetPrivate::RadiusRadialHandle;
344             mouseMoveEvent(e);
345             update();
346             return;
347         }
348     } else if (d_ptr->m_gradientType == QGradient::ConicalGradient) {
349         QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralConical);
350         double x = p.x() - centralPoint.x();
351         double y = p.y() - centralPoint.y();
352 
353         if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) {
354             d_ptr->m_dragHandle = QtGradientWidgetPrivate::CentralConicalHandle;
355             d_ptr->m_dragOffset = QPointF(x, y);
356             update();
357             return;
358         }
359         double radius = size().width();
360         if (size().height() < radius)
361             radius = size().height();
362         radius /= 2;
363         double corr = d_ptr->m_handleSize / 3;
364         radius -= corr;
365         QPointF vp = d_ptr->toViewport(d_ptr->m_centralConical);
366         x = p.x() - vp.x();
367         y = p.y() - vp.y();
368         if (((radius - corr) * (radius - corr) < (x * x + y * y)) &&
369             ((radius + corr) * (radius + corr) > (x * x + y * y))) {
370             QPointF central = d_ptr->toViewport(d_ptr->m_centralConical);
371             QPointF current(e->pos().x(), e->pos().y());
372             x = current.x() - central.x();
373             y = current.y() - central.y();
374             x /= size().width() / 2;
375             y /= size().height() / 2;
376             const double angle = qRadiansToDegrees(atan2(-y, x));
377 
378             d_ptr->m_angleOffset = d_ptr->m_angleConical - angle;
379             d_ptr->m_dragAngle = d_ptr->m_angleConical;
380             d_ptr->m_dragHandle = QtGradientWidgetPrivate::AngleConicalHandle;
381             update();
382             return;
383         }
384     }
385 }
386 
mouseReleaseEvent(QMouseEvent * e)387 void QtGradientWidget::mouseReleaseEvent(QMouseEvent *e)
388 {
389     Q_UNUSED(e);
390     d_ptr->m_dragHandle = QtGradientWidgetPrivate::NoHandle;
391     update();
392 }
393 
mouseMoveEvent(QMouseEvent * e)394 void QtGradientWidget::mouseMoveEvent(QMouseEvent *e)
395 {
396     if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::NoHandle)
397         return;
398 
399     const QPointF newPos = e->localPos() - d_ptr->m_dragOffset;
400     QPointF newPoint = d_ptr->fromViewport(newPos);
401     if (newPoint.x() < 0)
402         newPoint.setX(0);
403     else if (newPoint.x() > 1)
404         newPoint.setX(1);
405     if (newPoint.y() < 0)
406         newPoint.setY(0);
407     else if (newPoint.y() > 1)
408         newPoint.setY(1);
409 
410     if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::StartLinearHandle) {
411         d_ptr->m_startLinear = newPoint;
412         emit startLinearChanged(newPoint);
413     } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::EndLinearHandle) {
414         d_ptr->m_endLinear = newPoint;
415         emit endLinearChanged(newPoint);
416     } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralRadialHandle) {
417         d_ptr->m_centralRadial = newPoint;
418         emit centralRadialChanged(newPoint);
419     } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::FocalRadialHandle) {
420         d_ptr->m_focalRadial = newPoint;
421         emit focalRadialChanged(newPoint);
422     } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::RadiusRadialHandle) {
423         QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralRadial);
424         QPointF pF(e->pos().x(), e->pos().y());
425         double x = pF.x() - centralPoint.x();
426         double y = pF.y() - centralPoint.y();
427 
428         if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) {
429             if (d_ptr->m_radiusRadial != d_ptr->m_dragRadius) {
430                 d_ptr->m_radiusRadial = d_ptr->m_dragRadius;
431                 emit radiusRadialChanged(d_ptr->m_radiusRadial);
432             }
433         } else {
434             x = pF.x() / size().width() - d_ptr->m_centralRadial.x();
435             y = pF.y() / size().height() - d_ptr->m_centralRadial.y();
436             const double moveRadius = hypot(x, y);
437             //double newRadius = moveRadius + d_ptr->m_radiusOffset;
438             double newRadius = moveRadius * d_ptr->m_radiusFactor;
439             if (newRadius > 2)
440                 newRadius = 2;
441             d_ptr->m_radiusRadial = newRadius;
442             emit radiusRadialChanged(d_ptr->m_radiusRadial);
443         }
444     } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralConicalHandle) {
445         d_ptr->m_centralConical = newPoint;
446         emit centralConicalChanged(newPoint);
447     } else if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::AngleConicalHandle) {
448         QPointF centralPoint = d_ptr->toViewport(d_ptr->m_centralConical);
449         QPointF pF(e->pos().x(), e->pos().y());
450         double x = pF.x() - centralPoint.x();
451         double y = pF.y() - centralPoint.y();
452 
453         if ((d_ptr->m_handleSize * d_ptr->m_handleSize / 4) > (x * x + y * y)) {
454             if (d_ptr->m_angleConical != d_ptr->m_dragAngle) {
455                 d_ptr->m_angleConical = d_ptr->m_dragAngle;
456                 emit angleConicalChanged(d_ptr->m_angleConical);
457             }
458         } else {
459             QPointF central = d_ptr->toViewport(d_ptr->m_centralConical);
460             QPointF current = pF;
461             x = current.x() - central.x();
462             y = current.y() - central.y();
463             x /= size().width() / 2;
464             y /= size().height() / 2;
465 
466             const double angle = qRadiansToDegrees(atan2(-y, x)) + d_ptr->m_angleOffset;
467             d_ptr->setAngleConical(angle);
468         }
469     }
470     update();
471 }
472 
mouseDoubleClickEvent(QMouseEvent * e)473 void QtGradientWidget::mouseDoubleClickEvent(QMouseEvent *e)
474 {
475     mousePressEvent(e);
476 }
477 
paintEvent(QPaintEvent * e)478 void QtGradientWidget::paintEvent(QPaintEvent *e)
479 {
480     Q_UNUSED(e);
481 
482     QPainter p(this);
483 
484     if (d_ptr->m_backgroundCheckered) {
485         int pixSize = 40;
486         QPixmap pm(2 * pixSize, 2 * pixSize);
487 
488         QPainter pmp(&pm);
489         pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
490         pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
491         pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
492         pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
493 
494         p.setBrushOrigin((size().width() % pixSize + pixSize) / 2, (size().height() % pixSize + pixSize) / 2);
495         p.fillRect(rect(), pm);
496         p.setBrushOrigin(0, 0);
497     }
498 
499     QGradient *gradient = 0;
500     switch (d_ptr->m_gradientType) {
501         case QGradient::LinearGradient:
502             gradient = new QLinearGradient(d_ptr->m_startLinear, d_ptr->m_endLinear);
503             break;
504         case QGradient::RadialGradient:
505             gradient = new QRadialGradient(d_ptr->m_centralRadial, d_ptr->m_radiusRadial, d_ptr->m_focalRadial);
506             break;
507         case QGradient::ConicalGradient:
508             gradient = new QConicalGradient(d_ptr->m_centralConical, d_ptr->m_angleConical);
509             break;
510         default:
511             break;
512     }
513     if (!gradient)
514         return;
515 
516     gradient->setStops(d_ptr->m_gradientStops);
517     gradient->setSpread(d_ptr->m_gradientSpread);
518 
519     p.save();
520     p.scale(size().width(), size().height());
521     p.fillRect(QRect(0, 0, 1, 1), *gradient);
522     p.restore();
523 
524     p.setRenderHint(QPainter::Antialiasing);
525 
526     QColor c = QColor::fromRgbF(0.5, 0.5, 0.5, 0.5);
527     QBrush br(c);
528     p.setBrush(br);
529     QPen pen(Qt::white);
530     pen.setWidthF(1);
531     p.setPen(pen);
532     QPen dragPen = pen;
533     dragPen.setWidthF(2);
534     if (d_ptr->m_gradientType == QGradient::LinearGradient) {
535         p.save();
536         if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::StartLinearHandle)
537             p.setPen(dragPen);
538         d_ptr->paintPoint(&p, d_ptr->m_startLinear, d_ptr->m_handleSize);
539         p.restore();
540 
541         p.save();
542         if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::EndLinearHandle)
543             p.setPen(dragPen);
544         d_ptr->paintPoint(&p, d_ptr->m_endLinear, d_ptr->m_handleSize);
545         p.restore();
546     } else if (d_ptr->m_gradientType == QGradient::RadialGradient) {
547         QPointF central = d_ptr->toViewport(d_ptr->m_centralRadial);
548 
549         p.save();
550         QRectF r = d_ptr->pointRect(central, 2 * d_ptr->m_handleSize / 3);
551         QRectF r1(0, r.y(), size().width(), r.height());
552         QRectF r2(r.x(), 0, r.width(), r.y());
553         QRectF r3(r.x(), r.y() + r.height(), r.width(), size().height() - r.y() - r.height());
554         p.fillRect(r1, c);
555         p.fillRect(r2, c);
556         p.fillRect(r3, c);
557         p.setBrush(Qt::NoBrush);
558         p.save();
559         if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralRadialHandle)
560             p.setPen(dragPen);
561         d_ptr->paintPoint(&p, d_ptr->m_centralRadial, d_ptr->m_handleSize);
562         p.restore();
563 
564         const QRectF rect = QRectF(central.x() - d_ptr->m_radiusRadial * size().width(),
565                         central.y() - d_ptr->m_radiusRadial * size().height(),
566                         2 * d_ptr->m_radiusRadial * size().width(),
567                         2 * d_ptr->m_radiusRadial * size().height());
568         QRegion region(r1.toRect());
569         region += r2.toRect();
570         region += r3.toRect();
571         p.setClipRegion(region);
572 
573         p.drawEllipse(rect);
574         if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::RadiusRadialHandle) {
575             p.save();
576             p.setPen(dragPen);
577             QRectF rect = QRectF(central.x() - d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().width(),
578                     central.y() - d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().height(),
579                     2 * d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().width(),
580                     2 * d_ptr->m_radiusRadial / d_ptr->m_radiusFactor * size().height());
581             p.drawEllipse(rect);
582 
583             p.restore();
584         }
585         p.restore();
586 
587         p.save();
588         if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::FocalRadialHandle)
589             p.setPen(dragPen);
590         d_ptr->paintPoint(&p, d_ptr->m_focalRadial, 2 * d_ptr->m_handleSize / 3);
591         p.restore();
592     } else if (d_ptr->m_gradientType == QGradient::ConicalGradient) {
593         double radius = size().width();
594         if (size().height() < radius)
595             radius = size().height();
596         radius /= 2;
597         double corr = d_ptr->m_handleSize / 3;
598         radius -= corr;
599         QPointF central = d_ptr->toViewport(d_ptr->m_centralConical);
600 
601         p.save();
602         p.setBrush(Qt::NoBrush);
603         QPen pen2(c);
604         pen2.setWidthF(2 * d_ptr->m_handleSize / 3);
605         p.setPen(pen2);
606         p.drawEllipse(d_ptr->pointRect(central, 2 * radius));
607         p.restore();
608 
609         p.save();
610         p.setBrush(Qt::NoBrush);
611         int pointCount = 2;
612         for (int i = 0; i < pointCount; i++) {
613             const qreal angle = qDegreesToRadians(i * 180.0 / pointCount + d_ptr->m_angleConical);
614             const QPointF ray(cos(angle) * size().width() / 2,
615                              -sin(angle) * size().height() / 2);
616             const double mod = hypot(ray.x(), ray.y());
617             p.drawLine(QPointF(central.x() + ray.x() * (radius - corr) / mod,
618                         central.y() + ray.y() * (radius - corr) / mod),
619                     QPointF(central.x() + ray.x() * (radius + corr) / mod,
620                         central.y() + ray.y() * (radius + corr) / mod));
621             p.drawLine(QPointF(central.x() - ray.x() * (radius - corr) / mod,
622                         central.y() - ray.y() * (radius - corr) / mod),
623                     QPointF(central.x() - ray.x() * (radius + corr) / mod,
624                         central.y() - ray.y() * (radius + corr) / mod));
625         }
626         if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::AngleConicalHandle) {
627             p.save();
628             p.setPen(dragPen);
629             const qreal angle = qDegreesToRadians(d_ptr->m_angleConical - d_ptr->m_angleOffset);
630             const QPointF ray(cos(angle) * size().width() / 2,
631                              -sin(angle) * size().height() / 2);
632             const double mod = hypot(ray.x(), ray.y());
633             p.drawLine(QPointF(central.x() + ray.x() * (radius - corr) / mod,
634                         central.y() + ray.y() * (radius - corr) / mod),
635                     QPointF(central.x() + ray.x() * (radius + corr) / mod,
636                         central.y() + ray.y() * (radius + corr) / mod));
637             p.restore();
638         }
639 
640         p.restore();
641 
642         p.save();
643         if (d_ptr->m_dragHandle == QtGradientWidgetPrivate::CentralConicalHandle)
644             p.setPen(dragPen);
645         d_ptr->paintPoint(&p, d_ptr->m_centralConical, d_ptr->m_handleSize);
646         p.restore();
647 
648     }
649 
650     delete gradient;
651 }
652 
setGradientStops(const QGradientStops & stops)653 void QtGradientWidget::setGradientStops(const QGradientStops &stops)
654 {
655     d_ptr->m_gradientStops = stops;
656     update();
657 }
658 
gradientStops() const659 QGradientStops QtGradientWidget::gradientStops() const
660 {
661     return d_ptr->m_gradientStops;
662 }
663 
setGradientType(QGradient::Type type)664 void QtGradientWidget::setGradientType(QGradient::Type type)
665 {
666     if (type == QGradient::NoGradient)
667         return;
668     if (d_ptr->m_gradientType == type)
669         return;
670 
671     d_ptr->m_gradientType = type;
672     update();
673 }
674 
gradientType() const675 QGradient::Type QtGradientWidget::gradientType() const
676 {
677     return d_ptr->m_gradientType;
678 }
679 
setGradientSpread(QGradient::Spread spread)680 void QtGradientWidget::setGradientSpread(QGradient::Spread spread)
681 {
682     if (d_ptr->m_gradientSpread == spread)
683         return;
684 
685     d_ptr->m_gradientSpread = spread;
686     update();
687 }
688 
gradientSpread() const689 QGradient::Spread QtGradientWidget::gradientSpread() const
690 {
691     return d_ptr->m_gradientSpread;
692 }
693 
setStartLinear(const QPointF & point)694 void QtGradientWidget::setStartLinear(const QPointF &point)
695 {
696     if (d_ptr->m_startLinear == point)
697         return;
698 
699     d_ptr->m_startLinear = d_ptr->checkRange(point);
700     update();
701 }
702 
startLinear() const703 QPointF QtGradientWidget::startLinear() const
704 {
705     return d_ptr->m_startLinear;
706 }
707 
setEndLinear(const QPointF & point)708 void QtGradientWidget::setEndLinear(const QPointF &point)
709 {
710     if (d_ptr->m_endLinear == point)
711         return;
712 
713     d_ptr->m_endLinear = d_ptr->checkRange(point);
714     update();
715 }
716 
endLinear() const717 QPointF QtGradientWidget::endLinear() const
718 {
719     return d_ptr->m_endLinear;
720 }
721 
setCentralRadial(const QPointF & point)722 void QtGradientWidget::setCentralRadial(const QPointF &point)
723 {
724     if (d_ptr->m_centralRadial == point)
725         return;
726 
727     d_ptr->m_centralRadial = point;
728     update();
729 }
730 
centralRadial() const731 QPointF QtGradientWidget::centralRadial() const
732 {
733     return d_ptr->m_centralRadial;
734 }
735 
setFocalRadial(const QPointF & point)736 void QtGradientWidget::setFocalRadial(const QPointF &point)
737 {
738     if (d_ptr->m_focalRadial == point)
739         return;
740 
741     d_ptr->m_focalRadial = point;
742     update();
743 }
744 
focalRadial() const745 QPointF QtGradientWidget::focalRadial() const
746 {
747     return d_ptr->m_focalRadial;
748 }
749 
setRadiusRadial(qreal radius)750 void QtGradientWidget::setRadiusRadial(qreal radius)
751 {
752     if (d_ptr->m_radiusRadial == radius)
753         return;
754 
755     d_ptr->m_radiusRadial = radius;
756     update();
757 }
758 
radiusRadial() const759 qreal QtGradientWidget::radiusRadial() const
760 {
761     return d_ptr->m_radiusRadial;
762 }
763 
setCentralConical(const QPointF & point)764 void QtGradientWidget::setCentralConical(const QPointF &point)
765 {
766     if (d_ptr->m_centralConical == point)
767         return;
768 
769     d_ptr->m_centralConical = point;
770     update();
771 }
772 
centralConical() const773 QPointF QtGradientWidget::centralConical() const
774 {
775     return d_ptr->m_centralConical;
776 }
777 
setAngleConical(qreal angle)778 void QtGradientWidget::setAngleConical(qreal angle)
779 {
780     if (d_ptr->m_angleConical == angle)
781         return;
782 
783     d_ptr->m_angleConical = angle;
784     update();
785 }
786 
angleConical() const787 qreal QtGradientWidget::angleConical() const
788 {
789     return d_ptr->m_angleConical;
790 }
791 
792 QT_END_NAMESPACE
793