2 * Copyright 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
3 * Copyright 2007 Casper Boemann <cbr@boemann.dk>
4 * Copyright 2007 Fredrik Höglund <fredrik@kde.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License version 2 as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
23 #include <KGlobalSettings>
24 #include <KColorUtils>
25 #include <KColorScheme>
27 #include <QtGui/QPainter>
31 const double OxygenHelper::_shadowGain
= 1.5;
33 // NOTE: OxygenStyleHelper needs to use a KConfig from its own KComponentData
34 // Since the ctor order causes a SEGV if we try to pass in a KConfig here from
35 // a KComponentData constructed in the OxygenStyleHelper ctor, we'll just keep
36 // one here, even though the window decoration doesn't really need it.
37 OxygenHelper::OxygenHelper(const QByteArray
&componentName
)
38 : _componentData(componentName
, 0, KComponentData::SkipMainComponentRegistration
)
40 _config
= _componentData
.config();
41 _contrast
= KGlobalSettings::contrastF(_config
);
42 _bgcontrast
= 0.3;// // shouldn't use contrast for this _contrast; // TODO get style setting
44 m_backgroundCache
.setMaxCost(64);
45 m_windecoButtonCache
.setMaxCost(64);
48 KSharedConfigPtr
OxygenHelper::config() const
53 void OxygenHelper::reloadConfig()
55 double old_contrast
= _contrast
;
57 _config
->reparseConfiguration();
58 _contrast
= KGlobalSettings::contrastF(_config
);
60 if (_contrast
!= old_contrast
)
61 invalidateCaches(); // contrast changed, invalidate our caches
64 void OxygenHelper::invalidateCaches()
66 m_backgroundCache
.clear();
67 m_windecoButtonCache
.clear();
70 bool OxygenHelper::lowThreshold(const QColor
&color
)
72 QColor darker
= KColorScheme::shade(color
, KColorScheme::MidShade
, 0.5);
73 return KColorUtils::luma(darker
) > KColorUtils::luma(color
);
76 QColor
OxygenHelper::alphaColor(QColor color
, double alpha
)
80 color
.setAlphaF(qMax(0.0, alpha
) * color
.alphaF());
84 QColor
OxygenHelper::backgroundRadialColor(const QColor
&color
) const
86 if (lowThreshold(color
))
87 return KColorScheme::shade(color
, KColorScheme::LightShade
, 0.0);
89 return KColorScheme::shade(color
, KColorScheme::LightShade
, _bgcontrast
);
92 QColor
OxygenHelper::backgroundTopColor(const QColor
&color
) const
94 if (lowThreshold(color
))
95 return KColorScheme::shade(color
, KColorScheme::MidlightShade
, 0.0);
97 return KColorScheme::shade(color
, KColorScheme::MidlightShade
, _bgcontrast
);
100 QColor
OxygenHelper::backgroundBottomColor(const QColor
&color
) const
102 QColor midColor
= KColorScheme::shade(color
, KColorScheme::MidShade
, 0.0);
103 if (lowThreshold(color
))
106 double by
= KColorUtils::luma(color
), my
= KColorUtils::luma(midColor
);
107 return KColorUtils::shade(color
, (my
- by
) * _bgcontrast
);
110 QColor
OxygenHelper::calcLightColor(const QColor
&color
) const
112 return KColorScheme::shade(color
, KColorScheme::LightShade
, _contrast
);
115 QColor
OxygenHelper::calcDarkColor(const QColor
&color
) const
117 if (lowThreshold(color
))
118 return KColorUtils::mix(calcLightColor(color
), color
, 0.2 + 0.8 * _contrast
);
120 return KColorScheme::shade(color
, KColorScheme::MidShade
, _contrast
);
123 QColor
OxygenHelper::calcShadowColor(const QColor
&color
) const
125 return KColorScheme::shade(color
, KColorScheme::ShadowShade
, _contrast
);
128 QColor
OxygenHelper::backgroundColor(const QColor
&color
, int height
, int y
)
130 double h
= height
* 0.5;
132 double a
= double(y
) / h
;
133 return KColorUtils::mix(backgroundTopColor(color
), color
, a
);
136 double a
= (double(y
) - h
) / h
;
137 return KColorUtils::mix(color
, backgroundBottomColor(color
), a
);
141 QPixmap
OxygenHelper::verticalGradient(const QColor
&color
, int height
)
143 quint64 key
= (quint64(color
.rgba()) << 32) | height
| 0x8000;
144 QPixmap
*pixmap
= m_backgroundCache
.object(key
);
148 pixmap
= new QPixmap(32, height
);
150 QLinearGradient
gradient(0, 0, 0, height
);
151 gradient
.setColorAt(0.0, backgroundTopColor(color
));
152 gradient
.setColorAt(0.5, color
);
153 gradient
.setColorAt(1.0, backgroundBottomColor(color
));
156 p
.setCompositionMode(QPainter::CompositionMode_Source
);
157 p
.fillRect(pixmap
->rect(), gradient
);
159 m_backgroundCache
.insert(key
, pixmap
);
165 QPixmap
OxygenHelper::radialGradient(const QColor
&color
, int width
)
167 quint64 key
= (quint64(color
.rgba()) << 32) | width
| 0xb000;
168 QPixmap
*pixmap
= m_backgroundCache
.object(key
);
173 pixmap
= new QPixmap(width
, 64);
174 pixmap
->fill(QColor(0,0,0,0));
175 QColor radialColor
= backgroundRadialColor(color
);
176 radialColor
.setAlpha(255);
177 QRadialGradient
gradient(64, 0, 64);
178 gradient
.setColorAt(0, radialColor
);
179 radialColor
.setAlpha(101);
180 gradient
.setColorAt(0.5, radialColor
);
181 radialColor
.setAlpha(37);
182 gradient
.setColorAt(0.75, radialColor
);
183 radialColor
.setAlpha(0);
184 gradient
.setColorAt(1, radialColor
);
187 p
.scale(width
/128.0,1);
188 p
.fillRect(QRect(0,0,128,64), gradient
);
190 m_backgroundCache
.insert(key
, pixmap
);
196 void OxygenHelper::drawShadow(QPainter
&p
, const QColor
&color
, int size
) const
198 double m
= double(size
-2)*0.5;
200 const double offset
= 0.8;
201 double k0
= (m
-4.0) / m
;
202 QRadialGradient
shadowGradient(m
+1.0, m
+offset
+1.0, m
);
203 for (int i
= 0; i
< 8; i
++) { // sinusoidal gradient
204 double k1
= (k0
* double(8 - i
) + double(i
)) * 0.125;
205 double a
= (cos(3.14159 * i
* 0.125) + 1.0) * 0.25;
206 shadowGradient
.setColorAt(k1
, alphaColor(color
, a
* _shadowGain
));
208 shadowGradient
.setColorAt(1.0, alphaColor(color
, 0.0));
209 p
.setBrush(shadowGradient
);
210 p
.drawEllipse(QRectF(0, 0, size
, size
));
213 QLinearGradient
OxygenHelper::decoGradient(const QRect
&r
, const QColor
&color
)
215 QColor light
= KColorScheme::shade(color
, KColorScheme::LightShade
, _contrast
* 0.7);
216 QColor dark
= KColorScheme::shade(color
, KColorScheme::DarkShade
, _contrast
* 0.7);
217 double y
= KColorUtils::luma(color
);
218 double yd
= KColorUtils::luma(dark
);
219 double yl
= KColorUtils::luma(light
);
221 QLinearGradient
gradient(r
.topLeft(), r
.bottomLeft());
224 gradient
.setColorAt(0.2, color
);
225 gradient
.setColorAt(0.8, dark
);
229 gradient
.setColorAt(0.2, light
);
230 gradient
.setColorAt(0.8, color
);
234 gradient
.setColorAt(0.2, dark
);
235 gradient
.setColorAt(0.5, color
);
236 gradient
.setColorAt(0.8, light
);
242 QPixmap
OxygenHelper::windecoButton(const QColor
&color
, int size
)
244 quint64 key
= (quint64(color
.rgba()) << 32) | size
;
245 QPixmap
*pixmap
= m_windecoButtonCache
.object(key
);
249 pixmap
= new QPixmap(size
*3, size
*3);
250 pixmap
->fill(QColor(0,0,0,0));
253 p
.setRenderHints(QPainter::Antialiasing
);
255 p
.setWindow(0,0,21,21);
257 QColor light
= calcLightColor(color
);
258 QColor dark
= calcDarkColor(color
);
261 drawShadow(p
, calcShadowColor(color
), 21);
264 qreal y
= KColorUtils::luma(color
);
265 qreal yl
= KColorUtils::luma(light
);
266 qreal yd
= KColorUtils::luma(dark
);
267 QLinearGradient
bevelGradient(0, 1, 0, 20);
268 bevelGradient
.setColorAt(0.45, light
);
269 bevelGradient
.setColorAt(0.80, dark
);
270 if (y
< yl
&& y
> yd
) // no middle when color is very light/dark
271 bevelGradient
.setColorAt(0.55, color
);
272 p
.setBrush(QBrush(bevelGradient
));
273 p
.drawEllipse(QRectF(3.0,3.0,15.0,15.0));
276 QRadialGradient
maskGradient(10.5,10.5,7.5);
277 maskGradient
.setColorAt(0.70, QColor(0,0,0,0));
278 maskGradient
.setColorAt(0.85, QColor(0,0,0,140));
279 maskGradient
.setColorAt(0.95, QColor(0,0,0,255));
280 p
.setCompositionMode(QPainter::CompositionMode_DestinationIn
);
281 p
.setBrush(maskGradient
);
282 p
.drawRect(0,0,21,21);
285 QLinearGradient
innerGradient(0, 4, 0, 17);
286 innerGradient
.setColorAt(0.0, color
);
287 innerGradient
.setColorAt(1.0, light
);
288 p
.setCompositionMode(QPainter::CompositionMode_DestinationOver
);
289 p
.setBrush(innerGradient
);
290 p
.drawEllipse(QRectF(3.0,3.0,15.0,15.0));
293 QRadialGradient
highlightGradient(10.5,10,8.5);
294 highlightGradient
.setColorAt(0.85, alphaColor(light
, 0.0));
295 highlightGradient
.setColorAt(1.00, light
);
296 p
.setCompositionMode(QPainter::CompositionMode_SourceOver
);
297 p
.setBrush(highlightGradient
);
298 p
.drawEllipse(QRectF(3.0,3.0,15.0,15.0));
300 m_windecoButtonCache
.insert(key
, pixmap
);
306 QPixmap
OxygenHelper::glow(const QColor
&color
, int size
, int rsize
)
308 QPixmap
pixmap(rsize
, rsize
);
309 pixmap
.fill(QColor(0,0,0,0));
312 p
.setRenderHints(QPainter::Antialiasing
);
314 p
.setWindow(0,0,size
,size
);
316 QRectF
r(0, 0, size
, size
);
317 double m
= double(size
)*0.5;
319 const double width
= 3.0;
320 const double bias
= _glowBias
* double(size
) / double(rsize
);
321 double k0
= (m
-width
+bias
) / m
;
322 QRadialGradient
glowGradient(m
, m
, m
);
323 for (int i
= 0; i
< 8; i
++) { // inverse parabolic gradient
324 double k1
= (k0
* double(8 - i
) + double(i
)) * 0.125;
325 double a
= 1.0 - sqrt(i
* 0.125);
326 glowGradient
.setColorAt(k1
, alphaColor(color
, a
));
328 glowGradient
.setColorAt(1.0, alphaColor(color
, 0.0));
331 p
.setBrush(glowGradient
);
335 p
.setCompositionMode(QPainter::CompositionMode_DestinationOut
);
336 p
.setBrush(QBrush(Qt::black
));
337 p
.drawEllipse(r
.adjusted(width
, width
, -width
, -width
));
344 QPixmap
OxygenHelper::windecoButtonFocused(const QColor
&color
, const QColor
&glowColor
, int size
)
346 quint64 key
= (quint64(glowColor
.rgba()) << 32) | size
;
347 QPixmap
*pixmap
= m_windecoButtonCache
.object(key
);
351 pixmap
= new QPixmap(size
*3, size
*3);
352 pixmap
->fill(QColor(0,0,0,0));
355 p
.setRenderHints(QPainter::Antialiasing
);
357 p
.setWindow(0,0,21,21);
360 QPixmap slabPixmap
= windecoButton(color
, size
);
361 p
.drawPixmap(0, 0, slabPixmap
);
364 QPixmap gp
= glow(glowColor
, 21, size
*3);
365 p
.drawPixmap(0, 0, gp
);
369 m_windecoButtonCache
.insert(key
, pixmap
);
374 void OxygenHelper::drawFloatFrame(QPainter
*p
, const QRect r
, const QColor
&color
) const
376 p
->setRenderHint(QPainter::Antialiasing
);
378 frame
.adjust(1,1,-1,-1);
380 frame
.getRect(&x
, &y
, &w
, &h
);
382 QColor light
= calcLightColor(backgroundTopColor(color
));
383 QColor dark
= calcDarkColor(color
);
385 p
->setBrush(Qt::NoBrush
);
387 if (0) { // TODO make option
388 QColor shadow
= calcShadowColor(color
); // wrong, use kwin shadow color
389 p
->setPen(alphaColor(shadow
, 0.1));
390 p
->drawLine(QPointF(x
+4, y
-0.5), QPointF(x
+w
-4, y
-0.5));
391 p
->drawArc(QRectF(x
-0.5, y
-0.5, 11, 11),90*16, 90*16);
392 p
->drawArc(QRectF(x
+w
-11+0.5, y
-0.5, 11, 11), 0, 90*16);
393 p
->setPen(alphaColor(shadow
, 0.3));
394 p
->drawLine(QPointF(x
-0.5, y
+4), QPointF(x
-0.5, y
+h
));
395 p
->drawLine(QPointF(x
+w
+0.5, y
+4), QPointF(x
+w
+0.5, y
+h
));
396 p
->setPen(alphaColor(shadow
, 0.4));
397 p
->drawArc(QRectF(0.5, y
+h
-11+0.5, 11, 11),180*16, 90*16);
398 p
->drawArc(QRectF(x
+w
-11+0.5, y
+h
-11+0.5, 11, 11),270*16, 90*16);
399 p
->setPen(alphaColor(shadow
, 0.55));
400 p
->drawLine(QPointF(x
+4, y
+h
+0.5), QPointF(x
+w
-4, y
+h
+0.5));
402 else if (1) { // TODO make option
403 QColor shadow
= KColorUtils::darken(color
, 0.0, 0.0); // fully desaturate
404 p
->setPen(KColorUtils::darken(shadow
, 0.1));
405 p
->drawLine(QPointF(x
+4, y
-0.5), QPointF(x
+w
-4, y
-0.5));
406 p
->drawArc(QRectF(x
-0.5, y
-0.5, 11, 11),90*16, 90*16);
407 p
->drawArc(QRectF(x
+w
-11+0.5, y
-0.5, 11, 11), 0, 90*16);
408 p
->setPen(KColorUtils::darken(shadow
, 0.3));
409 p
->drawLine(QPointF(x
-0.5, y
+4), QPointF(x
-0.5, y
+h
-4));
410 p
->drawLine(QPointF(x
+w
+0.5, y
+4), QPointF(x
+w
+0.5, y
+h
-4));
411 p
->setPen(KColorUtils::darken(shadow
, 0.4));
412 p
->drawArc(QRectF(0.5, y
+h
-11+0.5, 11, 11),180*16, 90*16);
413 p
->drawArc(QRectF(x
+w
-11+0.5, y
+h
-11+0.5, 11, 11),270*16, 90*16);
414 p
->setPen(KColorUtils::darken(shadow
, 0.55));
415 p
->drawLine(QPointF(x
+4, y
+h
+0.5), QPointF(x
+w
-4, y
+h
+0.5));
418 p
->setPen(QPen(light
, 1.2));
419 p
->drawLine(QPointF(x
+4, y
+0.6), QPointF(x
+w
-4, y
+0.6));
420 QLinearGradient lg
= QLinearGradient(0.0, 1.5, 0.0, 4.5);
421 lg
.setColorAt(0, light
);
422 light
= calcLightColor(backgroundBottomColor(color
));
423 lg
.setColorAt(1, light
);
424 p
->setPen(QPen(lg
, 1.2));
425 p
->drawArc(QRectF(x
+0.6, y
+0.6, 9, 9),90*16, 90*16);
426 p
->drawArc(QRectF(x
+w
-9-0.6, y
+0.6, 9, 9), 0, 90*16);
427 p
->drawLine(QPointF(x
+0.6, y
+4), QPointF(x
+0.6, y
+h
-4));
428 p
->drawLine(QPointF(x
+w
-0.6, y
+4), QPointF(x
+w
-0.6, y
+h
-4));
430 lg
= QLinearGradient(0.0, y
+h
-4.5, 0.0, y
+h
-0.5);
431 lg
.setColorAt(0, light
);
432 lg
.setColorAt(1, dark
);
433 p
->setPen(QPen(lg
, 1.2));
434 p
->drawArc(QRectF(x
+0.6, y
+h
-9-0.6, 9, 9),180*16, 90*16);
435 p
->drawArc(QRectF(x
+w
-9-0.6, y
+h
-9-0.6, 9, 9), 270*16, 90*16);
436 p
->drawLine(QPointF(x
+4, y
+h
-0.6), QPointF(x
+w
-4, y
+h
-0.6));