1 /*****************************************************************************
2 * views.cpp : Views 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/views.hpp"
25 #include "components/playlist/playlist_model.hpp" /* PLModel */
26 #include "components/playlist/sorting.h" /* Columns List */
27 #include "input_manager.hpp" /* THEMIM */
31 #include <QStyleOptionViewItem>
32 #include <QFontMetrics>
34 #include <QDragMoveEvent>
38 /* ICON_SCALER comes currently from harrison-stetson method, so good value */
39 #define ICON_SCALER 16
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,
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
);
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
);
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
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
);
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 ) );
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
);
139 font
.setItalic( true );
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
) );
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
) );
163 QSize
PlIconViewItemDelegate::sizeHint ( const QStyleOptionViewItem
&, const QModelIndex
& index
) const
165 QFont
f( index
.data( Qt::FontRole
).value
<QFont
>() );
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 );
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() ) );
204 painter
->drawPixmap( artRect
, artPix
);
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
>() );
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 ),
235 textRect
.setLeft( textRect
.x() + dirPix
.width() + 5 );
238 painter
->drawText( textRect
,
239 fm
.elidedText( title
, Qt::ElideRight
, textRect
.width() ),
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() ),
260 QSize
PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem
&, const QModelIndex
& ) const
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
);
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
346 if ( event
->modifiers() == Qt::NoModifier
&& event
->key() == Qt::Key_Space
)
347 QWidget::keyPressEvent( event
);
348 //Otherwise, just do as usual.
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
368 if ( event
->modifiers() == Qt::NoModifier
&& event
->key() == Qt::Key_Space
)
369 QWidget::keyPressEvent( event
);
370 //Otherwise, just do as usual.
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
391 int PicFlowView::verticalOffset() const
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 */
408 if( index
.row() > currentIndex
)
410 picFlow
->setCenterIndex( index
.row() + offset
);
411 picFlow
->showSlide( index
.row() );
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
)
438 QRegion
PicFlowView::visualRegionForSelection(const QItemSelection
&) const
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
)
462 void PicFlowView::playItem( int i_item
)
464 emit
activated( model()->index(i_item
, 0) );