1 /*****************************************************************************
2 * icon_view.cpp : Icon view for the Playlist
3 ****************************************************************************
4 * Copyright © 2010 the VideoLAN team
7 * Authors: Jean-Baptiste Kempf <jb@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include "components/playlist/icon_view.hpp"
25 #include "components/playlist/playlist_model.hpp"
26 #include "components/playlist/sorting.h"
27 #include "input_manager.hpp"
29 #include <QApplication>
32 #include <QStyleOptionViewItem>
33 #include <QFontMetrics>
34 #include <QPixmapCache>
38 #define ART_SIZE_W 110
43 QString AbstractPlViewItemDelegate::getMeta( const QModelIndex & index, int meta ) const
45 return index.model()->index( index.row(),
46 PLModel::columnFromMeta( meta ),
51 void AbstractPlViewItemDelegate::paintBackground(
52 QPainter *painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
54 /* FIXME: This does not indicate item selection in all QStyles, so for the time being we
55 have to draw it ourselves, to ensure visible effect of selection on all platforms */
56 /* QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &option,
60 QRect r = option.rect.adjusted( 0, 0, -1, -1 );
61 if( option.state & QStyle::State_Selected )
63 painter->setBrush( option.palette.color( QPalette::Highlight ) );
64 painter->setPen( option.palette.color( QPalette::Highlight ).darker( 150 ) );
65 painter->drawRect( r );
67 else if( index.data( PLModel::IsCurrentRole ).toBool() )
69 painter->setBrush( QBrush( Qt::lightGray ) );
70 painter->setPen( QColor( Qt::darkGray ) );
71 painter->drawRect( r );
73 if( option.state & QStyle::State_MouseOver )
75 painter->setOpacity( 0.5 );
76 painter->setPen( Qt::NoPen );
77 painter->setBrush( option.palette.color( QPalette::Highlight ).lighter( 150 ) );
78 painter->drawRect( option.rect );
83 QPixmap AbstractPlViewItemDelegate::getArtPixmap( const QModelIndex & index, const QSize & size ) const
85 PLItem *item = static_cast<PLItem*>( index.internalPointer() );
88 QString artUrl = InputManager::decodeArtURL( item->inputItem() );
90 if( artUrl.isEmpty() )
92 for( int i = 0; i < item->childCount(); i++ )
94 artUrl = InputManager::decodeArtURL( item->child( i )->inputItem() );
95 if( !artUrl.isEmpty() )
102 QString key = artUrl + QString("%1%2").arg(size.width()).arg(size.height());
104 if( !QPixmapCache::find( key, artPix ))
106 if( artUrl.isEmpty() || !artPix.load( artUrl ) )
108 key = QString("noart%1%2").arg(size.width()).arg(size.height());
109 if( !QPixmapCache::find( key, artPix ) )
111 artPix = QPixmap( ":/noart" ).scaled( size,
113 Qt::SmoothTransformation );
114 QPixmapCache::insert( key, artPix );
119 artPix = artPix.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
120 QPixmapCache::insert( key, artPix );
127 void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
129 QString title = getMeta( index, COLUMN_TITLE );
130 QString artist = getMeta( index, COLUMN_ARTIST );
132 QPixmap artPix = getArtPixmap( index, QSize( ART_SIZE_W, ART_SIZE_H ) );
134 paintBackground( painter, option, index );
138 QRect artRect( option.rect.x() + 5 + ( ART_SIZE_W - artPix.width() ) / 2,
139 option.rect.y() + 5 + ( ART_SIZE_H - artPix.height() ) / 2,
140 artPix.width(), artPix.height() );
142 // Draw the drop shadow
144 painter->setOpacity( 0.7 );
145 painter->setBrush( QBrush( Qt::darkGray ) );
146 painter->setPen( Qt::NoPen );
147 painter->drawRoundedRect( artRect.adjusted( 0, 0, 2, 2 ), ART_RADIUS, ART_RADIUS );
150 // Draw the art pixmap
151 QPainterPath artRectPath;
152 artRectPath.addRoundedRect( artRect, ART_RADIUS, ART_RADIUS );
153 painter->setClipPath( artRectPath );
154 painter->drawPixmap( artRect, artPix );
155 painter->setClipping( false );
157 if( option.state & QStyle::State_Selected )
158 painter->setPen( option.palette.color( QPalette::HighlightedText ) );
160 QFont font( index.data( Qt::FontRole ).value<QFont>() );
161 font.setPointSize( 7 );
163 //Draw children indicator
164 if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
166 painter->setOpacity( 0.75 );
167 QRect r( option.rect );
168 r.setSize( QSize( 25, 25 ) );
170 painter->fillRect( r, option.palette.color( QPalette::Mid ) );
171 painter->setOpacity( 1.0 );
172 QPixmap dirPix( ":/type/node" );
173 QRect r2( dirPix.rect() );
174 r2.moveCenter( r.center() );
175 painter->drawPixmap( r2, dirPix );
179 font.setItalic( true );
180 painter->setFont( font );
182 QFontMetrics fm = painter->fontMetrics();
183 QRect textRect = option.rect.adjusted( 1, ART_SIZE_H + 10, 0, -1 );
184 textRect.setHeight( fm.height() );
186 painter->drawText( textRect,
187 fm.elidedText( title, Qt::ElideRight, textRect.width() ),
188 QTextOption( Qt::AlignCenter ) );
191 painter->setPen( painter->pen().color().lighter( 150 ) );
192 font.setItalic( false );
193 painter->setFont( font );
194 fm = painter->fontMetrics();
196 textRect.moveTop( textRect.bottom() + 1 );
198 painter->drawText( textRect,
199 fm.elidedText( artist, Qt::ElideRight, textRect.width() ),
200 QTextOption( Qt::AlignCenter ) );
205 QSize PlIconViewItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
210 QFontMetrics fm( f );
211 int textHeight = fm.height();
212 QSize sz ( ART_SIZE_W + 2 * SPACER,
213 ART_SIZE_H + 3 * SPACER + 2 * textHeight + 1 );
218 #define LISTVIEW_ART_SIZE 45
220 void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
222 QModelIndex parent = index.parent();
225 QString title = getMeta( index, COLUMN_TITLE );
226 QString duration = getMeta( index, COLUMN_DURATION );
227 if( !duration.isEmpty() ) title += QString(" [%1]").arg( duration );
229 QString artist = getMeta( index, COLUMN_ARTIST );
230 QString album = getMeta( index, COLUMN_ALBUM );
231 QString trackNum = getMeta( index, COLUMN_TRACK_NUMBER );
232 QString artistAlbum = artist
233 + ( artist.isEmpty() ? QString() : QString( ": " ) )
235 + ( album.isEmpty() || trackNum.isEmpty() ?
236 QString() : QString( " [#%1]" ).arg( trackNum ) );
238 QPixmap artPix = getArtPixmap( index, QSize( LISTVIEW_ART_SIZE, LISTVIEW_ART_SIZE ) );
240 //Draw selection rectangle and current playing item indication
241 paintBackground( painter, option, index );
243 QRect artRect( artPix.rect() );
244 artRect.moveCenter( QPoint( artRect.center().x() + 3,
245 option.rect.center().y() ) );
247 painter->drawPixmap( artRect, artPix );
252 if( option.state & QStyle::State_Selected )
253 painter->setPen( option.palette.color( QPalette::HighlightedText ) );
255 QTextOption textOpt( Qt::AlignVCenter | Qt::AlignLeft );
256 textOpt.setWrapMode( QTextOption::NoWrap );
258 QFont f( index.data( Qt::FontRole ).value<QFont>() );
262 painter->setFont( f );
263 QFontMetrics fm( painter->fontMetrics() );
265 QRect textRect = option.rect.adjusted( LISTVIEW_ART_SIZE + 10, 0, -10, 0 );
266 if( !artistAlbum.isEmpty() )
268 textRect.setHeight( fm.height() );
269 textRect.moveBottom( option.rect.center().y() - 2 );
272 //Draw children indicator
273 if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
275 QPixmap dirPix = QPixmap( ":/type/node" );
276 painter->drawPixmap( QPoint( textRect.x(), textRect.center().y() - dirPix.height() / 2 ),
278 textRect.setLeft( textRect.x() + dirPix.width() + 5 );
281 painter->drawText( textRect,
282 fm.elidedText( title, Qt::ElideRight, textRect.width() ),
285 // Draw artist and album info
286 if( !artistAlbum.isEmpty() )
288 f.setItalic( false );
289 painter->setFont( f );
290 fm = painter->fontMetrics();
292 textRect.moveTop( textRect.bottom() + 4 );
293 textRect.setLeft( textRect.x() + 20 );
295 painter->drawText( textRect,
296 fm.elidedText( artistAlbum, Qt::ElideRight, textRect.width() ),
303 QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
307 QFontMetrics fm( f );
308 int height = qMax( LISTVIEW_ART_SIZE, 2 * fm.height() + 4 ) + 6;
309 return QSize( 0, height );
312 PlIconView::PlIconView( PLModel *model, QWidget *parent ) : QListView( parent )
314 PlIconViewItemDelegate *delegate = new PlIconViewItemDelegate( this );
317 setViewMode( QListView::IconMode );
318 setMovement( QListView::Static );
319 setResizeMode( QListView::Adjust );
320 setGridSize( delegate->sizeHint() );
322 setUniformItemSizes( true );
323 setSelectionMode( QAbstractItemView::ExtendedSelection );
324 setDragEnabled(true);
325 /* dropping in QListView::IconMode does not seem to work */
326 //setAcceptDrops( true );
327 //setDropIndicatorShown(true);
329 setItemDelegate( delegate );
332 PlListView::PlListView( PLModel *model, QWidget *parent ) : QListView( parent )
335 setViewMode( QListView::ListMode );
336 setUniformItemSizes( true );
337 setSelectionMode( QAbstractItemView::ExtendedSelection );
338 setAlternatingRowColors( true );
339 setDragEnabled(true);
340 setAcceptDrops( true );
341 setDropIndicatorShown(true);
343 PlListViewItemDelegate *delegate = new PlListViewItemDelegate( this );
344 setItemDelegate( delegate );