1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-11 08:34:34 +02:00

add some animation

This commit is contained in:
Leo Franchi
2011-02-04 18:51:46 -05:00
parent 3ec455161d
commit 12d999fe0e
5 changed files with 151 additions and 10 deletions

View File

@@ -26,8 +26,10 @@ DynamicModel::DynamicModel( QObject* parent )
, m_startOnResolved( false )
, m_onDemandRunning( false )
, m_currentAttempts( 0 )
, m_lastResolvedRow( 0 )
{
connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), this, SLOT( newTrackLoading() ) );
}
DynamicModel::~DynamicModel()
@@ -38,6 +40,9 @@ DynamicModel::~DynamicModel()
void
DynamicModel::loadPlaylist( const Tomahawk::dynplaylist_ptr& playlist )
{
if( !m_playlist.isNull() ) {
disconnect( m_playlist->generator().data(), SIGNAL( nextTrackGenerated( Tomahawk::query_ptr ) ), this, SLOT( newTrackGenerated( Tomahawk::query_ptr ) ) );
}
m_playlist = playlist;
@@ -50,7 +55,6 @@ DynamicModel::startOnDemand()
{
m_playlist->generator()->startOnDemand();
connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), this, SLOT( newTrackLoading() ) );
m_onDemandRunning = true;
m_startOnResolved = true;
}
@@ -79,21 +83,31 @@ DynamicModel::stopOnDemand()
void
DynamicModel::trackResolved()
{
m_currentAttempts = 0;
Query* q = qobject_cast<Query*>(sender());
qDebug() << "Got successful resolved track:" << q->track() << q->artist() << m_lastResolvedRow << m_currentAttempts;
if( m_startOnResolved ) { // on first start
m_startOnResolved = false;
AudioEngine::instance()->play();
}
if( m_currentAttempts > 0 ) {
qDebug() << "EMITTING AN ASK FOR COLLAPSE:" << m_lastResolvedRow << m_currentAttempts;
emit collapseFromTo( m_lastResolvedRow, m_currentAttempts );
}
m_currentAttempts = 0;
}
void
DynamicModel::trackResolveFinished( bool success )
{
if( !success ) { // if it was successful, we've already gotten a trackResolved() signal
Query* q = qobject_cast<Query*>(sender());
qDebug() << "Got not resolved track:" << q->track() << q->artist() << m_lastResolvedRow << m_currentAttempts;
m_currentAttempts++;
if( m_currentAttempts < 100 ) {
if( m_currentAttempts < 30 ) {
m_playlist->generator()->fetchNext();
} else {
// TODO handle failure
}
}
}
@@ -103,6 +117,21 @@ void
DynamicModel::newTrackLoading()
{
if( m_onDemandRunning && m_currentAttempts == 0 ) { // if we're in dynamic mode and we're also currently idle
m_lastResolvedRow = rowCount( QModelIndex() );
m_playlist->generator()->fetchNext();
}
}
void
DynamicModel::removeIndex(const QModelIndex& index, bool moreToCome)
{
if ( isReadOnly() )
return;
if( m_playlist->mode() == OnDemand )
TrackModel::removeIndex( index );
// don't call onPlaylistChanged.
if( !moreToCome )
m_lastResolvedRow = rowCount( QModelIndex() );
}

View File

@@ -41,6 +41,10 @@ public:
void loadPlaylist( const dynplaylist_ptr& playlist );
virtual void removeIndex( const QModelIndex& index, bool moreToCome = false );
signals:
void collapseFromTo( int startRow, int num );
private slots:
void newTrackGenerated( const Tomahawk::query_ptr& query );
@@ -53,6 +57,7 @@ private:
bool m_startOnResolved;
bool m_onDemandRunning;
int m_currentAttempts;
int m_lastResolvedRow;
};
};

View File

