File indexing completed on 2024-05-12 15:56:41

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2008 Jan Hambrecht <jaham@gmx.net>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "KoGradientHelper.h"
0008 
0009 #include <QGradient>
0010 #include <math.h>
0011 
0012 QGradient* KoGradientHelper::defaultGradient(QGradient::Type type, QGradient::Spread spread, const QGradientStops &stops)
0013 {
0014     QGradient *gradient = 0;
0015     switch (type) {
0016     case QGradient::LinearGradient:
0017         gradient = new QLinearGradient(QPointF(0.0, 0.5), QPointF(1, 0.5));
0018         break;
0019     case QGradient::RadialGradient:
0020         gradient = new QRadialGradient(QPointF(0.5, 0.5), sqrt(0.5));
0021         break;
0022     case QGradient::ConicalGradient:
0023         gradient = new QConicalGradient(QPointF(0.5, 0.5), 0.0);
0024         break;
0025     default:
0026         return 0;
0027     }
0028     gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
0029     gradient->setSpread(spread);
0030     gradient->setStops(stops);
0031 
0032     return gradient;
0033 }
0034 
0035 QGradient* KoGradientHelper::convertGradient(const QGradient * gradient, QGradient::Type newType)
0036 {
0037     QPointF start, stop;
0038     // try to preserve gradient positions
0039     switch (gradient->type()) {
0040     case QGradient::LinearGradient: {
0041         const QLinearGradient *g = static_cast<const QLinearGradient*>(gradient);
0042         start = g->start();
0043         stop = g->finalStop();
0044         break;
0045     }
0046     case QGradient::RadialGradient: {
0047         const QRadialGradient *g = static_cast<const QRadialGradient*>(gradient);
0048         start = g->center();
0049         stop = QPointF(g->radius(), 0.0);
0050         break;
0051     }
0052     case QGradient::ConicalGradient: {
0053         const QConicalGradient *g = static_cast<const QConicalGradient*>(gradient);
0054         start = g->center();
0055         qreal radAngle = g->angle() * M_PI / 180.0;
0056         stop = QPointF(0.5 * cos(radAngle), 0.5 * sin(radAngle));
0057         break;
0058     }
0059     default:
0060         start = QPointF(0.0, 0.0);
0061         stop = QPointF(0.5, 0.5);
0062     }
0063 
0064     QGradient *newGradient = 0;
0065     switch (newType) {
0066     case QGradient::LinearGradient:
0067         newGradient = new QLinearGradient(start, stop);
0068         break;
0069     case QGradient::RadialGradient: {
0070         QPointF diff(stop - start);
0071         qreal radius = sqrt(diff.x()*diff.x() + diff.y()*diff.y());
0072         newGradient = new QRadialGradient(start, radius, start);
0073         break;
0074     }
0075     case QGradient::ConicalGradient: {
0076         QPointF diff(stop - start);
0077         qreal angle = atan2(diff.y(), diff.x());
0078         if (angle < 0.0)
0079             angle += 2 * M_PI;
0080         newGradient = new QConicalGradient(start, angle * 180/M_PI);
0081         break;
0082     }
0083     default:
0084         return 0;
0085     }
0086     newGradient->setCoordinateMode(QGradient::ObjectBoundingMode);
0087     newGradient->setSpread(gradient->spread());
0088     newGradient->setStops(gradient->stops());
0089 
0090     return newGradient;
0091 }
0092 
0093 QColor KoGradientHelper::colorAt(qreal position, const QGradientStops &stops)
0094 {
0095     if (! stops.count())
0096         return QColor();
0097 
0098     if (stops.count() == 1)
0099         return stops.first().second;
0100 
0101     QGradientStop prevStop(-1.0, QColor());
0102     QGradientStop nextStop(2.0, QColor());
0103     // find framing gradient stops
0104     Q_FOREACH (const QGradientStop & stop, stops) {
0105         if (stop.first > prevStop.first && stop.first < position)
0106             prevStop = stop;
0107         if (stop.first < nextStop.first && stop.first > position)
0108             nextStop = stop;
0109     }
0110 
0111     QColor theColor;
0112 
0113     if (prevStop.first < 0.0) {
0114         // new stop is before the first stop
0115         theColor = nextStop.second;
0116     } else if (nextStop.first > 1.0) {
0117         // new stop is after the last stop
0118         theColor = prevStop.second;
0119     } else {
0120         // linear interpolate colors between framing stops
0121         QColor prevColor = prevStop.second, nextColor = nextStop.second;
0122         qreal colorScale = (position - prevStop.first) / (nextStop.first - prevStop.first);
0123         theColor.setRedF(prevColor.redF() + colorScale *(nextColor.redF() - prevColor.redF()));
0124         theColor.setGreenF(prevColor.greenF() + colorScale *(nextColor.greenF() - prevColor.greenF()));
0125         theColor.setBlueF(prevColor.blueF() + colorScale *(nextColor.blueF() - prevColor.blueF()));
0126         theColor.setAlphaF(prevColor.alphaF() + colorScale *(nextColor.alphaF() - prevColor.alphaF()));
0127     }
0128     return theColor;
0129 }