Qt: correctly display the right treeView columns
[vlc.git] / modules / gui / qt4 / components / playlist / views.cpp
blob32009afd0fe6fca38a30ae1a9f15439e43475400
1 /*****************************************************************************
2 * views.cpp : Views for the Playlist
3 ****************************************************************************
4 * Copyright © 2010 the VideoLAN team
5 * $Id$
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/views.hpp"
25 #include "components/playlist/playlist_model.hpp" /* PLModel */
26 #include "components/playlist/sorting.h" /* Columns List */
27 #include "input_manager.hpp" /* THEMIM */
29 #include <QPainter>
30 #include <QRect>
31 #include <QStyleOptionViewItem>
32 #include <QFontMetrics>
33 #include <QDrag>
34 #include <QDragMoveEvent>
36 #include "assert.h"
38 /* ICON_SCALER comes currently from harrison-stetson method, so good value */
39 #define ICON_SCALER 16
40 #define ART_RADIUS 5
41 #define SPACER 5
43 void AbstractPlViewItemDelegate::paintBackground(
44 QPainter *painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
46 /* FIXME: This does not indicate item selection in all QStyles, so for the time being we
47 have to draw it ourselves, to ensure visible effect of selection on all platforms */
48 /* QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &option,
49 painter ); */
51 painter->save();
52 QRect r = option.rect.adjusted( 0, 0, -1, -1 );
53 if( option.state & QStyle::State_Selected )
55 painter->setBrush( option.palette.color( QPalette::Highlight ) );
56 painter->setPen( option.palette.color( QPalette::Highlight ).darker( 150 ) );
57 painter->drawRect( r );
59 else if( index.data( PLModel::IsCurrentRole ).toBool() )
61 painter->setBrush( QBrush( Qt::lightGray ) );
62 painter->setPen( QColor( Qt::darkGray ) );
63 painter->drawRect( r );
65 if( option.state & QStyle::State_MouseOver )
67 painter->setOpacity( 0.5 );
68 painter->setPen( Qt::NoPen );
69 painter->setBrush( option.palette.color( QPalette::Highlight ).lighter( 150 ) );
70 painter->drawRect( option.rect );
72 painter->restore();
75 void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
77 QString title = VLCModel::getMeta( index, COLUMN_TITLE );
78 QString artist = VLCModel::getMeta( index, COLUMN_ARTIST );
80 QFont font( index.data( Qt::FontRole ).value<QFont>() );
81 painter->setFont( font );
82 QFontMetrics fm = painter->fontMetrics();
84 int averagewidth = fm.averageCharWidth();
85 QSize rectSize = option.rect.size();
86 int art_width = averagewidth * ICON_SCALER;
87 int art_height = averagewidth * ICON_SCALER;
89 QPixmap artPix = VLCModel::getArtPixmap( index, QSize( art_width, art_height) );
91 paintBackground( painter, option, index );
93 painter->save();
95 QRect artRect( option.rect.x() + ( rectSize.width() - artPix.width() ) / 2,
96 option.rect.y() - averagewidth*3 + ( rectSize.height() - artPix.height() ) / 2,
97 artPix.width(), artPix.height() );
99 // Draw the drop shadow
100 painter->save();
101 painter->setOpacity( 0.7 );
102 painter->setBrush( QBrush( Qt::darkGray ) );
103 painter->setPen( Qt::NoPen );
104 painter->drawRoundedRect( artRect.adjusted( 0, 0, 2, 2 ), ART_RADIUS, ART_RADIUS );
105 painter->restore();
107 // Draw the art pixmap
108 QPainterPath artRectPath;
109 artRectPath.addRoundedRect( artRect, ART_RADIUS, ART_RADIUS );
110 painter->setClipPath( artRectPath );
111 painter->drawPixmap( artRect, artPix );
112 painter->setClipping( false );
114 if( option.state & QStyle::State_Selected )
115 painter->setPen( option.palette.color( QPalette::HighlightedText ) );
118 //Draw children indicator
119 if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
121 QRect r( option.rect );
122 r.setSize( QSize( 25, 25 ) );
123 r.translate( 5, 5 );
124 if( index.data( PLModel::IsCurrentsParentNodeRole ).toBool() )
126 painter->setOpacity( 0.75 );
127 QPainterPath nodeRectPath;
128 nodeRectPath.addRoundedRect( r, 4, 4 );
129 painter->fillPath( nodeRectPath, option.palette.color( QPalette::Highlight ) );
130 painter->setOpacity( 1.0 );
132 QPixmap dirPix( ":/type/node" );
133 QRect r2( dirPix.rect() );
134 r2.moveCenter( r.center() );
135 painter->drawPixmap( r2, dirPix );
138 // Draw title
139 font.setItalic( true );
141 QRect textRect;
142 textRect.setRect( option.rect.x() , artRect.bottom() + fm.height()/2, option.rect.width(), fm.height() );
144 painter->drawText( textRect,
145 fm.elidedText( title, Qt::ElideRight, textRect.width() ),
146 QTextOption( Qt::AlignCenter ) );
148 // Draw artist
149 painter->setPen( painter->pen().color().lighter( 150 ) );
150 font.setItalic( false );
151 painter->setFont( font );
152 fm = painter->fontMetrics();
154 textRect.moveTop( textRect.bottom() + 1 );
156 painter->drawText( textRect,
157 fm.elidedText( artist, Qt::ElideRight, textRect.width() ),
158 QTextOption( Qt::AlignCenter ) );
160 painter->restore();
163 QSize PlIconViewItemDelegate::sizeHint ( const QStyleOptionViewItem &, const QModelIndex & index ) const
165 QFont f( index.data( Qt::FontRole ).value<QFont>() );
166 f.setBold( true );
167 QFontMetrics fm( f );
168 int textHeight = fm.height();
169 int averagewidth = fm.averageCharWidth();
170 QSize sz ( averagewidth * ICON_SCALER + 4 * SPACER,
171 averagewidth * ICON_SCALER + 4 * SPACER + 2 * textHeight + 1 );
172 return sz;
176 #define LISTVIEW_ART_SIZE 45
178 void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
180 QString title = VLCModel::getMeta( index, COLUMN_TITLE );
181 QString duration = VLCModel::getMeta( index, COLUMN_DURATION );
182 if( !duration.isEmpty() ) title += QString(" [%1]").arg( duration );
184 QString artist = VLCModel::getMeta( index, COLUMN_ARTIST );
185 QString album = VLCModel::getMeta( index, COLUMN_ALBUM );
186 QString trackNum = VLCModel::getMeta( index, COLUMN_TRACK_NUMBER );
187 QString artistAlbum = artist;
188 if( !album.isEmpty() )
190 if( !artist.isEmpty() ) artistAlbum += ": ";
191 artistAlbum += album;
192 if( !trackNum.isEmpty() ) artistAlbum += QString( " [#%1]" ).arg( trackNum );
195 QPixmap artPix = VLCModel::getArtPixmap( index, QSize( LISTVIEW_ART_SIZE, LISTVIEW_ART_SIZE ) );
197 //Draw selection rectangle and current playing item indication
198 paintBackground( painter, option, index );
200 QRect artRect( artPix.rect() );
201 artRect.moveCenter( QPoint( artRect.center().x() + 3,
202 option.rect.center().y() ) );
203 //Draw album art
204 painter->drawPixmap( artRect, artPix );
206 //Start drawing text
207 painter->save();
209 if( option.state & QStyle::State_Selected )
210 painter->setPen( option.palette.color( QPalette::HighlightedText ) );
212 QTextOption textOpt( Qt::AlignVCenter | Qt::AlignLeft );
213 textOpt.setWrapMode( QTextOption::NoWrap );
215 QFont f( index.data( Qt::FontRole ).value<QFont>() );
217 //Draw title info
218 f.setItalic( true );
219 painter->setFont( f );
220 QFontMetrics fm( painter->fontMetrics() );
222 QRect textRect = option.rect.adjusted( LISTVIEW_ART_SIZE + 10, 0, -10, 0 );
223 if( !artistAlbum.isEmpty() )
225 textRect.setHeight( fm.height() );
226 textRect.moveBottom( option.rect.center().y() - 2 );
229 //Draw children indicator
230 if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
232 QPixmap dirPix = QPixmap( ":/type/node" );
233 painter->drawPixmap( QPoint( textRect.x(), textRect.center().y() - dirPix.height() / 2 ),
234 dirPix );
235 textRect.setLeft( textRect.x() + dirPix.width() + 5 );
238 painter->drawText( textRect,
239 fm.elidedText( title, Qt::ElideRight, textRect.width() ),
240 textOpt );
242 // Draw artist and album info
243 if( !artistAlbum.isEmpty() )
245 f.setItalic( false );
246 painter->setFont( f );
247 fm = painter->fontMetrics();
249 textRect.moveTop( textRect.bottom() + 4 );
250 textRect.setLeft( textRect.x() + 20 );
252 painter->drawText( textRect,
253 fm.elidedText( artistAlbum, Qt::ElideRight, textRect.width() ),
254 textOpt );
257 painter->restore();
260 QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem &, const QModelIndex & ) const
262 QFont f;
263 f.setBold( true );
264 QFontMetrics fm( f );
265 int height = qMax( LISTVIEW_ART_SIZE, 2 * fm.height() + 4 ) + 6;
266 return QSize( 0, height );
269 static inline void plViewStartDrag( QAbstractItemView *view, const Qt::DropActions & supportedActions )
271 QDrag *drag = new QDrag( view );
272 drag->setPixmap( QPixmap( ":/noart64" ) );
273 drag->setMimeData( view->model()->mimeData(
274 view->selectionModel()->selectedIndexes() ) );
275 drag->exec( supportedActions );
278 static void plViewDragMoveEvent( QAbstractItemView *, QDragMoveEvent * event )
280 if( event->keyboardModifiers() & Qt::ControlModifier &&
281 event->possibleActions() & Qt::CopyAction )
282 event->setDropAction( Qt::CopyAction );
283 else event->acceptProposedAction();
286 PlIconView::PlIconView( PLModel *, QWidget *parent ) : QListView( parent )
288 PlIconViewItemDelegate *delegate = new PlIconViewItemDelegate( this );
290 setViewMode( QListView::IconMode );
291 setMovement( QListView::Static );
292 setResizeMode( QListView::Adjust );
293 setWrapping( true );
294 setUniformItemSizes( true );
295 setSelectionMode( QAbstractItemView::ExtendedSelection );
296 setDragEnabled(true);
297 setAttribute( Qt::WA_MacShowFocusRect, false );
298 /* dropping in QListView::IconMode does not seem to work */
299 //setAcceptDrops( true );
300 //setDropIndicatorShown(true);
302 setItemDelegate( delegate );
305 void PlIconView::startDrag ( Qt::DropActions supportedActions )
307 plViewStartDrag( this, supportedActions );
310 void PlIconView::dragMoveEvent ( QDragMoveEvent * event )
312 plViewDragMoveEvent( this, event );
313 QAbstractItemView::dragMoveEvent( event );
316 PlListView::PlListView( PLModel *, QWidget *parent ) : QListView( parent )
318 setViewMode( QListView::ListMode );
319 setUniformItemSizes( true );
320 setSelectionMode( QAbstractItemView::ExtendedSelection );
321 setAlternatingRowColors( true );
322 setDragEnabled(true);
323 setAcceptDrops( true );
324 setDropIndicatorShown(true);
326 PlListViewItemDelegate *delegate = new PlListViewItemDelegate( this );
327 setItemDelegate( delegate );
328 setAttribute( Qt::WA_MacShowFocusRect, false );
331 void PlListView::startDrag ( Qt::DropActions supportedActions )
333 plViewStartDrag( this, supportedActions );
336 void PlListView::dragMoveEvent ( QDragMoveEvent * event )
338 plViewDragMoveEvent( this, event );
339 QAbstractItemView::dragMoveEvent( event );
342 void PlListView::keyPressEvent( QKeyEvent *event )
344 //If the space key is pressed, override the standard list behaviour to allow pausing
345 //to proceed.
346 if ( event->modifiers() == Qt::NoModifier && event->key() == Qt::Key_Space )
347 QWidget::keyPressEvent( event );
348 //Otherwise, just do as usual.
349 else
350 QListView::keyPressEvent( event );
353 void PlTreeView::startDrag ( Qt::DropActions supportedActions )
355 plViewStartDrag( this, supportedActions );
358 void PlTreeView::dragMoveEvent ( QDragMoveEvent * event )
360 plViewDragMoveEvent( this, event );
361 QAbstractItemView::dragMoveEvent( event );
364 void PlTreeView::keyPressEvent( QKeyEvent *event )
366 //If the space key is pressed, override the standard list behaviour to allow pausing
367 //to proceed.
368 if ( event->modifiers() == Qt::NoModifier && event->key() == Qt::Key_Space )
369 QWidget::keyPressEvent( event );
370 //Otherwise, just do as usual.
371 else
372 QTreeView::keyPressEvent( event );
375 #include <QHBoxLayout>
376 PicFlowView::PicFlowView( PLModel *p_model, QWidget *parent ) : QAbstractItemView( parent )
378 QHBoxLayout *layout = new QHBoxLayout( this );
379 layout->setMargin( 0 );
380 picFlow = new PictureFlow( this, p_model );
381 picFlow->setSlideSize(QSize(128,128));
382 layout->addWidget( picFlow );
383 setSelectionMode( QAbstractItemView::SingleSelection );
386 int PicFlowView::horizontalOffset() const
388 return 0;
391 int PicFlowView::verticalOffset() const
393 return 0;
396 QRect PicFlowView::visualRect(const QModelIndex & ) const
398 return QRect( QPoint(0,0), picFlow->slideSize() );
401 void PicFlowView::scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint)
403 int currentIndex = picFlow->centerIndex();
404 if( qAbs( currentIndex - index.row()) > 20 )
406 /* offset is offset from target index toward currentIndex */
407 int offset = -19;
408 if( index.row() > currentIndex )
409 offset = 19;
410 picFlow->setCenterIndex( index.row() + offset );
411 picFlow->showSlide( index.row() );
413 else
414 picFlow->showSlide( index.row() );
417 QModelIndex PicFlowView::indexAt(const QPoint &) const
419 return QModelIndex();
420 // No idea, PictureFlow doesn't provide anything to help this
423 QModelIndex PicFlowView::moveCursor(QAbstractItemView::CursorAction, Qt::KeyboardModifiers)
425 return QModelIndex();
428 bool PicFlowView::isIndexHidden(const QModelIndex &index) const
430 int currentIndex = picFlow->centerIndex();
431 if( index.row()-5 <= currentIndex &&
432 index.row()+5 >= currentIndex )
433 return false;
434 else
435 return true;
438 QRegion PicFlowView::visualRegionForSelection(const QItemSelection &) const
440 return QRect();
443 void PicFlowView::setSelection(const QRect &, QFlags<QItemSelectionModel::SelectionFlag>)
445 // No selection possible
448 void PicFlowView::dataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight )
450 int currentIndex = picFlow->centerIndex();
451 for(int i = topLeft.row(); i<=bottomRight.row(); i++ )
453 if( i-5 <= currentIndex &&
454 i+5 >= currentIndex )
456 picFlow->render();
457 return;
462 void PicFlowView::playItem( int i_item )
464 emit activated( model()->index(i_item, 0) );