Moved all shadow handling into global cache oxygenShadowCache. This allows to share same

shadow tilesets between clients, thus reducing the memory usage; to simplify the oxygenclient
class; and leave room for optimizing active/inactive shadow transitions. The global class is
declared using K_GLOBAL_STATIC_WITH_ARGS.

Also cleaned-up unnecessary headers.


svn path=/trunk/KDE/kdebase/workspace/; revision=1025063
icc-effect-5.14.5
Hugo Pereira Da Costa 2009-09-17 22:40:06 +00:00
parent d58e7b7812
commit 9eec5543bf
8 changed files with 499 additions and 344 deletions

View File

@ -13,6 +13,7 @@ set(kwin_oxygen_SRCS
oxygenexception.cpp
oxygenexceptionlist.cpp
oxygenshadowconfiguration.cpp
oxygenshadowcache.cpp
oxygensizegrip.cpp
x11util.cpp
)

View File

@ -27,12 +27,13 @@
#include "oxygen.h"
#include "oxygen.moc"
#include "oxygenclient.h"
#include "oxygenshadowcache.h"
#include <cassert>
#include <kdebug.h>
#include <kconfiggroup.h>
#include <KDebug>
#include <KConfigGroup>
#include <KWindowInfo>
#include <kdeversion.h>
#include <kwindowinfo.h>
#include <QApplication>
#include <QPainter>
@ -47,12 +48,11 @@ namespace Oxygen
// referenced from definition in Oxygendclient.cpp
OxygenHelper *oxygenHelper();
OxygenShadowCache *oxygenShadowCache();
// initialize static members
bool OxygenFactory::initialized_ = false;
OxygenConfiguration OxygenFactory::defaultConfiguration_;
OxygenShadowConfiguration OxygenFactory::activeShadowConfiguration_ = OxygenShadowConfiguration( QPalette::Active );
OxygenShadowConfiguration OxygenFactory::inactiveShadowConfiguration_ = OxygenShadowConfiguration( QPalette::Inactive );
OxygenExceptionList OxygenFactory::exceptions_;
//___________________________________________________
@ -85,15 +85,14 @@ namespace Oxygen
bool configuration_changed = readConfig();
setInitialized( true );
emit configurationChanged();
if( configuration_changed || (changed & (SettingDecoration | SettingButtons | SettingBorder)) )
{
emit configurationChanged();
return true;
} else {
emit configurationChanged();
resetDecorations(changed);
return false;
@ -129,23 +128,24 @@ namespace Oxygen
// read shadow configurations
OxygenShadowConfiguration activeShadowConfiguration( QPalette::Active, config.group( "ActiveShadow" ) );
if( !( activeShadowConfiguration == activeShadowConfiguration_ ) )
if( oxygenShadowCache()->shadowConfigurationChanged( activeShadowConfiguration ) )
{
activeShadowConfiguration_ = activeShadowConfiguration;
oxygenShadowCache()->setShadowConfiguration( activeShadowConfiguration );
changed = true;
}
// read shadow configurations
OxygenShadowConfiguration inactiveShadowConfiguration( QPalette::Inactive, config.group( "InactiveShadow" ) );
if( !( inactiveShadowConfiguration == inactiveShadowConfiguration_ ) )
if( oxygenShadowCache()->shadowConfigurationChanged( inactiveShadowConfiguration ) )
{
inactiveShadowConfiguration_ = inactiveShadowConfiguration;
oxygenShadowCache()->setShadowConfiguration( inactiveShadowConfiguration );
changed = true;
}
if( changed )
{
oxygenShadowCache()->invalidateCaches();
oxygenHelper()->invalidateCaches();
return true;

View File

@ -32,7 +32,6 @@
#include <kdeversion.h>
#include "oxygenconfiguration.h"
#include "oxygenshadowconfiguration.h"
#include "oxygenexceptionlist.h"
// TODO:
@ -103,22 +102,6 @@ namespace Oxygen
//! get configuration for a give client
static OxygenConfiguration configuration( const OxygenClient& );
//! shadow configuration
static OxygenShadowConfiguration activeShadowConfiguration( void )
{ return activeShadowConfiguration_; }
//! shadow configuration
static OxygenShadowConfiguration inactiveShadowConfiguration( void )
{ return inactiveShadowConfiguration_; }
//! shadow configuration
static OxygenShadowConfiguration shadowConfiguration( bool active )
{ return active ? activeShadowConfiguration():inactiveShadowConfiguration(); }
//! shadow size
static qreal shadowSize( void )
{ return qMax( activeShadowConfiguration().shadowSize(), inactiveShadowConfiguration().shadowSize() ); }
signals:
//! configuration has changed
@ -147,12 +130,6 @@ namespace Oxygen
//! default configuration
static OxygenConfiguration defaultConfiguration_;
//! shadow configuration
static OxygenShadowConfiguration activeShadowConfiguration_;
//! shadow configuration
static OxygenShadowConfiguration inactiveShadowConfiguration_;
//! exceptions
static OxygenExceptionList exceptions_;

View File

@ -31,7 +31,6 @@
#include <cmath>
#include <QPainterPath>
#include <QPainter>
#include <QPen>

View File

@ -30,11 +30,11 @@
#include "oxygen.h"
#include "oxygenbutton.h"
#include "oxygenshadowcache.h"
#include "oxygensizegrip.h"
#include <cassert>
#include <cmath>
#include <iostream>
#include <kdeversion.h>
#include <KGlobal>
@ -44,7 +44,6 @@
#include <QLabel>
#include <QPainter>
#include <QTextStream>
#include <QApplication>
using namespace std;
@ -52,16 +51,23 @@ namespace Oxygen
{
K_GLOBAL_STATIC_WITH_ARGS(OxygenHelper, globalHelper, ("oxygenDeco"))
K_GLOBAL_STATIC_WITH_ARGS(OxygenShadowCache, globalShadowCache, (512))
//___________________________________________
OxygenHelper *oxygenHelper()
{ return globalHelper; }
//___________________________________________
OxygenShadowCache *oxygenShadowCache()
{ return globalShadowCache; }
//___________________________________________
static void oxkwincleanupBefore()
{
OxygenHelper *h = globalHelper;
h->invalidateCaches();
globalHelper->invalidateCaches();
globalShadowCache->invalidateCaches();
}
//___________________________________________
@ -75,10 +81,6 @@ namespace Oxygen
KCommonDecorationUnstable(b, f),
colorCacheInvalid_(true),
sizeGrip_( 0 ),
inactiveShadowConfiguration_( QPalette::Inactive ),
activeShadowConfiguration_( QPalette::Active ),
inactiveShadowTiles_( 0 ),
activeShadowTiles_( 0 ),
helper_(*globalHelper),
initialized_( false )
{ qAddPostRoutine(oxkwincleanupBefore); }
@ -90,10 +92,6 @@ namespace Oxygen
// delete sizegrip if any
if( hasSizeGrip() ) deleteSizeGrip();
// delete tilesets
if( inactiveShadowTiles_ ) delete inactiveShadowTiles_;
if( activeShadowTiles_ ) delete activeShadowTiles_;
}
//___________________________________________
@ -267,7 +265,7 @@ namespace Oxygen
case LM_OuterPaddingRight:
case LM_OuterPaddingTop:
case LM_OuterPaddingBottom:
return OxygenFactory::shadowSize() - extraBorder;
return oxygenShadowCache()->shadowSize() - extraBorder;
default:
return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
@ -450,7 +448,8 @@ namespace Oxygen
}
QRect r = (isPreview()) ? OxygenClient::widget()->rect():window->rect();
r.adjust( OxygenFactory::shadowSize(), OxygenFactory::shadowSize(), -OxygenFactory::shadowSize(), -OxygenFactory::shadowSize() );
qreal shadowSize( oxygenShadowCache()->shadowSize() );
r.adjust( shadowSize, shadowSize, -shadowSize, -shadowSize );
r.adjust(0,0, 1, 1);
// mask and painting frame
@ -459,10 +458,10 @@ namespace Oxygen
// top line
{
int shadow_size = 5;
int shadowSize = 5;
int height = HFRAMESIZE;
QRect rect( r.topLeft()-position, QSize( r.width(), height ) );
helper().slab( palette.color( widget->backgroundRole() ), 0, shadow_size )->render( rect.adjusted(-shadow_size-1, 0, shadow_size+1, 2 ), painter, TileSet::Bottom );
helper().slab( palette.color( widget->backgroundRole() ), 0, shadowSize )->render( rect.adjusted(-shadowSize-1, 0, shadowSize+1, 2 ), painter, TileSet::Bottom );
mask += rect;
frame |= rect;
}
@ -513,10 +512,10 @@ namespace Oxygen
// shadow
{
int shadow_size = 7;
int voffset = -shadow_size;
int shadowSize = 7;
int voffset = -shadowSize;
if( !isMaximized() ) voffset += HFRAMESIZE;
helper().slab( palette.color( widget()->backgroundRole() ), 0, shadow_size )->render( rect.adjusted(0, voffset, 0, 0 ), painter, TileSet::Bottom|TileSet::Left|TileSet::Right );
helper().slab( palette.color( widget()->backgroundRole() ), 0, shadowSize )->render( rect.adjusted(0, voffset, 0, 0 ), painter, TileSet::Bottom|TileSet::Left|TileSet::Right );
}
// center
@ -553,15 +552,6 @@ namespace Oxygen
void OxygenClient::shadeChange( void )
{
if( hasSizeGrip() ) sizeGrip().setVisible( !( isShade() || isMaximized() ) );
// in border none mode, need to reinitialze shadowTiles because
// bottom corner rounding is changed
if( compositingActive() && configuration().frameBorder() == OxygenConfiguration::BorderNone )
{
inactiveShadowConfiguration_ = OxygenShadowConfiguration( QPalette::Active );
activeShadowConfiguration_ = OxygenShadowConfiguration( QPalette::Active );
}
KCommonDecorationUnstable::shadeChange();
}
@ -636,14 +626,16 @@ namespace Oxygen
// draw shadows
if( compositingActive() && !isMaximized() )
{
shadowTiles(
backgroundPalette( widget(), palette ).color( widget()->backgroundRole() ),
isActive() )->render( frame.adjusted( 4, 4, -4, -4),
oxygenShadowCache()->tileSet( this )->render(
frame.adjusted( 4, 4, -4, -4),
&painter, TileSet::Ring);
}
// adjust frame
frame.adjust( OxygenFactory::shadowSize(), OxygenFactory::shadowSize(), -OxygenFactory::shadowSize(), -OxygenFactory::shadowSize() );
qreal shadowSize( oxygenShadowCache()->shadowSize() );
frame.adjust( shadowSize, shadowSize, -shadowSize, -shadowSize );
// adjust mask
if( compositingActive() || isPreview() )
@ -835,265 +827,4 @@ namespace Oxygen
sizeGrip_ = 0;
}
//_________________________________________________________________
TileSet *OxygenClient::shadowTiles(const QColor& color, bool active)
{
OxygenShadowConfiguration shadowConfiguration( OxygenFactory::shadowConfiguration( active && useOxygenShadows() ) );
OxygenShadowConfiguration local( shadowConfiguration );
local.setShadowSize( OxygenFactory::shadowSize() );
OxygenShadowConfiguration current = active ? activeShadowConfiguration_:inactiveShadowConfiguration_;
bool optionChanged = !(current == local );
if (active && activeShadowTiles_ )
{
if( optionChanged) delete activeShadowTiles_;
else return activeShadowTiles_;
} else if (!active && inactiveShadowTiles_ ) {
if( optionChanged ) delete inactiveShadowTiles_;
else return inactiveShadowTiles_;
}
kDebug( 1212 ) << " creating tiles - active: " << active << endl;
TileSet *tileSet = 0;
//
qreal size( OxygenFactory::shadowSize() );
if( active && configuration().drawTitleOutline() && configuration().frameBorder() == OxygenConfiguration::BorderNone )
{
// a more complex tile set is needed for the configuration above:
// top corners must be beveled with the "active titlebar color" while
// bottom corners must be beveled with the "window background color".
// this requires generating two shadow pixmaps and tiling them in the tileSet.
QPixmap shadow = QPixmap( size*2, size*2 );
shadow.fill( Qt::transparent );
QPainter p( &shadow );
p.setRenderHint( QPainter::Antialiasing );
QPixmap shadowTop = shadowPixmap( color, active );
QRect topRect( shadow.rect() );
topRect.setBottom( int( size )-1 );
p.setClipRect( topRect );
p.drawPixmap( QPointF( 0, 0 ), shadowTop );
QPixmap shadowBottom = shadowPixmap( widget()->palette().color( widget()->backgroundRole() ), active );
QRect bottomRect( shadow.rect() );
bottomRect.setTop( int( size ) );
p.setClipRect( bottomRect );
p.drawPixmap( QPointF( 0, 0 ), shadowBottom );
p.end();
tileSet = new TileSet( shadow, size, size, 1, 1);
} else {
tileSet = new TileSet(
shadowPixmap( color, active ),
size, size, 1, 1);
}
// store option and style
if( active )
{
activeShadowConfiguration_ = local;
activeShadowTiles_ = tileSet;
} else {
inactiveShadowConfiguration_ = local;
inactiveShadowTiles_ = tileSet;
}
return tileSet;
}
//_________________________________________________________________
QPixmap OxygenClient::shadowPixmap(const QColor& color, bool active ) const
{
OxygenShadowConfiguration shadowConfiguration( OxygenFactory::shadowConfiguration( active && useOxygenShadows() ) );
static const qreal fixedSize = 25.5;
qreal size( OxygenFactory::shadowSize() );
qreal shadowSize( shadowConfiguration.shadowSize() );
QPixmap shadow = QPixmap( size*2, size*2 );
shadow.fill( Qt::transparent );
QPainter p( &shadow );
p.setRenderHint( QPainter::Antialiasing );
p.setPen( Qt::NoPen );
// offsets are scaled with the shadow size
// so that the ratio Top-shadow/Bottom-shadow is kept constant
// when shadow size is chqnged
qreal hoffset = shadowConfiguration.horizontalOffset()*shadowSize/fixedSize;
qreal voffset = shadowConfiguration.verticalOffset()*shadowSize/fixedSize;
if( active && useOxygenShadows() )
{
{
int values[5] = {255, 220, 180, 25, 0};
qreal x[5] = {4.4, 4.5, 5, 5.5, 6.5};
// the first point of this gradient does not scale
QRadialGradient rg( size, size, shadowSize );
QColor c = color;
for( int i = 0; i<5; i++ )
{ c.setAlpha( values[i] ); rg.setColorAt( x[0]/shadowSize+(x[i]-x[0])/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
// this gradient scales with shadow size
int nPoints = 8;
qreal values[8] = {1, 0.58, 0.43, 0.30, 0.22, 0.15, 0.08, 0 };
qreal x[8] = {0, 4.5, 5.5, 6.5, 7.5, 8.5, 11.5, 14.4};
// this gradient scales with shadow size
QRadialGradient rg(
size+hoffset,
size+voffset,
shadowSize );
QColor c = shadowConfiguration.innerColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
QRadialGradient rg = QRadialGradient( size, size, size );
QColor c = color;
c.setAlpha( 255 ); rg.setColorAt( 4.0/size, c );
c.setAlpha( 0 ); rg.setColorAt( 4.01/size, c );
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
} else {
{
int nPoints = 9;
qreal values[9] = { 0.17, 0.12, 0.11, 0.075, 0.06, 0.035, 0.025, 0.01, 0 };
qreal x[9] = {0, 4.5, 6.6, 8.5, 11.5, 14.5, 17.5, 21.5, 25.5 };
QRadialGradient rg = QRadialGradient(
size+20.0*hoffset,
size+20.0*voffset,
shadowSize );
QColor c = shadowConfiguration.outerColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
int nPoints = 7;
qreal values[7] = {0.55, 0.25, 0.20, 0.1, 0.06, 0.015, 0 };
qreal x[7] = {0, 4.5, 5.5, 7.5, 8.5, 11.5, 14.5 };
QRadialGradient rg = QRadialGradient(
size+10.0*hoffset,
size+10.0*voffset,
shadowSize );
QColor c = shadowConfiguration.midColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
int nPoints = 5;
qreal values[5] = { 1, 0.32, 0.22, 0.03, 0 };
qreal x[5] = { 0, 4.5, 5.0, 5.5, 6.5 };
QRadialGradient rg = QRadialGradient(
size+hoffset,
size+voffset,
shadowSize );
QColor c = shadowConfiguration.innerColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
QRadialGradient rg = QRadialGradient( size, size, size );
QColor c = color;
c.setAlpha( 255 ); rg.setColorAt( 4.0/size, c );
c.setAlpha( 0 ); rg.setColorAt( 4.01/size, c );
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
}
// draw the corner of the window - actually all 4 corners as one circle
// this is all fixedSize. Does not scale with shadow size
QLinearGradient lg = QLinearGradient(0.0, size-4.5, 0.0, size+4.5);
if( configuration().frameBorder() < OxygenConfiguration::BorderTiny )
{
lg.setColorAt(0.52, helper().backgroundTopColor(color));
lg.setColorAt(1.0, helper().backgroundBottomColor(color) );
} else {
QColor light = helper().calcLightColor( helper().backgroundTopColor(color) );
QColor dark = helper().calcDarkColor(helper().backgroundBottomColor(color));
lg.setColorAt(0.52, light);
lg.setColorAt(1.0, dark);
}
p.setBrush( Qt::NoBrush );
if( configuration().frameBorder() == OxygenConfiguration::BorderNone && !isShade() )
{ p.setClipRect( QRectF( 0, 0, 2*size, size ) ); }
p.setPen(QPen(lg, 0.8));
p.drawEllipse(QRectF(size-4, size-4, 8, 8));
p.end();
return shadow;
}
}

View File

@ -31,7 +31,6 @@
#include <kcommondecoration.h>
#include "oxygenconfiguration.h"
#include "oxygenshadowconfiguration.h"
#include "lib/helper.h"
#include "lib/tileset.h"
@ -65,10 +64,6 @@ namespace Oxygen
virtual bool drawSeparator( void ) const
{ return isActive() && configuration().drawSeparator() && !configuration().drawTitleOutline(); }
//! true when oxygen 'glow' shadow is to be drawn for active window
virtual bool useOxygenShadows( void ) const
{ return isActive() && configuration().useOxygenShadows(); }
//! dimensions
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
@ -120,12 +115,6 @@ namespace Oxygen
//! paint
void paintEvent( QPaintEvent* );
//! shadows
TileSet *shadowTiles(const QColor& color, bool active);
//! shadows
QPixmap shadowPixmap( const QColor& color, bool active ) const;
private:
//! calculate mask
@ -165,11 +154,6 @@ namespace Oxygen
//! size grip widget
OxygenSizeGrip* sizeGrip_;
OxygenShadowConfiguration inactiveShadowConfiguration_;
OxygenShadowConfiguration activeShadowConfiguration_;
TileSet *inactiveShadowTiles_;
TileSet *activeShadowTiles_;
//! helper
OxygenHelper& helper_;

View File

@ -0,0 +1,326 @@
//////////////////////////////////////////////////////////////////////////////
// oxygenshadowcache.cpp
// handles caching of TileSet objects to draw shadows
// -------------------
//
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////
#include "oxygenshadowcache.h"
#include "oxygenclient.h"
#include <KDebug>
#include <QPainter>
namespace Oxygen
{
//_______________________________________________________
bool OxygenShadowCache::shadowConfigurationChanged( const OxygenShadowConfiguration& other ) const
{
const OxygenShadowConfiguration& local = (other.colorGroup() == QPalette::Active ) ? activeShadowConfiguration_:inactiveShadowConfiguration_;
return !(local == other);
}
//_______________________________________________________
void OxygenShadowCache::setShadowConfiguration( const OxygenShadowConfiguration& other )
{
OxygenShadowConfiguration& local = (other.colorGroup() == QPalette::Active ) ? activeShadowConfiguration_:inactiveShadowConfiguration_;
local = other;
}
//_______________________________________________________
TileSet* OxygenShadowCache::tileSet( const OxygenClient* client )
{
// construct key
Key key = Key();
key.active = client->isActive();
key.useOxygenShadows = client->configuration().useOxygenShadows();
key.isShade = client->isShade();
key.hasNoBorder = client->configuration().frameBorder() == OxygenConfiguration::BorderNone;
key.hasTitleOutline = client->configuration().drawTitleOutline();
// check if tileset already in cache
int hash( key.hash() );
if( shadowCache_.contains(hash) ) return shadowCache_.object(hash);
// create tileset otherwise
qreal size( shadowSize() );
TileSet* tileSet = new TileSet( shadowPixmap( client, key.active ), size, size, 1, 1);
shadowCache_.insert( hash, tileSet );
return tileSet;
}
//_______________________________________________________
OxygenShadowCache::OxygenShadowCache( int maxIndex ):
maxIndex_( maxIndex ),
activeShadowConfiguration_( OxygenShadowConfiguration( QPalette::Active ) ),
inactiveShadowConfiguration_( OxygenShadowConfiguration( QPalette::Inactive ) )
{
kDebug(1212) << endl;
shadowCache_.setMaxCost( 1<<5 );
}
//_________________________________________________________________
QPixmap OxygenShadowCache::shadowPixmap(const OxygenClient* client, bool active ) const
{
// get window color
QPalette palette( client->backgroundPalette( client->widget(), client->widget()->palette() ) );
QColor color( palette.color( client->widget()->backgroundRole() ) );
if( active && client->configuration().drawTitleOutline() && client->configuration().frameBorder() == OxygenConfiguration::BorderNone )
{
// a more complex tile set is needed for the configuration above:
// top corners must be beveled with the "active titlebar color" while
// bottom corners must be beveled with the "window background color".
// this requires generating two shadow pixmaps and tiling them in the tileSet.
qreal size( shadowSize() );
QPixmap shadow( 2*size, 2*size );
shadow.fill( Qt::transparent );
QPainter p( &shadow );
p.setRenderHint( QPainter::Antialiasing );
QPixmap shadowTop = simpleShadowPixmap( color, client, active );
QRect topRect( shadow.rect() );
topRect.setBottom( int( size )-1 );
p.setClipRect( topRect );
p.drawPixmap( QPointF( 0, 0 ), shadowTop );
// get window color
palette = client->widget()->palette();
color = palette.color( client->widget()->backgroundRole() );
QPixmap shadowBottom = simpleShadowPixmap( color, client, active );
QRect bottomRect( shadow.rect() );
bottomRect.setTop( int( size ) );
p.setClipRect( bottomRect );
p.drawPixmap( QPointF( 0, 0 ), shadowBottom );
p.end();
return shadow;
} else return simpleShadowPixmap( color, client, active );
}
//_______________________________________________________
QPixmap OxygenShadowCache::simpleShadowPixmap( const QColor& color, const OxygenClient* client, bool active ) const
{
// local reference to relevant shadow configuration
const OxygenShadowConfiguration& shadowConfiguration(
active && client->configuration().useOxygenShadows() ?
activeShadowConfiguration_:inactiveShadowConfiguration_ );
static const qreal fixedSize = 25.5;
qreal size( shadowSize() );
qreal shadowSize( shadowConfiguration.shadowSize() );
QPixmap shadow = QPixmap( size*2, size*2 );
shadow.fill( Qt::transparent );
QPainter p( &shadow );
p.setRenderHint( QPainter::Antialiasing );
p.setPen( Qt::NoPen );
// offsets are scaled with the shadow size
// so that the ratio Top-shadow/Bottom-shadow is kept constant
// when shadow size is changed
qreal hoffset = shadowConfiguration.horizontalOffset()*shadowSize/fixedSize;
qreal voffset = shadowConfiguration.verticalOffset()*shadowSize/fixedSize;
if( active && client->configuration().useOxygenShadows() )
{
{
int values[5] = {255, 220, 180, 25, 0};
qreal x[5] = {4.4, 4.5, 5, 5.5, 6.5};
// the first point of this gradient does not scale
QRadialGradient rg( size, size, shadowSize );
QColor c = color;
for( int i = 0; i<5; i++ )
{ c.setAlpha( values[i] ); rg.setColorAt( x[0]/shadowSize+(x[i]-x[0])/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
// this gradient scales with shadow size
int nPoints = 8;
qreal values[8] = {1, 0.58, 0.43, 0.30, 0.22, 0.15, 0.08, 0 };
qreal x[8] = {0, 4.5, 5.5, 6.5, 7.5, 8.5, 11.5, 14.4};
// this gradient scales with shadow size
QRadialGradient rg(
size+hoffset,
size+voffset,
shadowSize );
QColor c = shadowConfiguration.innerColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
QRadialGradient rg = QRadialGradient( size, size, size );
QColor c = color;
c.setAlpha( 255 ); rg.setColorAt( 4.0/size, c );
c.setAlpha( 0 ); rg.setColorAt( 4.01/size, c );
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
} else {
{
int nPoints = 9;
qreal values[9] = { 0.17, 0.12, 0.11, 0.075, 0.06, 0.035, 0.025, 0.01, 0 };
qreal x[9] = {0, 4.5, 6.6, 8.5, 11.5, 14.5, 17.5, 21.5, 25.5 };
QRadialGradient rg = QRadialGradient(
size+20.0*hoffset,
size+20.0*voffset,
shadowSize );
QColor c = shadowConfiguration.outerColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
int nPoints = 7;
qreal values[7] = {0.55, 0.25, 0.20, 0.1, 0.06, 0.015, 0 };
qreal x[7] = {0, 4.5, 5.5, 7.5, 8.5, 11.5, 14.5 };
QRadialGradient rg = QRadialGradient(
size+10.0*hoffset,
size+10.0*voffset,
shadowSize );
QColor c = shadowConfiguration.midColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
int nPoints = 5;
qreal values[5] = { 1, 0.32, 0.22, 0.03, 0 };
qreal x[5] = { 0, 4.5, 5.0, 5.5, 6.5 };
QRadialGradient rg = QRadialGradient(
size+hoffset,
size+voffset,
shadowSize );
QColor c = shadowConfiguration.innerColor();
for( int i = 0; i<nPoints; i++ )
{ c.setAlphaF( values[i] ); rg.setColorAt( x[i]/fixedSize, c ); }
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
{
QRadialGradient rg = QRadialGradient( size, size, size );
QColor c = color;
c.setAlpha( 255 ); rg.setColorAt( 4.0/size, c );
c.setAlpha( 0 ); rg.setColorAt( 4.01/size, c );
p.setBrush( rg );
p.drawRect( shadow.rect() );
}
}
// draw the corner of the window - actually all 4 corners as one circle
// this is all fixedSize. Does not scale with shadow size
QLinearGradient lg = QLinearGradient(0.0, size-4.5, 0.0, size+4.5);
if( client->configuration().frameBorder() < OxygenConfiguration::BorderTiny )
{
lg.setColorAt(0.52, client->helper().backgroundTopColor(color));
lg.setColorAt(1.0, client->helper().backgroundBottomColor(color) );
} else {
QColor light = client->helper().calcLightColor( client->helper().backgroundTopColor(color) );
QColor dark = client->helper().calcDarkColor( client->helper().backgroundBottomColor(color));
lg.setColorAt(0.52, light);
lg.setColorAt(1.0, dark);
}
p.setBrush( Qt::NoBrush );
if( client->configuration().frameBorder() == OxygenConfiguration::BorderNone && !client->isShade() )
{ p.setClipRect( QRectF( 0, 0, 2*size, size ) ); }
p.setPen(QPen(lg, 0.8));
p.drawEllipse(QRectF(size-4, size-4, 8, 8));
p.end();
return shadow;
}
//_______________________________________________________
int OxygenShadowCache::Key::hash( void ) const
{
// note this can be optimized because not all of the flag configurations are actually relevant
// allocate 3 empty bits for flags
int out =
( active << 4 ) |
(useOxygenShadows << 3 ) |
(isShade<<2) |
(hasNoBorder<<1) |
(hasTitleOutline<<0);
return out;
}
}

View File

@ -0,0 +1,137 @@
#ifndef oxygenshadowcache_h
#define oxygenshadowcache_h
//////////////////////////////////////////////////////////////////////////////
// oxygenshadowcache.h
// handles caching of TileSet objects to draw shadows
// -------------------
//
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//////////////////////////////////////////////////////////////////////////////
#include <QCache>
#include "oxygenshadowconfiguration.h"
#include "lib/tileset.h"
namespace Oxygen
{
class OxygenClient;
class OxygenShadowCache
{
public:
//! constructor
OxygenShadowCache( int maxIndex );
//! destructor
virtual ~OxygenShadowCache( void )
{}
//! invalidate caches
void invalidateCaches( void )
{
shadowCache_.clear();
}
//! returns true if provided shadow configuration changes with respect to stored
/*!
use OxygenShadowConfiguration::colorRole() to decide whether it should be stored
as active or inactive
*/
bool shadowConfigurationChanged( const OxygenShadowConfiguration& ) const;
//! set shadowConfiguration
/*!
use OxygenShadowConfiguration::colorRole() to decide whether it should be stored
as active or inactive
*/
void setShadowConfiguration( const OxygenShadowConfiguration& );
//! shadow size
qreal shadowSize( void ) const
{ return qMax( activeShadowConfiguration_.shadowSize(), inactiveShadowConfiguration_.shadowSize() ); }
//! get shadow matching client
TileSet* tileSet( const OxygenClient* );
//! get shadow matching client and animation index
TileSet* tileSet( const OxygenClient*, int );
//! Key class to be used into QCache
class Key
{
public:
//! explicit constructor
explicit Key( void ):
active(false),
useOxygenShadows(false),
isShade(false),
hasNoBorder(false),
hasTitleOutline(false)
{}
//! hash function
int hash( void ) const;
bool active;
bool useOxygenShadows;
bool isShade;
bool hasNoBorder;
bool hasTitleOutline;
};
private:
//! complex pixmap (when needed)
QPixmap shadowPixmap( const OxygenClient*, bool active ) const;
//! simple pixmap
QPixmap simpleShadowPixmap( const QColor&, const OxygenClient*, bool active ) const;
private:
//! max index
/*! it is used to set caches max cost, and calculate animation opacity */
int maxIndex_;
//! shadow configuration
OxygenShadowConfiguration activeShadowConfiguration_;
//! shadow configuration
OxygenShadowConfiguration inactiveShadowConfiguration_;
//! cache
typedef QCache<int, TileSet> TileSetCache;
//! active shadow cache
TileSetCache shadowCache_;
};
}
#endif