From 87a43fad9d2224631a28987aa7c18076239176a6 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser <muesli@gmail.com> Date: Wed, 13 Aug 2014 07:49:21 +0200 Subject: [PATCH] * Simplify GridItemDelegate using HoverControls widget and adopt new style. --- src/libtomahawk/playlist/GridItemDelegate.cpp | 288 +++++++++--------- src/libtomahawk/playlist/GridItemDelegate.h | 13 +- 2 files changed, 143 insertions(+), 158 deletions(-) diff --git a/src/libtomahawk/playlist/GridItemDelegate.cpp b/src/libtomahawk/playlist/GridItemDelegate.cpp index 2a9d606a0..68b8e3251 100644 --- a/src/libtomahawk/playlist/GridItemDelegate.cpp +++ b/src/libtomahawk/playlist/GridItemDelegate.cpp @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> === * - * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org> + * Copyright 2010-2014, Christian Muehlhaeuser <muesli@tomahawk-player.org> * Copyright 2011-2012, Leo Franchi <lfranchi@kde.org> * * Tomahawk is free software: you can redistribute it and/or modify @@ -34,6 +34,7 @@ #include "audio/AudioEngine.h" #include "playlist/PlayableItem.h" #include "playlist/PlayableProxyModel.h" +#include "widgets/HoverControls.h" #include "widgets/ImageButton.h" #include "utils/TomahawkStyle.h" #include "utils/TomahawkUtilsGui.h" @@ -43,7 +44,7 @@ #include "utils/Logger.h" namespace { - static const int FADE_DURATION = 200; + static const int FADE_DURATION = 400; }; @@ -88,9 +89,11 @@ GridItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, QStyleOptionViewItemV4 opt = option; initStyleOption( &opt, QModelIndex() ); - qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter ); +// qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter ); QRect r = option.rect; + r.setHeight( r.width() ); + QString top, bottom; if ( !item->album().isNull() ) { @@ -138,94 +141,93 @@ GridItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, QSharedPointer< Tomahawk::PixmapDelegateFader > fader = m_covers[ index ]; if ( fader->size() != r.size() ) fader->setSize( r.size() ); - const QPixmap cover = fader->currentPixmap(); - painter->drawPixmap( r, cover ); - qreal opacity = -1.; + qreal opacity = -1.0; + qreal pct = -1.0; if ( m_hoverFaders.contains( index ) ) { - const qreal pct = ( m_hoverFaders[ index ]->currentFrame() / 100.0 ); - opacity = 0.15 - pct * 0.15; + pct = ( m_hoverFaders[ index ]->currentFrame() / 100.0 ); + opacity = 1.0 - pct * 0.70; } else if ( m_hoverIndex == index ) { - opacity = 0.15; + opacity = 0.3; + pct = 1.0; } - if ( opacity > -1.0 ) { painter->save(); - painter->setPen( TomahawkStyle::HOVER_GLOW ); - painter->setBrush( TomahawkStyle::HOVER_GLOW ); - painter->setOpacity( opacity ); + const int cropIn = pct * ( (qreal)cover.width() * 0.10 ); + const QRect crop = cover.rect().adjusted( cropIn, cropIn, -cropIn, -cropIn ); + + painter->drawPixmap( r, cover.copy( crop ).scaled( r.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) ); + + painter->setOpacity( 1.0 - opacity ); + painter->setPen( Qt::transparent ); + painter->setBrush( Qt::black ); painter->drawRect( r ); painter->restore(); } + else + { + painter->drawPixmap( r, cover ); + } QTextOption to; to.setWrapMode( QTextOption::NoWrap ); QString text; QFont font = opt.font; - font.setPointSize( TomahawkUtils::defaultFontSize() ); - QFont boldFont = font; - boldFont.setBold( true ); - boldFont.setPointSize( TomahawkUtils::defaultFontSize() + 1 ); + font.setPointSize( TomahawkUtils::defaultFontSize() + 2 ); + QFont smallFont = font; + smallFont.setBold( true ); + smallFont.setPointSize( TomahawkUtils::defaultFontSize() ); - int bottomHeight = QFontMetrics( font ).boundingRect( bottom ).height(); - int topHeight = QFontMetrics( boldFont ).boundingRect( top ).height(); - int frameHeight = bottomHeight + topHeight + 10; - - QRect gradientRect = r.adjusted( 0, r.height() - frameHeight * 1.2, 0, 0 ); - QColor gradientColor = opt.palette.background().color(); - gradientColor.setAlphaF( 0.66 ); - - painter->save(); - painter->setPen( Qt::transparent ); - painter->setBrush( gradientColor ); - painter->drawRect( gradientRect ); - painter->restore(); + int bottomHeight = QFontMetrics( smallFont ).boundingRect( bottom ).height(); + int topHeight = QFontMetrics( font ).boundingRect( top ).height(); painter->setPen( TomahawkStyle::SELECTION_FOREGROUND ); - QRect textRect = option.rect.adjusted( 6, option.rect.height() - frameHeight, -6, -6 ); + QRect textRect = option.rect.adjusted( 0, r.height() + 8, 0, 0 ); bool oneLiner = false; if ( bottom.isEmpty() ) oneLiner = true; - painter->setFont( boldFont ); + painter->setFont( font ); + painter->setPen( Qt::black ); if ( oneLiner ) { - to.setAlignment( Qt::AlignHCenter | Qt::AlignVCenter ); + to.setAlignment( Qt::AlignLeft | Qt::AlignTop ); text = painter->fontMetrics().elidedText( top, Qt::ElideRight, textRect.width() - 3 ); painter->drawText( textRect, text, to ); } else { - to.setAlignment( Qt::AlignHCenter | Qt::AlignTop ); + to.setAlignment( Qt::AlignLeft | Qt::AlignTop ); text = painter->fontMetrics().elidedText( top, Qt::ElideRight, textRect.width() - 3 ); painter->drawText( textRect, text, to ); - painter->setFont( font ); - // If the user is hovering over an artist rect, draw a background so she knows it's clickable - QRect r = textRect; + painter->setOpacity( 0.5 ); + painter->setFont( smallFont ); + // If the user is hovering over an artist rect, draw a background so they knows it's clickable +/* QRect r = textRect; r.setTop( r.bottom() - painter->fontMetrics().height() ); r.adjust( 4, 0, -4, -1 ); if ( m_hoveringOver == index ) { TomahawkUtils::drawQueryBackground( painter, r ); painter->setPen( TomahawkStyle::SELECTION_FOREGROUND ); - } + }*/ - to.setAlignment( Qt::AlignHCenter | Qt::AlignBottom ); + to.setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); text = painter->fontMetrics().elidedText( bottom, Qt::ElideRight, textRect.width() - 10 ); - painter->drawText( textRect.adjusted( 5, -1, -5, -1 ), text, to ); + painter->drawText( textRect.adjusted( 0, 2, 0, 2 ), text, to ); // Calculate rect of artist on-hover button click area - m_artistNameRects[ index ] = r; +// m_artistNameRects[ index ] = r; } painter->restore(); @@ -241,8 +243,10 @@ GridItemDelegate::onPlayClicked( const QPersistentModelIndex& index ) spinner->setAutoCenter( false ); spinner->fadeIn(); - QPoint pos = m_view->visualRect( index ).center() - QPoint( ( spinner->width() ) / 2 - 1, - ( spinner->height() ) / 2 - 1 ); + QRect r = m_view->visualRect( index ); + r.setHeight( r.width() ); + QPoint pos = r.center() - QPoint( ( spinner->width() ) / 2 - 1, + ( spinner->height() ) / 2 - 1 ); spinner->move( pos ); spinner->setFocusPolicy( Qt::NoFocus ); @@ -294,32 +298,33 @@ GridItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const Q else m_view->setCursor( Qt::ArrowCursor ); - foreach ( const QModelIndex& idx, m_playButton.keys() ) + foreach ( const QModelIndex& idx, m_hoverControls.keys() ) { if ( index != idx ) - m_playButton.take( idx )->deleteLater(); + m_hoverControls.take( idx )->deleteLater(); } - if ( !m_playButton.contains( index ) && !m_spinner.contains( index ) && !m_pauseButton.contains( index ) ) + if ( !m_hoverControls.contains( index ) && !m_spinner.contains( index ) ) { - foreach ( ImageButton* button, m_playButton ) - button->deleteLater(); - m_playButton.clear(); + foreach ( HoverControls* control, m_hoverControls ) + control->deleteLater(); + m_hoverControls.clear(); - ImageButton* button = new ImageButton( m_view ); - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PlayButton, TomahawkUtils::Original, QSize( 48, 48 ) ) ); - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PlayButtonPressed, TomahawkUtils::Original, QSize( 48, 48 ) ), QIcon::Off, QIcon::Active ); - button->setFixedSize( 48, 48 ); - button->move( option.rect.center() - QPoint( 23, 23 ) ); - button->setContentsMargins( 0, 0, 0, 0 ); - button->setFocusPolicy( Qt::NoFocus ); - button->installEventFilter( this ); - button->show(); + QRect cRect = option.rect; + cRect.setHeight( cRect.width() ); - NewClosure( button, SIGNAL( clicked( bool ) ), + HoverControls* controls = new HoverControls( m_view ); + controls->setFixedSize( 64, 40 ); + controls->move( cRect.center() - QPoint( controls->width() / 2 -1, controls->height() / 2 -1 ) ); + controls->setContentsMargins( 0, 0, 0, 0 ); + controls->setFocusPolicy( Qt::NoFocus ); + controls->installEventFilter( this ); + controls->show(); + + NewClosure( controls, SIGNAL( play() ), const_cast<GridItemDelegate*>(this), SLOT( onPlayClicked( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); - m_playButton[ index ] = button; + m_hoverControls[ index ] = controls; } if ( m_hoveringOver != index || ( !hoveringArtist && m_hoveringOver.isValid() ) ) @@ -338,19 +343,35 @@ GridItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const Q { if ( m_hoverIndex.isValid() ) { - QTimeLine* fadeOut = createTimeline( QTimeLine::Forward ); + int startFrame = 100; + if ( m_hoverFaders.contains( m_hoverIndex ) ) + { + QTimeLine* oldFader = m_hoverFaders.take( m_hoverIndex ); + startFrame = oldFader->currentFrame(); + oldFader->deleteLater(); + } + + QTimeLine* fadeOut = createTimeline( QTimeLine::Backward, startFrame ); _detail::Closure* c = NewClosure( fadeOut, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); c->setAutoDelete( false ); c = NewClosure( fadeOut, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); c->setAutoDelete( false ); + m_hoverFaders[ m_hoverIndex ] = fadeOut; fadeOut->start(); } - emit updateIndex( m_hoverIndex ); - m_hoverIndex = index; - QTimeLine* fadeIn = createTimeline( QTimeLine::Backward ); + m_hoverIndex = index; + int startFrame = 0; + if ( m_hoverFaders.contains( index ) ) + { + QTimeLine* oldFader = m_hoverFaders.take( index ); + startFrame = oldFader->currentFrame(); + oldFader->deleteLater(); + } + + QTimeLine* fadeIn = createTimeline( QTimeLine::Forward, startFrame ); _detail::Closure* c = NewClosure( fadeIn, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); c->setAutoDelete( false ); c = NewClosure( fadeIn, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( index ) ); @@ -428,17 +449,14 @@ GridItemDelegate::onViewChanged() foreach ( const QPersistentModelIndex& index, m_spinner.keys() ) { QRect rect = m_view->visualRect( index ); - m_spinner.value( index )->move( rect.center() - QPoint( 23, 23 ) ); + rect.setHeight( rect.width() ); + m_spinner.value( index )->move( rect.center() - QPoint( 15, 15 ) ); } - foreach ( const QPersistentModelIndex& index, m_playButton.keys() ) + foreach ( const QPersistentModelIndex& index, m_hoverControls.keys() ) { QRect rect = m_view->visualRect( index ); - m_playButton.value( index )->move( rect.center() - QPoint( 23, 23 ) ); - } - foreach ( const QPersistentModelIndex& index, m_pauseButton.keys() ) - { - QRect rect = m_view->visualRect( index ); - m_pauseButton.value( index )->move( rect.center() - QPoint( 23, 23 ) ); + rect.setHeight( rect.width() ); + m_hoverControls.value( index )->move( rect.center() - QPoint( m_hoverControls[ index ]->width() / 2 -1, m_hoverControls[ index ]->height() / 2 -1 ) ); } } @@ -452,57 +470,16 @@ GridItemDelegate::onPlaybackFinished() } -void -GridItemDelegate::onPlayPauseHover( const QPersistentModelIndex& index ) -{ - if( m_pauseButton.contains( index ) ) - { - updatePlayPauseButton( m_pauseButton[ index ] ); - } -} - - -void -GridItemDelegate::updatePlayPauseButton( ImageButton* button, bool setState ) -{ - if ( button ) - { - if ( button->property( "paused" ).toBool() ) - { - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PauseButton, TomahawkUtils::Original, QSize( 48, 48 ) ) ); - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PauseButtonPressed, TomahawkUtils::Original, QSize( 48, 48 ) ), QIcon::Off, QIcon::Active ); - } - else - { - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PlayButton, TomahawkUtils::Original, QSize( 48, 48 ) ) ); - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PlayButtonPressed, TomahawkUtils::Original, QSize( 48, 48 ) ), QIcon::Off, QIcon::Active ); - } - - if ( setState ) - button->setProperty( "paused", !button->property( "paused" ).toBool() ); - } -} - - -void -GridItemDelegate::onPlayPausedClicked() -{ - ImageButton* button = qobject_cast< ImageButton* >( QObject::sender() ); - updatePlayPauseButton( button, true ); -} - - void GridItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) { - if( m_spinner.contains( index ) ) + if ( m_spinner.contains( index ) ) { LoadingSpinner* spinner = static_cast<LoadingSpinner*>(m_spinner[ index ]); spinner->fadeOut(); } clearButtons(); - createPauseButton( index ); emit startedPlaying( index ); } @@ -511,12 +488,10 @@ GridItemDelegate::onPlaybackStarted( const QPersistentModelIndex& index ) void GridItemDelegate::clearButtons() { - foreach ( ImageButton* button, m_playButton ) - button->deleteLater(); - m_playButton.clear(); - foreach ( ImageButton* button, m_pauseButton ) - button->deleteLater(); - m_pauseButton.clear(); + foreach ( HoverControls* control, m_hoverControls ) + control->deleteLater(); + m_hoverControls.clear(); + foreach ( QWidget* widget, m_spinner ) widget->deleteLater(); m_spinner.clear(); @@ -539,9 +514,30 @@ GridItemDelegate::onCurrentIndexChanged() void GridItemDelegate::resetHoverIndex() { - foreach ( ImageButton* button, m_playButton ) - button->deleteLater(); - m_playButton.clear(); + foreach ( HoverControls* controls, m_hoverControls ) + controls->deleteLater(); + m_hoverControls.clear(); + + if ( m_hoverIndex.isValid() ) + { + int startFrame = 100; + if ( m_hoverFaders.contains( m_hoverIndex ) ) + { + QTimeLine* oldFader = m_hoverFaders.take( m_hoverIndex ); + startFrame = oldFader->currentFrame(); + oldFader->deleteLater(); + } + + QTimeLine* fadeOut = createTimeline( QTimeLine::Backward, startFrame ); + _detail::Closure* c = NewClosure( fadeOut, SIGNAL( frameChanged( int ) ), this, SLOT( fadingFrameChanged( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); + c->setAutoDelete( false ); + c = NewClosure( fadeOut, SIGNAL( finished() ), this, SLOT( fadingFrameFinished( QPersistentModelIndex ) ), QPersistentModelIndex( m_hoverIndex ) ); + c->setAutoDelete( false ); + + m_hoverFaders[ m_hoverIndex ] = fadeOut; + fadeOut->start(); + } + emit updateIndex( m_hoverIndex ); QModelIndex idx = m_hoveringOver; m_hoveringOver = QPersistentModelIndex(); @@ -550,27 +546,6 @@ GridItemDelegate::resetHoverIndex() } -void -GridItemDelegate::createPauseButton( const QPersistentModelIndex& index ) -{ - ImageButton* button = new ImageButton( m_view ); - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PauseButton, TomahawkUtils::Original, QSize( 48, 48 ) ) ); - button->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::PauseButtonPressed, TomahawkUtils::Original, QSize( 48, 48 ) ), QIcon::Off, QIcon::Active ); - button->setFixedSize( 48, 48 ); - button->move( m_view->visualRect( index ).center() - QPoint( 23, 23 ) ); - button->setContentsMargins( 0, 0, 0, 0 ); - button->setFocusPolicy( Qt::NoFocus ); - button->installEventFilter( this ); - button->setProperty( "paused", false ); - button->show(); - - connect( button, SIGNAL( clicked( bool ) ), AudioEngine::instance(), SLOT( playPause() ) ); - connect( button, SIGNAL( clicked( bool ) ), this, SLOT( onPlayPausedClicked() ) ); - - m_pauseButton[ index ] = button; -} - - void GridItemDelegate::fadingFrameChanged( const QPersistentModelIndex& idx ) { @@ -590,14 +565,29 @@ GridItemDelegate::fadingFrameFinished( const QPersistentModelIndex& idx ) QTimeLine* -GridItemDelegate::createTimeline( QTimeLine::Direction direction ) +GridItemDelegate::createTimeline( QTimeLine::Direction direction, int startFrame ) { - QTimeLine* timeline = new QTimeLine( FADE_DURATION, this ); + qreal dur = (qreal)FADE_DURATION * ( 1.0 - (qreal)startFrame / 100.0 ); + if ( direction == QTimeLine::Backward ) + { + dur = (qreal)FADE_DURATION * ( (qreal)startFrame / 100.0 ); + } + + QTimeLine* timeline = new QTimeLine( dur, this ); timeline->setDirection( direction ); timeline->setCurveShape( QTimeLine::LinearCurve ); - timeline->setUpdateInterval( 30 ); - timeline->setStartFrame( 0 ); - timeline->setEndFrame( 100 ); + timeline->setUpdateInterval( 20 ); + + if ( direction == QTimeLine::Forward ) + { + timeline->setStartFrame( startFrame ); + timeline->setEndFrame( 100 ); + } + else + { + timeline->setStartFrame( 0 ); + timeline->setEndFrame( startFrame ); + } return timeline; } diff --git a/src/libtomahawk/playlist/GridItemDelegate.h b/src/libtomahawk/playlist/GridItemDelegate.h index 002daa589..741e928f1 100644 --- a/src/libtomahawk/playlist/GridItemDelegate.h +++ b/src/libtomahawk/playlist/GridItemDelegate.h @@ -1,6 +1,6 @@ /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> === * - * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org> + * Copyright 2010-2014, Christian Muehlhaeuser <muesli@tomahawk-player.org> * Copyright 2011-2012, Leo Franchi <lfranchi@kde.org> * * Tomahawk is free software: you can redistribute it and/or modify @@ -37,6 +37,7 @@ class QEvent; class QTimeLine; class PlayableProxyModel; class ImageButton; +class HoverControls; class DLLEXPORT GridItemDelegate : public QStyledItemDelegate { @@ -79,13 +80,8 @@ private slots: void fadingFrameChanged( const QPersistentModelIndex& ); void fadingFrameFinished( const QPersistentModelIndex& ); - void updatePlayPauseButton(ImageButton* button , bool setState = false ); - void onPlayPauseHover( const QPersistentModelIndex& index ); - void onPlayPausedClicked(); - private: - QTimeLine* createTimeline( QTimeLine::Direction direction ); - void createPauseButton( const QPersistentModelIndex& index ); + QTimeLine* createTimeline( QTimeLine::Direction direction, int startFrame = 0 ); void clearButtons(); QAbstractItemView* m_view; @@ -101,8 +97,7 @@ private: QPixmap m_shadowPixmap; mutable QHash< QPersistentModelIndex, QWidget* > m_spinner; - mutable QHash< QPersistentModelIndex, ImageButton* > m_playButton; - mutable QHash< QPersistentModelIndex, ImageButton* > m_pauseButton; + mutable QHash< QPersistentModelIndex, HoverControls* > m_hoverControls; mutable QHash< QPersistentModelIndex, QTimeLine* > m_hoverFaders; };