Added smooth transition between active and inactive state. This affects (when enabled) the window shadow,

the horizontal separator line, the titlebar text color and the title+border window outline. 


svn path=/trunk/KDE/kdebase/workspace/; revision=1025111
icc-effect-5.14.5
Hugo Pereira Da Costa 2009-09-18 01:32:27 +00:00
parent 7813c45245
commit 635c93bc5b
5 changed files with 203 additions and 66 deletions

View File

@ -156,32 +156,29 @@ namespace Oxygen
QPainter painter(this);
painter.setClipRect(this->rect().intersected( event->rect() ) );
painter.setRenderHints(QPainter::Antialiasing);
QPalette palette = OxygenButton::palette();
if( client_.isActive() ) palette.setCurrentColorGroup(QPalette::Active);
else palette.setCurrentColorGroup(QPalette::Inactive);
// window background
client_.renderWindowBackground( &painter, rect(), this, palette );
if( client_.isActive() && client_.configuration().drawTitleOutline() && !client_.isMaximized() )
// window border
if( client_.drawTitleOutline() && !client_.isMaximized() )
{ client_.renderWindowBorder( &painter, rect(), this, client_.backgroundPalette( this, palette ) ); }
// draw dividing line
painter.setRenderHints(QPainter::Antialiasing);
QRect frame = client_.widget()->rect();
int x = -this->geometry().x()+1;
int w = frame.width()-2;
const int titleHeight = client_.layoutMetric(KCommonDecoration::LM_TitleHeight);
// colors
QColor color = palette.window().color();
QColor light = helper_.calcLightColor( color );
QColor dark = helper_.calcDarkColor( color );
dark.setAlpha(120);
if( client_.drawSeparator() )
{ helper_.drawSeparator(&painter, QRect(x, titleHeight-1.5, w, 2), color, Qt::Horizontal); }
{ client_.renderSeparator( &painter, rect(), this, color ); }
// for menu button the application icon is used
if (type_ == ButtonMenu)

View File

