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