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
This commit is contained in:
parent
7813c45245
commit
635c93bc5b
5 changed files with 203 additions and 66 deletions
|
@ -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)
|
||||
|
|
|
@ -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() )
|
||||
{
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue