]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/playlist/icon_view.cpp
9b8d1f183322df734d558044429b0d1af233729b
[vlc] / modules / gui / qt4 / components / playlist / icon_view.cpp
1 /*****************************************************************************
2  * icon_view.cpp : Icon view for the Playlist
3  ****************************************************************************
4  * Copyright © 2010 the VideoLAN team
5  * $Id$
6  *
7  * Authors:         Jean-Baptiste Kempf <jb@videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
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"
28
29 #include <QApplication>
30 #include <QPainter>
31 #include <QRect>
32 #include <QStyleOptionViewItem>
33 #include <QFontMetrics>
34 #include <QPixmapCache>
35
36 #include "assert.h"
37
38 #define ART_SIZE_W          110
39 #define ART_SIZE_H          80
40 #define ART_RADIUS          5
41 #define SPACER              5
42
43 QString AbstractPlViewItemDelegate::getMeta( const QModelIndex & index, int meta ) const
44 {
45     return index.model()->index( index.row(),
46                                   PLModel::columnFromMeta( meta ),
47                                   index.parent() )
48                                 .data().toString();
49 }
50
51 void AbstractPlViewItemDelegate::paintPlayingItemBg( QPainter *painter, const QStyleOptionViewItem & option ) const
52 {
53     painter->save();
54     painter->setOpacity( 0.5 );
55     painter->setBrush( QBrush( Qt::gray ) );
56     painter->fillRect( option.rect, option.palette.color( QPalette::Dark ) );
57     painter->restore();
58 }
59
60 QPixmap AbstractPlViewItemDelegate::getArtPixmap( const QModelIndex & index, const QSize & size ) const
61 {
62     PLItem *item = static_cast<PLItem*>( index.internalPointer() );
63     assert( item );
64
65     QString artUrl = InputManager::decodeArtURL( item->inputItem() );
66
67     if( artUrl.isEmpty() )
68     {
69         for( int i = 0; i < item->childCount(); i++ )
70         {
71             artUrl = InputManager::decodeArtURL( item->child( i )->inputItem() );
72             if( !artUrl.isEmpty() )
73                 break;
74         }
75     }
76
77     QPixmap artPix;
78
79     QString key = artUrl + QString("%1%2").arg(size.width()).arg(size.height());
80
81     if( !QPixmapCache::find( key, artPix ))
82     {
83         if( artUrl.isEmpty() || !artPix.load( artUrl ) )
84         {
85             artPix = QPixmap( ":/noart" ).scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
86         }
87         else
88         {
89             artPix = artPix.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
90             QPixmapCache::insert( key, artPix );
91         }
92     }
93
94     return artPix;
95 }
96
97 void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
98 {
99     QString title = getMeta( index, COLUMN_TITLE );
100     QString artist = getMeta( index, COLUMN_ARTIST );
101
102     QPixmap artPix = getArtPixmap( index, QSize( ART_SIZE_W, ART_SIZE_H ) );
103
104     QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &option,
105                                           painter );
106
107     painter->save();
108
109     if( index.data( PLModel::IsCurrentRole ).toBool() )
110     {
111        painter->save();
112        painter->setOpacity( 0.2 );
113        painter->setBrush( QBrush( Qt::gray ) );
114        painter->drawRoundedRect( option.rect.adjusted( 0, 0, -1, -1 ), ART_RADIUS, ART_RADIUS );
115        painter->restore();
116     }
117
118     QRect artRect( option.rect.x() + 5 + ( ART_SIZE_W - artPix.width() ) / 2,
119                    option.rect.y() + 5 + ( ART_SIZE_H - artPix.height() ) / 2,
120                    artPix.width(), artPix.height() );
121
122     // Draw the drop shadow
123     painter->save();
124     painter->setOpacity( 0.7 );
125     painter->setBrush( QBrush( Qt::darkGray ) );
126     painter->setPen( Qt::NoPen );
127     painter->drawRoundedRect( artRect.adjusted( 0, 0, 2, 2 ), ART_RADIUS, ART_RADIUS );
128     painter->restore();
129
130     // Draw the art pixmap
131     QPainterPath artRectPath;
132     artRectPath.addRoundedRect( artRect, ART_RADIUS, ART_RADIUS );
133     painter->setClipPath( artRectPath );
134     painter->drawPixmap( artRect, artPix );
135     painter->setClipping( false );
136
137     if( option.state & QStyle::State_Selected )
138         painter->setPen( option.palette.color( QPalette::HighlightedText ) );
139
140     QFont font( index.data( Qt::FontRole ).value<QFont>() );
141     font.setPointSize( 7 );
142
143     // Draw title
144     font.setItalic( true );
145     painter->setFont( font );
146
147     QFontMetrics fm = painter->fontMetrics();
148     QRect textRect = option.rect.adjusted( 1, ART_SIZE_H + 10, 0, -1 );
149     textRect.setHeight( fm.height() );
150
151     painter->drawText( textRect,
152                       fm.elidedText( title, Qt::ElideRight, textRect.width() ),
153                       QTextOption( Qt::AlignCenter ) );
154
155     // Draw artist
156     painter->setPen( painter->pen().color().lighter( 150 ) );
157     font.setItalic( false );
158     painter->setFont( font );
159     fm = painter->fontMetrics();
160
161     textRect.moveTop( textRect.bottom() + 1 );
162
163     painter->drawText(  textRect,
164                         fm.elidedText( artist, Qt::ElideRight, textRect.width() ),
165                         QTextOption( Qt::AlignCenter ) );
166
167     painter->restore();
168 }
169
170 QSize PlIconViewItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
171 {
172     QFont f;
173     f.setPointSize( 7 );
174     f.setBold( true );
175     QFontMetrics fm( f );
176     int textHeight = fm.height();
177     QSize sz ( ART_SIZE_W + 2 * SPACER,
178                ART_SIZE_H + 3 * SPACER + 2 * textHeight + 1 );
179     return sz;
180 }
181
182
183 #define LISTVIEW_ART_SIZE 45
184
185 void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
186 {
187     QModelIndex parent = index.parent();
188     QModelIndex i;
189
190     QString title = getMeta( index, COLUMN_TITLE );
191     QString duration = getMeta( index, COLUMN_DURATION );
192     if( !duration.isEmpty() ) title += QString(" [%1]").arg( duration );
193
194     QString artist = getMeta( index, COLUMN_ARTIST );
195     QString album = getMeta( index, COLUMN_ALBUM );
196     QString trackNum = getMeta( index, COLUMN_TRACK_NUMBER );
197     QString artistAlbum = artist
198                           + ( artist.isEmpty() ? QString() : QString( ": " ) )
199                           + album
200                           + ( album.isEmpty() || trackNum.isEmpty() ?
201                               QString() : QString( " [#%1]" ).arg( trackNum ) );
202
203     QPixmap artPix = getArtPixmap( index, QSize( LISTVIEW_ART_SIZE, LISTVIEW_ART_SIZE ) );
204
205     //Draw selection rectangle
206     QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &option, painter );
207
208     //Paint background if item is playing
209     if( index.data( PLModel::IsCurrentRole ).toBool() )
210         paintPlayingItemBg( painter, option );
211
212     QRect artRect( artPix.rect() );
213     artRect.moveCenter( QPoint( artRect.center().x() + 3,
214                                 option.rect.center().y() ) );
215     //Draw album art
216     painter->drawPixmap( artRect, artPix );
217
218     //Start drawing text
219     painter->save();
220
221     if( option.state & QStyle::State_Selected )
222         painter->setPen( option.palette.color( QPalette::HighlightedText ) );
223
224     QTextOption textOpt( Qt::AlignVCenter | Qt::AlignLeft );
225     textOpt.setWrapMode( QTextOption::NoWrap );
226
227     QFont f( index.data( Qt::FontRole ).value<QFont>() );
228
229     //Draw title info
230     f.setItalic( true );
231     painter->setFont( f );
232     QFontMetrics fm( painter->fontMetrics() );
233
234     QRect textRect = option.rect.adjusted( LISTVIEW_ART_SIZE + 10, 0, -10, 0 );
235     if( !artistAlbum.isEmpty() )
236     {
237         textRect.setHeight( fm.height() );
238         textRect.moveBottom( option.rect.center().y() - 1 );
239     }
240
241     painter->drawText( textRect,
242                        fm.elidedText( title, Qt::ElideRight, textRect.width() ),
243                        textOpt );
244
245     // Draw artist and album info
246     if( !artistAlbum.isEmpty() )
247     {
248         f.setItalic( false );
249         painter->setFont( f );
250         fm = painter->fontMetrics();
251
252         textRect.moveTop( textRect.bottom() + 2 );
253
254         painter->drawText( textRect,
255                            fm.elidedText( artistAlbum, Qt::ElideRight, textRect.width() ),
256                            textOpt );
257     }
258
259     painter->restore();
260 }
261
262 QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
263 {
264   QFont f;
265   f.setBold( true );
266   QFontMetrics fm( f );
267   int height = qMax( LISTVIEW_ART_SIZE, 2 * fm.height() + 2 ) + 6;
268   return QSize( 0, height );
269 }
270
271 PlIconView::PlIconView( PLModel *model, QWidget *parent ) : QListView( parent )
272 {
273     PlIconViewItemDelegate *delegate = new PlIconViewItemDelegate( this );
274
275     setModel( model );
276     setViewMode( QListView::IconMode );
277     setMovement( QListView::Static );
278     setResizeMode( QListView::Adjust );
279     setGridSize( delegate->sizeHint() );
280     setWrapping( true );
281     setUniformItemSizes( true );
282     setSelectionMode( QAbstractItemView::ExtendedSelection );
283     setDragEnabled(true);
284     /* dropping in QListView::IconMode does not seem to work */
285     //setAcceptDrops( true );
286     //setDropIndicatorShown(true);
287
288     setItemDelegate( delegate );
289 }
290
291 PlListView::PlListView( PLModel *model, QWidget *parent ) : QListView( parent )
292 {
293     setModel( model );
294     setViewMode( QListView::ListMode );
295     setUniformItemSizes( true );
296     setSelectionMode( QAbstractItemView::ExtendedSelection );
297     setAlternatingRowColors( true );
298     setDragEnabled(true);
299     setAcceptDrops( true );
300     setDropIndicatorShown(true);
301
302     PlListViewItemDelegate *delegate = new PlListViewItemDelegate( this );
303     setItemDelegate( delegate );
304 }