diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6a413d21..d6c8d0f81 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,6 +58,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/sourcesproxymodel.cpp sourcetree/sourcetreeview.cpp sourcetree/sourcedelegate.cpp + sourcetree/animationhelper.cpp sourcetree/items/sourcetreeitem.cpp sourcetree/items/collectionitem.cpp sourcetree/items/playlistitems.cpp @@ -103,6 +104,8 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui} sourcetree/sourcesmodel.h sourcetree/sourcesproxymodel.h sourcetree/sourcetreeview.h + sourcetree/sourcedelegate.h + sourcetree/animationhelper.h sourcetree/items/sourcetreeitem.h sourcetree/items/collectionitem.h sourcetree/items/playlistitems.h diff --git a/src/sourcetree/animationhelper.cpp b/src/sourcetree/animationhelper.cpp new file mode 100644 index 000000000..3b15b3a44 --- /dev/null +++ b/src/sourcetree/animationhelper.cpp @@ -0,0 +1,116 @@ +#include "animationhelper.h" + +#include "QDebug" + +AnimationHelper::AnimationHelper( const QModelIndex& index, QObject *parent ) + :QObject( parent ) + , m_index( index ) + , m_fullyExpanded( false ) + , m_expandAnimation( 0 ) + , m_forceClosing( false ) +{ + m_expandTimer.setSingleShot( true ); + m_expandTimer.setInterval( 1000 ); + connect( &m_expandTimer, SIGNAL(timeout()), SLOT(expandTimeout())); + + m_collapseTimer.setSingleShot( true ); + m_collapseTimer.setInterval( 1000 ); + connect( &m_collapseTimer, SIGNAL(timeout()), SLOT(collapseTimeout())); +} + +bool AnimationHelper::initialized() const +{ + return m_expandAnimation != 0; +} + +void AnimationHelper::initialize( const QSize& startValue, const QSize& endValue, int duration ) +{ + m_size = startValue; + m_targetSize = endValue; + m_startSize = startValue; + + m_expandAnimation = new QPropertyAnimation( this, "size", this ); + m_expandAnimation->setStartValue( startValue ); + m_expandAnimation->setEndValue( endValue ); + m_expandAnimation->setDuration( duration ); + m_expandAnimation->setEasingCurve( QEasingCurve::OutBounce ); + qDebug() << "starting animation" << startValue << endValue << duration; + connect( m_expandAnimation, SIGNAL( finished() ), SLOT(expandAnimationFinished())); + + m_collapseAnimation= new QPropertyAnimation( this, "size", this ); + m_collapseAnimation->setStartValue( endValue ); + m_collapseAnimation->setEndValue( startValue ); + m_collapseAnimation->setDuration( duration ); + m_collapseAnimation->setEasingCurve( QEasingCurve::OutBounce ); + connect( m_collapseAnimation, SIGNAL( finished() ), SLOT(collapseAnimationFinished())); + +} + +void AnimationHelper::setSize( const QSize& size ) +{ + m_size = size; + emit sizeChanged(); + qDebug() << "animaton setting size to" << size; +} + +void AnimationHelper::expand() +{ + m_collapseTimer.stop(); + m_expandTimer.start(); +} + +void AnimationHelper::collapse( bool immediately ) +{ + if ( immediately ) + { + m_fullyExpanded = false; + m_forceClosing = true; + m_collapseAnimation->start(); + } + else + { + //m_fullyExpanded = false; + m_expandTimer.stop(); + m_collapseTimer.start(); + } +} + +bool AnimationHelper::partlyExpanded() +{ + if ( m_forceClosing ) + return false; + + return m_fullyExpanded + || ( m_expandAnimation->state() == QPropertyAnimation::Running && m_expandAnimation->currentTime() > 250 ) + || ( m_collapseAnimation->state() == QPropertyAnimation::Running && m_collapseAnimation->currentTime() < 100 ); +} + +bool AnimationHelper::fullyExpanded() +{ + return m_fullyExpanded; +} + +void AnimationHelper::expandTimeout() +{ + m_expandAnimation->start(); +// m_fullyExpanded = true; +} + +void AnimationHelper::collapseTimeout() +{ +// m_size = m_startSize; + m_fullyExpanded = false; +// emit finished( m_index ); + m_collapseAnimation->start(); +} + +void AnimationHelper::expandAnimationFinished() +{ + m_fullyExpanded = true; +} + +void AnimationHelper::collapseAnimationFinished() +{ + m_fullyExpanded = false; + emit finished( m_index ); +} diff --git a/src/sourcetree/animationhelper.h b/src/sourcetree/animationhelper.h new file mode 100644 index 000000000..cc46013df --- /dev/null +++ b/src/sourcetree/animationhelper.h @@ -0,0 +1,58 @@ +#ifndef ANIMATIONHELPER_H +#define ANIMATIONHELPER_H + +#include +#include +#include +#include +#include + +class AnimationHelper: public QObject +{ + Q_OBJECT + Q_PROPERTY( QSize size READ size WRITE setSize NOTIFY sizeChanged ) + +public: + AnimationHelper( const QModelIndex& index, QObject *parent = 0 ); + + QSize originalSize() const { return m_startSize; } + QSize size() const { return m_size; } + + bool initialized() const; + void initialize( const QSize& startValue, const QSize& endValue, int duration ); + + void setSize( const QSize& size ); + + void expand(); + void collapse( bool immediately = false ); + + bool partlyExpanded(); + bool fullyExpanded(); + +signals: + void sizeChanged(); + void finished( const QModelIndex& index); + +private slots: + void expandTimeout(); + void collapseTimeout(); + void expandAnimationFinished(); + void collapseAnimationFinished(); + +private: + QModelIndex m_index; + QSize m_size; + QSize m_targetSize; + QSize m_startSize; + + QTimer m_expandTimer; + QTimer m_collapseTimer; + + bool m_fullyExpanded; + bool m_forceClosing; + + QPropertyAnimation *m_expandAnimation; + QPropertyAnimation *m_collapseAnimation; +}; + +#endif // ANIMATIONHELPER_H diff --git a/src/sourcetree/sourcedelegate.cpp b/src/sourcetree/sourcedelegate.cpp index 17cbef2d3..a059a8504 100644 --- a/src/sourcetree/sourcedelegate.cpp +++ b/src/sourcetree/sourcedelegate.cpp @@ -7,6 +7,7 @@ #include "utils/tomahawkutils.h" #include "items/temporarypageitem.h" +#include "animationhelper.h" #include #include @@ -14,6 +15,12 @@ #define TREEVIEW_INDENT_ADD -7 +SourceDelegate::SourceDelegate( QAbstractItemView* parent ) + : QStyledItemDelegate( parent ) + , m_parent( parent ) +{ +} + QSize SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const { @@ -21,11 +28,19 @@ SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& if ( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::Collection ) return QSize( option.rect.width(), 44 ); - else if ( index == m_dropHoverIndex ) + else if ( m_expandedMap.contains( index ) ) { - QSize originalSize = QStyledItemDelegate::sizeHint( option, index ); - qDebug() << "droptypecount is" << dropTypeCount( item ); - return originalSize + QSize( 0, originalSize.height() * dropTypeCount( item ) ); + if ( !m_expandedMap.value( index )->initialized() ) + { + qDebug() << "droptypecount is " << dropTypeCount( item ); + QSize originalSize = QStyledItemDelegate::sizeHint( option, index ); +// QSize targetSize = originalSize + QSize( 0, originalSize.height() * dropTypeCount( item ) ); // useful for vertical menu + QSize targetSize = originalSize + QSize( 0, 56 ); + m_expandedMap.value( index )->initialize( originalSize, targetSize, 500 ); + m_expandedMap.value( index )->expand(); + } + QMetaObject::invokeMethod( m_parent, "update", Qt::QueuedConnection, Q_ARG( QModelIndex, index ) ); + return m_expandedMap.value( index )->size(); } else return QStyledItemDelegate::sizeHint( option, index ); @@ -141,105 +156,298 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co } else if ( type == SourcesModel::StaticPlaylist || type == SourcesModel::CategoryAdd ) { + if ( !( m_expandedMap.contains( index) && m_expandedMap.value( index )->partlyExpanded() && dropTypeCount( item ) > 0 ) ) + { + QStyledItemDelegate::paint( painter, option, index ); + return; + } + + // Let Qt paint the original item. We add our stuff after it + QStyleOptionViewItem o = option; + o.rect.adjust( 0, 0, 0, - option.rect.height() + m_expandedMap.value( index )->originalSize().height() + 2 ); + QStyledItemDelegate::paint( painter, o, index ); + painter->save(); - QFont bold = painter->font(); - bold.setBold( true ); - QString name = index.data().toString(); - if ( type == SourcesModel::StaticPlaylist ) + // Get whole rect for the menu + QRect itemsRect = option.rect.adjusted( -option.rect.x(), m_expandedMap.value( index )->originalSize().height(), 0, 0 ); + + // draw the background + + QLinearGradient linearGradient( 0, 0, 0, itemsRect.height() ); + linearGradient.setColorAt( 0.0, QColor( 0xdb, 0x1b, 0x06 ) ); + linearGradient.setColorAt( 1.0, QColor( 0xf4, 0x17, 0x05 ) ); + painter->setBrush( linearGradient ); + painter->drawRect( itemsRect ); + + int totalCount = dropTypeCount( item ); + int itemWidth = itemsRect.width() / totalCount; + int iconSpacing = ( itemWidth - 32 ) / 2; + + // adjust to one single entry + itemsRect.adjust( 0, 0, -itemsRect.width() + itemWidth, 0 ); + + int count = 0; + + QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() ); + + QPen pen(Qt::white); + painter->setPen(pen); + + QFont font = painter->font(); + font.setPixelSize( 10 ); + painter->setFont( font ); + QFont fontBold = painter->font(); + fontBold.setBold( true ); + + QString text; + QRect textRect; + QPixmap icon = QPixmap( ":/data/images/new-additions.png" ).scaledToHeight( 32, Qt::SmoothTransformation ); + + QMap< int, SourceTreeItem::DropType > dropTypeMap; + dropTypeMap.insert( 0, SourceTreeItem::DropTypeThisTrack ); + dropTypeMap.insert( 1, SourceTreeItem::DropTypeThisAlbum ); + dropTypeMap.insert( 2, SourceTreeItem::DropTypeAllFromArtist ); + dropTypeMap.insert( 3, SourceTreeItem::DropTypeLocalItems ); + dropTypeMap.insert( 4, SourceTreeItem::DropTypeTop50 ); + + QMap< int, QString > dropTypeTextMap; + dropTypeTextMap.insert( 0, "Track" ); + dropTypeTextMap.insert( 1, "Album" ); + dropTypeTextMap.insert( 2, "Artist" ); + dropTypeTextMap.insert( 3, "Local" ); + dropTypeTextMap.insert( 4, "Top 10" ); + + SourceTreeItem::DropTypes dropTypes = item->supportedDropTypes( m_dropMimeData ); + + for ( int i = 0; i < 5; ++i ) { - PlaylistItem* plItem = qobject_cast< PlaylistItem* >( item ); - Q_ASSERT( plItem ); + if ( !dropTypes.testFlag( dropTypeMap.value( i ) ) ) + continue; - if ( plItem && !plItem->playlist().isNull() ) + text = dropTypeTextMap.value( i ); + + if ( count > 0 ) + itemsRect.adjust( itemWidth, 0, itemWidth, 0 ); + + if ( itemsRect.contains( cursorPos ) ) { - name = plItem->playlist()->title(); + painter->setFont( fontBold ); + m_hoveredDropType = dropTypeMap.value( i ); } - } - else if ( type == SourcesModel::CategoryAdd ) - { - CategoryAddItem* cItem = qobject_cast< CategoryAddItem* >( item ); - Q_ASSERT( cItem ); + else + painter->setFont( font ); - name = cItem->text(); + textRect = itemsRect.adjusted( 0, 4, 0, 0 ); + painter->drawPixmap( textRect.x() + iconSpacing, textRect.y(), icon ); + + int textSpacing = ( itemWidth - painter->fontMetrics().width( text ) ) / 2; + textRect.adjust( textSpacing, 32 + 4, 0, 0 ); + painter->drawText( textRect, text ); + count++; } - int height = option.rect.height(); - if ( index == m_dropHoverIndex ) - height /= ( dropTypeCount( item ) + 1 ); - QRect iconRect = option.rect.adjusted( 4, 1, -option.rect.width() + height - 2 + 4, -option.rect.height() + height -1 ); +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisTrack ) ) +// { +// text = tr( "Track" ); - QPixmap avatar = index.data( Qt::DecorationRole ).value< QIcon >().pixmap( iconRect.width(), iconRect.height() ); - painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) ); +// itemsRect.adjust( itemWidth * count, 0, itemWidth * count, 0 ); +// if ( itemRect.contains( cursorPos ) ) +// { +// painter->setFont( fontBold ); +// m_hoveredDropType = SourceTreeItem::DropTypeThisTrack; +// } +// else +// painter->setFont( font ); - if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected ) - { - painter->setPen( o.palette.color( QPalette::HighlightedText ) ); - } +// textRect = itemsRect.adjusted( 0, 4, 0, 0 ); +// painter->drawPixmap( textRect.x() + iconSpacing, textRect.y(), icon ); - QRect textRect = option.rect.adjusted( iconRect.width() + 8, 2, /*-figWidth - 24*/ 0, 0 ); - QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() ); - painter->drawText( textRect, text ); +// int textSpacing = ( itemWidth - painter->fontMetrics().width( text ) ) / 2; +// textRect.adjust( textSpacing, 32 + 4, 0, 0 ); +// painter->drawText( textRect, text ); +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisAlbum ) ) +// { +// text = tr( "Album" ); +// itemsRect.adjust( itemWidth * count, 0, itemWidth * count, 0 ); +// if ( itemRect.contains( cursorPos ) ) +// { +// painter->setFont( fontBold ); +// m_hoveredDropType = SourceTreeItem::DropTypeThisTrack; +// } +// else +// painter->setFont( font ); - if ( index == m_dropHoverIndex ) - { - QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() ); - int hoveredDropTypeIndex = ( cursorPos.y() - o.rect.y() ) / height; - int verticalOffset = height * hoveredDropTypeIndex; - QRect selectionRect = o.rect.adjusted( 0, verticalOffset, 0, -o.rect.height() + height + verticalOffset ); - painter->drawRoundedRect( selectionRect, 5, 5 ); +// textRect = itemsRect.adjusted( 0, 4, 0, 0 ); +// painter->drawPixmap( textRect.x() + iconSpacing, textRect.y(), icon ); - int count = 1; - SourceTreeItem::DropTypes dropTypes = item->supportedDropTypes( m_dropMimeData ); - if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisTrack ) ) - { - text = tr( "This track" ); - textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); - painter->drawText( textRect, text ); - if ( count == hoveredDropTypeIndex ) - m_hoveredDropType = SourceTreeItem::DropTypeThisTrack; - count++; - } - if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisAlbum ) ) - { - text = tr( "This album" ); - textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); - painter->drawText( textRect, text ); - if ( count == hoveredDropTypeIndex ) - m_hoveredDropType = SourceTreeItem::DropTypeThisAlbum; - count++; - } - if ( dropTypes.testFlag( SourceTreeItem::DropTypeAllFromArtist ) ) - { - text = tr( "All from artist" ); - textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); - painter->drawText( textRect, text ); - if ( count == hoveredDropTypeIndex ) - m_hoveredDropType = SourceTreeItem::DropTypeAllFromArtist; - count++; - } - if ( dropTypes.testFlag( SourceTreeItem::DropTypeLocalItems ) ) - { - text = tr( "All local from Artist" ); - textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); - painter->drawText( textRect, text ); - if ( count == hoveredDropTypeIndex ) - m_hoveredDropType = SourceTreeItem::DropTypeLocalItems; - count++; - } - if ( dropTypes.testFlag( SourceTreeItem::DropTypeTop50 ) ) - { - text = tr( "Top 50" ); - textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); - painter->drawText( textRect, text ); - if ( count == hoveredDropTypeIndex ) - m_hoveredDropType = SourceTreeItem::DropTypeTop50; - count++; - } - } +// int textSpacing = ( itemWidth - painter->fontMetrics().width( text ) ) / 2; +// textRect.adjust( textSpacing, 32 + 4, 0, 0 ); +// painter->drawText( textRect, text ); +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeAllFromArtist ) ) +// { +// text = tr( "Artist" ); +// textRect = itemsRect.adjusted( itemWidth * count, 4, itemWidth * count, 0 ); +// painter->drawPixmap( textRect.x() + iconSpacing, textRect.y(), icon ); + +// if ( itemRect.contains( cursorPos ) ) +// { +// painter->setFont( fontBold ); +// m_hoveredDropType = SourceTreeItem::DropTypeAllFromArtist; +// } +// else +// painter->setFont( font ); + +// int textSpacing = ( itemWidth - painter->fontMetrics().width( text ) ) / 2; +// textRect.adjust( textSpacing, 32 + 4, 0, 0 ); +// painter->drawText( textRect, text ); +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeLocalItems ) ) +// { +// text = tr( "Local" ); +// textRect = itemsRect.adjusted( itemWidth * count, 4, itemWidth * count, 0 ); +// painter->drawPixmap( textRect.x() + iconSpacing, textRect.y(), icon ); + +// if ( itemRect.contains( cursorPos ) ) +// { +// painter->setFont( fontBold ); +// m_hoveredDropType = SourceTreeItem::DropTypeLocalItems; +// } +// else +// painter->setFont( font ); + +// int textSpacing = ( itemWidth - painter->fontMetrics().width( text ) ) / 2; +// textRect.adjust( textSpacing, 32 + 4, 0, 0 ); +// painter->drawText( textRect, text ); +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeTop50 ) ) +// { +// text = tr( "Top 10" ); +// textRect = itemsRect.adjusted( itemWidth * count, 4, itemWidth * count, 0 ); +// painter->drawPixmap( textRect.x() + iconSpacing, textRect.y(), icon ); + +// if ( itemRect.contains( cursorPos ) ) +// { +// painter->setFont( fontBold ); +// m_hoveredDropType = SourceTreeItem::DropTypeTop50; +// } +// else +// painter->setFont( font ); + +// int textSpacing = ( itemWidth - painter->fontMetrics().width( text ) ) / 2; +// textRect.adjust( textSpacing, 32 + 4, 0, 0 ); +// painter->drawText( textRect, text ); +// count++; +// } + + + +// QFont bold = painter->font(); +// bold.setBold( true ); + +// QString name = index.data().toString(); +// if ( type == SourcesModel::StaticPlaylist ) +// { +// PlaylistItem* plItem = qobject_cast< PlaylistItem* >( item ); +// Q_ASSERT( plItem ); + + +// if ( plItem && !plItem->playlist().isNull() ) +// { +// name = plItem->playlist()->title(); +// } +// } +// else if ( type == SourcesModel::CategoryAdd ) +// { +// CategoryAddItem* cItem = qobject_cast< CategoryAddItem* >( item ); +// Q_ASSERT( cItem ); + +// name = cItem->text(); +// } + +// int height = option.rect.height(); +// if ( m_expandedMap.contains( index ) && m_expandedMap.value( index )->partlyExpanded() ) +// height /= ( dropTypeCount( item ) + 1 ); + +// QRect iconRect = option.rect.adjusted( 4, 1, -option.rect.width() + option.decorationSize.width() - 2 + 4, -option.rect.height() + option.decorationSize.height() -1 ); + +// QPixmap avatar = index.data( Qt::DecorationRole ).value< QIcon >().pixmap( iconRect.width(), iconRect.height() ); +// painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) ); + +// if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected ) +// { +// painter->setPen( o.palette.color( QPalette::HighlightedText ) ); +// } + +// QRect textRect = option.rect.adjusted( iconRect.width() + 8, 2, /*-figWidth - 24*/ 0, 0 ); +// QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() ); +// painter->drawText( textRect, text ); + +// if ( m_expandedMap.contains( index ) && m_expandedMap.value( index )->partlyExpanded() ) +// { +// QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() ); +// int hoveredDropTypeIndex = ( cursorPos.y() - o.rect.y() ) / height; +// int verticalOffset = height * hoveredDropTypeIndex; +// QRect selectionRect = o.rect.adjusted( 0, verticalOffset, 0, -o.rect.height() + height + verticalOffset ); +// painter->drawRoundedRect( selectionRect, 5, 5 ); + +// int count = 1; +// SourceTreeItem::DropTypes dropTypes = item->supportedDropTypes( m_dropMimeData ); +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisTrack ) ) +// { +// text = tr( "This track" ); +// textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); +// painter->drawText( textRect, text ); +// if ( count == hoveredDropTypeIndex ) +// m_hoveredDropType = SourceTreeItem::DropTypeThisTrack; +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisAlbum ) ) +// { +// text = tr( "This album" ); +// textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); +// painter->drawText( textRect, text ); +// if ( count == hoveredDropTypeIndex ) +// m_hoveredDropType = SourceTreeItem::DropTypeThisAlbum; +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeAllFromArtist ) ) +// { +// text = tr( "All from artist" ); +// textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); +// painter->drawText( textRect, text ); +// if ( count == hoveredDropTypeIndex ) +// m_hoveredDropType = SourceTreeItem::DropTypeAllFromArtist; +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeLocalItems ) ) +// { +// text = tr( "All local from Artist" ); +// textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); +// painter->drawText( textRect, text ); +// if ( count == hoveredDropTypeIndex ) +// m_hoveredDropType = SourceTreeItem::DropTypeLocalItems; +// count++; +// } +// if ( dropTypes.testFlag( SourceTreeItem::DropTypeTop50 ) ) +// { +// text = tr( "Top 50" ); +// textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 ); +// painter->drawText( textRect, text ); +// if ( count == hoveredDropTypeIndex ) +// m_hoveredDropType = SourceTreeItem::DropTypeTop50; +// count++; +// } +// } painter->restore(); @@ -335,3 +543,40 @@ SourceDelegate::hoveredDropType() const { return m_hoveredDropType; } + +void +SourceDelegate::hovered(const QModelIndex &index, const QMimeData *mimeData) +{ + if ( !index.isValid() ) + { + return; + } + if ( !m_expandedMap.contains( index ) ) + { + foreach ( AnimationHelper *helper, m_expandedMap ) + { + helper->collapse(); + } + + m_newDropHoverIndex = index; + m_dropMimeData = const_cast< QMimeData* >( mimeData ); + m_expandedMap.insert( m_newDropHoverIndex, new AnimationHelper( m_newDropHoverIndex ) ); + connect( m_expandedMap.value( m_newDropHoverIndex ), SIGNAL( finished( QModelIndex ) ), SLOT( animationFinished( QModelIndex ) ) ); + + } +} + +void +SourceDelegate::dragLeaveEvent() +{ + foreach ( AnimationHelper *helper, m_expandedMap ) + { + helper->collapse( true ); + } +} + +void +SourceDelegate::animationFinished( const QModelIndex& index ) +{ + delete m_expandedMap.take( index ); +} diff --git a/src/sourcetree/sourcedelegate.h b/src/sourcetree/sourcedelegate.h index 124b8c3c7..e764b9340 100644 --- a/src/sourcetree/sourcedelegate.h +++ b/src/sourcetree/sourcedelegate.h @@ -5,13 +5,18 @@ #include "items/sourcetreeitem.h" #include +#include + +class AnimationHelper; class SourceDelegate : public QStyledItemDelegate { + Q_OBJECT public: - SourceDelegate( QAbstractItemView* parent = 0 ) : QStyledItemDelegate( parent ), m_parent( parent ) {} + SourceDelegate( QAbstractItemView* parent = 0 ); - void setDropHoverIndex( const QModelIndex &index, const QMimeData *mimeData ) { m_dropHoverIndex = index; m_dropMimeData = const_cast< QMimeData* >( mimeData ); } + void hovered( const QModelIndex &index, const QMimeData *mimeData ); + void dragLeaveEvent(); SourceTreeItem::DropType hoveredDropType() const; @@ -22,12 +27,16 @@ protected: virtual int dropTypeCount( SourceTreeItem* item ) const; virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index ); +private slots: + void animationFinished( const QModelIndex& ); private: QAbstractItemView* m_parent; mutable int m_iconHeight; QModelIndex m_dropHoverIndex; + QModelIndex m_newDropHoverIndex; QMimeData *m_dropMimeData; mutable SourceTreeItem::DropType m_hoveredDropType; // Hack to keep easily track of the current highlighted DropType in paint() + QMap< QModelIndex, AnimationHelper* > m_expandedMap; }; #endif // SOURCEDELEGATE_H diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index bd40aa415..c7bc2c7c7 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -439,7 +439,7 @@ SourceTreeView::dragLeaveEvent( QDragLeaveEvent* event ) m_dragging = false; setDirtyRegion( m_dropRect ); - m_delegate->setDropHoverIndex( QModelIndex(), 0 ); + m_delegate->dragLeaveEvent(); dataChanged(m_dropIndex, m_dropIndex); m_dropIndex = QPersistentModelIndex(); } @@ -456,7 +456,6 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event ) setDirtyRegion( m_dropRect ); const QPoint pos = event->pos(); const QModelIndex index = indexAt( pos ); - m_delegate->setDropHoverIndex( QModelIndex(), event->mimeData() ); dataChanged(m_dropIndex, m_dropIndex); m_dropIndex = QPersistentModelIndex( index ); @@ -469,7 +468,7 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event ) if( item->willAcceptDrag( event->mimeData() ) ) { accept = true; - m_delegate->setDropHoverIndex( index, event->mimeData() ); + m_delegate->hovered( index, event->mimeData() ); dataChanged(index, index); } } @@ -497,7 +496,7 @@ SourceTreeView::dropEvent( QDropEvent* event ) const QPoint pos = event->pos(); const QModelIndex index = indexAt( pos ); - if ( model()->data( index, SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::PlaylistsCategory ) + if ( model()->data( index, SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::StaticPlaylist ) { PlaylistItem* item = itemFromIndex< PlaylistItem >( index ); Q_ASSERT( item ); @@ -506,10 +505,21 @@ SourceTreeView::dropEvent( QDropEvent* event ) qDebug() << "dropType is " << m_delegate->hoveredDropType(); } - QTreeView::dropEvent( event ); + // Need to fake the dropevent because the treeview would reject it if it is outside the item (on the tree) + if ( pos.x() < 100 ) + { + QDropEvent* newEvent = new QDropEvent( pos + QPoint( 100, 0 ), event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers(), event->type() ); + QTreeView::dropEvent( newEvent ); + delete newEvent; + } + else + { + QTreeView::dropEvent( event ); + } + m_dragging = false; m_dropIndex = QPersistentModelIndex(); - m_delegate->setDropHoverIndex( QModelIndex(), 0 ); + m_delegate->dragLeaveEvent(); dataChanged( index, index ); } @@ -573,3 +583,8 @@ SourceTreeView::itemFromIndex( const QModelIndex& index ) const return item; } +void +SourceTreeView::update( const QModelIndex &index ) +{ + dataChanged( index, index ); +} diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index 8bba33076..6a60e07cf 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -24,6 +24,7 @@ #include "source.h" #include "sourcetree/sourcesmodel.h" +#include "sourcetree/sourcedelegate.h" class CollectionModel; class PlaylistModel; @@ -42,6 +43,9 @@ public slots: void showOfflineSources( bool offlineSourcesShown ); void renamePlaylist(); + + void update( const QModelIndex &index ); + signals: void onOnline( const QModelIndex& index ); void onOffline( const QModelIndex& index );