@ -50,8 +50,9 @@ using namespace std;
namespace Oxygen
{
const int maxAnimationIndex( 256 );
K_GLOBAL_STATIC_WITH_ARGS(OxygenHelper, globalHelper, ("oxygenDeco"))
K_GLOBAL_STATIC_WITH_ARGS(OxygenShadowCache, globalShadowCache, (512))
K_GLOBAL_STATIC_WITH_ARGS(OxygenShadowCache, globalShadowCache, (maxAnimationIndex))
//___________________________________________
OxygenHelper *oxygenHelper()
@ -81,6 +82,7 @@ namespace Oxygen
KCommonDecorationUnstable(b, f),
colorCacheInvalid_(true),
sizeGrip_( 0 ),
timeLine_( 200, this ),
helper_(*globalHelper),
initialized_( false )
{ qAddPostRoutine(oxkwincleanupBefore); }
@ -105,6 +107,13 @@ namespace Oxygen
KCommonDecoration::init();
widget()->setAttribute(Qt::WA_NoSystemBackground );
widget()->setAutoFillBackground( false );
// initialize timeLine
timeLine_.setFrameRange( 0, maxAnimationIndex );
timeLine_.setCurveShape( QTimeLine::EaseInOutCurve );
connect( &timeLine_, SIGNAL( frameChanged( int ) ), widget(), SLOT( update() ) );
connect( &timeLine_, SIGNAL( finished() ), widget(), SLOT( update() ) );
initialized_ = true;
// in case of preview, one wants to make the label used
@ -184,10 +193,6 @@ namespace Oxygen
// make resizing easier
border = qMax(frameBorder, 4);
} else if( configuration().frameBorder() == OxygenConfiguration::BorderNone && isPreview() && !compositingActive() ) {
border = 1;
} else if( frameBorder < OxygenConfiguration::BorderTiny ) {
border = 0;
@ -379,7 +384,14 @@ namespace Oxygen
if( configuration().drawTitleOutline() )
{
return options()->color(ColorFont, isActive());
if( timeLineIsRunning() )
{
return KColorUtils::mix(
options()->color(ColorFont, false),
options()->color(ColorFont, true ), opacity() );
} else return options()->color(ColorFont, isActive());
} else if (isActive()) {
@ -443,9 +455,8 @@ namespace Oxygen
// save painter
painter->save();
if (clipRect.isValid()) {
painter->setClipRegion(clipRect,Qt::IntersectClip);
}
if( timeLineIsRunning() ) painter->setOpacity( opacity() );
if( clipRect.isValid() ) painter->setClipRegion(clipRect,Qt::IntersectClip);
QRect r = (isPreview()) ? OxygenClient::widget()->rect():window->rect();
qreal shadowSize( oxygenShadowCache()->shadowSize() );
@ -506,10 +517,59 @@ namespace Oxygen
}
//_________________________________________________________
void OxygenClient::renderSeparator( QPainter* painter, const QRect& clipRect, const QWidget* widget, const QColor& color ) const
{
const QWidget* window = (isPreview()) ? OxygenClient::widget() : widget->window();
// get coordinates relative to the client area
// this is annoying. One could use mapTo if this was taking const QWidget* and not
// const QWidget* as argument.
QPoint position( 0, 0 );
{
const QWidget* w = widget;
while ( w != window && !w->isWindow() && w != w->parentWidget() ) {
position += w->geometry().topLeft();
w = w->parentWidget();
}
}
// setup painter
painter->save();
if( timeLineIsRunning() ) painter->setOpacity( opacity() );
if (clipRect.isValid()) painter->setClipRegion(clipRect,Qt::IntersectClip);
QRect r = (isPreview()) ? OxygenClient::widget()->rect():window->rect();
qreal shadowSize( oxygenShadowCache()->shadowSize() );
r.adjust( shadowSize, shadowSize, -shadowSize, -shadowSize );
r.adjust(0,0, 1, 1);
int extraBorder = ( isMaximized() && compositingActive() ) ? 0 : EXTENDED_HITAREA;
// dimensions
const int titleHeight = layoutMetric(LM_TitleHeight);
const int titleTop = layoutMetric(LM_TitleEdgeTop) + r.top() - extraBorder;
// dimensions
int x,y,w,h;
r.getRect(&x, &y, &w, &h);
helper().drawSeparator( painter, QRect(x, titleTop+titleHeight-1.5, w, 2).translated( -position ), color, Qt::Horizontal);
painter->restore();
}
//_________________________________________________________
void OxygenClient::renderTitleOutline( QPainter* painter, const QRect& rect, const QPalette& palette ) const
{
if( timeLineIsRunning() )
{
painter->save();
painter->setOpacity( opacity() );
}
// shadow
{
int shadowSize = 7;
@ -524,6 +584,8 @@ namespace Oxygen
renderWindowBackground(painter, rect.adjusted( 4, voffset, -4, -4 ), widget(), palette );
}
if( timeLineIsRunning() ) painter->restore();
}
//_________________________________________________________
@ -537,6 +599,14 @@ namespace Oxygen
sizeGrip().update();
}
// reset animation
if( animateActiveChange() )
{
timeLine_.setDirection( isActive() ? QTimeLine::Forward : QTimeLine::Backward );
if(timeLine_.state() == QTimeLine::NotRunning )
{ timeLine_.start(); }
}
KCommonDecorationUnstable::activeChange();
}
@ -627,9 +697,20 @@ namespace Oxygen
if( compositingActive() && !isMaximized() )
{
oxygenShadowCache()->tileSet( this )->render(
frame.adjusted( 4, 4, -4, -4),
&painter, TileSet::Ring);
if( configuration().useOxygenShadows() && timeLineIsRunning() )
{
oxygenShadowCache()->tileSet( this, timeLine_.currentFrame() )->render(
frame.adjusted( 4, 4, -4, -4),
&painter, TileSet::Ring);
} else {
oxygenShadowCache()->tileSet( this )->render(
frame.adjusted( 4, 4, -4, -4),
&painter, TileSet::Ring);
}
}
@ -678,38 +759,11 @@ namespace Oxygen
// window background
renderWindowBackground( &painter, frame, widget(), palette );
if( isActive() && configuration().drawTitleOutline() && !isMaximized() )
{
renderWindowBorder( &painter, frame, widget(), backgroundPalette( widget(), palette ) );
}
if( drawTitleOutline() && !isMaximized() ) renderWindowBorder( &painter, frame, widget(), backgroundPalette( widget(), palette ) );
// clipping
if( compositingActive() ) painter.setClipping(false);
// in preview mode and when frame border is 0,
// one still draw a small rect around, unless kde is recent enough,
// useOxygenShadow is set to true,
// and copositing is active
// (that makes a lot of ifs)
if( isPreview() && configuration().frameBorder() == OxygenConfiguration::BorderNone && !compositingActive() )
{
painter.save();
painter.setBrush( Qt::NoBrush );
painter.setPen( QPen( helper().calcDarkColor( widget()->palette().window().color() ), 1 ) );
QPainterPath path;
QPoint first( frame.topLeft()+QPoint( 0, 6 ) );
path.moveTo( first );
path.quadTo( frame.topLeft(), frame.topLeft()+QPoint( 6, 0 ) );
path.lineTo( frame.topRight()-QPoint( 6, 0 ) );
path.quadTo( frame.topRight(), frame.topRight()+QPoint( 0, 6 ) );
path.lineTo( frame.bottomRight() );
path.lineTo( frame.bottomLeft() );
path.lineTo( first );
painter.drawPath( path );
painter.restore();
}
int extraBorder = ( isMaximized() && compositingActive() ) ? 0 : EXTENDED_HITAREA;
// dimensions
@ -728,7 +782,7 @@ namespace Oxygen
QRect titleRect( titleLeft, titleTop-1, titleWidth, titleHeight );
painter.setFont( options()->font(isActive(), false) );
if( isActive() && configuration().drawTitleOutline() )
if( drawTitleOutline() )
{
// get title bounding rect
@ -739,11 +793,13 @@ namespace Oxygen
boundingRect.setBottom( titleTop+titleHeight );
boundingRect.setLeft( qMax( boundingRect.left(), titleLeft ) - 2*HFRAMESIZE );
boundingRect.setRight( qMin( boundingRect.right(), titleLeft + titleWidth ) + 2*HFRAMESIZE );
renderTitleOutline( &painter, boundingRect, backgroundPalette( widget(), palette ) );
}
// separator
if( drawSeparator() ) renderSeparator(&painter, frame, widget(), color );
// draw title text
painter.setPen( titlebarTextColor( backgroundPalette( widget(), palette ) ) );
@ -751,16 +807,12 @@ namespace Oxygen
painter.setRenderHint(QPainter::Antialiasing);
// adjust if there are shadows
if (compositingActive()) frame.adjust(-1,-1, 1, 1);
if( compositingActive() ) frame.adjust(-1,-1, 1, 1);
// dimensions
int x,y,w,h;
frame.getRect(&x, &y, &w, &h);
// separator
if( drawSeparator() )
{ helper().drawSeparator(&painter, QRect(x, titleTop+titleHeight-1.5, w, 2), color, Qt::Horizontal); }
// shadow and resize handles
if( configuration().frameBorder() >= OxygenConfiguration::BorderTiny && !isMaximized() )
{

View File

@ -29,6 +29,7 @@
//////////////////////////////////////////////////////////////////////////////
#include <kcommondecoration.h>
#include <QTimeLine>
#include "oxygenconfiguration.h"
#include "lib/helper.h"
@ -60,9 +61,22 @@ namespace Oxygen
//! true if window is maximized
virtual bool isMaximized( void ) const;
//! true when title outline is to be drawn
bool drawTitleOutline( void ) const
{
return
( timeLineIsRunning() || isActive() ) &&
configuration().drawTitleOutline();
}
//! true when separator is to be drawn
virtual bool drawSeparator( void ) const
{ return isActive() && configuration().drawSeparator() && !configuration().drawTitleOutline(); }
bool drawSeparator( void ) const
{
return
( timeLineIsRunning() || isActive() ) &&
configuration().drawSeparator() &&
!configuration().drawTitleOutline();
}
//! dimensions
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
@ -93,6 +107,9 @@ namespace Oxygen
// this draws a "blue" border around active window
virtual void renderWindowBorder( QPainter*, const QRect&, const QWidget*, const QPalette& ) const;
//! separator
virtual void renderSeparator( QPainter*, const QRect&, const QWidget*, const QColor& ) const;
//! title outline
virtual void renderTitleOutline( QPainter*, const QRect&, const QPalette& ) const;
@ -117,6 +134,23 @@ namespace Oxygen
private:
//! return true when activity change are animated
bool animateActiveChange( void ) const
{
return
configuration().useOxygenShadows() ||
configuration().drawSeparator() ||
configuration().drawTitleOutline();
}
//! return true if timeLine is running
bool timeLineIsRunning( void ) const
{ return timeLine_.state() == QTimeLine::Running; }
//! return animation opacity
qreal opacity( void ) const
{ return qreal( timeLine_.currentFrame() )/qreal( timeLine_.endFrame() ); }
//! calculate mask
QRegion calcMask( void ) const;
@ -154,6 +188,9 @@ namespace Oxygen
//! size grip widget
OxygenSizeGrip* sizeGrip_;
//! animation timeLine
QTimeLine timeLine_;
//! helper
OxygenHelper& helper_;

View File

@ -27,12 +27,25 @@
#include "oxygenshadowcache.h"
#include "oxygenclient.h"
#include <cassert>
#include <KDebug>
#include <QPainter>
namespace Oxygen
{
//_______________________________________________________
OxygenShadowCache::OxygenShadowCache( int maxIndex ):
maxIndex_( maxIndex ),
activeShadowConfiguration_( OxygenShadowConfiguration( QPalette::Active ) ),
inactiveShadowConfiguration_( OxygenShadowConfiguration( QPalette::Inactive ) )
{
kDebug(1212) << endl;
shadowCache_.setMaxCost( 1<<5 );
animatedShadowCache_.setMaxCost( maxIndex_<<5 );
}
//_______________________________________________________
bool OxygenShadowCache::shadowConfigurationChanged( const OxygenShadowConfiguration& other ) const
{
@ -72,13 +85,44 @@ namespace Oxygen
}
//_______________________________________________________
OxygenShadowCache::OxygenShadowCache( int maxIndex ):
maxIndex_( maxIndex ),
activeShadowConfiguration_( OxygenShadowConfiguration( QPalette::Active ) ),
inactiveShadowConfiguration_( OxygenShadowConfiguration( QPalette::Inactive ) )
TileSet* OxygenShadowCache::tileSet( const OxygenClient* client, int index )
{
kDebug(1212) << endl;
shadowCache_.setMaxCost( 1<<5 );
assert( index <= maxIndex_ );
// construct key
Key key = Key();
key.index = index;
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( animatedShadowCache_.contains(hash) ) return animatedShadowCache_.object(hash);
// create shadow and tileset otherwise
qreal size( shadowSize() );
qreal opacity( qreal(index)/qreal(maxIndex_) );
QPixmap shadow( size*2, size*2 );
shadow.fill( Qt::transparent );
QPainter p( &shadow );
p.setRenderHint( QPainter::Antialiasing );
p.setOpacity( 1.0 - opacity );
p.drawPixmap( QPointF(0,0), shadowPixmap( client, false ) );
p.setOpacity( opacity );
p.drawPixmap( QPointF(0,0), shadowPixmap( client, true ) );
p.end();
TileSet* tileSet = new TileSet(shadow, size, size, 1, 1);
animatedShadowCache_.insert( hash, tileSet );
return tileSet;
}
//_________________________________________________________________
@ -313,6 +357,7 @@ namespace Oxygen
// note this can be optimized because not all of the flag configurations are actually relevant
// allocate 3 empty bits for flags
int out =
( index << 5 ) |
( active << 4 ) |
(useOxygenShadows << 3 ) |
(isShade<<2) |

View File

@ -52,6 +52,7 @@ namespace Oxygen
void invalidateCaches( void )
{
shadowCache_.clear();
animatedShadowCache_.clear();
}
//! returns true if provided shadow configuration changes with respect to stored
@ -86,6 +87,7 @@ namespace Oxygen
//! explicit constructor
explicit Key( void ):
index(0),
active(false),
useOxygenShadows(false),
isShade(false),
@ -96,6 +98,7 @@ namespace Oxygen
//! hash function
int hash( void ) const;
int index;
bool active;
bool useOxygenShadows;
bool isShade;
@ -127,9 +130,12 @@ namespace Oxygen
//! cache
typedef QCache<int, TileSet> TileSetCache;
//! active shadow cache
//! shadow cache
TileSetCache shadowCache_;
//! animated shadow cache
TileSetCache animatedShadowCache_;
};
}