1 /* This file is part of the KDE project
2  * Copyright (C) 2008 Jan Hambrecht <jaham@gmx.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "KoGradientHelper.h"
21 
22 #include <QGradient>
23 #include <math.h>
24 
defaultGradient(QGradient::Type type,QGradient::Spread spread,const QGradientStops & stops)25 QGradient* KoGradientHelper::defaultGradient(QGradient::Type type, QGradient::Spread spread, const QGradientStops &stops)
26 {
27     QGradient *gradient = 0;
28     switch (type) {
29     case QGradient::LinearGradient:
30         gradient = new QLinearGradient(QPointF(0.0, 0.5), QPointF(1, 0.5));
31         break;
32     case QGradient::RadialGradient:
33         gradient = new QRadialGradient(QPointF(0.5, 0.5), sqrt(0.5));
34         break;
35     case QGradient::ConicalGradient:
36         gradient = new QConicalGradient(QPointF(0.5, 0.5), 0.0);
37         break;
38     default:
39         return 0;
40     }
41     gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
42     gradient->setSpread(spread);
43     gradient->setStops(stops);
44 
45     return gradient;
46 }
47 
convertGradient(const QGradient * gradient,QGradient::Type newType)48 QGradient* KoGradientHelper::convertGradient(const QGradient * gradient, QGradient::Type newType)
49 {
50     QPointF start, stop;
51     // try to preserve gradient positions
52     switch (gradient->type()) {
53     case QGradient::LinearGradient: {
54         const QLinearGradient *g = static_cast<const QLinearGradient*>(gradient);
55         start = g->start();
56         stop = g->finalStop();
57         break;
58     }
59     case QGradient::RadialGradient: {
60         const QRadialGradient *g = static_cast<const QRadialGradient*>(gradient);
61         start = g->center();
62         stop = QPointF(g->radius(), 0.0);
63         break;
64     }
65     case QGradient::ConicalGradient: {
66         const QConicalGradient *g = static_cast<const QConicalGradient*>(gradient);
67         start = g->center();
68         qreal radAngle = g->angle() * M_PI / 180.0;
69         stop = QPointF(0.5 * cos(radAngle), 0.5 * sin(radAngle));
70         break;
71     }
72     default:
73         start = QPointF(0.0, 0.0);
74         stop = QPointF(0.5, 0.5);
75     }
76 
77     QGradient *newGradient = 0;
78     switch (newType) {
79     case QGradient::LinearGradient:
80         newGradient = new QLinearGradient(start, stop);
81         break;
82     case QGradient::RadialGradient: {
83         QPointF diff(stop - start);
84         qreal radius = sqrt(diff.x()*diff.x() + diff.y()*diff.y());
85         newGradient = new QRadialGradient(start, radius, start);
86         break;
87     }
88     case QGradient::ConicalGradient: {
89         QPointF diff(stop - start);
90         qreal angle = atan2(diff.y(), diff.x());
91         if (angle < 0.0)
92             angle += 2 * M_PI;
93         newGradient = new QConicalGradient(start, angle * 180/M_PI);
94         break;
95     }
96     default:
97         return 0;
98     }
99     newGradient->setCoordinateMode(QGradient::ObjectBoundingMode);
100     newGradient->setSpread(gradient->spread());
101     newGradient->setStops(gradient->stops());
102 
103     return newGradient;
104 }
105 
colorAt(qreal position,const QGradientStops & stops)106 QColor KoGradientHelper::colorAt(qreal position, const QGradientStops &stops)
107 {
108     if (! stops.count())
109         return QColor();
110 
111     if (stops.count() == 1)
112         return stops.first().second;
113 
114     QGradientStop prevStop(-1.0, QColor());
115     QGradientStop nextStop(2.0, QColor());
116     // find framing gradient stops
117     foreach(const QGradientStop & stop, stops) {
118         if (stop.first > prevStop.first && stop.first < position)
119             prevStop = stop;
120         if (stop.first < nextStop.first && stop.first > position)
121             nextStop = stop;
122     }
123 
124     QColor theColor;
125 
126     if (prevStop.first < 0.0) {
127         // new stop is before the first stop
128         theColor = nextStop.second;
129     } else if (nextStop.first > 1.0) {
130         // new stop is after the last stop
131         theColor = prevStop.second;
132     } else {
133         // linear interpolate colors between framing stops
134         QColor prevColor = prevStop.second, nextColor = nextStop.second;
135         qreal colorScale = (position - prevStop.first) / (nextStop.first - prevStop.first);
136         theColor.setRedF(prevColor.redF() + colorScale *(nextColor.redF() - prevColor.redF()));
137         theColor.setGreenF(prevColor.greenF() + colorScale *(nextColor.greenF() - prevColor.greenF()));
138         theColor.setBlueF(prevColor.blueF() + colorScale *(nextColor.blueF() - prevColor.blueF()));
139         theColor.setAlphaF(prevColor.alphaF() + colorScale *(nextColor.alphaF() - prevColor.alphaF()));
140     }
141     return theColor;
142 }
143