diff --git a/clients/oxygen/CMakeLists.txt b/clients/oxygen/CMakeLists.txt index a1766789b4..5a6d2ae83f 100644 --- a/clients/oxygen/CMakeLists.txt +++ b/clients/oxygen/CMakeLists.txt @@ -17,6 +17,7 @@ set(kwin_oxygen_SRCS oxygenshadowconfiguration.cpp oxygenshadowcache.cpp oxygensizegrip.cpp + oxygentitleanimationdata.cpp ) kde4_add_plugin(kwin3_oxygen ${kwin_oxygen_SRCS}) diff --git a/clients/oxygen/oxygenclient.cpp b/clients/oxygen/oxygenclient.cpp index e04d163123..bf360cb32f 100644 --- a/clients/oxygen/oxygenclient.cpp +++ b/clients/oxygen/oxygenclient.cpp @@ -84,9 +84,8 @@ namespace Oxygen factory_( f ), sizeGrip_( 0 ), glowAnimation_( new Animation( 200, this ) ), - titleAnimation_( new Animation( 200, this ) ), + titleAnimationData_( new TitleAnimationData( this ) ), glowIntensity_(0), - titleOpacity_(0), initialized_( false ), forceActive_( false ), mouseButton_( Qt::NoButton ), @@ -126,15 +125,10 @@ namespace Oxygen connect( glowAnimation().data(), SIGNAL( finished( void ) ), widget(), SLOT( update( void ) ) ); connect( glowAnimation().data(), SIGNAL( finished() ), this, SLOT( clearForceActive() ) ); - // setup title animation - titleAnimation().data()->setStartValue( 0 ); - titleAnimation().data()->setEndValue( 1 ); - titleAnimation().data()->setTargetObject( this ); - titleAnimation().data()->setPropertyName( "titleOpacity" ); - titleAnimation().data()->setCurveShape( Animation::EaseInOutCurve ); - connect( titleAnimation().data(), SIGNAL( valueChanged( const QVariant& ) ), widget(), SLOT( update( void ) ) ); - connect( titleAnimation().data(), SIGNAL( finished( void ) ), widget(), SLOT( update( void ) ) ); - connect( titleAnimation().data(), SIGNAL( finished( void ) ), this, SLOT( updateOldCaption() ) ); + + // title animation data + titleAnimationData_.data()->initialize(); + connect( titleAnimationData_.data(), SIGNAL( pixmapsChanged() ), widget(), SLOT( update( void ) ) ); // lists connect( itemData_.animation().data(), SIGNAL( finished() ), this, SLOT( clearTargetItem() ) ); @@ -177,9 +171,12 @@ namespace Oxygen // animations duration glowAnimation().data()->setDuration( configuration_.animationsDuration() ); - titleAnimation().data()->setDuration( configuration_.animationsDuration() ); + titleAnimationData_.data()->setDuration( configuration_.animationsDuration() ); itemData_.animation().data()->setDuration( configuration_.animationsDuration() ); + // reset title transitions + titleAnimationData_.data()->reset(); + // should also update animations for buttons resetButtons(); @@ -190,9 +187,6 @@ namespace Oxygen if( item.closeButton_ ) { item.closeButton_.data()->reset(0); } } - // copy current caption to old - updateOldCaption(); - // reset tab geometry itemData_.setDirty( true ); @@ -814,51 +808,41 @@ namespace Oxygen void OxygenClient::renderTitleText( QPainter* painter, const QRect& rect, const QColor& color, const QColor& contrast ) const { - if( titleIsAnimated() ) + if( !titleAnimationData_.data()->isValid() ) + { + // contrast pixmap + titleAnimationData_.data()->reset( + rect, + renderTitleText( rect, caption(), color ), + renderTitleText( rect, caption(), contrast ) ); + } + + if( titleAnimationData_.data()->isDirty() ) { - // due to alpha blending issues, one must first draw the contrast text, - // then the plain text. - if( contrast.isValid() ) - { + // contrast pixmap + titleAnimationData_.data()->setPixmaps( + rect, + renderTitleText( rect, caption(), color ), + renderTitleText( rect, caption(), contrast ) ); - painter->translate( 0, 1 ); - if( !oldCaption().isEmpty() ) { + titleAnimationData_.data()->setDirty( false ); + titleAnimationData_.data()->startAnimation(); + renderTitleText( painter, rect, color, contrast ); - renderTitleText( - painter, rect, oldCaption(), - helper().alphaColor( contrast, 1.0 - titleOpacity() ), - QColor(), false ); + } else if( titleAnimationData_.data()->isAnimated() ) { + if( isMaximized() ) painter->translate( 0, 2 ); + if( !titleAnimationData_.data()->contrastPixmap().isNull() ) + { + painter->translate( 0, 1 ); + painter->drawPixmap( rect.topLeft(), titleAnimationData_.data()->contrastPixmap() ); + painter->translate( 0, -1 ); } - if( !caption().isEmpty() ) { + painter->drawPixmap( rect.topLeft(), titleAnimationData_.data()->pixmap() ); - renderTitleText( - painter, rect, caption(), - helper().alphaColor( contrast, titleOpacity() ), QColor() ); - - } - - painter->translate( 0, -1 ); - - } - - if( !oldCaption().isEmpty() ) { - - renderTitleText( - painter, rect, oldCaption(), - helper().alphaColor( color, 1.0 - titleOpacity() ), QColor(), false ); - - } - - if( !caption().isEmpty() ) { - - renderTitleText( - painter, rect, caption(), - helper().alphaColor( color, titleOpacity() ), QColor() ); - - } + if( isMaximized() ) painter->translate( 0, -2 ); } else if( !caption().isEmpty() ) { @@ -894,6 +878,26 @@ namespace Oxygen } + //_______________________________________________________________________ + QPixmap OxygenClient::renderTitleText( const QRect& rect, const QString& caption, const QColor& color, bool elide ) const + { + + QPixmap out( rect.size() ); + out.fill( Qt::transparent ); + if( caption.isEmpty() || !color.isValid() ) return out; + + QPainter painter( &out ); + painter.setFont( options()->font(isActive(), false) ); + Qt::Alignment alignment( configuration().titleAlignment() | Qt::AlignVCenter ); + QString local( elide ? QFontMetrics( painter.font() ).elidedText( caption, Qt::ElideRight, rect.width() ):caption ); + + painter.setPen( color ); + painter.drawText( out.rect(), alignment, local ); + painter.end(); + return out; + + } + //_______________________________________________________________________ void OxygenClient::renderItem( QPainter* painter, int index, const QPalette& palette ) { @@ -1154,10 +1158,11 @@ namespace Oxygen //_________________________________________________________ void OxygenClient::captionChange( void ) { + KCommonDecorationUnstable::captionChange(); itemData_.setDirty( true ); - if( !animateTitleChange() ) return; - titleAnimation().data()->restart(); + if( animateTitleChange() ) + { titleAnimationData_.data()->setDirty( true ); } } @@ -1495,6 +1500,8 @@ namespace Oxygen int itemClicked( OxygenClient::itemClicked( point ) ); if( itemClicked < 0 ) return false; + titleAnimationData_.data()->reset(); + QDrag *drag = new QDrag( widget() ); QMimeData *groupData = new QMimeData(); groupData->setData( clientGroupItemDragMimeType(), QString().setNum( itemId( itemClicked )).toAscii() ); @@ -1660,6 +1667,7 @@ namespace Oxygen } + titleAnimationData_.data()->reset(); return true; } diff --git a/clients/oxygen/oxygenclient.h b/clients/oxygen/oxygenclient.h index 8285a6c68e..e07e1f68fd 100644 --- a/clients/oxygen/oxygenclient.h +++ b/clients/oxygen/oxygenclient.h @@ -31,6 +31,7 @@ #include "oxygen.h" #include "oxygenclientgroupitemdata.h" #include "oxygenconfiguration.h" +#include "oxygentitleanimationdata.h" #include "lib/oxygenanimation.h" #include "lib/helper.h" @@ -51,9 +52,6 @@ namespace Oxygen //!Q_PROPERTY( qreal glowIntensity READ glowIntensity WRITE setGlowIntensity ) Q_PROPERTY( qreal glowIntensity READ glowIntensityUnbiased WRITE setGlowIntensity ) - //! declare title opacity - Q_PROPERTY( qreal titleOpacity READ titleOpacity WRITE setTitleOpacity ) - public: //! constructor @@ -262,6 +260,9 @@ namespace Oxygen /*! second color, if valid, is for contrast pixel */ virtual void renderTitleText( QPainter*, const QRect&, const QString&, const QColor&, const QColor& = QColor(), bool elide = true ) const; + //! title text + virtual QPixmap renderTitleText( const QRect&, const QString&, const QColor&, bool elide = true ) const; + //! GroupItem virtual void renderItem( QPainter*, int, const QPalette& ); @@ -286,31 +287,6 @@ namespace Oxygen //! return pixmap corresponding to a given tab, for dragging QPixmap itemDragPixmap( int, const QRect& ); - //!@name title animation - //@{ - - const Animation::Pointer& titleAnimation( void ) const - { return titleAnimation_; } - - bool titleIsAnimated( void ) const - { return titleAnimation().data()->isRunning(); } - - qreal titleOpacity( void ) const - { return titleOpacity_; } - - void setTitleOpacity( qreal value ) - { titleOpacity_ = value; } - - //@} - - //! old caption if any - const QString& oldCaption( void ) const - { return oldCaption_; } - - //! old caption - void setOldCaption( const QString& value ) - { oldCaption_ = value; } - //! return true when activity change are animated bool animateActiveChange( void ) const { return ( configuration().useAnimations() && !isPreview() ); } @@ -363,10 +339,6 @@ namespace Oxygen protected slots: - //! update old caption with current - void updateOldCaption( void ) - { setOldCaption( caption() ); } - //! set target item to -1 void clearTargetItem( void ); @@ -392,18 +364,12 @@ namespace Oxygen //! glow animation Animation::Pointer glowAnimation_; - //! title animation - Animation::Pointer titleAnimation_; + //! title animation data + TitleAnimationData::Pointer titleAnimationData_; //! glow intensity qreal glowIntensity_; - //! title opacity - qreal titleOpacity_; - - //! old caption - QString oldCaption_; - //! true when initialized bool initialized_; diff --git a/clients/oxygen/oxygentitleanimationdata.cpp b/clients/oxygen/oxygentitleanimationdata.cpp new file mode 100644 index 0000000000..faddb384a6 --- /dev/null +++ b/clients/oxygen/oxygentitleanimationdata.cpp @@ -0,0 +1,133 @@ +////////////////////////////////////////////////////////////////////////////// +// oxygentitleanimationdata.h +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// Copyright (c) 2003, 2004 David Johnson +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// 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 "oxygentitleanimationdata.h" +#include "oxygentitleanimationdata.moc" + +#include + +namespace Oxygen +{ + + //_________________________________________________________ + TitleAnimationData::TitleAnimationData( QObject* parent ): + QObject( parent ), + dirty_( false ), + animation_( new Animation( 200, this ) ), + opacity_(0) + {} + + //_________________________________________________________ + void TitleAnimationData::initialize( void ) + { + + // setup title animation + animation().data()->setStartValue( 0 ); + animation().data()->setEndValue( 1 ); + animation().data()->setTargetObject( this ); + animation().data()->setPropertyName( "opacity" ); + animation().data()->setCurveShape( Animation::EaseInOutCurve ); + connect( animation().data(), SIGNAL( valueChanged( const QVariant& ) ), SLOT( updatePixmaps( void ) ) ); + connect( animation().data(), SIGNAL( finished( void ) ), SLOT( updatePixmaps( void ) ) ); + + } + + + //_________________________________________________________ + void TitleAnimationData::setPixmaps( QRect rect, QPixmap pixmap, QPixmap contrast ) + { + + // stop animation + if( isAnimated() ) animation().data()->stop(); + + // update pixmaps + contrastPixmap_.initialize( rect, contrast ); + pixmap_.initialize( rect, pixmap ); + + setOpacity(0); + updatePixmaps(); + + } + + //_________________________________________________________ + void TitleAnimationData::updatePixmaps( void ) + { + contrastPixmap_.blend( opacity() ); + pixmap_.blend( opacity() ); + emit pixmapsChanged(); + } + + //_________________________________________________________ + void TitleAnimationData::BlendedPixmap::blend( qreal opacity ) + { + + currentPixmap_ = QPixmap( endRect_.size() ); + currentPixmap_.fill( Qt::transparent ); + + QPainter painter( ¤tPixmap_ ); + if( opacity < 1 && !startPixmap_.isNull() ) + { painter.drawPixmap( startRect_.topLeft() - endRect_.topLeft(), fade( startPixmap_, 1.0 - opacity ) ); } + + if( opacity > 0 && !endPixmap_.isNull() ) + { painter.drawPixmap( QPoint(0,0), fade( endPixmap_, opacity ) ); } + + painter.end(); + return; + + } + + //_________________________________________________________ + QPixmap TitleAnimationData::BlendedPixmap::fade( QPixmap source, qreal opacity ) const + { + + if( source.isNull() ) return QPixmap(); + + QPixmap out( source.size() ); + out.fill( Qt::transparent ); + + // do nothing if opacity is too small + if( opacity*255 < 1 ) return out; + + // draw pixmap + QPainter p( &out ); + p.drawPixmap( QPoint(0,0), source ); + + // opacity mask + if( opacity*255 <= 254 ) + { + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + QColor color( Qt::black ); + color.setAlphaF( opacity ); + p.fillRect(out.rect(), color ); + } + + p.end(); + return out; + + } + +} diff --git a/clients/oxygen/oxygentitleanimationdata.h b/clients/oxygen/oxygentitleanimationdata.h new file mode 100644 index 0000000000..08d6f60fdc --- /dev/null +++ b/clients/oxygen/oxygentitleanimationdata.h @@ -0,0 +1,226 @@ +#ifndef oxygentitleanimationdata_h +#define oxygentitleanimationdata_h + +////////////////////////////////////////////////////////////////////////////// +// oxygentitleanimationdata.h +// ------------------- +// +// Copyright (c) 2009 Hugo Pereira Da Costa +// Copyright (c) 2003, 2004 David Johnson +// Copyright (c) 2006, 2007 Riccardo Iaconelli +// +// 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 "lib/oxygenanimation.h" + +#include +#include +#include +#include + +namespace Oxygen +{ + + class TitleAnimationData: public QObject + { + + Q_OBJECT + + //! declare title opacity + Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity ) + + public: + + typedef QPointer Pointer; + + //! constructor + TitleAnimationData( QObject* ); + + //! reset + void reset( void ) + { + setOpacity(0); + contrastPixmap_.reset(); + pixmap_.reset(); + } + + //! initialize + void initialize( void ); + + // reset + void reset( QRect rect, QPixmap pixmap, QPixmap contrast ) + { + setOpacity(0); + contrastPixmap_.reset( rect, contrast ); + pixmap_.reset( rect, pixmap ); + } + + //! set pixmaps + void setPixmaps( QRect, QPixmap pixmap, QPixmap contrast ); + + //! duration + void setDuration( int duration ) + { + assert( animation() ); + animation().data()->setDuration( duration ); + } + + //! retrieve contrast pixmap + QPixmap contrastPixmap( void ) const + { return contrastPixmap_.currentPixmap(); } + + //! pixmap + QPixmap pixmap( void ) const + { return pixmap_.currentPixmap(); } + + //!@name animation + //@{ + + + bool isAnimated( void ) const + { return animation().data()->isRunning(); } + + //! start animation + void startAnimation( void ) + { + assert( !isAnimated() ); + animation().data()->start(); + } + + //@} + + //!@name opacity + //@{ + + qreal opacity( void ) const + { return opacity_; } + + void setOpacity( qreal value ) + { opacity_ = value; } + + //@} + + //! validity + bool isValid( void ) const + { return pixmap_.isValid(); } + + //! dirty flag + void setDirty( bool value ) + { dirty_ = value; } + + //! dirty flag + bool isDirty( void ) const + { return dirty_; } + + signals: + + virtual void pixmapsChanged( void ); + + protected slots: + + //! update pixmaps + virtual void updatePixmaps( void ); + + protected: + + //! animation object + const Animation::Pointer& animation( void ) const + { return animation_; } + + private: + + //! used to blend pixmap + class BlendedPixmap + { + + public: + + // reset everything + void reset( void ) + { + startRect_ = endRect_ = QRect(); + startPixmap_ = endPixmap_ = currentPixmap_ = QPixmap(); + } + + //! reset + void reset( const QRect& rect, QPixmap pixmap ) + { + startRect_ = endRect_ = rect; + startPixmap_ = endPixmap_ = currentPixmap_ = pixmap; + } + + // update pixmaps + void initialize( const QRect& rect, QPixmap pixmap ) + { + startRect_ = endRect_; + endRect_ = rect; + startPixmap_ = currentPixmap_; + endPixmap_ = pixmap; + } + + //! update currentPixmap by blending start and end pixmap + void blend( qreal opacity ); + + //! current pixmap + QPixmap currentPixmap( void ) const + { return currentPixmap_; } + + //! validity + bool isValid( void ) const + { return !(endRect_.isNull() || endPixmap_.isNull() ); } + + protected: + + // fade pixmap by some amount + QPixmap fade( QPixmap, qreal ) const; + + private: + + //! animation starting pixmap + QPixmap startPixmap_; + + //! animation ending pixmap + QPixmap endPixmap_; + + //! animation current pixmap + QPixmap currentPixmap_; + + QRect startRect_; + QRect endRect_; + + }; + + bool dirty_; + + BlendedPixmap contrastPixmap_; + BlendedPixmap pixmap_; + + //! title animation + Animation::Pointer animation_; + + //! title opacity + qreal opacity_; + + }; + + +} + +#endif