mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-03 20:57:52 +02:00
more work on the drag and drop menu
This commit is contained in:
@@ -58,6 +58,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
|||||||
sourcetree/sourcesproxymodel.cpp
|
sourcetree/sourcesproxymodel.cpp
|
||||||
sourcetree/sourcetreeview.cpp
|
sourcetree/sourcetreeview.cpp
|
||||||
sourcetree/sourcedelegate.cpp
|
sourcetree/sourcedelegate.cpp
|
||||||
|
sourcetree/animationhelper.cpp
|
||||||
sourcetree/items/sourcetreeitem.cpp
|
sourcetree/items/sourcetreeitem.cpp
|
||||||
sourcetree/items/collectionitem.cpp
|
sourcetree/items/collectionitem.cpp
|
||||||
sourcetree/items/playlistitems.cpp
|
sourcetree/items/playlistitems.cpp
|
||||||
@@ -103,6 +104,8 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
|
|||||||
sourcetree/sourcesmodel.h
|
sourcetree/sourcesmodel.h
|
||||||
sourcetree/sourcesproxymodel.h
|
sourcetree/sourcesproxymodel.h
|
||||||
sourcetree/sourcetreeview.h
|
sourcetree/sourcetreeview.h
|
||||||
|
sourcetree/sourcedelegate.h
|
||||||
|
sourcetree/animationhelper.h
|
||||||
sourcetree/items/sourcetreeitem.h
|
sourcetree/items/sourcetreeitem.h
|
||||||
sourcetree/items/collectionitem.h
|
sourcetree/items/collectionitem.h
|
||||||
sourcetree/items/playlistitems.h
|
sourcetree/items/playlistitems.h
|
||||||
|
116
src/sourcetree/animationhelper.cpp
Normal file
116
src/sourcetree/animationhelper.cpp
Normal file
@@ -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 );
|
||||||
|
}
|
58
src/sourcetree/animationhelper.h
Normal file
58
src/sourcetree/animationhelper.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef ANIMATIONHELPER_H
|
||||||
|
#define ANIMATIONHELPER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QModelIndex>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
|
||||||
|
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
|
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "utils/tomahawkutils.h"
|
#include "utils/tomahawkutils.h"
|
||||||
#include "items/temporarypageitem.h"
|
#include "items/temporarypageitem.h"
|
||||||
|
#include "animationhelper.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
@@ -14,6 +15,12 @@
|
|||||||
|
|
||||||
#define TREEVIEW_INDENT_ADD -7
|
#define TREEVIEW_INDENT_ADD -7
|
||||||
|
|
||||||
|
SourceDelegate::SourceDelegate( QAbstractItemView* parent )
|
||||||
|
: QStyledItemDelegate( parent )
|
||||||
|
, m_parent( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QSize
|
QSize
|
||||||
SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
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 )
|
if ( index.data( SourcesModel::SourceTreeItemTypeRole ).toInt() == SourcesModel::Collection )
|
||||||
return QSize( option.rect.width(), 44 );
|
return QSize( option.rect.width(), 44 );
|
||||||
else if ( index == m_dropHoverIndex )
|
else if ( m_expandedMap.contains( index ) )
|
||||||
{
|
{
|
||||||
|
if ( !m_expandedMap.value( index )->initialized() )
|
||||||
|
{
|
||||||
|
qDebug() << "droptypecount is " << dropTypeCount( item );
|
||||||
QSize originalSize = QStyledItemDelegate::sizeHint( option, index );
|
QSize originalSize = QStyledItemDelegate::sizeHint( option, index );
|
||||||
qDebug() << "droptypecount is" << dropTypeCount( item );
|
// QSize targetSize = originalSize + QSize( 0, originalSize.height() * dropTypeCount( item ) ); // useful for vertical menu
|
||||||
return originalSize + QSize( 0, originalSize.height() * dropTypeCount( item ) );
|
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
|
else
|
||||||
return QStyledItemDelegate::sizeHint( option, index );
|
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 )
|
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();
|
painter->save();
|
||||||
|
|
||||||
QFont bold = painter->font();
|
|
||||||
bold.setBold( true );
|
|
||||||
|
|
||||||
QString name = index.data().toString();
|
// Get whole rect for the menu
|
||||||
if ( type == SourcesModel::StaticPlaylist )
|
QRect itemsRect = option.rect.adjusted( -option.rect.x(), m_expandedMap.value( index )->originalSize().height(), 0, 0 );
|
||||||
{
|
|
||||||
PlaylistItem* plItem = qobject_cast< PlaylistItem* >( item );
|
|
||||||
Q_ASSERT( plItem );
|
|
||||||
|
|
||||||
|
// draw the background
|
||||||
|
|
||||||
if ( plItem && !plItem->playlist().isNull() )
|
QLinearGradient linearGradient( 0, 0, 0, itemsRect.height() );
|
||||||
{
|
linearGradient.setColorAt( 0.0, QColor( 0xdb, 0x1b, 0x06 ) );
|
||||||
name = plItem->playlist()->title();
|
linearGradient.setColorAt( 1.0, QColor( 0xf4, 0x17, 0x05 ) );
|
||||||
}
|
painter->setBrush( linearGradient );
|
||||||
}
|
painter->drawRect( itemsRect );
|
||||||
else if ( type == SourcesModel::CategoryAdd )
|
|
||||||
{
|
|
||||||
CategoryAddItem* cItem = qobject_cast< CategoryAddItem* >( item );
|
|
||||||
Q_ASSERT( cItem );
|
|
||||||
|
|
||||||
name = cItem->text();
|
int totalCount = dropTypeCount( item );
|
||||||
}
|
int itemWidth = itemsRect.width() / totalCount;
|
||||||
|
int iconSpacing = ( itemWidth - 32 ) / 2;
|
||||||
|
|
||||||
int height = option.rect.height();
|
// adjust to one single entry
|
||||||
if ( index == m_dropHoverIndex )
|
itemsRect.adjust( 0, 0, -itemsRect.width() + itemWidth, 0 );
|
||||||
height /= ( dropTypeCount( item ) + 1 );
|
|
||||||
|
|
||||||
QRect iconRect = option.rect.adjusted( 4, 1, -option.rect.width() + height - 2 + 4, -option.rect.height() + height -1 );
|
int count = 0;
|
||||||
|
|
||||||
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 ( index == m_dropHoverIndex )
|
|
||||||
{
|
|
||||||
QPoint cursorPos = m_parent->mapFromGlobal( QCursor::pos() );
|
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;
|
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 );
|
SourceTreeItem::DropTypes dropTypes = item->supportedDropTypes( m_dropMimeData );
|
||||||
if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisTrack ) )
|
|
||||||
|
for ( int i = 0; i < 5; ++i )
|
||||||
{
|
{
|
||||||
text = tr( "This track" );
|
if ( !dropTypes.testFlag( dropTypeMap.value( i ) ) )
|
||||||
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
text = dropTypeTextMap.value( i );
|
||||||
|
|
||||||
|
if ( count > 0 )
|
||||||
|
itemsRect.adjust( itemWidth, 0, itemWidth, 0 );
|
||||||
|
|
||||||
|
if ( itemsRect.contains( cursorPos ) )
|
||||||
|
{
|
||||||
|
painter->setFont( fontBold );
|
||||||
|
m_hoveredDropType = dropTypeMap.value( i );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
painter->setFont( font );
|
||||||
|
|
||||||
|
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 );
|
painter->drawText( textRect, text );
|
||||||
if ( count == hoveredDropTypeIndex )
|
|
||||||
m_hoveredDropType = SourceTreeItem::DropTypeThisTrack;
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisAlbum ) )
|
|
||||||
{
|
|
||||||
text = tr( "This album" );
|
// if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisTrack ) )
|
||||||
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
// {
|
||||||
painter->drawText( textRect, text );
|
// text = tr( "Track" );
|
||||||
if ( count == hoveredDropTypeIndex )
|
|
||||||
m_hoveredDropType = SourceTreeItem::DropTypeThisAlbum;
|
// itemsRect.adjust( itemWidth * count, 0, itemWidth * count, 0 );
|
||||||
count++;
|
// if ( itemRect.contains( cursorPos ) )
|
||||||
}
|
// {
|
||||||
if ( dropTypes.testFlag( SourceTreeItem::DropTypeAllFromArtist ) )
|
// painter->setFont( fontBold );
|
||||||
{
|
// m_hoveredDropType = SourceTreeItem::DropTypeThisTrack;
|
||||||
text = tr( "All from artist" );
|
// }
|
||||||
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
// else
|
||||||
painter->drawText( textRect, text );
|
// painter->setFont( font );
|
||||||
if ( count == hoveredDropTypeIndex )
|
|
||||||
m_hoveredDropType = SourceTreeItem::DropTypeAllFromArtist;
|
// textRect = itemsRect.adjusted( 0, 4, 0, 0 );
|
||||||
count++;
|
// painter->drawPixmap( textRect.x() + iconSpacing, textRect.y(), icon );
|
||||||
}
|
|
||||||
if ( dropTypes.testFlag( SourceTreeItem::DropTypeLocalItems ) )
|
// int textSpacing = ( itemWidth - painter->fontMetrics().width( text ) ) / 2;
|
||||||
{
|
// textRect.adjust( textSpacing, 32 + 4, 0, 0 );
|
||||||
text = tr( "All local from Artist" );
|
// painter->drawText( textRect, text );
|
||||||
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
// count++;
|
||||||
painter->drawText( textRect, text );
|
// }
|
||||||
if ( count == hoveredDropTypeIndex )
|
// if ( dropTypes.testFlag( SourceTreeItem::DropTypeThisAlbum ) )
|
||||||
m_hoveredDropType = SourceTreeItem::DropTypeLocalItems;
|
// {
|
||||||
count++;
|
// text = tr( "Album" );
|
||||||
}
|
// itemsRect.adjust( itemWidth * count, 0, itemWidth * count, 0 );
|
||||||
if ( dropTypes.testFlag( SourceTreeItem::DropTypeTop50 ) )
|
// if ( itemRect.contains( cursorPos ) )
|
||||||
{
|
// {
|
||||||
text = tr( "Top 50" );
|
// painter->setFont( fontBold );
|
||||||
textRect = option.rect.adjusted( iconRect.width() + 8, 2 + ( count * height ), 0, 0 );
|
// m_hoveredDropType = SourceTreeItem::DropTypeThisTrack;
|
||||||
painter->drawText( textRect, text );
|
// }
|
||||||
if ( count == hoveredDropTypeIndex )
|
// else
|
||||||
m_hoveredDropType = SourceTreeItem::DropTypeTop50;
|
// painter->setFont( font );
|
||||||
count++;
|
|
||||||
}
|
// 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++;
|
||||||
|
// }
|
||||||
|
// 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();
|
painter->restore();
|
||||||
|
|
||||||
@@ -335,3 +543,40 @@ SourceDelegate::hoveredDropType() const
|
|||||||
{
|
{
|
||||||
return m_hoveredDropType;
|
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 );
|
||||||
|
}
|
||||||
|
@@ -5,13 +5,18 @@
|
|||||||
#include "items/sourcetreeitem.h"
|
#include "items/sourcetreeitem.h"
|
||||||
|
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
|
||||||
|
class AnimationHelper;
|
||||||
|
|
||||||
class SourceDelegate : public QStyledItemDelegate
|
class SourceDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
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;
|
SourceTreeItem::DropType hoveredDropType() const;
|
||||||
|
|
||||||
@@ -22,12 +27,16 @@ protected:
|
|||||||
virtual int dropTypeCount( SourceTreeItem* item ) const;
|
virtual int dropTypeCount( SourceTreeItem* item ) const;
|
||||||
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void animationFinished( const QModelIndex& );
|
||||||
private:
|
private:
|
||||||
QAbstractItemView* m_parent;
|
QAbstractItemView* m_parent;
|
||||||
mutable int m_iconHeight;
|
mutable int m_iconHeight;
|
||||||
QModelIndex m_dropHoverIndex;
|
QModelIndex m_dropHoverIndex;
|
||||||
|
QModelIndex m_newDropHoverIndex;
|
||||||
QMimeData *m_dropMimeData;
|
QMimeData *m_dropMimeData;
|
||||||
mutable SourceTreeItem::DropType m_hoveredDropType; // Hack to keep easily track of the current highlighted DropType in paint()
|
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
|
#endif // SOURCEDELEGATE_H
|
||||||
|
@@ -439,7 +439,7 @@ SourceTreeView::dragLeaveEvent( QDragLeaveEvent* event )
|
|||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
setDirtyRegion( m_dropRect );
|
setDirtyRegion( m_dropRect );
|
||||||
|
|
||||||
m_delegate->setDropHoverIndex( QModelIndex(), 0 );
|
m_delegate->dragLeaveEvent();
|
||||||
dataChanged(m_dropIndex, m_dropIndex);
|
dataChanged(m_dropIndex, m_dropIndex);
|
||||||
m_dropIndex = QPersistentModelIndex();
|
m_dropIndex = QPersistentModelIndex();
|
||||||
}
|
}
|
||||||
@@ -456,7 +456,6 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
|
|||||||
setDirtyRegion( m_dropRect );
|
setDirtyRegion( m_dropRect );
|
||||||
const QPoint pos = event->pos();
|
const QPoint pos = event->pos();
|
||||||
const QModelIndex index = indexAt( pos );
|
const QModelIndex index = indexAt( pos );
|
||||||
m_delegate->setDropHoverIndex( QModelIndex(), event->mimeData() );
|
|
||||||
dataChanged(m_dropIndex, m_dropIndex);
|
dataChanged(m_dropIndex, m_dropIndex);
|
||||||
m_dropIndex = QPersistentModelIndex( index );
|
m_dropIndex = QPersistentModelIndex( index );
|
||||||
|
|
||||||
@@ -469,7 +468,7 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
|
|||||||
if( item->willAcceptDrag( event->mimeData() ) )
|
if( item->willAcceptDrag( event->mimeData() ) )
|
||||||
{
|
{
|
||||||
accept = true;
|
accept = true;
|
||||||
m_delegate->setDropHoverIndex( index, event->mimeData() );
|
m_delegate->hovered( index, event->mimeData() );
|
||||||
dataChanged(index, index);
|
dataChanged(index, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,7 +496,7 @@ SourceTreeView::dropEvent( QDropEvent* event )
|
|||||||
const QPoint pos = event->pos();
|
const QPoint pos = event->pos();
|
||||||
const QModelIndex index = indexAt( 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 );
|
PlaylistItem* item = itemFromIndex< PlaylistItem >( index );
|
||||||
Q_ASSERT( item );
|
Q_ASSERT( item );
|
||||||
@@ -506,10 +505,21 @@ SourceTreeView::dropEvent( QDropEvent* event )
|
|||||||
qDebug() << "dropType is " << m_delegate->hoveredDropType();
|
qDebug() << "dropType is " << m_delegate->hoveredDropType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 );
|
QTreeView::dropEvent( event );
|
||||||
|
}
|
||||||
|
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
m_dropIndex = QPersistentModelIndex();
|
m_dropIndex = QPersistentModelIndex();
|
||||||
m_delegate->setDropHoverIndex( QModelIndex(), 0 );
|
m_delegate->dragLeaveEvent();
|
||||||
dataChanged( index, index );
|
dataChanged( index, index );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,3 +583,8 @@ SourceTreeView::itemFromIndex( const QModelIndex& index ) const
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreeView::update( const QModelIndex &index )
|
||||||
|
{
|
||||||
|
dataChanged( index, index );
|
||||||
|
}
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
#include "sourcetree/sourcesmodel.h"
|
#include "sourcetree/sourcesmodel.h"
|
||||||
|
#include "sourcetree/sourcedelegate.h"
|
||||||
|
|
||||||
class CollectionModel;
|
class CollectionModel;
|
||||||
class PlaylistModel;
|
class PlaylistModel;
|
||||||
@@ -42,6 +43,9 @@ public slots:
|
|||||||
void showOfflineSources( bool offlineSourcesShown );
|
void showOfflineSources( bool offlineSourcesShown );
|
||||||
|
|
||||||
void renamePlaylist();
|
void renamePlaylist();
|
||||||
|
|
||||||
|
void update( const QModelIndex &index );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void onOnline( const QModelIndex& index );
|
void onOnline( const QModelIndex& index );
|
||||||
void onOffline( const QModelIndex& index );
|
void onOffline( const QModelIndex& index );
|
||||||
|
Reference in New Issue
Block a user