Commit d6a48806 authored by Jean-Baptiste Kempf's avatar Jean-Baptiste Kempf

Qt: initial pass for CoverFlow view of the playlist

This code is unfinished, and is commited as a Proof-of-Concept
If people agree on it, we will go on this experiment, else revert.
A lot of the code is broken, you are warned.
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent f80154be
......@@ -67,6 +67,7 @@ nodist_SOURCES_qt4 = \
util/input_slider.moc.cpp \
util/customwidgets.moc.cpp \
util/qvlcapp.moc.cpp \
util/pictureflow.moc.cpp \
resources.cpp \
ui/equalizer.h \
ui/video_effects.h \
......@@ -273,7 +274,8 @@ SOURCES_qt4 = qt4.cpp \
components/sout/sout_widgets.cpp \
util/input_slider.cpp \
util/customwidgets.cpp \
util/registry.cpp
util/registry.cpp \
util/pictureflow.cpp
noinst_HEADERS = \
qt4.hpp \
......@@ -337,6 +339,7 @@ noinst_HEADERS = \
util/qvlcapp.hpp \
util/qt_dirs.hpp \
util/registry.hpp \
util/pictureflow.hpp
util/singleton.hpp
......
......@@ -611,6 +611,9 @@ QPixmap PLModel::getArtPixmap( const QModelIndex & index, const QSize & size )
PLItem *item = static_cast<PLItem*>( index.internalPointer() );
assert( item );
if( item == NULL )
return NULL;
QString artUrl = InputManager::decodeArtURL( item->inputItem() );
/* If empty, take one of the children art URL */
......@@ -624,6 +627,9 @@ QPixmap PLModel::getArtPixmap( const QModelIndex & index, const QSize & size )
}
}
if( artUrl.isEmpty() )
return NULL;
QPixmap artPix;
QString key = artUrl + QString("%1%2").arg(size.width()).arg(size.height());
......@@ -682,15 +688,17 @@ void PLModel::processItemAppend( int i_item, int i_parent )
{
playlist_item_t *p_item = NULL;
PLItem *newItem = NULL;
input_thread_t *currentInputThread;
int pos;
PLItem *nodeItem = findById( rootItem, i_parent );
if( !nodeItem ) return;
/* Find the Parent */
PLItem *nodeParentItem = findById( rootItem, i_parent );
if( !nodeParentItem ) return;
foreach( const PLItem *existing, nodeItem->children )
/* Search for an already matching children */
foreach( const PLItem *existing, nodeParentItem->children )
if( existing->i_id == i_item ) return;
/* Find the child */
PL_LOCK;
p_item = playlist_ItemGetById( p_playlist, i_item );
if( !p_item || p_item->i_flags & PLAYLIST_DBL_FLAG )
......@@ -701,11 +709,12 @@ void PLModel::processItemAppend( int i_item, int i_parent )
for( pos = 0; pos < p_item->p_parent->i_children; pos++ )
if( p_item->p_parent->pp_children[pos] == p_item ) break;
newItem = new PLItem( p_item, nodeItem );
newItem = new PLItem( p_item, nodeParentItem );
PL_UNLOCK;
beginInsertRows( index( nodeItem, 0 ), pos, pos );
nodeItem->insertChild( newItem, pos );
/* We insert the newItem (children) inside the parent */
beginInsertRows( index( nodeParentItem, 0 ), pos, pos );
nodeParentItem->insertChild( newItem, pos );
endInsertRows();
if( newItem->p_input == THEMIM->currentInputItem() )
......@@ -760,6 +769,7 @@ void PLModel::insertChildren( PLItem *node, QList<PLItem*>& items, int i_pos )
assert( node );
int count = items.size();
if( !count ) return;
printf( "Here I am\n");
beginInsertRows( index( node, 0 ), i_pos, i_pos + count - 1 );
for( int i = 0; i < count; i++ )
{
......
......@@ -64,21 +64,21 @@ public:
/*** QModel subclassing ***/
/* Data structure */
QVariant data( const QModelIndex &index, const int role ) const;
QVariant headerData( int section, Qt::Orientation orientation,
virtual QVariant data( const QModelIndex &index, const int role ) const;
virtual QVariant headerData( int section, Qt::Orientation orientation,
int role = Qt::DisplayRole ) const;
int rowCount( const QModelIndex &parent = QModelIndex() ) const;
int columnCount( const QModelIndex &parent = QModelIndex() ) const;
Qt::ItemFlags flags( const QModelIndex &index ) const;
QModelIndex index( const int r, const int c, const QModelIndex &parent ) const;
QModelIndex parent( const QModelIndex &index ) const;
virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const;
virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const;
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
virtual QModelIndex index( const int r, const int c, const QModelIndex &parent ) const;
virtual QModelIndex parent( const QModelIndex &index ) const;
/* Drag and Drop */
Qt::DropActions supportedDropActions() const;
QMimeData* mimeData( const QModelIndexList &indexes ) const;
bool dropMimeData( const QMimeData *data, Qt::DropAction action,
virtual Qt::DropActions supportedDropActions() const;
virtual QMimeData* mimeData( const QModelIndexList &indexes ) const;
virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &target );
QStringList mimeTypes() const;
virtual QStringList mimeTypes() const;
/**** Custom ****/
......
......@@ -61,19 +61,20 @@ StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
viewStack->setSpacing( 0 ); viewStack->setMargin( 0 );
setMinimumWidth( 300 );
iconView = NULL;
treeView = NULL;
listView = NULL;
iconView = NULL;
treeView = NULL;
listView = NULL;
picFlowView = NULL;
currentRootIndexId = -1;
lastActivatedId = -1;
/* Saved Settings */
getSettings()->beginGroup("Playlist");
int i_viewMode = getSettings()->value( "view-mode", TREE_VIEW ).toInt();
int i_savedViewMode = getSettings()->value( "view-mode", TREE_VIEW ).toInt();
getSettings()->endGroup();
showView( i_viewMode );
showView( i_savedViewMode );
DCONNECT( THEMIM, leafBecameParent( input_item_t *),
this, browseInto( input_item_t * ) );
......@@ -96,6 +97,8 @@ StandardPLPanel::~StandardPLPanel()
getSettings()->setValue( "view-mode", LIST_VIEW );
else if( currentView == iconView )
getSettings()->setValue( "view-mode", ICON_VIEW );
else if( currentView == picFlowView )
getSettings()->setValue( "view-mode", PICTUREFLOW_VIEW );
getSettings()->endGroup();
}
......@@ -161,7 +164,7 @@ void StandardPLPanel::search( const QString& searchText )
p_selector->getCurrentSelectedItem( &type, &name );
if( type != SD_TYPE )
{
bool flat = currentView == iconView || currentView == listView;
bool flat = currentView == iconView || currentView == listView || currentView == picFlowView;
model->search( searchText,
flat ? currentView->rootIndex() : QModelIndex(),
!flat );
......@@ -190,7 +193,7 @@ void StandardPLPanel::setRoot( playlist_item_t *p_item )
void StandardPLPanel::browseInto( const QModelIndex &index )
{
if( currentView == iconView || currentView == listView )
if( currentView == iconView || currentView == listView || currentView == picFlowView )
{
currentRootIndexId = model->itemId( index );
currentView->setRootIndex( index );
......@@ -258,6 +261,18 @@ void StandardPLPanel::createListView()
viewStack->addWidget( listView );
}
void StandardPLPanel::createCoverView()
{
picFlowView = new PicFlowView( model, this );
picFlowView->setContextMenuPolicy( Qt::CustomContextMenu );
CONNECT( picFlowView, customContextMenuRequested( const QPoint & ),
this, popupPlView( const QPoint & ) );
CONNECT( picFlowView, activated( const QModelIndex & ),
this, activate( const QModelIndex & ) );
viewStack->addWidget( picFlowView );
picFlowView->installEventFilter( this );
}
void StandardPLPanel::createTreeView()
{
/* Create and configure the QTreeView */
......@@ -344,6 +359,13 @@ void StandardPLPanel::showView( int i_view )
currentView = listView;
break;
}
case PICTUREFLOW_VIEW:
{
if( picFlowView == NULL )
createCoverView();
currentView = picFlowView;
break;
}
default: return;
}
......@@ -360,6 +382,8 @@ const int StandardPLPanel::getViewNumber()
return ICON_VIEW;
else if( currentView == listView )
return LIST_VIEW;
else
return PICTUREFLOW_VIEW;
}
void StandardPLPanel::cycleViews()
......@@ -369,6 +393,8 @@ void StandardPLPanel::cycleViews()
else if( currentView == treeView )
showView( LIST_VIEW );
else if( currentView == listView )
showView( PICTUREFLOW_VIEW );
else if( currentView == picFlowView )
showView( ICON_VIEW );
else
assert( 0 );
......@@ -376,6 +402,7 @@ void StandardPLPanel::cycleViews()
void StandardPLPanel::activate( const QModelIndex &index )
{
/* If we are not a leaf node */
if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
{
if( currentView != treeView )
......@@ -406,7 +433,6 @@ void StandardPLPanel::browseInto( input_item_t *p_input )
}
QModelIndex index = model->index( p_item->i_id, 0 );
playlist_Unlock( THEPL );
if( currentView == treeView )
......
......@@ -46,16 +46,12 @@ class QAbstractItemView;
class QTreeView;
class PlIconView;
class PlListView;
class PicFlowView;
class LocationBar;
class PLSelector;
class PlaylistWidget;
static const QString viewNames[3 /* VIEW_COUNT */]
= { qtr( "Detailed View" ),
qtr( "Icon View" ),
qtr( "List View" ) };
class StandardPLPanel: public QWidget
{
Q_OBJECT
......@@ -68,7 +64,8 @@ public:
enum { TREE_VIEW = 0,
ICON_VIEW,
LIST_VIEW,
VIEW_COUNT };
PICTUREFLOW_VIEW,
VIEW_COUNT };
const int getViewNumber();
......@@ -84,6 +81,8 @@ private:
QTreeView *treeView;
PlIconView *iconView;
PlListView *listView;
PicFlowView *picFlowView;
QAbstractItemView *currentView;
QStackedLayout *viewStack;
......@@ -96,6 +95,7 @@ private:
void createTreeView();
void createIconView();
void createListView();
void createCoverView();
bool eventFilter ( QObject * watched, QEvent * event );
public slots:
......@@ -126,4 +126,11 @@ signals:
void viewChanged( const QModelIndex& );
};
static const QString viewNames[ StandardPLPanel::VIEW_COUNT ]
= { qtr( "Detailed View" ),
qtr( "Icon View" ),
qtr( "List View" ),
qtr( "PictureFlow View ") };
#endif
......@@ -22,11 +22,10 @@
*****************************************************************************/
#include "components/playlist/views.hpp"
#include "components/playlist/playlist_model.hpp"
#include "components/playlist/sorting.h"
#include "input_manager.hpp"
#include "components/playlist/playlist_model.hpp" /* PLModel */
#include "components/playlist/sorting.h" /* Columns List */
#include "input_manager.hpp" /* THEMIM */
#include <QApplication>
#include <QPainter>
#include <QRect>
#include <QStyleOptionViewItem>
......@@ -178,9 +177,6 @@ QSize PlIconViewItemDelegate::sizeHint ( const QStyleOptionViewItem & option, co
void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QModelIndex parent = index.parent();
QModelIndex i;
QString title = PLModel::getMeta( index, COLUMN_TITLE );
QString duration = PLModel::getMeta( index, COLUMN_DURATION );
if( !duration.isEmpty() ) title += QString(" [%1]").arg( duration );
......@@ -263,14 +259,14 @@ void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QFont f;
f.setBold( true );
QFontMetrics fm( f );
int height = qMax( LISTVIEW_ART_SIZE, 2 * fm.height() + 4 ) + 6;
return QSize( 0, height );
QFont f;
f.setBold( true );
QFontMetrics fm( f );
int height = qMax( LISTVIEW_ART_SIZE, 2 * fm.height() + 4 ) + 6;
return QSize( 0, height );
}
static void plViewStartDrag( QAbstractItemView *view, const Qt::DropActions & supportedActions )
static inline void plViewStartDrag( QAbstractItemView *view, const Qt::DropActions & supportedActions )
{
QDrag *drag = new QDrag( view );
drag->setPixmap( QPixmap( ":/noart64" ) );
......@@ -375,3 +371,84 @@ void PlTreeView::keyPressEvent( QKeyEvent *event )
else
QTreeView::keyPressEvent( event );
}
#include <QHBoxLayout>
PicFlowView::PicFlowView( PLModel *p_model, QWidget *parent ) : QAbstractItemView( parent )
{
QHBoxLayout *layout = new QHBoxLayout( this );
layout->setMargin( 0 );
picFlow = new PictureFlow( this );
picFlow->setSlideSize(QSize(128,128));
layout->addWidget( picFlow );
setSelectionMode( QAbstractItemView::SingleSelection );
setModel( p_model );
CONNECT( picFlow, centerIndexChanged(int), this, playItem(int) );
}
int PicFlowView::horizontalOffset() const
{
return 0;
}
int PicFlowView::verticalOffset() const
{
return 0;
}
QRect PicFlowView::visualRect(const QModelIndex &index ) const
{
return QRect( QPoint(0,0), picFlow->slideSize() );
}
void PicFlowView::scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint)
{
if( index.column() >= 0 && picFlow->slideCount() > 0 )
picFlow->showSlide( index.column() );
}
QModelIndex PicFlowView::indexAt(const QPoint &) const
{
// No idea, PictureFlow doesn't provide anything to help this
}
QModelIndex PicFlowView::moveCursor(QAbstractItemView::CursorAction action, Qt::KeyboardModifiers)
{
}
bool PicFlowView::isIndexHidden(const QModelIndex &) const
{
return false;
}
QRegion PicFlowView::visualRegionForSelection(const QItemSelection &) const
{
return QRect();
}
void PicFlowView::setSelection(const QRect &, QFlags<QItemSelectionModel::SelectionFlag>)
{
// No selection possible
}
void PicFlowView::rowsInserted(const QModelIndex &parent, int start, int end)
{
for( int i = start; i <= end; i++ )
{
const QModelIndex index = model()->index( i, 0, parent );
if( !index.isValid() )
return;
/* FIXME, this returns no art, so far */
QPixmap pix = PLModel::getArtPixmap( index, QSize(128,128) );
picFlow->addSlide(pix);
}
picFlow->render();
}
void PicFlowView::playItem( int i_item )
{
emit activated( model()->index(i_item, 0) );
}
......@@ -27,6 +27,8 @@
#include <QStyledItemDelegate>
#include <QListView>
#include <QTreeView>
#include <QAbstractItemView>
#include "util/pictureflow.hpp"
class QPainter;
class PLModel;
......@@ -93,5 +95,31 @@ protected:
virtual void keyPressEvent( QKeyEvent *event );
};
#endif
class PicFlowView : public QAbstractItemView
{
Q_OBJECT
public:
PicFlowView( PLModel *model, QWidget *parent = 0 );
virtual QRect visualRect(const QModelIndex&) const;
virtual void scrollTo(const QModelIndex&, QAbstractItemView::ScrollHint);
virtual QModelIndex indexAt(const QPoint&) const;
protected:
virtual int horizontalOffset() const;
virtual int verticalOffset() const;
virtual QModelIndex moveCursor(QAbstractItemView::CursorAction, Qt::KeyboardModifiers);
virtual bool isIndexHidden(const QModelIndex&) const;
virtual QRegion visualRegionForSelection(const QItemSelection&) const;
virtual void setSelection(const QRect&, QFlags<QItemSelectionModel::SelectionFlag>);
private:
PictureFlow *picFlow;
protected slots:
void rowsInserted ( const QModelIndex & parent, int start, int end );
private slots:
void playItem( int );
};
#endif
This diff is collapsed.
/*
PictureFlow - animated image show widget
http://pictureflow.googlecode.com
Copyright (C) 2009 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2008 Ariya Hidayat (ariya@kde.org)
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PICTUREFLOW_H
#define PICTUREFLOW_H
#include <qwidget.h>
class PictureFlowPrivate;
/*!
Class PictureFlow implements an image show widget with animation effect
like Apple's CoverFlow (in iTunes and iPod). Images are arranged in form
of slides, one main slide is shown at the center with few slides on
the left and right sides of the center slide. When the next or previous
slide is brought to the front, the whole slides flow to the right or
the right with smooth animation effect; until the new slide is finally
placed at the center.
*/
class PictureFlow : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
Q_PROPERTY(QSize slideSize READ slideSize WRITE setSlideSize)
Q_PROPERTY(int slideCount READ slideCount)
Q_PROPERTY(int centerIndex READ centerIndex WRITE setCenterIndex)
public:
enum ReflectionEffect {
NoReflection,
PlainReflection,
BlurredReflection
};
/*!
Creates a new PictureFlow widget.
*/
PictureFlow(QWidget* parent = 0);
/*!
Destroys the widget.
*/
~PictureFlow();
/*!
Returns the background color.
*/
QColor backgroundColor() const;
/*!
Sets the background color. By default it is black.
*/
void setBackgroundColor(const QColor& c);
/*!
Returns the dimension of each slide (in pixels).
*/
QSize slideSize() const;
/*!
Sets the dimension of each slide (in pixels).
*/
void setSlideSize(QSize size);
/*!
Returns the total number of slides.
*/
int slideCount() const;
/*!
Returns QImage of specified slide.
*/
QImage slide(int index) const;
/*!
Returns the index of slide currently shown in the middle of the viewport.
*/
int centerIndex() const;
/*!
Returns the effect applied to the reflection.
*/
ReflectionEffect reflectionEffect() const;
/*!
Sets the effect applied to the reflection. The default is PlainReflection.
*/
void setReflectionEffect(ReflectionEffect effect);
public slots:
/*!
Adds a new slide.
*/
void addSlide(const QImage& image);
/*!
Adds a new slide.
*/
void addSlide(const QPixmap& pixmap);
/*!
Removes an existing slide.
*/
void removeSlide(int index);
/*!
Sets an image for specified slide. If the slide already exists,
it will be replaced.
*/
void setSlide(int index, const QImage& image);
/*!
Sets a pixmap for specified slide. If the slide already exists,
it will be replaced.
*/
void setSlide(int index, const QPixmap& pixmap);
/*!
Sets slide to be shown in the middle of the viewport. No animation
effect will be produced, unlike using showSlide.
*/
void setCenterIndex(int index);
/*!
Clears all slides.
*/
void clear();
/*!
Shows previous slide using animation effect.
*/
void showPrevious();
/*!
Shows next slide using animation effect.
*/
void showNext();
/*!
Go to specified slide using animation effect.
*/
void showSlide(int index);
/*!
Rerender the widget. Normally this function will be automatically invoked
whenever necessary, e.g. during the transition animation.
*/
void render();
/*!
Schedules a rendering update. Unlike render(), this function does not cause
immediate rendering.
*/
void triggerRender();
signals:
void centerIndexChanged(int index);
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent* event);
void mousePressEvent(QMouseEvent* event);
void resizeEvent(QResizeEvent* event);
private slots:
void updateAnimation();
private:
PictureFlowPrivate* d;
};
#endif // PICTUREFLOW_H
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment