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 }