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