@@ -18,16 +18,35 @@
#include "widgets/overlaywidget.h"
#include "playlistmodel.h"
#include "trackproxymodel.h"
#include <QPainter>
#include <QPaintEvent>
#include <QtGui/qpaintengine.h>
using namespace Tomahawk;
#define FADE_LENGTH 800
#define SLIDE_LENGTH 300
#define SLIDE_OFFSET 500
#define LONG_MULT 0.4 // to avoid superfast slides when the length is long, make it longer incrementally
DynamicView::DynamicView( QWidget* parent )
: PlaylistView( parent )
, m_onDemand( false )
{
m_fadeOutAnim.setDuration( FADE_LENGTH );
m_fadeOutAnim.setCurveShape( QTimeLine::LinearCurve );
m_fadeOutAnim.setFrameRange( 100, 0 );
m_fadeOutAnim.setUpdateInterval( 10 );
QEasingCurve curve( QEasingCurve::OutBounce );
curve.setAmplitude( .2 );
m_slideAnim.setEasingCurve( curve );
m_slideAnim.setDirection( QTimeLine::Forward );
m_fadeOutAnim.setUpdateInterval( 10 );
connect( &m_fadeOutAnim, SIGNAL( frameChanged( int ) ), viewport(), SLOT( update() ) );
}
DynamicView::~DynamicView()
@@ -74,3 +93,77 @@ DynamicView::onTrackCountChanged( unsigned int tracks )
else
overlay()->hide();
}
void
DynamicView::collapseEntries( int startRow, int num )
{
if( m_fadeOutAnim.state() == QTimeLine::Running )
qDebug() << "COLLAPSING TWICE!";
// we capture the image of the rows we're going to collapse
// then we capture the image of the target row we're going to animate downwards
// then we fade the first image out while sliding the second image up.
QModelIndex topLeft = proxyModel()->index( startRow, 0, QModelIndex() );
QModelIndex bottomRight = proxyModel()->index( startRow + num - 1, proxyModel()->columnCount( QModelIndex() ) - 1, QModelIndex() );
QItemSelection sel( topLeft, bottomRight );
QRect fadingRect = visualRegionForSelection( sel ).boundingRect();
m_fadingIndexes = QPixmap::grabWidget( viewport(), fadingRect );
m_fadingPointAnchor = fadingRect.topLeft();
qDebug() << "Grabbed fading indexes from rect:" << fadingRect << m_fadingIndexes.size();
topLeft = proxyModel()->index( startRow + num, 0, QModelIndex() );
bottomRight = proxyModel()->index( startRow + num, proxyModel()->columnCount( QModelIndex() ) - 1, QModelIndex() );
QRect slidingRect = visualRegionForSelection( QItemSelection( topLeft, bottomRight ) ).boundingRect();
m_slidingIndex = QPixmap::grabWidget( viewport(), slidingRect );
m_bottomAnchor = slidingRect.topLeft();
qDebug() << "Grabbed sliding index from rect:" << slidingRect << m_slidingIndex.size();
// slide from the current position to the new one
int frameRange = fadingRect.topLeft().y() - slidingRect.topLeft().y();
m_slideAnim.setDuration( SLIDE_LENGTH + frameRange * LONG_MULT );
m_slideAnim.setFrameRange( slidingRect.topLeft().y(), fadingRect.topLeft().y() );
m_fadeOutAnim.start();
QTimer::singleShot( SLIDE_OFFSET, &m_slideAnim, SLOT( start() ) );
QModelIndexList todel;
for( int i = 0; i < num; i++ ) {
for( int k = 0; k < proxyModel()->columnCount( QModelIndex() ); k++ ) {
todel << proxyModel()->index( startRow + i, k );
}
}
proxyModel()->removeIndexes( todel );
}
void
DynamicView::paintEvent( QPaintEvent* event )
{
TrackView::paintEvent(event);
QPainter p( viewport() );
if( m_fadeOutAnim.state() == QTimeLine::Running ) { // both run together
p.save();
QRect bg = m_fadingIndexes.rect();
bg.moveTo( m_fadingPointAnchor ); // cover up the background
p.fillRect( bg, Qt::white );
// qDebug() << "FAST SETOPACITY:" << p.paintEngine()->hasFeature(QPaintEngine::ConstantOpacity);
p.setOpacity( m_fadeOutAnim.currentFrame() );
p.drawPixmap( m_fadingPointAnchor, m_fadingIndexes );
p.restore();
if( m_slideAnim.state() == QTimeLine::Running ) {
// draw the collapsing entry
QRect bg = m_slidingIndex.rect();
bg.moveTo( m_bottomAnchor );
p.fillRect( bg, Qt::white );
p.drawPixmap( 0, m_slideAnim.currentFrame(), m_slidingIndex );
} else if( m_fadeOutAnim.state() == QTimeLine::Running ) {
p.drawPixmap( m_bottomAnchor, m_slidingIndex );
}
}
}

View File

@@ -20,6 +20,7 @@
#include "playlist/playlistview.h"
#include <QTimer>
#include <QPropertyAnimation>
#include <QTimeLine>
class PlaylistModel;
class TrackModel;
@@ -36,20 +37,33 @@ public:
virtual void setModel( PlaylistModel* model );
void setOnDemand( bool onDemand );
virtual void paintEvent(QPaintEvent* event);
public slots:
void showMessageTimeout( const QString& title, const QString& body );
// collapse and animate the transition
// there MUST be a row *after* startRow + num. that is, you can't collapse
// entries unless there is at least one entry after the last collapsed row
void collapseEntries( int startRow, int num );
private slots:
void onTrackCountChanged( unsigned int );
private:
QTimer m_showTimer;
QPropertyAnimation* m_fadeOut;
QString m_title;
QString m_body;
bool m_onDemand;
// for collapsing animation
QPoint m_fadingPointAnchor;
QPoint m_bottomAnchor;
QPixmap m_fadingIndexes;
QPixmap m_slidingIndex;
QTimeLine m_fadeOutAnim;
QTimeLine m_slideAnim;
};
};

View File

@@ -90,7 +90,7 @@ DynamicWidget::DynamicWidget( const Tomahawk::dynplaylist_ptr& playlist, QWidget
m_view->setModel( m_model );
m_view->setContentsMargins( 0, 0, 0, 0 );
m_layout->addWidget( m_view, 1 );
connect( m_model, SIGNAL( collapseFromTo( int, int ) ), m_view, SLOT( collapseEntries( int, int ) ), Qt::QueuedConnection );
loadDynamicPlaylist( playlist );