mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-07 14:46:33 +02:00
Show headphones next to a source's now playing track to listen along
This commit is contained in:
@@ -119,5 +119,7 @@
|
|||||||
<file>data/images/uploading.png</file>
|
<file>data/images/uploading.png</file>
|
||||||
<file>data/images/downloading.png</file>
|
<file>data/images/downloading.png</file>
|
||||||
<file>data/images/headphones.png</file>
|
<file>data/images/headphones.png</file>
|
||||||
|
<file>data/images/headphones-off.png</file>
|
||||||
|
<file>data/images/headphones-sidebar.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -61,7 +61,8 @@ SourceDelegate::SourceDelegate( QAbstractItemView* parent )
|
|||||||
|
|
||||||
m_dropMimeData = new QMimeData();
|
m_dropMimeData = new QMimeData();
|
||||||
|
|
||||||
m_headphones.load( RESPATH "images/headphones.png" );
|
m_headphonesOff.load( RESPATH "images/headphones-off.png" );
|
||||||
|
m_headphonesOn.load( RESPATH "images/headphones-sidebar.png" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -158,15 +159,6 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
|
|||||||
QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
|
QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
|
||||||
|
|
||||||
QPixmap avatar = colItem->icon().pixmap( iconRect.size() );
|
QPixmap avatar = colItem->icon().pixmap( iconRect.size() );
|
||||||
if ( index.data( SourcesModel::LatchedOnRole ).toBool() && !m_headphones.isNull() )
|
|
||||||
{
|
|
||||||
// Draw headphones around the source
|
|
||||||
painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
|
|
||||||
// painter->drawPixmap( iconRect, m_headphones.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
|
|
||||||
// QRect inHeadphones = iconRect.adjusted( 5, 10, -5, 0);
|
|
||||||
// painter->drawPixmap( inHeadphones, avatar.scaledToHeight( inHeadphones.height(), Qt::SmoothTransformation ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
|
painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );
|
||||||
|
|
||||||
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
|
||||||
@@ -180,16 +172,38 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
|
|||||||
QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
|
QString text = painter->fontMetrics().elidedText( name, Qt::ElideRight, textRect.width() );
|
||||||
painter->drawText( textRect, text );
|
painter->drawText( textRect, text );
|
||||||
|
|
||||||
|
bool isPlaying = false;
|
||||||
QString desc = status ? colItem->source()->textStatus() : tr( "Offline" );
|
QString desc = status ? colItem->source()->textStatus() : tr( "Offline" );
|
||||||
if ( colItem->source().isNull() )
|
if ( colItem->source().isNull() )
|
||||||
desc = tr( "All available tracks" );
|
desc = tr( "All available tracks" );
|
||||||
if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() )
|
if ( status && desc.isEmpty() && !colItem->source()->currentTrack().isNull() )
|
||||||
|
{
|
||||||
desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track();
|
desc = colItem->source()->currentTrack()->artist() + " - " + colItem->source()->currentTrack()->track();
|
||||||
|
isPlaying = true;
|
||||||
|
}
|
||||||
if ( desc.isEmpty() )
|
if ( desc.isEmpty() )
|
||||||
desc = tr( "Online" );
|
desc = tr( "Online" );
|
||||||
|
|
||||||
textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 6, -figWidth - 24, -4 );
|
textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 6, -figWidth - 24, -4 );
|
||||||
painter->setFont( normal );
|
painter->setFont( normal );
|
||||||
|
if ( isPlaying )
|
||||||
|
{
|
||||||
|
// Show a listen icon
|
||||||
|
QPixmap pm;
|
||||||
|
if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
|
||||||
|
{
|
||||||
|
// Currently listening along
|
||||||
|
pm = m_headphonesOn;
|
||||||
|
} else {
|
||||||
|
pm = m_headphonesOff;
|
||||||
|
}
|
||||||
|
QRect pmRect = textRect;
|
||||||
|
pmRect.setTop( pmRect.bottom() - painter->fontMetrics().height() );
|
||||||
|
pmRect.setRight( pmRect.left() + pmRect.height() );
|
||||||
|
// tDebug() << "DOING HEADPHONES RECT:" << pmRect;
|
||||||
|
painter->drawPixmap( pmRect, pm.scaledToHeight( pmRect.height(), Qt::SmoothTransformation ) );
|
||||||
|
textRect.adjust( pmRect.width() + 3, 0, 0, 0 );
|
||||||
|
}
|
||||||
text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
|
text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
|
||||||
QTextOption to( Qt::AlignBottom );
|
QTextOption to( Qt::AlignBottom );
|
||||||
painter->drawText( textRect, text, to );
|
painter->drawText( textRect, text, to );
|
||||||
@@ -382,6 +396,30 @@ SourceDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QS
|
|||||||
|
|
||||||
if ( r.contains( ev->pos() ) )
|
if ( r.contains( ev->pos() ) )
|
||||||
gpi->removeFromList();
|
gpi->removeFromList();
|
||||||
|
} else if ( type == SourcesModel::Collection )
|
||||||
|
{
|
||||||
|
CollectionItem* colItem = qobject_cast< CollectionItem* >( index.data( SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
|
||||||
|
Q_ASSERT( colItem );
|
||||||
|
if ( !colItem->source()->currentTrack().isNull() )
|
||||||
|
{
|
||||||
|
QMouseEvent* ev = static_cast< QMouseEvent* >( event );
|
||||||
|
|
||||||
|
QStyleOptionViewItemV4 o = option;
|
||||||
|
initStyleOption( &o, index );
|
||||||
|
QFontMetrics fm( o.font );
|
||||||
|
const int height = fm.height() + 3;
|
||||||
|
|
||||||
|
QRect headphonesRect( option.rect.height() + 10, o.rect.bottom() - height, height, height );
|
||||||
|
// tDebug() << "CHECKING CLICK RECT:" << headphonesRect;
|
||||||
|
if ( headphonesRect.contains( ev->pos() ) )
|
||||||
|
{
|
||||||
|
if ( index.data( SourcesModel::LatchedOnRole ).toBool() )
|
||||||
|
// unlatch
|
||||||
|
emit latchOff( colItem->source() );
|
||||||
|
else
|
||||||
|
emit latchOn( colItem->source() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -41,6 +41,10 @@ public:
|
|||||||
|
|
||||||
SourceTreeItem::DropType hoveredDropType() const;
|
SourceTreeItem::DropType hoveredDropType() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void latchOn( const Tomahawk::source_ptr& idx );
|
||||||
|
void latchOff( const Tomahawk::source_ptr& idx );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
@@ -59,7 +63,7 @@ private:
|
|||||||
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;
|
QMap< QModelIndex, AnimationHelper* > m_expandedMap;
|
||||||
QPixmap m_headphones;
|
QPixmap m_headphonesOn, m_headphonesOff;
|
||||||
|
|
||||||
QMap< int, SourceTreeItem::DropType > m_dropTypeMap;
|
QMap< int, SourceTreeItem::DropType > m_dropTypeMap;
|
||||||
QMap< int, QString > m_dropTypeTextMap;
|
QMap< int, QString > m_dropTypeTextMap;
|
||||||
|
@@ -78,6 +78,9 @@ SourceTreeView::SourceTreeView( QWidget* parent )
|
|||||||
// setAnimated( true );
|
// setAnimated( true );
|
||||||
|
|
||||||
m_delegate = new SourceDelegate( this );
|
m_delegate = new SourceDelegate( this );
|
||||||
|
connect( m_delegate, SIGNAL( latchOn( Tomahawk::source_ptr ) ), this, SLOT( doLatchOn( Tomahawk::source_ptr ) ), Qt::QueuedConnection );
|
||||||
|
connect( m_delegate, SIGNAL( latchOff( Tomahawk::source_ptr ) ), this, SLOT( doLatchOff( Tomahawk::source_ptr ) ), Qt::QueuedConnection );
|
||||||
|
|
||||||
setItemDelegate( m_delegate );
|
setItemDelegate( m_delegate );
|
||||||
|
|
||||||
setContextMenuPolicy( Qt::CustomContextMenu );
|
setContextMenuPolicy( Qt::CustomContextMenu );
|
||||||
@@ -337,9 +340,7 @@ SourceTreeView::addToLocal()
|
|||||||
void
|
void
|
||||||
SourceTreeView::latchOn()
|
SourceTreeView::latchOn()
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO;
|
if ( !m_contextMenuIndex.isValid() )
|
||||||
QModelIndex idx = m_contextMenuIndex;
|
|
||||||
if ( !idx.isValid() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
|
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
|
||||||
@@ -348,6 +349,15 @@ SourceTreeView::latchOn()
|
|||||||
|
|
||||||
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
|
CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
|
||||||
source_ptr source = item->source();
|
source_ptr source = item->source();
|
||||||
|
|
||||||
|
doLatchOn( source );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreeView::doLatchOn( const source_ptr& source )
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
|
||||||
PlaylistInterface* pi = AudioEngine::instance()->playlist();
|
PlaylistInterface* pi = AudioEngine::instance()->playlist();
|
||||||
|
|
||||||
if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
|
if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
|
||||||
@@ -372,6 +382,17 @@ SourceTreeView::latchOn()
|
|||||||
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
|
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceTreeView::doLatchOff( const source_ptr& source )
|
||||||
|
{
|
||||||
|
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
|
||||||
|
|
||||||
|
|
||||||
|
AudioEngine::instance()->stop();
|
||||||
|
AudioEngine::instance()->setPlaylist( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceTreeView::playlistChanged( PlaylistInterface* newInterface )
|
SourceTreeView::playlistChanged( PlaylistInterface* newInterface )
|
||||||
{
|
{
|
||||||
@@ -423,8 +444,7 @@ void
|
|||||||
SourceTreeView::latchOff()
|
SourceTreeView::latchOff()
|
||||||
{
|
{
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
QModelIndex idx = m_contextMenuIndex;
|
if ( !m_contextMenuIndex.isValid() )
|
||||||
if ( !idx.isValid() )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
|
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
|
||||||
@@ -434,11 +454,7 @@ SourceTreeView::latchOff()
|
|||||||
const CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
|
const CollectionItem* item = itemFromIndex< CollectionItem >( m_contextMenuIndex );
|
||||||
const source_ptr source = item->source();
|
const source_ptr source = item->source();
|
||||||
|
|
||||||
AudioEngine::instance()->playItem( source->getPlaylistInterface().data(), source->getPlaylistInterface()->nextItem() );
|
doLatchOff( source );
|
||||||
|
|
||||||
|
|
||||||
AudioEngine::instance()->stop();
|
|
||||||
AudioEngine::instance()->setPlaylist( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -62,7 +62,10 @@ private slots:
|
|||||||
void addToLocal();
|
void addToLocal();
|
||||||
|
|
||||||
void latchOn();
|
void latchOn();
|
||||||
|
void doLatchOn( const Tomahawk::source_ptr& idx );
|
||||||
void latchOff();
|
void latchOff();
|
||||||
|
void doLatchOff( const Tomahawk::source_ptr& idx );
|
||||||
|
|
||||||
void playlistChanged( Tomahawk::PlaylistInterface* = 0 );
|
void playlistChanged( Tomahawk::PlaylistInterface* = 0 );
|
||||||
|
|
||||||
void onCustomContextMenu( const QPoint& pos );
|
void onCustomContextMenu( const QPoint& pos );
|
||||||
|
Reference in New Issue
Block a user