Commit 5d5b824b authored by Ludovic Fauvet's avatar Ludovic Fauvet

Merge branch 'etix-timeline'

parents 6cea7749 3659c7f1
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
#define FPS 30 #define FPS 30
#endif #endif
#ifndef MAX_TRACKS
#define MAX_TRACKS 64
#endif
class TrackWorkflow : public QObject class TrackWorkflow : public QObject
{ {
Q_OBJECT Q_OBJECT
......
...@@ -41,3 +41,14 @@ void AbstractGraphicsMediaItem::mouseReleaseEvent( QGraphicsSceneMouseEvent* ) ...@@ -41,3 +41,14 @@ void AbstractGraphicsMediaItem::mouseReleaseEvent( QGraphicsSceneMouseEvent* )
{ {
setCursor( Qt::OpenHandCursor ); setCursor( Qt::OpenHandCursor );
} }
int AbstractGraphicsMediaItem::trackNumber()
{
if ( parentItem() )
{
GraphicsTrack* graphicsTrack = dynamic_cast<GraphicsTrack*>( parentItem() );
if ( graphicsTrack )
return graphicsTrack->trackNumber();
}
return -1;
}
...@@ -47,6 +47,8 @@ public: ...@@ -47,6 +47,8 @@ public:
/// Should return the unique uid of the contained media. /// Should return the unique uid of the contained media.
virtual const QUuid& uuid() const = 0; virtual const QUuid& uuid() const = 0;
int trackNumber();
protected: protected:
/** /**
* Returns the current tracksView for the item, * Returns the current tracksView for the item,
......
...@@ -20,14 +20,21 @@ ...@@ -20,14 +20,21 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/ *****************************************************************************/
#include "GraphicsMovieItem.h"
#include "TracksView.h"
#include <QPainter> #include <QPainter>
#include <QLinearGradient>
#include <QDebug> #include <QDebug>
#include <QTime>
#include "GraphicsMovieItem.h"
#include "TracksView.h"
GraphicsMovieItem::GraphicsMovieItem( Media* media ) : m_media ( media ), m_width( 0 ), m_height( 0 ) GraphicsMovieItem::GraphicsMovieItem( Clip* clip ) : m_clip( clip ), m_width( 0 ), m_height( 0 )
{ {
QTime length = QTime().addMSecs( clip->getParent()->getLength() );
QString tooltip( tr( "<p style='white-space:pre'><b>Name:</b> %1"
"<br><b>Length:</b> %2" )
.arg( clip->getParent()->getFileInfo()->fileName() )
.arg( length.toString("hh:mm:ss.zzz") ) );
setToolTip( tooltip );
} }
GraphicsMovieItem::~GraphicsMovieItem() GraphicsMovieItem::~GraphicsMovieItem()
...@@ -41,7 +48,12 @@ QRectF GraphicsMovieItem::boundingRect() const ...@@ -41,7 +48,12 @@ QRectF GraphicsMovieItem::boundingRect() const
void GraphicsMovieItem::paint( QPainter* painter, const QStyleOptionGraphicsItem*, QWidget* ) void GraphicsMovieItem::paint( QPainter* painter, const QStyleOptionGraphicsItem*, QWidget* )
{ {
painter->setBrush( Qt::red ); QLinearGradient gradient( 0, 0, m_width, m_height );
gradient.setColorAt( 0, QColor::fromRgb( 32, 52, 142 ) );
gradient.setColorAt( 1, QColor::fromRgb( 43, 69, 181 ) );
painter->setPen( QPen( Qt::NoPen ) );
painter->setBrush( QBrush( gradient ) );
painter->drawRect( boundingRect() ); painter->drawRect( boundingRect() );
paintAudioSpectrum( painter ); paintAudioSpectrum( painter );
...@@ -69,14 +81,14 @@ void GraphicsMovieItem::paintAudioSpectrum( QPainter* painter ) ...@@ -69,14 +81,14 @@ void GraphicsMovieItem::paintAudioSpectrum( QPainter* painter )
QLineF line; QLineF line;
for (int i = 0; i < m_media->getAudioFrameList().size(); i++) for (int i = 0; i < m_clip->getParent()->getAudioFrameList().size(); i++)
{ {
//qDebug() << "Frame: " << i << "/" << m_media->getAudioFrameList().size(); //qDebug() << "Frame: " << i << "/" << m_media->getAudioFrameList().size();
for (unsigned int u = 0; u < m_media->getAudioNbSample(); u += 400) for (unsigned int u = 0; u < m_clip->getParent()->getAudioNbSample(); u += 400)
{ {
int value = m_media->getAudioFrameList()[i][u]; int value = m_clip->getParent()->getAudioFrameList()[i][u];
value /= 30; value /= 30;
if( value > 48 ) value = 48; if( value > 48 ) value = 48;
if( value < 0 ) value = 0; if( value < 0 ) value = 0;
...@@ -101,3 +113,8 @@ void GraphicsMovieItem::paintAudioSpectrum( QPainter* painter ) ...@@ -101,3 +113,8 @@ void GraphicsMovieItem::paintAudioSpectrum( QPainter* painter )
} }
} }
} }
Clip* GraphicsMovieItem::clip() const
{
return m_clip;
}
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define GRAPHICSMOVIEITEM_H #define GRAPHICSMOVIEITEM_H
#include "AbstractGraphicsMediaItem.h" #include "AbstractGraphicsMediaItem.h"
#include "Clip.h"
#include "Media.h" #include "Media.h"
#include "TracksView.h" #include "TracksView.h"
...@@ -32,23 +33,24 @@ class GraphicsMovieItem : public AbstractGraphicsMediaItem ...@@ -32,23 +33,24 @@ class GraphicsMovieItem : public AbstractGraphicsMediaItem
Q_OBJECT Q_OBJECT
public: public:
enum { Type = UserType + 1 }; enum { Type = UserType + 1 };
GraphicsMovieItem( Media* media ); GraphicsMovieItem( Clip* clip );
virtual ~GraphicsMovieItem(); virtual ~GraphicsMovieItem();
virtual int type() const { return Type; } virtual int type() const { return Type; }
virtual bool expandable() const { return false; } virtual bool expandable() const { return false; }
virtual bool moveable() const { return true; } virtual bool moveable() const { return true; }
virtual const QUuid& uuid() const { return m_media->getUuid(); } virtual const QUuid& uuid() const { return m_clip->getUuid(); }
virtual QRectF boundingRect() const; virtual QRectF boundingRect() const;
virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 ); virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 );
void setWidth( int width ); void setWidth( int width );
void setHeight( int height ); void setHeight( int height );
Clip* clip() const;
//void setAudioSpectrum( QVector<float*> spectrum ); //void setAudioSpectrum( QVector<float*> spectrum );
void paintAudioSpectrum( QPainter* painter ); void paintAudioSpectrum( QPainter* painter );
private: private:
Media* m_media; Clip* m_clip;
int m_width; int m_width;
int m_height; int m_height;
QVector<float*> m_audioSpectrum; QVector<float*> m_audioSpectrum;
......
...@@ -36,7 +36,7 @@ Timeline::Timeline( QWidget *parent ) : ...@@ -36,7 +36,7 @@ Timeline::Timeline( QWidget *parent ) :
m_instance = this; m_instance = this;
m_ui.setupUi( this ); m_ui.setupUi( this );
m_mainWorkflow = new MainWorkflow( this, 5 ); m_mainWorkflow = new MainWorkflow( this, MAX_TRACKS );
m_tracksScene = new TracksScene( this ); m_tracksScene = new TracksScene( this );
m_tracksView = new TracksView( m_tracksScene, m_mainWorkflow, m_ui.tracksFrame ); m_tracksView = new TracksView( m_tracksScene, m_mainWorkflow, m_ui.tracksFrame );
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "TracksScene.h" #include "TracksScene.h"
#include "TracksRuler.h" #include "TracksRuler.h"
#include "Workflow/MainWorkflow.h" #include "Workflow/MainWorkflow.h"
#include "Workflow/TrackWorkflow.h"
class Timeline : public QWidget class Timeline : public QWidget
{ {
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#include <QScrollBar> #include <QScrollBar>
#include <QMouseEvent> #include <QMouseEvent>
#include <QWheelEvent> #include <QWheelEvent>
#include <QGraphicsLinearLayout>
#include <QGraphicsWidget>
#include <QGraphicsSceneDragDropEvent>
#include <QtDebug> #include <QtDebug>
#include <cmath> #include <cmath>
#include "TracksView.h" #include "TracksView.h"
...@@ -35,49 +38,221 @@ TracksView::TracksView( QGraphicsScene* scene, MainWorkflow* mainWorkflow, QWidg ...@@ -35,49 +38,221 @@ TracksView::TracksView( QGraphicsScene* scene, MainWorkflow* mainWorkflow, QWidg
: QGraphicsView( scene, parent ), m_scene( scene ), m_mainWorkflow( mainWorkflow ) : QGraphicsView( scene, parent ), m_scene( scene ), m_mainWorkflow( mainWorkflow )
{ {
//TODO should be defined by the settings //TODO should be defined by the settings
m_tracksHeight = 50; m_tracksHeight = 25;
//TODO should be dynamic
m_tracksCount = mainWorkflow->getTrackCount(); m_tracksCount = mainWorkflow->getTrackCount();
m_fps = 30; m_fps = 30;
m_numAudioTrack = 0;
m_numVideoTrack = 0;
m_videoTracksCounter = MAX_TRACKS - 1;
m_dragItem = NULL;
m_actionMove = false;
m_actionRelativeX = -1;
m_actionItem = NULL;
setMouseTracking( true ); setMouseTracking( true );
setAcceptDrops( true ); setAcceptDrops( true );
setContentsMargins( 0, 0, 0, 0 ); setContentsMargins( 0, 0, 0, 0 );
setFrameStyle( QFrame::NoFrame ); setFrameStyle( QFrame::NoFrame );
// Adjust the height using the number of tracks //// Adjust the height using the number of tracks
const int maxHeight = m_tracksHeight * m_tracksCount; //const int maxHeight = m_tracksHeight * m_tracksCount;
setSceneRect( 0, 0, sceneRect().width(), maxHeight ); //setSceneRect( 0, 0, sceneRect().width(), maxHeight );
const int maxHeight = m_tracksHeight * 4;
m_cursorLine = new GraphicsCursorItem( maxHeight, QPen( QColor( 220, 30, 30 ) ) ); m_cursorLine = new GraphicsCursorItem( maxHeight, QPen( QColor( 220, 30, 30 ) ) );
m_scene->addItem( m_cursorLine ); m_scene->addItem( m_cursorLine );
createLayout();
connect( m_cursorLine, SIGNAL( cursorPositionChanged(int) ), connect( m_cursorLine, SIGNAL( cursorPositionChanged(int) ),
this, SLOT( ensureCursorVisible() ) ); this, SLOT( ensureCursorVisible() ) );
} }
void TracksView::createLayout()
{
m_layout = new QGraphicsLinearLayout( Qt::Vertical );
m_layout->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
m_layout->setContentsMargins( 0, 0, 0, 0 );
m_layout->setSpacing( 0 );
m_layout->setPreferredWidth( 0 );
QGraphicsWidget* container = new QGraphicsWidget();
container->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
container->setContentsMargins( 0, 0, 0, 0 );
container->setLayout( m_layout );
// Create the initial layout
// - 1 video track
// - a separator
// - 1 audio track
addVideoTrack();
m_separator = new QGraphicsWidget();
m_separator->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
m_separator->setPreferredHeight( 20 );
m_layout->insertItem( 1, m_separator );
addAudioTrack();
m_scene->addItem( container );
}
void TracksView::addVideoTrack()
{
GraphicsTrack* track = new GraphicsTrack( GraphicsTrack::Video, m_videoTracksCounter );
track->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
track->setPreferredHeight( m_tracksHeight );
track->setContentsMargins( 0, 0, 0, 0 );
m_layout->insertItem( 0, track );
m_numVideoTrack++;
m_videoTracksCounter--;
m_scene->invalidate();
//FIXME this should maybe go elsewhere
setSceneRect( m_layout->contentsRect().adjusted( 0, 0, 100, 100 ) );
}
void TracksView::addAudioTrack()
{
GraphicsTrack* track = new GraphicsTrack( GraphicsTrack::Audio, 0 );
track->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
track->setPreferredHeight( m_tracksHeight );
track->setContentsMargins( 0, 0, 0, 0 );
m_layout->insertItem( 1000, track );
m_numAudioTrack++;
m_scene->invalidate();
//FIXME this should maybe go elsewhere
setSceneRect( m_layout->contentsRect().adjusted( 0, 0, 100, 100 ) );
}
void TracksView::dragEnterEvent( QDragEnterEvent* event ) void TracksView::dragEnterEvent( QDragEnterEvent* event )
{ {
if ( event->mimeData()->hasFormat( "vlmc/uuid" ) ) if ( event->mimeData()->hasFormat( "vlmc/uuid" ) )
event->acceptProposedAction(); event->acceptProposedAction();
}
void TracksView::dropEvent( QDropEvent* event )
{
QUuid uuid = QUuid( (const QString& )event->mimeData()->data( "vlmc/uuid" ) ); QUuid uuid = QUuid( (const QString& )event->mimeData()->data( "vlmc/uuid" ) );
Media* media = Library::getInstance()->getMedia( uuid ); Media* media = Library::getInstance()->getMedia( uuid );
if ( !media ) if ( !media ) return;
return;
qreal mappedXPos = ( mapToScene( event->pos() ).x() + 0.5 );
if ( m_dragItem ) delete m_dragItem;
m_dragItem = new GraphicsMovieItem( new Clip( media ) );
m_dragItem->setWidth( ( (double)media->getLength() / 1000 ) * m_fps );
m_dragItem->setHeight( tracksHeight() );
m_dragItem->setPos( mappedXPos, 0 );
m_dragItem->setParentItem( m_layout->itemAt( 0 )->graphicsItem() );
moveMediaItem( m_dragItem, event->pos() );
}
addClip( media, event->pos() ); void TracksView::dragMoveEvent( QDragMoveEvent* event )
{
if ( !m_dragItem ) return;
moveMediaItem( m_dragItem, event->pos() );
}
void TracksView::moveMediaItem( AbstractGraphicsMediaItem* item, QPoint position )
{
int track = (unsigned int)( mapToScene( position ).y() / m_tracksHeight );
if ( track < 0 )
track = 0;
else if ( track > m_numVideoTrack - 1)
track = m_numVideoTrack - 1;
qreal mappedXPos = ( mapToScene( position ).x() + 0.5 );
event->acceptProposedAction(); QPointF oldPos = item->pos();
QGraphicsItem* oldParent = item->parentItem();
// Check for vertical collisions
item->setParentItem( m_layout->itemAt( track )->graphicsItem() );
bool continueSearch = true;
while ( continueSearch )
{
QList<QGraphicsItem*> colliding = item->collidingItems( Qt::IntersectsItemShape );
bool itemCollision = false;
for ( int i = 0; i < colliding.size(); ++i )
{
AbstractGraphicsMediaItem* currentItem = dynamic_cast<AbstractGraphicsMediaItem*>( colliding.at( i ) );
if ( currentItem )
{
// Collision with an item of the same type
itemCollision = true;
if ( currentItem->pos().y() < position.y() )
{
if ( track < 0 )
{
item->setParentItem( oldParent );
continueSearch = false;
break;
}
track -= 1;
item->setParentItem( m_layout->itemAt( track )->graphicsItem() );
}
else if ( currentItem->pos().y() > position.y() )
{
if ( track >= m_numVideoTrack - 1 )
{
item->setParentItem( oldParent );
continueSearch = false;
break;
}
track += 1;
item->setParentItem( m_layout->itemAt( track )->graphicsItem() );
}
}
}
if ( !itemCollision )
continueSearch = false;
}
// Check for horizontal collisions
mappedXPos = qMax( mappedXPos, (qreal)0 );
item->setPos( mappedXPos, 0 );
QList<QGraphicsItem*> colliding = item->collidingItems( Qt::IntersectsItemShape );
for ( int i = 0; i < colliding.size(); ++i )
{
AbstractGraphicsMediaItem* currentItem = dynamic_cast<AbstractGraphicsMediaItem*>( colliding.at( i ) );
if ( currentItem )
{
// Collision with an item of the same type
// Restoring original position (horizontal)
item->setPos( oldPos );
break;
}
}
} }
void TracksView::dragMoveEvent( QDragMoveEvent* ) void TracksView::dragLeaveEvent( QDragLeaveEvent* event )
{ {
Q_UNUSED( event )
if ( m_dragItem )
{
delete m_dragItem;
m_dragItem = NULL;
updateDuration();
}
}
void TracksView::dropEvent( QDropEvent* event )
{
if ( m_dragItem )
{
updateDuration();
if ( m_layout->itemAt( 0 )->graphicsItem()->childItems().count() > 0 )
addVideoTrack();
event->acceptProposedAction();
qreal mappedXPos = ( mapToScene( event->pos() ).x() + 0.5 );
//FIXME this leaks, but it will be corrected once we really use Clip instead
// of Media
m_mainWorkflow->addClip( m_dragItem->clip(),
m_dragItem->trackNumber(),
(qint64)mappedXPos );
m_dragItem = NULL; // Temporary action
}
} }
void TracksView::setDuration( int duration ) void TracksView::setDuration( int duration )
...@@ -100,7 +275,16 @@ void TracksView::resizeEvent( QResizeEvent* event ) ...@@ -100,7 +275,16 @@ void TracksView::resizeEvent( QResizeEvent* event )
void TracksView::drawBackground( QPainter* painter, const QRectF& rect ) void TracksView::drawBackground( QPainter* painter, const QRectF& rect )
{ {
QColor base = palette().button().color(); QRectF r = rect;
r.setWidth( r.width() + 1 );
painter->setBrush( QBrush( palette().dark().color(), Qt::Dense3Pattern ) );
painter->setPen( Qt::transparent );
painter->drawRect( r.left(), m_separator->y(),
r.right(),
m_separator->boundingRect().height() );
/*QColor base = palette().button().color();
QRectF r = rect; QRectF r = rect;
r.setWidth( r.width() + 1 ); r.setWidth( r.width() + 1 );
...@@ -113,40 +297,79 @@ void TracksView::drawBackground( QPainter* painter, const QRectF& rect ) ...@@ -113,40 +297,79 @@ void TracksView::drawBackground( QPainter* painter, const QRectF& rect )
int lowerLimit = m_tracksHeight * m_tracksCount + 1; int lowerLimit = m_tracksHeight * m_tracksCount + 1;
if ( height() > lowerLimit ) if ( height() > lowerLimit )
painter->fillRect( QRectF ( r.left(), lowerLimit, r.width(), height() - lowerLimit ), QBrush( base ) ); painter->fillRect( QRectF ( r.left(), lowerLimit, r.width(),
height() - lowerLimit ), QBrush( base ) );*/
} }
void TracksView::mouseMoveEvent( QMouseEvent* event ) void TracksView::mouseMoveEvent( QMouseEvent* event )
{ {
if ( event->modifiers() == Qt::NoModifier &&
event->buttons() == Qt::LeftButton &&
m_actionMove == true )
{
if ( m_actionRelativeX < 0 )
m_actionRelativeX = event->pos().x() - mapFromScene( m_actionItem->pos() ).x();
moveMediaItem( m_actionItem, QPoint( event->pos().x() - m_actionRelativeX, event->pos().y() ) );
}
QGraphicsView::mouseMoveEvent( event ); QGraphicsView::mouseMoveEvent( event );
} }
void TracksView::mousePressEvent( QMouseEvent* event ) void TracksView::mousePressEvent( QMouseEvent* event )
{ {
QList<AbstractGraphicsMediaItem*> mediaCollisionList = mediaItems( event->pos() );
QList<QGraphicsItem*> collisionList = items( event->pos() ); if ( event->modifiers() == Qt::ControlModifier && mediaCollisionList.count() == 0 )
if ( event->modifiers() == Qt::ControlModifier && collisionList.count() == 0 )
{ {
setDragMode( QGraphicsView::ScrollHandDrag ); setDragMode( QGraphicsView::ScrollHandDrag );
QGraphicsView::mousePressEvent( event ); QGraphicsView::mousePressEvent( event );
return; return;
} }
if ( event->modifiers() & Qt::ShiftModifier && collisionList.count() == 0 ) if ( event->modifiers() == Qt::NoModifier &&
event->button() == Qt::LeftButton &&
mediaCollisionList.count() == 1 )
{
AbstractGraphicsMediaItem* item = mediaCollisionList.at( 0 );
if ( item->moveable() )
{
m_actionMove = true;
m_actionItem = mediaCollisionList.at( 0 );
}
return;
}
/*if ( event->modifiers() & Qt::ShiftModifier && collisionList.count() == 0 )
{ {
setDragMode( QGraphicsView::RubberBandDrag ); setDragMode( QGraphicsView::RubberBandDrag );
if ( !event->modifiers() & Qt::ControlModifier ) if ( !event->modifiers() & Qt::ControlModifier )
scene()->clearSelection(); scene()->clearSelection();
QGraphicsView::mousePressEvent( event ); QGraphicsView::mousePressEvent( event );
return; return;
} }*/
QGraphicsView::mousePressEvent( event ); QGraphicsView::mousePressEvent( event );
} }
void TracksView::mouseReleaseEvent( QMouseEvent* event ) void TracksView::mouseReleaseEvent( QMouseEvent* event )
{ {
if ( m_actionMove )
{
GraphicsMovieItem* movieItem = qgraphicsitem_cast<GraphicsMovieItem*>( m_actionItem );
if ( movieItem )
{
updateDuration();
if ( m_layout->itemAt( 0 )->graphicsItem()->childItems().count() > 0 )
addVideoTrack();