1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-01-31 13:48:09 +01:00

* Simplify GridItemDelegate using HoverControls widget and adopt new style.

This commit is contained in:
Christian Muehlhaeuser 2014-08-13 07:49:21 +02:00
parent 7c778029cf
commit 87a43fad9d
2 changed files with 143 additions and 158 deletions

View File

@ -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;
}

View File

@ -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;
};