delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / kstyles / oxygen / lib / helper.cpp
blob92ca732dc1007e1926427ee505344cce32e5d663
1 /*
2 * Copyright 2008 Long Huynh Huu <long.upcase@googlemail.com>
3 * Copyright 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
4 * Copyright 2007 Casper Boemann <cbr@boemann.dk>
5 * Copyright 2007 Fredrik Höglund <fredrik@kde.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License version 2 as published by the Free Software Foundation.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "helper.h"
24 #include <KGlobalSettings>
25 #include <KColorUtils>
26 #include <KColorScheme>
28 #include <QtGui/QWidget>
29 #include <QtGui/QPainter>
31 #include <math.h>
33 const double OxygenHelper::_shadowGain = 1.5;
35 // NOTE: OxygenStyleHelper needs to use a KConfig from its own KComponentData
36 // Since the ctor order causes a SEGV if we try to pass in a KConfig here from
37 // a KComponentData constructed in the OxygenStyleHelper ctor, we'll just keep
38 // one here, even though the window decoration doesn't really need it.
39 OxygenHelper::OxygenHelper(const QByteArray &componentName)
40 : _componentData(componentName, 0, KComponentData::SkipMainComponentRegistration)
42 _config = _componentData.config();
43 _contrast = KGlobalSettings::contrastF(_config);
44 _bgcontrast = 0.3;// // shouldn't use contrast for this _contrast; // TODO get style setting
46 m_backgroundCache.setMaxCost(64);
47 m_windecoButtonCache.setMaxCost(64);
48 m_windecoButtonGlowCache.setMaxCost(64);
51 KSharedConfigPtr OxygenHelper::config() const
53 return _config;
56 void OxygenHelper::reloadConfig()
58 double old_contrast = _contrast;
60 _config->reparseConfiguration();
61 _contrast = KGlobalSettings::contrastF(_config);
63 if (_contrast != old_contrast)
64 invalidateCaches(); // contrast changed, invalidate our caches
67 void OxygenHelper::renderWindowBackground(QPainter *p, const QRect &clipRect, const QWidget *widget, const QPalette & pal, int y_shift)
69 const QWidget* window = widget->window();
70 // get coordinates relative to the client area
71 const QWidget* w = widget;
72 int x = 0, y = -y_shift;
73 while (!w->isWindow()) {
74 x += w->geometry().x();
75 y += w->geometry().y();
76 w = w->parentWidget();
79 if (clipRect.isValid()) {
80 p->save();
81 p->setClipRegion(clipRect,Qt::IntersectClip);
83 QRect r = window->rect();
84 QColor color = pal.color(window->backgroundRole());
85 int splitY = qMin(300, 3*r.height()/4);
87 QRect upperRect = QRect(-x, -y, r.width(), splitY);
88 QPixmap tile = verticalGradient(color, splitY);
89 p->drawTiledPixmap(upperRect, tile);
91 QRect lowerRect = QRect(-x, splitY-y, r.width(), r.height() - splitY-y_shift);
92 p->fillRect(lowerRect, backgroundBottomColor(color));
94 int radialW = qMin(600, r.width());
95 int frameH = 10; // on first paint the frame may not have been done yet, so just fixate it
96 QRect radialRect = QRect((r.width() - radialW) / 2-x, -y, radialW, 64-frameH);
97 if (clipRect.intersects(radialRect))
99 tile = radialGradient(color, radialW);
100 p->drawPixmap(radialRect, tile);
103 if (clipRect.isValid())
104 p->restore();
107 void OxygenHelper::invalidateCaches()
109 m_backgroundCache.clear();
110 m_windecoButtonCache.clear();
111 m_windecoButtonGlowCache.clear();
114 bool OxygenHelper::lowThreshold(const QColor &color)
116 QColor darker = KColorScheme::shade(color, KColorScheme::MidShade, 0.5);
117 return KColorUtils::luma(darker) > KColorUtils::luma(color);
120 QColor OxygenHelper::alphaColor(QColor color, double alpha)
122 if (alpha >= 1.0)
123 return color;
124 color.setAlphaF(qMax(0.0, alpha) * color.alphaF());
125 return color;
128 QColor OxygenHelper::backgroundRadialColor(const QColor &color) const
130 if (lowThreshold(color))
131 return KColorScheme::shade(color, KColorScheme::LightShade, 0.0);
132 else
133 return KColorScheme::shade(color, KColorScheme::LightShade, _bgcontrast);
136 QColor OxygenHelper::backgroundTopColor(const QColor &color) const
138 if (lowThreshold(color))
139 return KColorScheme::shade(color, KColorScheme::MidlightShade, 0.0);
140 else
141 return KColorScheme::shade(color, KColorScheme::MidlightShade, _bgcontrast);
144 QColor OxygenHelper::backgroundBottomColor(const QColor &color) const
146 QColor midColor = KColorScheme::shade(color, KColorScheme::MidShade, 0.0);
147 if (lowThreshold(color))
148 return midColor;
150 double by = KColorUtils::luma(color), my = KColorUtils::luma(midColor);
151 return KColorUtils::shade(color, (my - by) * _bgcontrast);
154 QColor OxygenHelper::calcLightColor(const QColor &color) const
156 return KColorScheme::shade(color, KColorScheme::LightShade, _contrast);
159 QColor OxygenHelper::calcDarkColor(const QColor &color) const
161 if (lowThreshold(color))
162 return KColorUtils::mix(calcLightColor(color), color, 0.2 + 0.8 * _contrast);
163 else
164 return KColorScheme::shade(color, KColorScheme::MidShade, _contrast);
167 QColor OxygenHelper::calcShadowColor(const QColor &color) const
169 return KColorScheme::shade(KColorUtils::mix(QColor(255,255,255),color, color.alpha()*(1/255.0)),
170 KColorScheme::ShadowShade, _contrast);
174 QColor OxygenHelper::backgroundColor(const QColor &color, int height, int y)
176 double h = height * 0.5;
177 if (y > height>>1) {
178 double a = double(y) / h;
179 return KColorUtils::mix(backgroundTopColor(color), color, a);
181 else {
182 double a = (double(y) - h) / h;
183 return KColorUtils::mix(color, backgroundBottomColor(color), a);
187 QPixmap OxygenHelper::verticalGradient(const QColor &color, int height)
189 quint64 key = (quint64(color.rgba()) << 32) | height | 0x8000;
190 QPixmap *pixmap = m_backgroundCache.object(key);
192 if (!pixmap)
194 pixmap = new QPixmap(32, height);
196 QLinearGradient gradient(0, 0, 0, height);
197 gradient.setColorAt(0.0, backgroundTopColor(color));
198 gradient.setColorAt(0.5, color);
199 gradient.setColorAt(1.0, backgroundBottomColor(color));
201 QPainter p(pixmap);
202 p.setCompositionMode(QPainter::CompositionMode_Source);
203 p.fillRect(pixmap->rect(), gradient);
205 m_backgroundCache.insert(key, pixmap);
208 return *pixmap;
211 QPixmap OxygenHelper::radialGradient(const QColor &color, int width)
213 quint64 key = (quint64(color.rgba()) << 32) | width | 0xb000;
214 QPixmap *pixmap = m_backgroundCache.object(key);
216 if (!pixmap)
218 // width /= 2;
219 pixmap = new QPixmap(width, 64);
220 pixmap->fill(QColor(0,0,0,0));
221 QColor radialColor = backgroundRadialColor(color);
222 radialColor.setAlpha(255);
223 QRadialGradient gradient(64, 0, 64);
224 gradient.setColorAt(0, radialColor);
225 radialColor.setAlpha(101);
226 gradient.setColorAt(0.5, radialColor);
227 radialColor.setAlpha(37);
228 gradient.setColorAt(0.75, radialColor);
229 radialColor.setAlpha(0);
230 gradient.setColorAt(1, radialColor);
232 QPainter p(pixmap);
233 p.scale(width/128.0,1);
234 p.fillRect(QRect(0,0,128,64), gradient);
236 m_backgroundCache.insert(key, pixmap);
239 return *pixmap;
242 void OxygenHelper::drawShadow(QPainter &p, const QColor &color, int size) const
244 double m = double(size-2)*0.5;
246 const double offset = 0.8;
247 double k0 = (m-4.0) / m;
248 QRadialGradient shadowGradient(m+1.0, m+offset+1.0, m);
249 for (int i = 0; i < 8; i++) { // sinusoidal gradient
250 double k1 = (k0 * double(8 - i) + double(i)) * 0.125;
251 double a = (cos(3.14159 * i * 0.125) + 1.0) * 0.25;
252 shadowGradient.setColorAt(k1, alphaColor(color, a * _shadowGain));
254 shadowGradient.setColorAt(1.0, alphaColor(color, 0.0));
255 p.setBrush(shadowGradient);
256 p.drawEllipse(QRectF(0, 0, size, size));
259 QLinearGradient OxygenHelper::decoGradient(const QRect &r, const QColor &color)
261 QColor light = KColorScheme::shade(color, KColorScheme::LightShade, _contrast * 0.7);
262 QColor dark = KColorScheme::shade(color, KColorScheme::DarkShade, _contrast * 0.7);
263 double y = KColorUtils::luma(color);
264 double yd = KColorUtils::luma(dark);
265 double yl = KColorUtils::luma(light);
267 QLinearGradient gradient(r.topLeft(), r.bottomLeft());
268 if (yd > y)
270 gradient.setColorAt(0.2, color);
271 gradient.setColorAt(0.8, dark);
273 else if (yl < y)
275 gradient.setColorAt(0.2, light);
276 gradient.setColorAt(0.8, color);
278 else
280 gradient.setColorAt(0.2, dark);
281 gradient.setColorAt(0.5, color);
282 gradient.setColorAt(0.8, light);
285 return gradient;
288 QPixmap OxygenHelper::windecoButton(const QColor &color, bool pressed, int size)
290 quint64 key = (quint64(color.rgba()) << 32) | (size << 1) | pressed;
291 QPixmap *pixmap = m_windecoButtonCache.object(key);
293 if (!pixmap)
295 pixmap = new QPixmap(size, size);
296 pixmap->fill(Qt::transparent);
298 QPainter p(pixmap);
299 p.setRenderHints(QPainter::Antialiasing);
300 p.setPen(Qt::NoPen);
302 double u = size/21.0;
304 QColor light = calcLightColor(color);
305 QColor dark = calcDarkColor(color);
306 QColor shadow = calcShadowColor(color);
308 QRectF rect(0.0, 0.0, size, size);
309 QRectF buttonRect = rect.adjusted(2*u,2*u,-2*u,-2*u);
311 QLinearGradient fill(QPointF(0.0, 0.0*u),
312 QPointF(0.0, 21.0*u));
313 fill.setColorAt(0.0, alphaColor(light, 0.7));
314 fill.setColorAt(1.0, alphaColor(dark, 0.7));
316 p.setBrush(fill);
317 p.drawEllipse(buttonRect);
318 p.setBrush(Qt::NoBrush);
320 // shadow
321 if (pressed)
323 p.setPen(alphaColor(dark, 0.4));
324 p.drawEllipse(buttonRect.adjusted(0.9, 0.6, -0.7, -0.7).adjusted(1.7,1.7,-1.7,-1.7));
325 p.setPen(alphaColor(dark, 0.8));
326 p.drawEllipse(buttonRect.adjusted(0.9, 0.6, -0.7, -0.7).adjusted(1.2,1.2,-1.2,-1.2));
328 p.setPen(QPen(KColorUtils::mix(dark, shadow, 0.12), 2.0));
329 p.drawEllipse(buttonRect.adjusted(0.9, 0.6, -0.7, -0.7).adjusted(0,0.1,0,-0.1));
330 p.setPen(QPen(KColorUtils::mix(dark, shadow, 0.6), 1.2));
331 p.drawEllipse(buttonRect.adjusted(1.0, 1.4, -0.8, -0.8));
333 // reflection
334 QLinearGradient lightgr(QPointF(0.0, 0.0*u),
335 QPointF(0.0, 21.0*u));
336 lightgr.setColorAt(0.0, Qt::transparent);
337 lightgr.setColorAt(1.0, light);
338 p.setPen(QPen(lightgr, 1.7));
339 p.drawEllipse(buttonRect.adjusted(0.0, -0.5, -0.1, 0.0));
341 m_windecoButtonCache.insert(key, pixmap);
344 return *pixmap;
347 QPixmap OxygenHelper::windecoButtonGlow(const QColor &color, int size)
349 quint64 key = (quint64(color.rgba()) << 32) | size;
350 QPixmap *pixmap = m_windecoButtonGlowCache.object(key);
352 if (!pixmap)
354 pixmap = new QPixmap(size, size);
355 pixmap->fill(Qt::transparent);
357 QPainter p(pixmap);
358 p.setRenderHints(QPainter::Antialiasing);
359 p.setPen(Qt::NoPen);
361 double u = size/21.0;
362 QRectF rect(0.0, 0.0, size, size);
363 QRectF buttonRect = rect.adjusted(2*u,2*u,-2*u,-2*u);
365 //mask
366 p.setBrush(QColor(0,0,0,125));
367 p.drawEllipse(rect.adjusted(u, 0, -u, -2*u));
369 //glow
370 QColor dark = calcDarkColor(color);
371 QColor light = calcLightColor(color);
373 QRadialGradient glow(QPointF(size/2.0, size/2.0 + 0.25), size/2.0);
374 glow.setColorAt(12.0 / 21.0, Qt::transparent);
375 glow.setColorAt(16.0 / 21.0, dark);
376 glow.setColorAt(18.0 / 21.0, alphaColor(light, 0.25));
377 glow.setColorAt(20.0 / 21.0, Qt::transparent);
379 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
380 p.setBrush(glow);
381 p.drawEllipse(rect);
383 m_windecoButtonGlowCache.insert(key, pixmap);
386 return *pixmap;
389 QPixmap OxygenHelper::glow(const QColor &color, int size, int rsize)
391 QPixmap pixmap(rsize, rsize);
392 pixmap.fill(QColor(0,0,0,0));
394 QPainter p(&pixmap);
395 p.setRenderHints(QPainter::Antialiasing);
396 p.setPen(Qt::NoPen);
397 p.setWindow(0,0,size,size);
399 QRectF r(0, 0, size, size);
400 double m = double(size)*0.5;
402 const double width = 3.0;
403 const double bias = _glowBias * double(size) / double(rsize);
404 double k0 = (m-width+bias) / m;
405 QRadialGradient glowGradient(m, m, m);
406 for (int i = 0; i < 8; i++) { // inverse parabolic gradient
407 double k1 = (k0 * double(8 - i) + double(i)) * 0.125;
408 double a = 1.0 - sqrt(i * 0.125);
409 glowGradient.setColorAt(k1, alphaColor(color, a));
411 glowGradient.setColorAt(1.0, alphaColor(color, 0.0));
413 // glow
414 p.setBrush(glowGradient);
415 p.drawEllipse(r);
417 // mask
418 p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
419 p.setBrush(QBrush(Qt::black));
420 p.drawEllipse(r.adjusted(width, width, -width, -width));
422 p.end();
424 return pixmap;
427 void OxygenHelper::drawFloatFrame(QPainter *p, const QRect r, const QColor &color, bool drawUglyShadow, bool isActive, const QColor &frameColor) const
429 p->setRenderHint(QPainter::Antialiasing);
430 QRect frame = r;
431 frame.adjust(1,1,-1,-1);
432 int x,y,w,h;
433 frame.getRect(&x, &y, &w, &h);
435 QColor light = calcLightColor(backgroundTopColor(color));
436 QColor dark = calcLightColor(backgroundBottomColor(color));
437 QColor glow = KColorUtils::mix(QColor(128,128,128),frameColor,0.7);
439 p->setBrush(Qt::NoBrush);
441 if (drawUglyShadow) {
442 if(isActive) { //window active - it's a glow - not a shadow
443 p->setPen(glow);
444 p->drawLine(QPointF(x+4, y-0.5), QPointF(x+w-4, y-0.5));
445 p->drawArc(QRectF(x-0.5, y-0.5, 11, 11),90*16, 90*16);
446 p->drawArc(QRectF(x+w-11+0.5, y-0.5, 11, 11), 0, 90*16);
447 p->drawLine(QPointF(x-0.5, y+4), QPointF(x-0.5, y+h-4));
448 p->drawLine(QPointF(x+w+0.5, y+4), QPointF(x+w+0.5, y+h-4));
449 p->drawArc(QRectF(0.5, y+h-11+0.5, 11, 11),180*16, 90*16);
450 p->drawArc(QRectF(x+w-11+0.5, y+h-11+0.5, 11, 11),270*16, 90*16);
451 p->drawLine(QPointF(x+4, y+h+0.5), QPointF(x+w-4, y+h+0.5));
452 light = KColorUtils::mix(light, frameColor);
453 dark = KColorUtils::mix(dark, frameColor);
455 else { //window inactive - draw something resembling shadow
456 QColor shadow = KColorUtils::darken(color, 0.0, 0.0); // fully desaturate
457 p->setPen(KColorUtils::darken(shadow, 0.2));
458 p->drawLine(QPointF(x+4, y-0.5), QPointF(x+w-4, y-0.5));
459 p->drawArc(QRectF(x-0.5, y-0.5, 11, 11),90*16, 90*16);
460 p->drawArc(QRectF(x+w-11+0.5, y-0.5, 11, 11), 0, 90*16);
461 p->setPen(KColorUtils::darken(shadow, 0.35));
462 p->drawLine(QPointF(x-0.5, y+4), QPointF(x-0.5, y+h-4));
463 p->drawLine(QPointF(x+w+0.5, y+4), QPointF(x+w+0.5, y+h-4));
464 p->setPen(KColorUtils::darken(shadow, 0.45));
465 p->drawArc(QRectF(0.5, y+h-11+0.5, 11, 11),180*16, 90*16);
466 p->drawArc(QRectF(x+w-11+0.5, y+h-11+0.5, 11, 11),270*16, 90*16);
467 p->setPen(KColorUtils::darken(shadow, 0.6));
468 p->drawLine(QPointF(x+4, y+h+0.5), QPointF(x+w-4, y+h+0.5));
472 p->setPen(QPen(light, 0.8));
473 p->drawLine(QPointF(x+4, y+0.6), QPointF(x+w-4, y+0.6));
474 QLinearGradient lg = QLinearGradient(0.0, 1.5, 0.0, 4.5);
475 lg.setColorAt(0, light);
476 lg.setColorAt(1, dark);
477 p->setPen(QPen(lg, 0.8));
478 p->drawArc(QRectF(x+0.6, y+0.6, 9, 9),90*16, 90*16);
479 p->drawArc(QRectF(x+w-9-0.6, y+0.6, 9, 9), 0, 90*16);
480 p->drawLine(QPointF(x+0.6, y+4), QPointF(x+0.6, y+h-4));
481 p->drawLine(QPointF(x+w-0.6, y+4), QPointF(x+w-0.6, y+h-4));
483 return;
486 void OxygenHelper::drawSeparator(QPainter *p, const QRect &rect, const QColor &color, Qt::Orientation orientation) const
488 QColor light = calcLightColor(color);
489 QColor dark = calcDarkColor(color);
491 bool antialias = p->testRenderHint(QPainter::Antialiasing);
492 p->setRenderHint(QPainter::Antialiasing,false);
494 QPoint start,end,offset;
496 if (orientation == Qt::Horizontal) {
497 start = QPoint(rect.x(),rect.y()+rect.height()/2-1);
498 end = QPoint(rect.right(),rect.y()+rect.height()/2-1);
499 offset = QPoint(0,1);
500 } else {
501 start = QPoint(rect.x()+rect.width()/2-1,rect.y());
502 end = QPoint(rect.x()+rect.width()/2-1,rect.bottom());
503 offset = QPoint(1,0);
504 light.setAlpha(150);
507 QLinearGradient lg(start,end);
508 lg.setColorAt(0.3, dark);
509 lg.setColorAt(0.7, dark);
510 dark.setAlpha(0);
511 lg.setColorAt(0.0, dark);
512 lg.setColorAt(1.0, dark);
513 p->setPen(QPen(lg,1));
515 if (orientation == Qt::Horizontal)
516 p->drawLine(start,end);
517 else
518 p->drawLine(start+offset,end+offset);
520 lg = QLinearGradient(start,end);
521 lg.setColorAt(0.3, light);
522 lg.setColorAt(0.7, light);
523 light.setAlpha(0);
524 lg.setColorAt(0.0, light);
525 lg.setColorAt(1.0, light);
526 p->setPen(QPen(lg,1));
529 if (orientation == Qt::Horizontal)
530 p->drawLine(start+offset,end+offset);
531 else
533 p->drawLine(start,end);
534 p->drawLine(start+offset*2,end+offset*2);
537 p->setRenderHint(QPainter::Antialiasing, antialias);