Chop ::paint into more managable pieces ( using big axe ) as it was getting really...
[amarok.git] / src / playlist / PlaylistGraphicsItem.cpp
blob2f2430b8232b6c7a799b33c5bf554f799b7ccc79
1 /***************************************************************************
2 * copyright : (C) 2007 Ian Monroe <ian@monroe.nu>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
22 #include "debug.h"
23 #include "meta/MetaUtility.h"
24 #include "AmarokMimeData.h"
25 #include "PlaylistGraphicsItem.h"
26 #include "PlaylistGraphicsView.h"
27 #include "PlaylistDropVis.h"
28 #include "PlaylistModel.h"
29 #include "PlaylistTextItem.h"
30 #include "TheInstances.h"
31 #include "CoverManager.h"
33 #include "KStandardDirs"
35 #include <QBrush>
36 #include <QDrag>
37 #include <QFontMetricsF>
38 #include <QGraphicsScene>
39 #include <QGraphicsTextItem>
40 #include <QGraphicsPixmapItem>
41 #include <QGraphicsRectItem>
42 #include <QGraphicsSceneMouseEvent>
43 #include <QGraphicsView>
44 #include <QMimeData>
45 #include <QPen>
46 #include <QPixmapCache>
47 #include <QRadialGradient>
48 #include <QScrollBar>
49 #include <QStyleOptionGraphicsItem>
51 #include <KLocale>
53 struct Playlist::GraphicsItem::ActiveItems
55 ActiveItems()
56 : foreground( 0 )
57 , bottomLeftText( 0 )
58 , bottomRightText( 0 )
59 , topLeftText( 0 )
60 , topRightText( 0 )
61 , lastWidth( -5 )
62 , groupedTracks ( 0 )
63 , collapsible( true )
64 { }
66 ~ActiveItems()
68 delete bottomLeftText;
69 delete bottomRightText;
70 delete foreground;
71 delete topLeftText;
72 delete topRightText;
76 QGraphicsPixmapItem* foreground;
77 Playlist::TextItem* bottomLeftText;
78 Playlist::TextItem* bottomRightText;
79 Playlist::TextItem* topLeftText;
80 Playlist::TextItem* topRightText;
82 QColor overlayGradientStart;
83 QColor overlayGradientEnd;
85 int lastWidth;
86 int groupedTracks;
87 bool collapsible;
89 QRectF preDragLocation;
90 Meta::TrackPtr track;
94 const qreal Playlist::GraphicsItem::ALBUM_WIDTH = 50.0;
95 const qreal Playlist::GraphicsItem::MARGIN = 4.0;
96 QFontMetricsF* Playlist::GraphicsItem::s_fm = 0;
97 QSvgRenderer * Playlist::GraphicsItem::s_svgRenderer = 0;
100 Playlist::GraphicsItem::GraphicsItem()
101 : QGraphicsItem()
102 , m_items( 0 )
103 , m_height( -1 )
104 , m_groupMode( -1 )
105 , m_groupModeChanged ( false )
106 , m_collapsible ( true )
107 , m_dataChanged( false )
109 setZValue( 1.0 );
110 if( !s_fm )
112 s_fm = new QFontMetricsF( QFont() );
113 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + 2 * MARGIN;
116 if ( !s_svgRenderer ) {
117 s_svgRenderer = new QSvgRenderer( KStandardDirs::locate( "data","amarok/images/playlist_items.svg" ));
118 if ( ! s_svgRenderer->isValid() )
119 debug() << "svg is kaputski";
122 setFlag( QGraphicsItem::ItemIsSelectable );
123 setFlag( QGraphicsItem::ItemIsMovable );
124 setAcceptDrops( true );
125 // setHandlesChildEvents( true ); // don't let drops etc hit the text items, doing stupid things
128 Playlist::GraphicsItem::~GraphicsItem()
130 delete m_items;
133 void
134 Playlist::GraphicsItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget )
136 // ::paint RULES:
137 // 1) You do not talk about ::paint method
138 // 2) You DO NOT talk about ::paint method
139 // 3) Do not show or hide item that are already shown or hidden, respectively
140 // 4) Do not setBrush without making sure its hasn't already been set to that brush().
141 // 5) ::paint RULES apply to all methods called from ::paint as well ( duh! )
142 // 6) If this is your first night at ::paint method, you HAVE to paint.
143 Q_UNUSED( painter ); Q_UNUSED( widget );
145 //debug() << "painting row: " << m_currentRow;
146 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
148 if( m_dataChanged || !m_items || ( option->rect.width() != m_items->lastWidth ) || m_groupModeChanged )
151 if( !m_items )
153 const Meta::TrackPtr track = index.data( ItemRole ).value< Playlist::Item* >()->track();
154 m_items = new Playlist::GraphicsItem::ActiveItems();
155 m_items->track = track;
156 init( track );
158 m_groupModeChanged = false;
159 resize( m_items->track, option->rect.width() );
162 bool isActiveTrack = index.data( ActiveTrackRole ).toBool();
165 // call paint method based on type
166 if ( m_groupMode == None ) {
167 paintSingleTrack( painter, option, isActiveTrack );
168 } else if ( m_groupMode == Head ) {
169 paintHead( painter, option, isActiveTrack );
170 } else if ( m_groupMode == Head_Collapsed ) {
171 paintCollapsedHead( painter, option, isActiveTrack );
172 } else if ( m_groupMode == Body ) {
173 paintBody( painter, option, isActiveTrack, index.data( GroupedAlternateRole ).toBool() );
174 } else if ( m_groupMode == End ) {
175 paintTail( painter, option, isActiveTrack, index.data( GroupedAlternateRole ).toBool() );
176 } else if ( m_groupMode == Collapsed ) {
177 paintCollapsed( );
180 return;
184 void
185 Playlist::GraphicsItem::init( Meta::TrackPtr track )
187 Q_UNUSED( track );
188 QFont font;
189 font.setPointSize( font.pointSize() - 1 );
190 #define NewText( X ) \
191 X = new Playlist::TextItem( this ); \
192 X->setTextInteractionFlags( Qt::TextEditorInteraction ); \
193 X->setFont( font );
194 NewText( m_items->topLeftText )
195 NewText( m_items->bottomLeftText )
196 NewText( m_items->topRightText )
197 NewText( m_items->bottomRightText )
198 #undef NewText
201 void
202 Playlist::GraphicsItem::resize( Meta::TrackPtr track, int totalWidth )
204 if( totalWidth == -1 /*|| totalWidth == m_items->lastWidth */) //no change needed
205 return;
206 if( m_items->lastWidth != -5 ) //this isn't the first "resize"
207 prepareGeometryChange();
208 m_items->lastWidth = totalWidth;
210 QString prettyLength;
212 if ( m_groupMode == Head_Collapsed )
214 uint seconds = 0;
215 for( int i = m_currentRow; i < m_currentRow + m_items->groupedTracks; i++ )
216 seconds += The::playlistModel()->itemList()[ i ]->track()->length();
217 prettyLength = Meta::secToPrettyTime( seconds );
219 else
220 prettyLength = Meta::secToPrettyTime( track->length() );
222 QString album;
223 if( track->album() )
224 album = track->album()->name();
226 const qreal lineTwoY = m_height / 2 + MARGIN;
227 const qreal textWidth = ( ( qreal( totalWidth ) - ALBUM_WIDTH ) / 2.0 );
228 const qreal leftAlignX = ALBUM_WIDTH + MARGIN;
229 qreal topRightAlignX;
230 qreal bottomRightAlignX;
233 qreal middle = textWidth + ALBUM_WIDTH + ( MARGIN * 2.0 );
234 qreal rightWidth = totalWidth - qMax( s_fm->width( album )
235 , s_fm->width( prettyLength ) );
236 topRightAlignX = qMax( middle, rightWidth );
239 //lets use all the horizontal space we can get for now..
240 int lengthStringWidth = (int)(s_fm->width( prettyLength ));
241 bottomRightAlignX = ( totalWidth - 4 * MARGIN ) - lengthStringWidth ;
246 qreal spaceForTopLeft = totalWidth - ( totalWidth - topRightAlignX ) - leftAlignX;
247 qreal spaceForBottomLeft = totalWidth - ( totalWidth - bottomRightAlignX ) - leftAlignX;
249 if ( m_groupMode == Head_Collapsed ) {
251 m_items->bottomLeftText->setEditableText( QString("%1 tracks").arg( QString::number( m_items->groupedTracks ) ) , spaceForBottomLeft );
252 QFont f = m_items->bottomLeftText->font();
253 f.setItalic( true );
254 m_items->bottomLeftText->setFont( f );
255 m_items->bottomRightText->setEditableText( prettyLength, totalWidth - bottomRightAlignX );
257 } else {
258 m_items->bottomLeftText->setFont( m_items->bottomRightText->font() );
259 m_items->bottomLeftText->setEditableText( QString("%1 - %2").arg( QString::number( track->trackNumber() ), track->name() ) , spaceForBottomLeft );
260 m_items->bottomRightText->setEditableText( prettyLength, totalWidth - bottomRightAlignX );
262 if ( m_groupMode == None ) {
264 m_items->topRightText->setPos( topRightAlignX, MARGIN );
265 m_items->topRightText->setEditableText( album, totalWidth - topRightAlignX );
268 QString artist;
269 if( track->artist() )
270 artist = track->artist()->name();
271 m_items->topLeftText->setEditableText( artist, spaceForTopLeft );
272 m_items->topLeftText->setPos( leftAlignX, MARGIN );
275 m_items->bottomLeftText->setPos( leftAlignX, lineTwoY );
276 m_items->bottomRightText->setPos( bottomRightAlignX, lineTwoY );
277 } else if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
279 int headingCenter = (int)( MARGIN + ( ALBUM_WIDTH - s_fm->height()) / 2 );
281 m_items->topRightText->setPos( topRightAlignX, headingCenter );
282 m_items->topRightText->setEditableText( album, totalWidth - topRightAlignX );
285 QString artist;
286 //various artist handling:
287 //if the album has no albumartist, use Various Artists, otherwise use the albumartist's name
288 if( track->album()->albumArtist() )
289 artist = track->album()->albumArtist()->name();
290 else
292 artist = findArtistForCurrentAlbum();
293 if( artist.isEmpty() )
294 artist = i18n( "Various Artists" );
296 m_items->topLeftText->setEditableText( artist, spaceForTopLeft );
297 m_items->topLeftText->setPos( leftAlignX, headingCenter );
300 int underImageY = (int)( MARGIN + ALBUM_WIDTH + 6 );
302 m_items->bottomLeftText->setPos( MARGIN * 3, underImageY );
303 m_items->bottomRightText->setPos( bottomRightAlignX, underImageY );
305 } else {
306 m_items->bottomLeftText->setPos( MARGIN * 3, 0 );
307 m_items->bottomRightText->setPos( bottomRightAlignX, 0 );
310 //make sure the activ eitem overlay has the correct width
314 if( m_items->foreground )
317 QRectF trackRect;
318 if ( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) {
319 trackRect = QRectF( 0, ALBUM_WIDTH + 2 * MARGIN, totalWidth, s_fm->height() /*+ MARGIN*/ );
320 } else {
321 trackRect = QRectF( 0, 0, totalWidth, m_height );
322 if ( ( m_groupMode != Body) && !( ( m_groupMode == Head ) ) )
323 trackRect.setHeight( trackRect.height() - 2 ); // add a little space between items
326 debug() << "Resizing active track overlay";
328 QString key = QString("active_overlay:%1x%2").arg(trackRect.width()).arg(trackRect.height());
330 QPixmap background( (int)( trackRect.width() ), (int)( trackRect.height() ) );
331 background.fill( Qt::transparent );
334 if (!QPixmapCache::find(key, background)) {
335 QPainter pt( &background );
336 s_svgRenderer->render( &pt, "active_overlay", QRectF( 0, 0, trackRect.width(), trackRect.height() ) );
337 QPixmapCache::insert(key, background);
339 m_items->foreground->setPixmap( background );
340 m_items->foreground->setZValue( 10.0 );
342 debug() << "Done";
346 m_items->lastWidth = totalWidth;
349 QString
350 Playlist::GraphicsItem::findArtistForCurrentAlbum() const
352 if( !( ( m_groupMode == Head ) || ( m_groupMode == Head_Collapsed ) ) )
353 return QString();
355 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
356 if( ! ( ( index.data( GroupRole ).toInt() == Head ) || ( index.data( GroupRole ).toInt() == Head_Collapsed ) ) )
358 return QString();
360 else
362 QString artist;
363 Meta::TrackPtr currentTrack = index.data( TrackRole ).value< Meta::TrackPtr >();
364 if( currentTrack->artist() )
365 artist = currentTrack->artist()->name();
366 else
367 return QString();
368 //it's an album group, and the current row is the head, so the next row is either Body or End
369 //that means we have to execute the loop at least once
370 QModelIndex idx;
371 int row = m_currentRow + 1;
374 idx = The::playlistModel()->index( row++, 0 );
375 Meta::TrackPtr track = idx.data( TrackRole ).value< Meta::TrackPtr >();
376 if( track->artist() )
378 if( artist != track->artist()->name() )
379 return QString();
381 else
383 return QString();
386 while( idx.data( GroupRole ).toInt() == Body );
388 return artist;
392 QRectF
393 Playlist::GraphicsItem::boundingRect() const
395 // the viewport()->size() takes scrollbars into account
396 return QRectF( 0.0, 0.0, The::playlistView()->viewport()->size().width(), m_height );
399 void
400 Playlist::GraphicsItem::play()
402 The::playlistModel()->play( m_currentRow );
405 void
406 Playlist::GraphicsItem::showImage() const
408 ( new CoverViewDialog( m_items->track->album(), The::playlistView() ) )->show();
411 void
412 Playlist::GraphicsItem::fetchImage()
414 CoverFetcher *fetcher = The::coverFetcher();
415 fetcher->manualFetch( m_items->track->album() );
418 void
419 Playlist::GraphicsItem::unsetImage()
421 m_items->track->album()->removeImage();
424 void
425 Playlist::GraphicsItem::dataChanged()
427 m_dataChanged = true;
430 const bool
431 Playlist::GraphicsItem::hasImage() const
433 return m_items->track->album()->hasImage();
436 void
437 Playlist::GraphicsItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent *event )
439 if( m_items )
441 event->accept();
442 play();
443 return;
445 QGraphicsItem::mouseDoubleClickEvent( event );
448 void
449 Playlist::GraphicsItem::mousePressEvent( QGraphicsSceneMouseEvent *event )
451 if( event->buttons() & Qt::RightButton || !m_items )
453 event->ignore();
454 return;
456 m_items->preDragLocation = mapToScene( boundingRect() ).boundingRect();
458 //did we hit the collapse / expand button?
459 if( m_collapsible )
461 QRectF rect( boundingRect().width() - ( 16 + MARGIN ), MARGIN, 16, 16 );
462 if( rect.contains( event->pos() ) )
464 if ( m_groupMode == Head_Collapsed )
465 The::playlistModel()->setCollapsed( m_currentRow, false );
466 else if ( m_groupMode == Head )
467 The::playlistModel()->setCollapsed( m_currentRow, true );
471 QGraphicsItem::mousePressEvent( event );
474 // With help from QGraphicsView::mouseMoveEvent()
475 void
476 Playlist::GraphicsItem::mouseMoveEvent( QGraphicsSceneMouseEvent *event )
478 if( (event->buttons() & Qt::LeftButton) && ( flags() & QGraphicsItem::ItemIsMovable) && m_items )
480 QPointF scenePosition = event->scenePos();
482 if( scenePosition.y() < 0 )
483 return;
485 bool dragOverOriginalPosition = m_items->preDragLocation.contains( scenePosition );
487 //make sure item is drawn on top of other items
488 setZValue( 2.0 );
490 // Determine the list of selected items
491 QList<QGraphicsItem *> selectedItems = scene()->selectedItems();
492 if( !isSelected() )
493 selectedItems << this;
494 // Move all selected items
495 foreach( QGraphicsItem *item, selectedItems )
497 if( (item->flags() & QGraphicsItem::ItemIsMovable) && (!item->parentItem() || !item->parentItem()->isSelected()) )
499 Playlist::GraphicsItem *above = 0;
500 QPointF diff;
501 if( item == this && !dragOverOriginalPosition )
503 diff = event->scenePos() - event->lastScenePos();
504 QList<QGraphicsItem*> collisions = scene()->items( event->scenePos() );
505 foreach( QGraphicsItem *i, collisions )
507 Playlist::GraphicsItem *c = dynamic_cast<Playlist::GraphicsItem *>( i );
508 if( c && c != this )
510 above = c;
511 break;
515 else
517 diff = item->mapToParent( item->mapFromScene(event->scenePos()))
518 - item->mapToParent(item->mapFromScene(event->lastScenePos()));
521 item->moveBy( 0, diff.y() );
522 if( item->flags() & ItemIsSelectable )
523 item->setSelected( true );
525 if( dragOverOriginalPosition )
526 Playlist::DropVis::instance()->show( m_items->preDragLocation.y() );
527 else
528 Playlist::DropVis::instance()->show( above );
532 else
534 QGraphicsItem::mouseMoveEvent( event );
538 void
539 Playlist::GraphicsItem::dragEnterEvent( QGraphicsSceneDragDropEvent *event )
541 foreach( const QString &mime, The::playlistModel()->mimeTypes() )
543 if( event->mimeData()->hasFormat( mime ) )
545 event->accept();
546 Playlist::DropVis::instance()->show( this );
547 break;
552 void
553 Playlist::GraphicsItem::dropEvent( QGraphicsSceneDragDropEvent * event )
555 event->accept();
556 setZValue( 1.0 );
557 The::playlistModel()->dropMimeData( event->mimeData(), Qt::CopyAction, m_currentRow, 0, QModelIndex() );
558 Playlist::DropVis::instance()->hide();
561 void
562 Playlist::GraphicsItem::refresh()
564 QPixmap albumPixmap;
565 if( !m_items || !m_items->track )
566 return;
568 if( m_items->track->album() )
570 if( !m_items->track->album()->hasImage( int(ALBUM_WIDTH) ) )
572 The::coverFetcher()->queueAlbum( m_items->track->album() );
574 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
577 //m_items->albumArt->hide();
578 //delete ( m_items->albumArt );
579 //m_items->albumArt = new QGraphicsPixmapItem( albumPixmap, this );
580 //m_items->albumArt->setPos( 0.0, MARGIN );
583 void Playlist::GraphicsItem::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
585 bool dragOverOriginalPosition = m_items->preDragLocation.contains( event->scenePos() );
586 if( dragOverOriginalPosition )
588 setPos( m_items->preDragLocation.topLeft() );
589 Playlist::DropVis::instance()->hide();
590 return;
593 Playlist::GraphicsItem *above = 0;
594 QList<QGraphicsItem*> collisions = scene()->items( event->scenePos() );
595 foreach( QGraphicsItem *i, collisions )
597 Playlist::GraphicsItem *c = dynamic_cast<Playlist::GraphicsItem *>( i );
598 if( c && c != this )
600 above = c;
601 break;
604 // if we've dropped ourself ontop of another item, then we need to shuffle the tracks below down
605 if( above )
607 setPos( above->pos() );
608 The::playlistView()->moveItem( this, above );
609 } else {
610 //Don't just drop item into the void, make it the last item!
612 The::playlistView()->moveItem( this, 0 );
613 //setPos( above->pos() );
614 //The::playlistView()->moveItem( this, above );
618 //make sure item resets its z value
619 setZValue( 1.0 );
620 Playlist::DropVis::instance()->hide();
623 void Playlist::GraphicsItem::setRow(int row)
625 //DEBUG_BLOCK
626 m_currentRow = row;
628 const QModelIndex index = The::playlistModel()->index( m_currentRow, 0 );
630 //figure out our group state and set height accordingly
631 int currentGroupState = index.data( GroupRole ).toInt();
633 if ( currentGroupState != m_groupMode ) {
635 debug() << "Group changed for row " << row;
637 prepareGeometryChange();
640 m_groupMode = currentGroupState;
641 m_groupModeChanged = true;
643 switch ( m_groupMode ) {
645 case None:
646 debug() << "None";
647 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + 2 * MARGIN + 2;
648 break;
649 case Head:
650 debug() << "Head";
651 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + MARGIN + s_fm->height() + 6;
652 break;
653 case Head_Collapsed:
654 debug() << "Collapsed head";
655 m_height = qMax( ALBUM_WIDTH, s_fm->height() * 2 ) + MARGIN + s_fm->height() + 10;
656 if ( !m_items ) {
657 const Meta::TrackPtr track = index.data( ItemRole ).value< Playlist::Item* >()->track();
658 m_items = new Playlist::GraphicsItem::ActiveItems();
659 m_items->track = track;
660 init( track );
662 m_items->groupedTracks = index.data( GroupedTracksRole ).toInt();
663 break;
664 case Body:
665 debug() << "Body";
666 m_height = s_fm->height()/*+ 2 * MARGIN*/;
667 break;
668 case End:
669 debug() << "End";
670 m_height = s_fm->height() + 6 /*+ 2 * MARGIN*/;
671 break;
672 case Collapsed:
673 debug() << "Collapsed";
674 m_height = 0;
675 break;
676 default:
677 debug() << "ERROR!!??";
682 void Playlist::GraphicsItem::hoverEnterEvent( QGraphicsSceneHoverEvent *event )
684 Q_UNUSED( event );
685 //DEBUG_BLOCK
687 /*if ( m_groupMode == Head_Collapsed )
688 The::playlistModel()->setCollapsed( m_currentRow, false ); */
691 void Playlist::GraphicsItem::paintSingleTrack( QPainter * painter, const QStyleOptionGraphicsItem * option, bool active )
693 DEBUG_BLOCK
695 QRectF trackRect = option->rect;
696 painter->drawPixmap( 0, 0, getCachedSvg( "track", trackRect.width(), trackRect.height() ) );
698 //paint cover
699 QPixmap albumPixmap;
700 if( m_items->track->album() )
702 if( !m_items->track->album()->hasImage( int( ALBUM_WIDTH ) ) )
704 The::coverFetcher()->queueAlbum( m_items->track->album() );
706 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
708 painter->drawPixmap( imageLocation(), albumPixmap, QRectF( albumPixmap.rect() ) );
709 //and make sure the top text elements are shown
710 if( !m_items->topRightText->isVisible() )
711 m_items->topRightText->show();
712 if( !m_items->topLeftText->isVisible() )
713 m_items->topLeftText->show();
716 //set selection marker if needed
717 if( option->state & QStyle::State_Selected )
719 painter->drawPixmap( 2, (int)trackRect.top(), getCachedSvg( "selection_left", 40, trackRect.height() ) );
720 painter->drawPixmap( (int)trackRect.width() - 42, (int)trackRect.top(), getCachedSvg( "selection_right", 40, trackRect.height() ) );
724 //set overlay if item is active:
725 handleActiveOverlay( trackRect, active );
729 void Playlist::GraphicsItem::paintHead( QPainter * painter, const QStyleOptionGraphicsItem * option, bool active )
731 QRectF trackRect = QRectF( option->rect.x(), ALBUM_WIDTH + 2 * MARGIN, option->rect.width(), s_fm->height() /*+ MARGIN*/ );
732 QRectF headRect = option->rect;
734 painter->drawPixmap( 0, 0, getCachedSvg( "head", headRect.width(), headRect.height() ) );
737 //paint collapse button
738 QString collapseString;
739 if ( m_groupMode == Head )
741 if ( m_collapsible )
742 collapseString = "collapse_button";
743 else
744 collapseString = "collapse_button_grayed_out";
746 else
747 collapseString = "expand_button";
749 painter->drawPixmap( (int)( option->rect.width() - ( 16 + MARGIN ) ), (int)MARGIN, getCachedSvg( collapseString, 16, 16 ) );
752 //paint cover
753 QPixmap albumPixmap;
754 if( m_items->track->album() )
756 if( !m_items->track->album()->hasImage( int( ALBUM_WIDTH ) ) )
758 The::coverFetcher()->queueAlbum( m_items->track->album() );
760 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
762 painter->drawPixmap( imageLocation(), albumPixmap, QRectF( albumPixmap.rect() ) );
763 //and make sure the top text elements are shown
764 if( !m_items->topRightText->isVisible() )
765 m_items->topRightText->show();
766 if( !m_items->topLeftText->isVisible() )
767 m_items->topLeftText->show();
770 //set selection marker if needed
771 if( option->state & QStyle::State_Selected )
773 painter->drawPixmap( 2, (int)trackRect.top() + 2, getCachedSvg( "selection_left", 40, trackRect.height() ) );
774 painter->drawPixmap( (int)trackRect.width() - 42, (int)trackRect.top() + 2, getCachedSvg( "selection_right", 40, trackRect.height() ) );
777 //set overlay if item is active:
778 handleActiveOverlay( trackRect, active );
782 void Playlist::GraphicsItem::paintCollapsedHead( QPainter * painter, const QStyleOptionGraphicsItem * option, bool active )
784 QRectF trackRect = QRectF( option->rect.x(), ALBUM_WIDTH + 2 * MARGIN, option->rect.width(), s_fm->height() /*+ MARGIN*/ );
785 QRectF headRect = QRectF( option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height() - 2 );
787 //paint background
788 painter->drawPixmap( 0, 0, getCachedSvg( "collapsed_head", headRect.width(), headRect.height() ) );
790 //paint collapse button
791 QString collapseString;
792 if ( m_groupMode == Head )
794 if ( m_collapsible )
795 collapseString = "collapse_button";
796 else
797 collapseString = "collapse_button_grayed_out";
799 else
800 collapseString = "expand_button";
802 painter->drawPixmap( (int)( option->rect.width() - ( 16 + MARGIN ) ), (int)MARGIN, getCachedSvg( collapseString, 16, 16 ) );
804 //paint cover:
805 QPixmap albumPixmap;
806 if( m_items->track->album() )
808 if( !m_items->track->album()->hasImage( int( ALBUM_WIDTH ) ) )
810 The::coverFetcher()->queueAlbum( m_items->track->album() );
812 albumPixmap = m_items->track->album()->image( int( ALBUM_WIDTH ) );
814 painter->drawPixmap( imageLocation(), albumPixmap, QRectF( albumPixmap.rect() ) );
815 //and make sure the top text elements are shown
816 if( !m_items->topRightText->isVisible() )
817 m_items->topRightText->show();
818 if( !m_items->topLeftText->isVisible() )
819 m_items->topLeftText->show();
821 //set selection marker if needed
822 if( option->state & QStyle::State_Selected )
824 painter->drawPixmap( 2, (int)trackRect.top(), getCachedSvg( "selection_left", 40, trackRect.height() ) );
825 painter->drawPixmap( (int)trackRect.width() - 42, (int)trackRect.top(), getCachedSvg( "selection_right", 40, trackRect.height() ) );
828 //set overlay if item is active
829 handleActiveOverlay( trackRect, active );
833 void Playlist::GraphicsItem::paintBody( QPainter * painter, const QStyleOptionGraphicsItem * option, bool active, bool alternate )
835 QRectF trackRect = option->rect;
837 painter->drawPixmap( 0, 0, getCachedSvg( "body", trackRect.width(), trackRect.height() ) );
840 //draw alternate background if needed
841 if ( alternate )
842 painter->drawPixmap( 5, 0, getCachedSvg( "body_background", trackRect.width() - 10, trackRect.height() ) );
844 //make sure that the top text items are not shown
845 if( m_items->topRightText->isVisible() )
846 m_items->topRightText->hide();
847 if( m_items->topLeftText->isVisible() )
848 m_items->topLeftText->hide();
849 if( !m_items->bottomRightText->isVisible() )
850 m_items->bottomRightText->show();
851 if( !m_items->bottomLeftText->isVisible() )
852 m_items->bottomLeftText->show();
854 //set selection marker if needed
855 if( option->state & QStyle::State_Selected )
858 painter->drawPixmap( 2, (int)trackRect.top(), getCachedSvg( "selection_left", 40, trackRect.height() ) );
859 painter->drawPixmap( (int)trackRect.width() - 42, (int)trackRect.top(), getCachedSvg( "selection_right", 40, trackRect.height() ) );
862 //set overlay if item is active
863 handleActiveOverlay( trackRect, active );
868 void Playlist::GraphicsItem::paintTail( QPainter * painter, const QStyleOptionGraphicsItem * option, bool active, bool alternate )
870 QRectF trackRect = option->rect;
871 trackRect.setHeight( trackRect.height() - 2 ); // add a little space between items
873 painter->drawPixmap( 0, 0, getCachedSvg( "tail", trackRect.width(), trackRect.height() ) );
875 if ( alternate )
878 QRectF tempRect = trackRect;
879 tempRect.setWidth( tempRect.width() - 10 );
880 tempRect.setHeight( tempRect.height() - 4 );
881 painter->drawPixmap( 5, 0, getCachedSvg( "body_background", tempRect.width(), tempRect.height() ) );
885 //make sure that the top text items are not shown
886 if( m_items->topRightText->isVisible() )
887 m_items->topRightText->hide();
888 if( m_items->topLeftText->isVisible() )
889 m_items->topLeftText->hide();
890 if( !m_items->bottomRightText->isVisible() )
891 m_items->bottomRightText->show();
892 if( !m_items->bottomLeftText->isVisible() )
893 m_items->bottomLeftText->show();
895 //set selection marker if needed
896 if( option->state & QStyle::State_Selected )
899 painter->drawPixmap( 2, (int)trackRect.top(), getCachedSvg( "selection_left", 40, trackRect.height() ) );
900 painter->drawPixmap( (int)trackRect.width() - 42, (int)trackRect.top(), getCachedSvg( "selection_right", 40, trackRect.height() ) );
903 //set overlay if item is active
904 handleActiveOverlay( trackRect, active );
908 void Playlist::GraphicsItem::paintCollapsed()
911 // just make sure text items are hidden and then get the heck out of here...
912 if( m_items->topRightText->isVisible() )
913 m_items->topRightText->hide();
914 if( m_items->topLeftText->isVisible() )
915 m_items->topLeftText->hide();
916 if( m_items->bottomRightText->isVisible() )
917 m_items->bottomRightText->hide();
918 if( m_items->bottomLeftText->isVisible() )
919 m_items->bottomLeftText->hide();
922 QPixmap Playlist::GraphicsItem::getCachedSvg( QString name, int width, int height )
924 QString key = QString("%1:%2x%3").arg( name ).arg( width ).arg( height );
925 QPixmap pixmap( width, height );
926 pixmap.fill( Qt::transparent );
928 if( !QPixmapCache::find(key, pixmap) )
930 QPainter pt2( &pixmap );
931 s_svgRenderer->render( &pt2, name, QRectF( 0, 0, width, height ) );
932 QPixmapCache::insert(key, pixmap);
935 return pixmap;
938 void Playlist::GraphicsItem::handleActiveOverlay( QRectF rect, bool active )
940 if( active )
942 if( !m_items->foreground )
945 debug() << "Creating active track overlay";
946 m_items->foreground = new QGraphicsPixmapItem( this );
947 m_items->foreground->setPos( 0.0, rect.top() );
948 m_items->foreground->setZValue( 10.0 );
950 m_items->foreground->setPixmap( getCachedSvg( "active_overlay", rect.width(), rect.height() ) );
951 m_items->foreground->show();
952 debug() << "Done";
955 if( !m_items->foreground->isVisible() )
956 m_items->foreground->show();
958 else if( m_items->foreground && m_items->foreground->isVisible() )
959 m_items->foreground->hide();