• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KStyles

helper.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
00003  * Copyright 2007 Casper Boemann <cbr@boemann.dk>
00004  * Copyright 2007 Fredrik Höglund <fredrik@kde.org>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License version 2 as published by the Free Software Foundation.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "helper.h"
00022 
00023 #include <KGlobalSettings>
00024 #include <KColorUtils>
00025 #include <KColorScheme>
00026 
00027 #include <QtGui/QWidget>
00028 #include <QtGui/QPainter>
00029 
00030 #include <math.h>
00031 
00032 const double OxygenHelper::_shadowGain = 1.5;
00033 
00034 // NOTE: OxygenStyleHelper needs to use a KConfig from its own KComponentData
00035 // Since the ctor order causes a SEGV if we try to pass in a KConfig here from
00036 // a KComponentData constructed in the OxygenStyleHelper ctor, we'll just keep
00037 // one here, even though the window decoration doesn't really need it.
00038 OxygenHelper::OxygenHelper(const QByteArray &componentName)
00039     : _componentData(componentName, 0, KComponentData::SkipMainComponentRegistration)
00040 {
00041     _config = _componentData.config();
00042     _contrast = KGlobalSettings::contrastF(_config);
00043     _bgcontrast = 0.3;// // shouldn't use contrast for this _contrast; // TODO get style setting
00044 
00045     m_backgroundCache.setMaxCost(64);
00046     m_windecoButtonCache.setMaxCost(64);
00047 }
00048 
00049 KSharedConfigPtr OxygenHelper::config() const
00050 {
00051     return _config;
00052 }
00053 
00054 void OxygenHelper::reloadConfig()
00055 {
00056     double old_contrast = _contrast;
00057 
00058     _config->reparseConfiguration();
00059     _contrast = KGlobalSettings::contrastF(_config);
00060 
00061     if (_contrast != old_contrast)
00062         invalidateCaches(); // contrast changed, invalidate our caches
00063 }
00064 
00065 void OxygenHelper::renderWindowBackground(QPainter *p, const QRect &clipRect, const QWidget *widget, const QPalette & pal)
00066 {
00067     const QWidget* window = widget->window();
00068     // get coordinates relative to the client area
00069     const QWidget* w = widget;
00070     int x = 0, y = 0;
00071     while (!w->isWindow()) {
00072         x += w->geometry().x();
00073         y += w->geometry().y();
00074         w = w->parentWidget();
00075     } 
00076     
00077     if (clipRect.isValid()) {
00078         p->save();
00079         p->setClipRegion(clipRect,Qt::IntersectClip);
00080     }
00081     QRect r = window->rect();
00082     QColor color = pal.color(window->backgroundRole());
00083     int splitY = qMin(300, 3*r.height()/4);
00084 
00085     QRect upperRect = QRect(-x, -y, r.width(), splitY);
00086     QPixmap tile = verticalGradient(color, splitY);
00087     p->drawTiledPixmap(upperRect, tile);
00088 
00089     QRect lowerRect = QRect(-x, splitY-y, r.width(), r.height() - splitY);
00090     p->fillRect(lowerRect, backgroundBottomColor(color));
00091 
00092     int radialW = qMin(600, r.width());
00093     int frameH = 32; // on first paint the frame may not have been done yet, so just fixate it
00094     QRect radialRect = QRect((r.width() - radialW) / 2-x, -y, radialW, 64-frameH);
00095     if (clipRect.intersects(radialRect))
00096     {
00097         tile = radialGradient(color, radialW);
00098         p->drawPixmap(radialRect, tile, QRect(0, frameH, radialW, 64-frameH));
00099     }
00100 
00101     if (clipRect.isValid())
00102         p->restore();
00103 }
00104 
00105 void OxygenHelper::invalidateCaches()
00106 {
00107     m_backgroundCache.clear();
00108     m_windecoButtonCache.clear();
00109 }
00110 
00111 bool OxygenHelper::lowThreshold(const QColor &color)
00112 {
00113     QColor darker = KColorScheme::shade(color, KColorScheme::MidShade, 0.5);
00114     return KColorUtils::luma(darker) > KColorUtils::luma(color);
00115 }
00116 
00117 QColor OxygenHelper::alphaColor(QColor color, double alpha)
00118 {
00119     if (alpha >= 1.0)
00120         return color;
00121     color.setAlphaF(qMax(0.0, alpha) * color.alphaF());
00122     return color;
00123 }
00124 
00125 QColor OxygenHelper::backgroundRadialColor(const QColor &color) const
00126 {
00127     if (lowThreshold(color))
00128         return KColorScheme::shade(color, KColorScheme::LightShade, 0.0);
00129     else
00130         return KColorScheme::shade(color, KColorScheme::LightShade, _bgcontrast);
00131 }
00132 
00133 QColor OxygenHelper::backgroundTopColor(const QColor &color) const
00134 {
00135     if (lowThreshold(color))
00136         return KColorScheme::shade(color, KColorScheme::MidlightShade, 0.0);
00137     else
00138         return KColorScheme::shade(color, KColorScheme::MidlightShade, _bgcontrast);
00139 }
00140 
00141 QColor OxygenHelper::backgroundBottomColor(const QColor &color) const
00142 {
00143     QColor midColor = KColorScheme::shade(color, KColorScheme::MidShade, 0.0);
00144     if (lowThreshold(color))
00145         return midColor;
00146 
00147     double by = KColorUtils::luma(color), my = KColorUtils::luma(midColor);
00148     return KColorUtils::shade(color, (my - by) * _bgcontrast);
00149 }
00150 
00151 QColor OxygenHelper::calcLightColor(const QColor &color) const
00152 {
00153     return KColorScheme::shade(color, KColorScheme::LightShade, _contrast);
00154 }
00155 
00156 QColor OxygenHelper::calcDarkColor(const QColor &color) const
00157 {
00158     if (lowThreshold(color))
00159         return KColorUtils::mix(calcLightColor(color), color, 0.2 + 0.8 * _contrast);
00160     else
00161         return KColorScheme::shade(color, KColorScheme::MidShade, _contrast);
00162 }
00163 
00164 QColor OxygenHelper::calcShadowColor(const QColor &color) const
00165 {
00166     return KColorScheme::shade(KColorUtils::mix(QColor(255,255,255),color, color.alpha()*(1/255.0)),
00167                     KColorScheme::ShadowShade, _contrast);
00168 
00169 }
00170 
00171 QColor OxygenHelper::backgroundColor(const QColor &color, int height, int y)
00172 {
00173     double h = height * 0.5;
00174     if (y > height>>1) {
00175         double a = double(y) / h;
00176         return KColorUtils::mix(backgroundTopColor(color), color, a);
00177     }
00178     else {
00179         double a = (double(y) - h) / h;
00180         return KColorUtils::mix(color, backgroundBottomColor(color), a);
00181     }
00182 }
00183 
00184 QPixmap OxygenHelper::verticalGradient(const QColor &color, int height)
00185 {
00186     quint64 key = (quint64(color.rgba()) << 32) | height | 0x8000;
00187     QPixmap *pixmap = m_backgroundCache.object(key);
00188 
00189     if (!pixmap)
00190     {
00191         pixmap = new QPixmap(32, height);
00192 
00193         QLinearGradient gradient(0, 0, 0, height);
00194         gradient.setColorAt(0.0, backgroundTopColor(color));
00195         gradient.setColorAt(0.5, color);
00196         gradient.setColorAt(1.0, backgroundBottomColor(color));
00197 
00198         QPainter p(pixmap);
00199         p.setCompositionMode(QPainter::CompositionMode_Source);
00200         p.fillRect(pixmap->rect(), gradient);
00201 
00202         m_backgroundCache.insert(key, pixmap);
00203     }
00204 
00205     return *pixmap;
00206 }
00207 
00208 QPixmap OxygenHelper::radialGradient(const QColor &color, int width)
00209 {
00210     quint64 key = (quint64(color.rgba()) << 32) | width | 0xb000;
00211     QPixmap *pixmap = m_backgroundCache.object(key);
00212 
00213     if (!pixmap)
00214     {
00215 //        width /= 2;
00216         pixmap = new QPixmap(width, 64);
00217         pixmap->fill(QColor(0,0,0,0));
00218         QColor radialColor = backgroundRadialColor(color);
00219         radialColor.setAlpha(255);
00220         QRadialGradient gradient(64, 0, 64);
00221         gradient.setColorAt(0, radialColor);
00222         radialColor.setAlpha(101);
00223         gradient.setColorAt(0.5, radialColor);
00224         radialColor.setAlpha(37);
00225         gradient.setColorAt(0.75, radialColor);
00226         radialColor.setAlpha(0);
00227         gradient.setColorAt(1, radialColor);
00228 
00229         QPainter p(pixmap);
00230         p.scale(width/128.0,1);
00231         p.fillRect(QRect(0,0,128,64), gradient);
00232 
00233         m_backgroundCache.insert(key, pixmap);
00234     }
00235 
00236     return *pixmap;
00237 }
00238 
00239 void OxygenHelper::drawShadow(QPainter &p, const QColor &color, int size) const
00240 {
00241     double m = double(size-2)*0.5;
00242 
00243     const double offset = 0.8;
00244     double k0 = (m-4.0) / m;
00245     QRadialGradient shadowGradient(m+1.0, m+offset+1.0, m);
00246     for (int i = 0; i < 8; i++) { // sinusoidal gradient
00247         double k1 = (k0 * double(8 - i) + double(i)) * 0.125;
00248         double a = (cos(3.14159 * i * 0.125) + 1.0) * 0.25;
00249         shadowGradient.setColorAt(k1, alphaColor(color, a * _shadowGain));
00250     }
00251     shadowGradient.setColorAt(1.0, alphaColor(color, 0.0));
00252     p.setBrush(shadowGradient);
00253     p.drawEllipse(QRectF(0, 0, size, size));
00254 }
00255 
00256 QLinearGradient OxygenHelper::decoGradient(const QRect &r, const QColor &color)
00257 {
00258     QColor light = KColorScheme::shade(color, KColorScheme::LightShade, _contrast * 0.7);
00259     QColor dark = KColorScheme::shade(color, KColorScheme::DarkShade, _contrast * 0.7);
00260     double y = KColorUtils::luma(color);
00261     double yd = KColorUtils::luma(dark);
00262     double yl = KColorUtils::luma(light);
00263 
00264     QLinearGradient gradient(r.topLeft(), r.bottomLeft());
00265     if (yd > y)
00266     {
00267         gradient.setColorAt(0.2, color);
00268         gradient.setColorAt(0.8, dark);
00269     }
00270     else if (yl < y)
00271     {
00272         gradient.setColorAt(0.2, light);
00273         gradient.setColorAt(0.8, color);
00274     }
00275     else
00276     {
00277         gradient.setColorAt(0.2, dark);
00278         gradient.setColorAt(0.5, color);
00279         gradient.setColorAt(0.8, light);
00280     }
00281 
00282     return gradient;
00283 }
00284 
00285 QPixmap OxygenHelper::windecoButton(const QColor &color, bool pressed, int size)
00286 {
00287     quint64 key = (quint64(color.rgba()) << 32) | (size << 1) | pressed;
00288     QPixmap *pixmap = m_windecoButtonCache.object(key);
00289 
00290     if (!pixmap)
00291     {
00292         pixmap = new QPixmap(size, size);
00293         pixmap->fill(Qt::transparent);
00294 
00295         QPainter p(pixmap);
00296         p.setRenderHints(QPainter::Antialiasing);
00297         p.setPen(Qt::NoPen);
00298         p.setWindow(0,0,21,21);
00299 
00300         QColor light = alphaColor(calcLightColor(color), 0.2);
00301         QColor dark = alphaColor(calcShadowColor(color), 0.2);
00302 
00303         // penWidth should always be 1px;
00304         int penWidth = 1 / (size / 21.0);
00305 
00306         // inside
00307         QLinearGradient innerGradient(0, 0, 0, 21);
00308         if (!pressed) {
00309             innerGradient.setColorAt(0.0, Qt::transparent);
00310             innerGradient.setColorAt(1.0, alphaColor(color, 0.1));
00311         } else {
00312             innerGradient.setColorAt(0.0, alphaColor(color, 0.1));
00313             innerGradient.setColorAt(1.0, Qt::transparent);
00314         }
00315         p.setBrush(innerGradient);
00316         p.drawEllipse(QRectF(3.0,3.0,15.0,15.0));
00317 
00318         // grove
00319         QLinearGradient darklg(QPoint(0,0), QPoint(21,0));
00320         darklg.setColorAt(0.0, Qt::transparent);
00321         darklg.setColorAt(0.5, dark);
00322         darklg.setColorAt(1.0, Qt::transparent);
00323 
00324         QLinearGradient lightlg(QPoint(0,0), QPoint(21,0));
00325         lightlg.setColorAt(0.0, Qt::transparent);
00326         lightlg.setColorAt(0.5, light);
00327         lightlg.setColorAt(1.0, Qt::transparent);
00328 
00329         p.setPen(QPen(darklg, 1.5*penWidth));
00330         for(int i = 0; i < 2; ++i)
00331             p.drawEllipse(QRectF(3.0,2.7,15.0,15.0));
00332         p.setPen(QPen(lightlg, 1.0*penWidth));
00333         for(int i = 0; i < 8; ++i)
00334             p.drawEllipse(QRectF(3.0,4.0,15.0,15.0));
00335 
00336         m_windecoButtonCache.insert(key, pixmap);
00337     }
00338 
00339     return *pixmap;
00340 }
00341 
00342 QPixmap OxygenHelper::glow(const QColor &color, int size, int rsize)
00343 {
00344     QPixmap pixmap(rsize, rsize);
00345     pixmap.fill(QColor(0,0,0,0));
00346 
00347     QPainter p(&pixmap);
00348     p.setRenderHints(QPainter::Antialiasing);
00349     p.setPen(Qt::NoPen);
00350     p.setWindow(0,0,size,size);
00351 
00352     QRectF r(0, 0, size, size);
00353     double m = double(size)*0.5;
00354 
00355     const double width = 3.0;
00356     const double bias = _glowBias * double(size) / double(rsize);
00357     double k0 = (m-width+bias) / m;
00358     QRadialGradient glowGradient(m, m, m);
00359     for (int i = 0; i < 8; i++) { // inverse parabolic gradient
00360         double k1 = (k0 * double(8 - i) + double(i)) * 0.125;
00361         double a = 1.0 - sqrt(i * 0.125);
00362         glowGradient.setColorAt(k1, alphaColor(color, a));
00363     }
00364     glowGradient.setColorAt(1.0, alphaColor(color, 0.0));
00365 
00366     // glow
00367     p.setBrush(glowGradient);
00368     p.drawEllipse(r);
00369 
00370     // mask
00371     p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00372     p.setBrush(QBrush(Qt::black));
00373     p.drawEllipse(r.adjusted(width, width, -width, -width));
00374 
00375     p.end();
00376 
00377     return pixmap;
00378 }
00379 
00380 void OxygenHelper::drawFloatFrame(QPainter *p, const QRect r, const QColor &color) const
00381 {
00382     p->setRenderHint(QPainter::Antialiasing);
00383     QRect frame = r;
00384     frame.adjust(1,1,-1,-1);
00385     int x,y,w,h;
00386     frame.getRect(&x, &y, &w, &h);
00387 
00388     QColor light = calcLightColor(backgroundTopColor(color));
00389     QColor dark = calcDarkColor(color);
00390 
00391     p->setBrush(Qt::NoBrush);
00392 
00393     if (0) { // TODO make option
00394         QColor shadow = calcShadowColor(color); // wrong, use kwin shadow color
00395         p->setPen(alphaColor(shadow, 0.1));
00396         p->drawLine(QPointF(x+4, y-0.5), QPointF(x+w-4, y-0.5));
00397         p->drawArc(QRectF(x-0.5, y-0.5, 11, 11),90*16, 90*16);
00398         p->drawArc(QRectF(x+w-11+0.5, y-0.5, 11, 11), 0, 90*16);
00399         p->setPen(alphaColor(shadow, 0.3));
00400         p->drawLine(QPointF(x-0.5, y+4), QPointF(x-0.5, y+h));
00401         p->drawLine(QPointF(x+w+0.5, y+4), QPointF(x+w+0.5, y+h));
00402         p->setPen(alphaColor(shadow, 0.4));
00403         p->drawArc(QRectF(0.5, y+h-11+0.5, 11, 11),180*16, 90*16);
00404         p->drawArc(QRectF(x+w-11+0.5, y+h-11+0.5, 11, 11),270*16, 90*16);
00405         p->setPen(alphaColor(shadow, 0.55));
00406         p->drawLine(QPointF(x+4, y+h+0.5), QPointF(x+w-4, y+h+0.5));
00407     }
00408     else if (1) { // TODO make option
00409         QColor shadow = KColorUtils::darken(color, 0.0, 0.0); // fully desaturate
00410         p->setPen(KColorUtils::darken(shadow, 0.1));
00411         p->drawLine(QPointF(x+4, y-0.5), QPointF(x+w-4, y-0.5));
00412         p->drawArc(QRectF(x-0.5, y-0.5, 11, 11),90*16, 90*16);
00413         p->drawArc(QRectF(x+w-11+0.5, y-0.5, 11, 11), 0, 90*16);
00414         p->setPen(KColorUtils::darken(shadow, 0.3));
00415         p->drawLine(QPointF(x-0.5, y+4), QPointF(x-0.5, y+h-4));
00416         p->drawLine(QPointF(x+w+0.5, y+4), QPointF(x+w+0.5, y+h-4));
00417         p->setPen(KColorUtils::darken(shadow, 0.4));
00418         p->drawArc(QRectF(0.5, y+h-11+0.5, 11, 11),180*16, 90*16);
00419         p->drawArc(QRectF(x+w-11+0.5, y+h-11+0.5, 11, 11),270*16, 90*16);
00420         p->setPen(KColorUtils::darken(shadow, 0.55));
00421         p->drawLine(QPointF(x+4, y+h+0.5), QPointF(x+w-4, y+h+0.5));
00422     }
00423 
00424     p->setPen(QPen(light, 1.2));
00425     p->drawLine(QPointF(x+4, y+0.6), QPointF(x+w-4, y+0.6));
00426     QLinearGradient lg = QLinearGradient(0.0, 1.5, 0.0, 4.5);
00427     lg.setColorAt(0, light);
00428     light = calcLightColor(backgroundBottomColor(color));
00429     lg.setColorAt(1, light);
00430     p->setPen(QPen(lg, 1.2));
00431     p->drawArc(QRectF(x+0.6, y+0.6, 9, 9),90*16, 90*16);
00432     p->drawArc(QRectF(x+w-9-0.6, y+0.6, 9, 9), 0, 90*16);
00433     p->drawLine(QPointF(x+0.6, y+4), QPointF(x+0.6, y+h-4));
00434     p->drawLine(QPointF(x+w-0.6, y+4), QPointF(x+w-0.6, y+h-4));
00435 
00436     return;
00437 }

KStyles

Skip menu "KStyles"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KCMShell
  • KNotify
  • KStyles
  • Nepomuk Daemons
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal