/* * Copyright 2013 Hugo Pereira Da Costa * Copyright 2008 Long Huynh Huu * Copyright 2007 Matthew Woehlke * Copyright 2007 Casper Boemann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "oxygenstylehelper.h" #include #include #include #include #include #include #include #ifdef Q_WS_X11 #include #include #endif namespace Oxygen { //______________________________________________________________________________ StyleHelper::StyleHelper( const QByteArray &componentName ): Helper( componentName ), _debugArea( 90230 ), // see kdebug.areas _useBackgroundGradient( true ) { #ifdef Q_WS_X11 // get display Display *display = QX11Info::display(); // create compositing screen QByteArray buffer; QTextStream( &buffer ) << "_NET_WM_CM_S" << DefaultScreen( display ); _compositingManagerAtom = XInternAtom( display, buffer.constData(), False); #endif } //______________________________________________________________________________ void StyleHelper::invalidateCaches( void ) { _dialSlabCache.clear(); _roundSlabCache.clear(); _sliderSlabCache.clear(); _holeCache.clear(); _midColorCache.clear(); _dockWidgetButtonCache.clear(); _progressBarCache.clear(); _cornerCache.clear(); _selectionCache.clear(); _holeFlatCache.clear(); _slopeCache.clear(); _grooveCache.clear(); _slitCache.clear(); _dockFrameCache.clear(); _scrollHoleCache.clear(); _scrollHandleCache.clear(); Helper::invalidateCaches(); } //____________________________________________________________________ void StyleHelper::setMaxCacheSize( int value ) { // base class Helper::setMaxCacheSize( value ); // assign max cache size _dialSlabCache.setMaxCacheSize( value ); _roundSlabCache.setMaxCacheSize( value ); _sliderSlabCache.setMaxCacheSize( value ); _holeCache.setMaxCacheSize( value ); _scrollHandleCache.setMaxCacheSize( value ); _dockWidgetButtonCache.setMaxCost( value ); _progressBarCache.setMaxCost( value ); _cornerCache.setMaxCost( value ); _selectionCache.setMaxCost( value ); _holeFlatCache.setMaxCost( value ); _slopeCache.setMaxCost( value ); _grooveCache.setMaxCost( value ); _slitCache.setMaxCost( value ); _dockFrameCache.setMaxCost( value ); _scrollHoleCache.setMaxCost( value ); } //____________________________________________________________________ void StyleHelper::renderWindowBackground( QPainter* p, const QRect& clipRect, const QWidget* widget, const QColor& color, int y_shift, int gradientHeight) { if( _useBackgroundGradient ) { // normal background gradient Helper::renderWindowBackground( p, clipRect, widget, widget->window(), color, y_shift, gradientHeight ); } else { // if background gradient is disabled, simply render flat background if ( clipRect.isValid() ) { p->setClipRegion( clipRect,Qt::IntersectClip ); } p->fillRect( widget->rect(), color ); } } //____________________________________________________________________ void StyleHelper::setHasBackgroundGradient( WId id, bool value ) const { if( _useBackgroundGradient ) { Helper::setHasBackgroundGradient( id, value ); } } //____________________________________________________________________ void StyleHelper::renderMenuBackground( QPainter* p, const QRect& clipRect, const QWidget* widget, const QColor& color ) { // get coordinates relative to the client area // this is stupid. One could use mapTo if this was taking const QWidget* and not // QWidget* as argument. const QWidget* w( widget ); int x( 0 ); int y( 0 ); while( !w->isWindow() && w != w->parentWidget() ) { x += w->geometry().x(); y += w->geometry().y(); w = w->parentWidget(); } if ( clipRect.isValid() ) { p->save(); p->setClipRegion( clipRect,Qt::IntersectClip ); } // calculate upper part height // special tricks are needed // to handle both window contents and window decoration QRect r = w->rect(); const int height( w->frameGeometry().height() ); const int splitY( qMin( 200, ( 3*height )/4 ) ); const QRect upperRect( QRect( 0, 0, r.width(), splitY ) ); const QPixmap tile( verticalGradient( color, splitY ) ); p->drawTiledPixmap( upperRect, tile ); const QRect lowerRect( 0,splitY, r.width(), r.height() - splitY ); p->fillRect( lowerRect, backgroundBottomColor( color ) ); if ( clipRect.isValid() ) { p->restore(); } } //______________________________________________________________________________ QPalette StyleHelper::mergePalettes( const QPalette& source, qreal ratio ) const { QPalette out( source ); out.setColor( QPalette::Background, KColorUtils::mix( source.color( QPalette::Active, QPalette::Background ), source.color( QPalette::Disabled, QPalette::Background ), 1.0-ratio ) ); out.setColor( QPalette::Highlight, KColorUtils::mix( source.color( QPalette::Active, QPalette::Highlight ), source.color( QPalette::Disabled, QPalette::Highlight ), 1.0-ratio ) ); out.setColor( QPalette::WindowText, KColorUtils::mix( source.color( QPalette::Active, QPalette::WindowText ), source.color( QPalette::Disabled, QPalette::WindowText ), 1.0-ratio ) ); out.setColor( QPalette::ButtonText, KColorUtils::mix( source.color( QPalette::Active, QPalette::ButtonText ), source.color( QPalette::Disabled, QPalette::ButtonText ), 1.0-ratio ) ); out.setColor( QPalette::Text, KColorUtils::mix( source.color( QPalette::Active, QPalette::Text ), source.color( QPalette::Disabled, QPalette::Text ), 1.0-ratio ) ); out.setColor( QPalette::Button, KColorUtils::mix( source.color( QPalette::Active, QPalette::Button ), source.color( QPalette::Disabled, QPalette::Button ), 1.0-ratio ) ); return out; } //______________________________________________________________________________ QPixmap StyleHelper::dockWidgetButton( const QColor& color, bool pressed, int size ) { const quint64 key( ( colorKey(color) << 32 ) | ( size << 1 ) | quint64( pressed ) ); QPixmap *pixmap = _dockWidgetButtonCache.object( key ); if ( !pixmap ) { pixmap = new QPixmap( size, size ); pixmap->fill( Qt::transparent ); const QColor light( calcLightColor( color ) ); const QColor dark( calcDarkColor( color ) ); QPainter p( pixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); const qreal u( size/18.0 ); p.translate( 0.5*u, ( 0.5-0.668 )*u ); { // outline circle qreal penWidth = 1.2; QLinearGradient lg( 0, u*( 1.665-penWidth ), 0, u*( 12.33+1.665-penWidth ) ); lg.setColorAt( 0, dark ); lg.setColorAt( 1, light ); QRectF r( u*0.5*( 17-12.33+penWidth ), u*( 1.665+penWidth ), u*( 12.33-penWidth ), u*( 12.33-penWidth ) ); p.setPen( QPen( lg, penWidth*u ) ); p.drawEllipse( r ); p.end(); } _dockWidgetButtonCache.insert( key, pixmap ); } return *pixmap; } //________________________________________________________________________________________________________ TileSet *StyleHelper::roundCorner( const QColor& color, int size ) { const quint64 key( ( colorKey(color) << 32 )|size ); TileSet *tileSet = _cornerCache.object( key ); if ( !tileSet ) { QPixmap pixmap = QPixmap( size*2, size*2 ); pixmap.fill( Qt::transparent ); QPainter p( &pixmap ); p.setRenderHint( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); QLinearGradient lg = QLinearGradient( 0.0, size-4.5, 0.0, size+4.5 ); lg.setColorAt( 0.50, calcLightColor( backgroundTopColor( color ) ) ); lg.setColorAt( 0.51, backgroundBottomColor( color ) ); // draw ellipse. p.setBrush( lg ); p.drawEllipse( QRectF( size-4, size-4, 8, 8 ) ); // mask p.setCompositionMode( QPainter::CompositionMode_DestinationOut ); p.setBrush( Qt::black ); p.drawEllipse( QRectF( size-3, size-3, 6, 6 ) ); tileSet = new TileSet( pixmap, size, size, 1, 1 ); _cornerCache.insert( key, tileSet ); } return tileSet; } //________________________________________________________________________________________________________ TileSet *StyleHelper::slope( const QColor& color, qreal shade, int size ) { const quint64 key( ( colorKey(color) << 32 )|( quint64( 256.0*shade )<<24 )|size ); TileSet *tileSet = _slopeCache.object( key ); if ( !tileSet ) { QPixmap pixmap( size*4, size*4 ); pixmap.fill( Qt::transparent ); QPainter p( &pixmap ); p.setPen( Qt::NoPen ); // edges TileSet *slabTileSet = slab( color, shade, size ); slabTileSet->render( QRect( 0, 0, size*4, size*5 ), &p, TileSet::Left | TileSet::Right | TileSet::Top ); p.setWindow( 0,0,28,28 ); // bottom QColor light = KColorUtils::shade( calcLightColor( color ), shade ); QLinearGradient fillGradient( 0, -28, 0, 28 ); light.setAlphaF( 0.4 ); fillGradient.setColorAt( 0.0, light ); light.setAlphaF( 0.0 ); fillGradient.setColorAt( 1.0, light ); p.setBrush( fillGradient ); p.setCompositionMode( QPainter::CompositionMode_DestinationOver ); p.drawRect( 3, 9, 22, 17 ); // fade bottom QLinearGradient maskGradient( 0, 7, 0, 28 ); maskGradient.setColorAt( 0.0, Qt::black ); maskGradient.setColorAt( 1.0, Qt::transparent ); p.setBrush( maskGradient ); p.setCompositionMode( QPainter::CompositionMode_DestinationIn ); p.drawRect( 0, 9, 28, 19 ); p.end(); tileSet = new TileSet( pixmap, size, size, size*2, 2 ); _slopeCache.insert( key, tileSet ); } return tileSet; } //__________________________________________________________________________________________________________ TileSet* StyleHelper::progressBarIndicator( const QPalette& pal, int dimension ) { const QColor highlight( pal.color( QPalette::Highlight ) ); const quint64 key( ( colorKey(highlight) << 32 ) | dimension ); TileSet *tileSet = _progressBarCache.object( key ); if ( !tileSet ) { QRect local( 0, 0, dimension, dimension ); QPixmap pixmap( local.size() ); pixmap.fill( Qt::transparent ); QPainter p( &pixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setBrush( Qt::NoBrush ); const QColor lhighlight( calcLightColor( highlight ) ); const QColor color( pal.color( QPalette::Active, QPalette::Window ) ); const QColor light( calcLightColor( color ) ); const QColor dark( calcDarkColor( color ) ); const QColor shadow( calcShadowColor( color ) ); // shadow { p.setPen( QPen( alphaColor( shadow, 0.4 ),0.6 ) ); p.drawRoundedRect( QRectF( local ).adjusted( 0.5, 0.5, -0.5, 0.5 ), 3.0, 3.0 ); } // fill local.adjust( 1, 1, -1, 0 ); { p.setPen( Qt::NoPen ); p.setBrush( KColorUtils::mix( highlight, dark, 0.2 ) ); p.drawRoundedRect( local, 2.5, 2.5 ); } // fake radial gradient { QPixmap pm( local.size() ); pm.fill( Qt::transparent ); { QRectF pmRect = pm.rect(); QLinearGradient mask( pmRect.topLeft(), pmRect.topRight() ); mask.setColorAt( 0.0, Qt::transparent ); mask.setColorAt( 0.4, Qt::black ); mask.setColorAt( 0.6, Qt::black ); mask.setColorAt( 1.0, Qt::transparent ); QLinearGradient radial( pmRect.topLeft(), pmRect.bottomLeft() ); radial.setColorAt( 0.0, KColorUtils::mix( lhighlight, light, 0.3 ) ); radial.setColorAt( 0.5, Qt::transparent ); radial.setColorAt( 0.6, Qt::transparent ); radial.setColorAt( 1.0, KColorUtils::mix( lhighlight, light, 0.3 ) ); QPainter pp( &pm ); pp.fillRect( pm.rect(), mask ); pp.setCompositionMode( QPainter::CompositionMode_SourceIn ); pp.fillRect( pm.rect(), radial ); pp.end(); } p.drawPixmap( QPoint( 1,1 ), pm ); } // bevel { QLinearGradient bevel( QPointF( 0, 0.5 ) + local.topLeft(), QPointF( 0, -0.5 ) + local.bottomLeft() ); bevel.setColorAt( 0, lhighlight ); bevel.setColorAt( 0.5, highlight ); bevel.setColorAt( 1, calcDarkColor( highlight ) ); p.setBrush( Qt::NoBrush ); p.setPen( QPen( bevel, 1 ) ); p.drawRoundedRect( QRectF(local).adjusted( 0.5, 0.5, -0.5, -0.5 ), 2.5, 2.5 ); } // bright top edge { QLinearGradient lightHl( local.topLeft(),local.topRight() ); lightHl.setColorAt( 0, Qt::transparent ); lightHl.setColorAt( 0.5, KColorUtils::mix( highlight, light, 0.8 ) ); lightHl.setColorAt( 1, Qt::transparent ); p.setPen( QPen( lightHl, 1 ) ); p.drawLine( QPointF( 0.5, 0.5 ) + local.topLeft(), QPointF( 0.5, 0.5 ) + local.topRight() ); } p.end(); // generate tileSet and save in cache const int radius = qMin( 3, pixmap.width()/2 ); tileSet = new TileSet( pixmap, radius, radius, pixmap.width()-2*radius, pixmap.height()-2*radius, true ); _progressBarCache.insert( key, tileSet ); } return tileSet; } //______________________________________________________________________________ QPixmap StyleHelper::dialSlab( const QColor& color, const QColor& glow, qreal shade, int size ) { Oxygen::Cache::Value* cache = _dialSlabCache.get( color ); const quint64 key( ( colorKey(glow) << 32 ) | ( quint64( 256.0 * shade ) << 24 ) | size ); QPixmap *pixmap = cache->object( key ); if ( !pixmap ) { pixmap = new QPixmap( size, size ); pixmap->fill( Qt::transparent ); QRectF rect( pixmap->rect() ); QPainter p( pixmap ); p.setPen( Qt::NoPen ); p.setRenderHints( QPainter::Antialiasing ); // colors const QColor base( KColorUtils::shade( color, shade ) ); const QColor light( KColorUtils::shade( calcLightColor( color ), shade ) ); const QColor mid( KColorUtils::shade( calcMidColor( color ), shade ) ); const QColor shadow( calcShadowColor( color ) ); // shadow drawShadow( p, shadow, rect.width() ); if( glow.isValid() ) { drawOuterGlow( p, glow, rect.width() ); } const qreal baseOffset( 3.5 ); { //plain background QLinearGradient lg( 0, baseOffset-0.5*rect.height(), 0, baseOffset+rect.height() ); lg.setColorAt( 0, light ); lg.setColorAt( 0.8, base ); p.setBrush( lg ); const qreal offset( baseOffset ); p.drawEllipse( rect.adjusted( offset, offset, -offset, -offset ) ); } { // outline circle const qreal penWidth( 0.7 ); QLinearGradient lg( 0, baseOffset, 0, baseOffset + 2*rect.height() ); lg.setColorAt( 0, light ); lg.setColorAt( 1, mid ); p.setBrush( Qt::NoBrush ); p.setPen( QPen( lg, penWidth ) ); const qreal offset( baseOffset+0.5*penWidth ); p.drawEllipse( rect.adjusted( offset, offset, -offset, -offset ) ); } cache->insert( key, pixmap ); } return *pixmap; } //__________________________________________________________________________________________________________ QPixmap StyleHelper::roundSlab( const QColor& color, const QColor& glow, qreal shade, int size ) { Oxygen::Cache::Value* cache( _roundSlabCache.get( color ) ); const quint64 key( ( colorKey(glow) << 32 ) | ( quint64( 256.0 * shade ) << 24 ) | size ); QPixmap *pixmap = cache->object( key ); if ( !pixmap ) { pixmap = new QPixmap( size*3, size*3 ); pixmap->fill( Qt::transparent ); QPainter p( pixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); p.setWindow( 0,0,21,21 ); // draw normal shadow drawShadow( p, calcShadowColor( color ), 21 ); // draw glow. if( glow.isValid() ) { drawOuterGlow( p, glow, 21 ); } drawRoundSlab( p, color, shade ); p.end(); cache->insert( key, pixmap ); } return *pixmap; } //__________________________________________________________________________________________________________ QPixmap StyleHelper::sliderSlab( const QColor& color, const QColor& glow, bool sunken, qreal shade, int size ) { Oxygen::Cache::Value* cache( _sliderSlabCache.get( color ) ); const quint64 key( ( colorKey(glow) << 32 ) | ( quint64( 256.0 * shade ) << 24 ) | (sunken << 23 ) | size ); QPixmap *pixmap = cache->object( key ); if ( !pixmap ) { pixmap = new QPixmap( size*3, size*3 ); pixmap->fill( Qt::transparent ); QPainter p( pixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); p.setWindow( -1, -1, 23, 23 ); if( color.isValid() ) drawShadow( p, alphaColor( calcShadowColor( color ), 0.8 ), 21 ); if( glow.isValid() ) drawOuterGlow( p, glow, 21 ); // draw slab p.setWindow( -2, -2, 25, 25 ); drawSliderSlab( p, color, sunken, shade ); p.end(); cache->insert( key, pixmap ); } return *pixmap; } //__________________________________________________________________________________________________________ void StyleHelper::drawRoundSlab( QPainter& p, const QColor& color, qreal shade ) { p.save(); // colors const QColor base( KColorUtils::shade( color, shade ) ); const QColor light( KColorUtils::shade( calcLightColor( color ), shade ) ); // bevel, part 1 QLinearGradient bevelGradient1( 0, 10, 0, 18 ); bevelGradient1.setColorAt( 0.0, light ); bevelGradient1.setColorAt( 0.9, alphaColor( light, 0.85 ) ); p.setBrush( bevelGradient1 ); p.drawEllipse( QRectF( 3.0,3.0,15.0,15.0 ) ); // bevel, part 2 if ( _slabThickness > 0.0 ) { QLinearGradient bevelGradient2( 0, 7, 0, 28 ); bevelGradient2.setColorAt( 0.0, light ); bevelGradient2.setColorAt( 0.9, base ); p.setBrush( bevelGradient2 ); p.drawEllipse( QRectF( 3.6,3.6,13.8,13.8 ) ); } // inside QLinearGradient innerGradient( 0, -17, 0, 20 ); innerGradient.setColorAt( 0, light ); innerGradient.setColorAt( 1, base ); p.setBrush( innerGradient ); const qreal ic( 3.6 + _slabThickness ); const qreal is( 21.0 - 2.0*ic ); p.drawEllipse( QRectF( ic, ic, is, is ) ); p.restore(); } //__________________________________________________________________________________________________________ void StyleHelper::drawSliderSlab( QPainter& p, const QColor& color, bool sunken, qreal shade ) { p.save(); const QColor light( KColorUtils::shade( calcLightColor(color), shade ) ); const QColor dark( KColorUtils::shade( calcDarkColor(color), shade ) ); p.setPen(Qt::NoPen); { //plain background QLinearGradient lg( 0, 3, 0, 21 ); lg.setColorAt( 0, light ); lg.setColorAt( 1, dark ); const QRectF r( 3, 3, 15, 15 ); p.setBrush( lg ); p.drawEllipse( r ); } if( sunken ) { //plain background QLinearGradient lg( 0, 3, 0, 21 ); lg.setColorAt( 0, dark ); lg.setColorAt( 1, light ); const QRectF r( 5, 5, 11, 11 ); p.setBrush( lg ); p.drawEllipse( r ); } { // outline circle const qreal penWidth( 1 ); QLinearGradient lg( 0, 3, 0, 30 ); lg.setColorAt( 0, light ); lg.setColorAt( 1, dark ); const QRectF r( 3.5, 3.5, 14, 14 ); p.setPen( QPen( lg, penWidth ) ); p.setBrush( Qt::NoBrush ); p.drawEllipse( r ); } p.restore(); } //________________________________________________________________________________________________________ void StyleHelper::drawInverseGlow( QPainter& p, const QColor& color, int pad, int size, int rsize ) const { const QRectF r( pad, pad, size, size ); const qreal m( qreal( size )*0.5 ); const qreal width( 3.5 ); const qreal bias( _glowBias*7.0/rsize ); qreal k0( ( m-width )/( m-bias ) ); if (k0 < 0.0) { k0 = -k0; } QRadialGradient glowGradient( pad+m, pad+m, m-bias ); for ( int i = 0; i < 8; i++ ) { // inverse parabolic gradient qreal k1 = ( k0 * qreal( i ) + qreal( 8 - i ) ) * 0.125; qreal a = 1.0 - sqrt( i * 0.125 ); glowGradient.setColorAt( k1, alphaColor( color, a ) ); } glowGradient.setColorAt( k0, alphaColor( color, 0.0 ) ); p.setBrush( glowGradient ); p.drawEllipse( r ); } //________________________________________________________________________________________________________ bool StyleHelper::compositingActive( void ) const { #ifdef Q_WS_X11 // direct call to X return XGetSelectionOwner( QX11Info::display(), _compositingManagerAtom ) != None; #else // use KWindowSystem return KWindowSystem::compositingActive(); #endif } //________________________________________________________________________________________________________ bool StyleHelper::hasDecoration( const QWidget* widget ) const { if( !widget->isTopLevel() ) return false; if( widget->windowFlags() & (Qt::X11BypassWindowManagerHint|Qt::FramelessWindowHint) ) { return false; } return true; } //________________________________________________________________________________________________________ void StyleHelper::fillHole( QPainter& p, const QRect& rect, int size ) const { const qreal s( ( 3.0*size )/7.0 ); p.drawRoundedRect( rect.adjusted( s,s,-s,-s ), 4, 4 ); } //____________________________________________________________________________________ void StyleHelper::renderHole( QPainter* p, const QColor& base, const QRect& r, HoleOptions options, TileSet::Tiles tiles ) { if( !r.isValid() ) return; if( options & HoleFocus ) { const QColor glow( viewFocusBrush().brush( QPalette::Active ).color() ); hole( base, glow, 7, options )->render( r, p, tiles ); } else if( options & HoleHover ) { const QColor glow( viewHoverBrush().brush( QPalette::Active ).color() ); hole( base, glow, 7, options )->render( r, p, tiles ); } else { hole( base, 7, options )->render( r, p, tiles ); } } //________________________________________________________________________________________________________ TileSet *StyleHelper::holeFlat( const QColor& color, qreal shade, bool fill, int size ) { const quint64 key( ( colorKey(color) << 32 ) | ( quint64( 256.0 * shade ) << 24 ) | size << 1 | fill ); TileSet *tileSet = _holeFlatCache.object( key ); if ( !tileSet ) { QPixmap pixmap( size*2, size*2 ); pixmap.fill( Qt::transparent ); QPainter p( &pixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); p.setWindow( 0,0,14,14 ); if( fill ) { // hole inside p.setBrush( color ); p.drawRoundedRect( QRectF( 1, 0, 12, 13 ), 3.0, 3.0 ); p.setBrush( Qt::NoBrush ); { // shadow (top) const QColor dark( KColorUtils::shade( calcDarkColor( color ), shade ) ); QLinearGradient gradient( 0, -2, 0, 14 ); gradient.setColorAt( 0.0, dark ); gradient.setColorAt( 0.5, Qt::transparent ); p.setPen( QPen( gradient, 1 ) ); p.drawRoundedRect( QRectF( 1.5, 0.5, 11, 12 ), 2.5, 2.5 ); } { // contrast (bottom) const QColor light( KColorUtils::shade( calcLightColor( color ), shade ) ); QLinearGradient gradient( 0, 0, 0, 18 ); gradient.setColorAt( 0.5, Qt::transparent ); gradient.setColorAt( 1.0, light ); p.setPen( QPen( gradient, 1 ) ); p.drawRoundedRect( QRectF( 0.5, 0.5, 13, 13 ), 3.5, 3.5 ); } } else { // hole inside p.setBrush( color ); p.drawRoundedRect( QRectF( 1, 1, 12, 12 ), 3.0, 3.0 ); p.setBrush( Qt::NoBrush ); { // shadow (top) const QColor dark( KColorUtils::shade( calcDarkColor( color ), shade ) ); QLinearGradient gradient( 0, 1, 0, 12 ); gradient.setColorAt( 0.0, dark ); gradient.setColorAt( 0.5, Qt::transparent ); p.setPen( QPen( gradient, 1 ) ); p.drawRoundedRect( QRectF( 1.5, 1.5, 11, 11 ), 2.5, 2.5 ); } { // contrast (bottom) const QColor light( KColorUtils::shade( calcLightColor( color ), shade ) ); QLinearGradient gradient( 0, 1, 0, 12 ); gradient.setColorAt( 0.5, Qt::transparent ); gradient.setColorAt( 1.0, light ); p.setPen( QPen( gradient, 1 ) ); p.drawRoundedRect( QRectF( 1.5, 1.5, 11, 11 ), 2.5, 2.5 ); } } p.end(); tileSet = new TileSet( pixmap, size, size, size, size, size-1, size, 2, 1 ); _holeFlatCache.insert( key, tileSet ); } return tileSet; } //________________________________________________________________________________________________________ TileSet *StyleHelper::hole( const QColor& color, const QColor& glow, int size, HoleOptions options ) { // get key Oxygen::Cache::Value* cache( _holeCache.get( glow ) ); const quint64 key( ( colorKey(color) << 32 ) | (size << 4) | options ); TileSet *tileSet = cache->object( key ); if ( !tileSet ) { // first create shadow int shadowSize( (size*5)/7 ); QPixmap shadowPixmap( shadowSize*2, shadowSize*2 ); // calc alpha channel and fade const int alpha( glow.isValid() ? glow.alpha():0 ); { shadowPixmap.fill( Qt::transparent ); QPainter p( &shadowPixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); p.setWindow( 0, 0, 10, 10 ); // fade-in shadow if( alpha < 255 ) { QColor shadowColor( calcShadowColor( color ) ); shadowColor.setAlpha( 255-alpha ); drawInverseShadow( p, shadowColor, 1, 8, 0.0 ); } // fade-out glow if( alpha > 0 ) { drawInverseGlow( p, glow, 1, 8, shadowSize ); } p.end(); } // create pixmap QPixmap pixmap( size*2, size*2 ); pixmap.fill( Qt::transparent ); QPainter p( &pixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); p.setWindow( 0, 0, 14, 14 ); // hole mask p.setCompositionMode( QPainter::CompositionMode_DestinationOut ); p.setBrush( Qt::black ); p.drawRoundedRect( QRectF( 1, 1, 12, 12 ), 2.5, 2.5 ); p.setCompositionMode( QPainter::CompositionMode_SourceOver ); // render shadow TileSet( shadowPixmap, shadowSize, shadowSize, shadowSize, shadowSize, shadowSize-1, shadowSize, 2, 1 ). render( pixmap.rect(), &p ); if( (options&HoleOutline) && alpha < 255 ) { QColor dark( calcDarkColor( color ) ); dark.setAlpha( 255 - alpha ); QLinearGradient blend( 0, 0, 0, 14 ); blend.setColorAt( 0, Qt::transparent ); blend.setColorAt( 0.8, dark ); p.setBrush( Qt::NoBrush ); p.setPen( QPen( blend, 1 ) ); p.drawRoundedRect( QRectF( 1.5, 1.5, 11, 11 ), 3.0, 3.0 ); p.setPen( Qt::NoPen ); } if( options&HoleContrast ) { QColor light( calcLightColor( color ) ); QLinearGradient blend( 0, 0, 0, 18 ); blend.setColorAt( 0.5, Qt::transparent ); blend.setColorAt( 1.0, light ); p.setBrush( Qt::NoBrush ); p.setPen( QPen( blend, 1 ) ); p.drawRoundedRect( QRectF( 0.5, 0.5, 13, 13 ), 4.0, 4.0 ); p.setPen( Qt::NoPen ); } p.end(); // create tileset and return tileSet = new TileSet( pixmap, size, size, size, size, size-1, size, 2, 1 ); cache->insert( key, tileSet ); } return tileSet; } //______________________________________________________________________________ TileSet *StyleHelper::scrollHole( const QColor& color, Qt::Orientation orientation, bool smallShadow ) { const quint64 key( colorKey(color) << 32 | ( orientation == Qt::Horizontal ? 2 : 0 ) | ( smallShadow ? 1 : 0 ) ); TileSet *tileSet = _scrollHoleCache.object( key ); if ( !tileSet ) { QPixmap pm( 15, 15 ); pm.fill( Qt::transparent ); QPainter p( &pm ); const QColor dark( calcDarkColor( color ) ); const QColor light( calcLightColor( color ) ); const QColor shadow( calcShadowColor( color ) ); // use space for white border const QRect r( QRect( 0,0,15,15 ) ); const QRect rect( r.adjusted( 1, 0, -1, -1 ) ); p.setRenderHints( QPainter::Antialiasing ); p.setBrush( dark ); p.setPen( Qt::NoPen ); // base const qreal radius( smallShadow ? 2.5:3.0 ); p.drawRoundedRect( rect, radius, radius ); // slight shadow across the whole hole if( true ) { QLinearGradient shadowGradient( rect.topLeft(), orientation == Qt::Horizontal ? rect.bottomLeft():rect.topRight() ); shadowGradient.setColorAt( 0.0, alphaColor( shadow, 0.1 ) ); shadowGradient.setColorAt( 0.6, Qt::transparent ); p.setBrush( shadowGradient ); p.drawRoundedRect( rect, radius, radius ); } // first create shadow int shadowSize( 5 ); QPixmap shadowPixmap( shadowSize*2, shadowSize*2 ); { shadowPixmap.fill( Qt::transparent ); QPainter p( &shadowPixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); // fade-in shadow QColor shadowColor( calcShadowColor( color ) ); if( smallShadow ) shadowColor = alphaColor( shadowColor, 0.6 ); drawInverseShadow( p, shadowColor, 1, 8, 0.0 ); p.end(); } // render shadow TileSet( shadowPixmap, shadowSize, shadowSize, shadowSize, shadowSize, shadowSize-1, shadowSize, 2, 1 ). render( rect.adjusted( -1, -1, 1, 1 ), &p, TileSet::Full ); // light border QLinearGradient borderGradient( 0, r.top(), 0, r.bottom() ); if( smallShadow && orientation == Qt::Vertical ) { borderGradient.setColorAt( 0.8, Qt::transparent ); borderGradient.setColorAt( 1.0, alphaColor( light, 0.5 ) ); } else { borderGradient.setColorAt( 0.5, Qt::transparent ); borderGradient.setColorAt( 1.0, alphaColor( light, 0.6 ) ); } p.setPen( QPen( borderGradient, 1.0 ) ); p.setBrush( Qt::NoBrush ); p.drawRoundedRect( QRectF(r).adjusted( 0.5,0.5,-0.5,-0.5 ), radius+0.5, radius+0.5 ); p.end(); tileSet = new TileSet( pm, 7, 7, 1, 1 ); _scrollHoleCache.insert( key, tileSet ); } return tileSet; } //________________________________________________________________________________________________________ TileSet *StyleHelper::scrollHandle( const QColor& color, const QColor& glow, int size) { // get key Oxygen::Cache::Value* cache( _scrollHandleCache.get( glow ) ); const quint64 key( ( colorKey(color) << 32 ) | size ); TileSet *tileSet = cache->object( key ); if ( !tileSet ) { QPixmap pm( 2*size, 2*size ); pm.fill( Qt::transparent ); QPainter p( &pm ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); p.setWindow( 0, 0, 14, 14 ); QPixmap shadowPixmap( 10, 10 ); { shadowPixmap.fill( Qt::transparent ); QPainter p( &shadowPixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); // shadow/glow drawOuterGlow( p, glow, 10 ); p.end(); } TileSet( shadowPixmap, 4, 4, 1, 1 ).render( QRect( 0, 0, 14, 14 ), &p, TileSet::Full ); // outline { const QColor mid( calcMidColor( color ) ); QLinearGradient lg( 0, 3, 0, 11 ); lg.setColorAt( 0, color ); lg.setColorAt( 1, mid ); p.setPen( Qt::NoPen ); p.setBrush( lg ); p.drawRoundedRect( QRectF( 3, 3, 8, 8 ), 2.5, 2.5 ); } // contrast { const QColor light( calcLightColor( color ) ); QLinearGradient lg( 0, 3, 0, 11 ); lg.setColorAt( 0., alphaColor( light, 0.9 ) ); lg.setColorAt( 0.5, alphaColor( light, 0.44 ) ); p.setBrush( lg ); p.drawRoundedRect( QRectF( 3, 3, 8, 8 ), 2.5, 2.5 ); } p.end(); // create tileset and return tileSet = new TileSet( pm, size-1, size, 1, 1 ); cache->insert( key, tileSet ); } return tileSet; } //______________________________________________________________________________ TileSet *StyleHelper::groove( const QColor& color, int size ) { const quint64 key( ( colorKey(color) << 32 ) | size ); TileSet *tileSet = _grooveCache.object( key ); if ( !tileSet ) { const int rsize( ( int )ceil( qreal( size ) * 3.0/7.0 ) ); QPixmap pixmap( rsize*2, rsize*2 ); pixmap.fill( Qt::transparent ); QPainter p( &pixmap ); p.setRenderHints( QPainter::Antialiasing ); p.setPen( Qt::NoPen ); p.setWindow( 0, 0, 6, 6 ); // hole mask p.setCompositionMode( QPainter::CompositionMode_DestinationOut ); p.setBrush( Qt::black ); p.drawEllipse( 2, 2, 2, 2 ); // shadow p.setCompositionMode( QPainter::CompositionMode_SourceOver ); drawInverseShadow( p, calcShadowColor( color ), 1, 4, 0.0 ); p.end(); tileSet = new TileSet( pixmap, rsize, rsize, rsize, rsize, rsize-1, rsize, 2, 1 ); _grooveCache.insert( key, tileSet ); } return tileSet; } //________________________________________________________________________________________________________ TileSet *StyleHelper::slitFocused( const QColor& glow ) { const quint64 key( ( colorKey(glow) << 32 ) ); TileSet *tileSet = _slitCache.object( key ); if ( !tileSet ) { QPixmap pixmap( 9,9 ); QPainter p; pixmap.fill( Qt::transparent ); p.begin( &pixmap ); p.setPen( Qt::NoPen ); p.setRenderHint( QPainter::Antialiasing ); QRadialGradient rg = QRadialGradient( 4.5, 4.5, 3.5 ); rg.setColorAt( 1.0, alphaColor( glow, 180.0/255 ) ); rg.setColorAt( 0.5, alphaColor( glow, 0 ) ); p.setBrush( rg ); p.drawEllipse( QRectF( 1, 1, 7, 7 ) ); p.end(); tileSet = new TileSet( pixmap, 4, 4, 1, 1 ); _slitCache.insert( key, tileSet ); } return tileSet; } //____________________________________________________________________ TileSet *StyleHelper::dockFrame( const QColor& top, const QColor& bottom ) { const quint64 key( colorKey(top) << 32 | colorKey(bottom) ); TileSet *tileSet = _dockFrameCache.object( key ); if ( !tileSet ) { int size( 13 ); QPixmap pm( size, size ); pm.fill( Qt::transparent ); QPainter p( &pm ); p.setRenderHints( QPainter::Antialiasing ); p.setBrush( Qt::NoBrush ); const QColor lightTop = alphaColor( calcLightColor( top ), 0.5 ); const QColor lightBottom = alphaColor( calcLightColor( bottom ), 0.5 ); const QColor darkTop = alphaColor( calcDarkColor( top ), 0.6 ); const QColor darkBottom = alphaColor( calcDarkColor( bottom ), 0.6 ); // dark frame { QLinearGradient lg( 0, 0.5, 0, size-1.5 ); lg.setColorAt( 0.0, darkTop ); lg.setColorAt( 1.0, darkBottom ); p.setPen( QPen( lg, 1 ) ); p.drawRoundedRect( QRectF( 1.5, 0.5, size-3, size-2 ), 4, 4 ); } // bottom contrast { QLinearGradient lg( 0, 0.5, 0, size-0.5 ); lg.setColorAt( 0.0, Qt::transparent ); lg.setColorAt( 1.0, lightBottom ); p.setPen( QPen( lg, 1.0 ) ); p.drawRoundedRect( QRectF( 0.5, 0.5, size-1, size-1 ), 4.5, 4.5 ); } // top contrast { QLinearGradient lg( 0, 1.5, 0, size-2.5 ); lg.setColorAt( 0.0, lightTop ); lg.setColorAt( 1.0, Qt::transparent ); p.setPen( QPen( lg, 1.0 ) ); p.drawRoundedRect( QRectF( 2.5, 1.5, size-5, size-4 ), 3.5, 3.5 ); } p.end(); tileSet = new TileSet( pm, (size-1)/2, (size-1)/2, 1, 1 ); _dockFrameCache.insert( key, tileSet ); } return tileSet; } //____________________________________________________________________ TileSet *StyleHelper::selection( const QColor& color, int height, bool custom ) { const quint64 key( ( colorKey(color) << 32 ) | ( height << 1 ) | custom ); TileSet *tileSet = _selectionCache.object( key ); if ( !tileSet ) { const qreal rounding( 2.5 ); QPixmap pixmap( 32+16, height ); pixmap.fill( Qt::transparent ); QRectF r( pixmap.rect() ); QPainter p( &pixmap ); p.setRenderHint( QPainter::Antialiasing ); // items with custom background brushes always have their background drawn // regardless of whether they are hovered or selected or neither so // the gradient effect needs to be more subtle { // fill const int lightenAmount( custom ? 110 : 130 ); QLinearGradient gradient( 0, 0, 0, r.bottom() ); gradient.setColorAt( 0, color.lighter( lightenAmount ) ); gradient.setColorAt( 1, color ); p.setPen( Qt::NoPen ); p.setBrush( gradient ); p.drawRoundedRect( r, rounding+0.5, rounding+0.5 ); } { // contrast QLinearGradient gradient( 0, 0, 0, r.bottom() ); gradient.setColorAt( 0, color ); gradient.setColorAt( 1, Qt::transparent ); r.adjust( 0.5, 0.5, -0.5, -0.5 ); p.setPen( QPen( color, 1 ) ); p.setBrush( Qt::NoBrush ); p.drawRoundedRect( r, rounding, rounding ); } tileSet = new TileSet( pixmap, 8, 0, 32, height ); _selectionCache.insert( key, tileSet ); } return tileSet; } }