Commit d3636d7a authored by Geoffroy Lacarriere's avatar Geoffroy Lacarriere
Browse files

Merge commit 'origin/master' into geoff_project_saving

Conflicts:
	src/GUI/GraphicsMovieItem.h
parents da993d4e cecae387
......@@ -24,6 +24,8 @@
#define COMMANDS_HPP
#include <QUndoCommand>
#include <QObject>
#include <QVector>
#include "UndoStack.h"
#include "MainWorkflow.h"
#include "Clip.h"
......@@ -39,13 +41,20 @@ namespace Commands
namespace MainWorkflow
{
struct ClipActionInfo
{
Clip* clip;
quint32 trackNumber;
qint64 pos;
};
NEW_COMMAND( AddClip )
{
public:
AddClip( ::MainWorkflow* workflow, Clip* clip, unsigned int trackNumber, qint64 pos ) :
m_workflow( workflow ), m_clip( clip ), m_trackNumber( trackNumber ), m_pos( pos )
{
setText( "Adding clip to track" + QString::number( trackNumber ) );
setText( QObject::tr( "Adding clip to track %1" ).arg( QString::number( trackNumber ) ) );
}
virtual void redo()
{
......@@ -56,7 +65,7 @@ namespace Commands
m_workflow->removeClip( m_clip->getUuid(), m_trackNumber );
}
private:
::MainWorkflow* m_workflow;
::MainWorkflow* m_workflow;
Clip* m_clip;
unsigned int m_trackNumber;
qint64 m_pos;
......@@ -70,18 +79,16 @@ namespace Commands
m_workflow( workflow ), m_uuid( uuid ), m_oldTrack( oldTrack ),
m_newTrack( newTrack ), m_pos( newPos ), m_oldPos( oldPos )
{
setText( "Moving clip" );
setText( QObject::tr( "Moving clip" ) );
m_undoRedoAction = false;
}
virtual void redo()
{
qDebug() << "Moving from track" << m_oldTrack << "to" << m_newTrack << "at pos" << m_pos;
m_workflow->moveClip( m_uuid, m_oldTrack, m_newTrack, m_pos, m_undoRedoAction );
m_undoRedoAction = true;
}
virtual void undo()
{
qDebug() << "Moving from track" << m_newTrack << "to" << m_oldTrack << "at pos" << m_oldPos;
m_workflow->moveClip( m_uuid, m_newTrack, m_oldTrack, m_oldPos, m_undoRedoAction );
m_undoRedoAction = true;
}
......@@ -95,6 +102,62 @@ namespace Commands
qint64 m_oldPos;
bool m_undoRedoAction;
};
NEW_COMMAND( RemoveClips )
{
public:
RemoveClips( ::MainWorkflow* workflow, const QVector<ClipActionInfo>& clipsInfos ) :
m_workflow( workflow ), m_clips( clipsInfos )
{
setText( QObject::tr( "Remove clip" ) );
}
virtual void redo()
{
for (int i = 0; i < m_clips.size(); ++i )
m_workflow->removeClip( m_clips.at( i ).clip->getUuid(), m_clips.at( i ).trackNumber );
}
virtual void undo()
{
for (int i = 0; i < m_clips.size(); ++i )
m_workflow->addClip( m_clips.at( i ).clip, m_clips.at( i ).trackNumber, m_clips.at( i ).pos );
}
private:
::MainWorkflow* m_workflow;
QVector<ClipActionInfo> m_clips;
};
NEW_COMMAND( ResizeClip )
{
public:
ResizeClip( ::MainWorkflow* mainWorkflow, const QUuid& uuid, unsigned int trackId,
float newBegin, float newEnd ) :
m_mainWorkflow( mainWorkflow ),
m_newBegin( newBegin ),
m_newEnd( newEnd )
{
m_clip = mainWorkflow->getClip( uuid, trackId );
m_oldBegin = m_clip->getBegin();
m_oldEnd = m_clip->getEnd();
}
virtual void redo()
{
m_clip->setBegin( m_newBegin );
m_clip->setEnd( m_newEnd );
}
virtual void undo()
{
m_clip->setBegin( m_oldBegin );
m_clip->setEnd( m_oldEnd );
}
private:
::MainWorkflow* m_mainWorkflow;
float m_oldBegin;
float m_oldEnd;
float m_newBegin;
float m_newEnd;
Clip* m_clip;
};
}
}
......
......@@ -47,7 +47,7 @@ int AbstractGraphicsMediaItem::trackNumber()
{
if ( parentItem() )
{
GraphicsTrack* graphicsTrack = dynamic_cast<GraphicsTrack*>( parentItem() );
GraphicsTrack* graphicsTrack = qgraphicsitem_cast<GraphicsTrack*>( parentItem() );
if ( graphicsTrack )
return graphicsTrack->trackNumber();
}
......
......@@ -25,7 +25,10 @@
#include <QGraphicsItem>
#include <QUuid>
#include "TracksView.h"
#include <QCursor>
#include "GraphicsTrack.hpp"
class TracksView;
class AbstractGraphicsMediaItem : public QObject, public QGraphicsItem
{
......
#include <QtDebug>
#include "GraphicsCursorItem.h"
GraphicsCursorItem::GraphicsCursorItem( int height, const QPen& pen )
: m_pen( pen ), m_moveRequired( false )
GraphicsCursorItem::GraphicsCursorItem( const QPen& pen )
: m_pen( pen )
{
setFlags( QGraphicsItem::ItemIgnoresTransformations | QGraphicsItem::ItemIsMovable );
setCursor( QCursor( Qt::SizeHorCursor ) );
......@@ -32,23 +32,14 @@ QVariant GraphicsCursorItem::itemChange( GraphicsItemChange change, const QVaria
}
if ( change == ItemPositionHasChanged )
{
if ( m_moveRequired == false )
emit cursorPositionChanged( ( qint64 ) pos().x() );
else
m_moveRequired = false;
emit cursorPositionChanged( ( qint64 ) pos().x() );
}
return QGraphicsItem::itemChange( change, value );
}
void GraphicsCursorItem::setCursorPos( int position )
void GraphicsCursorItem::setCursorPos( qint64 position )
{
setPos( position, pos().y() );
m_moveRequired = true;
}
void GraphicsCursorItem::updateCursorPos( qint64 position )
{
setCursorPos( (qint64) position );
}
void GraphicsCursorItem::setHeight( int height )
......
......@@ -13,9 +13,8 @@ class GraphicsCursorItem : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
GraphicsCursorItem( int height, const QPen& pen );
GraphicsCursorItem( const QPen& pen );
int cursorPos() const { return ( int )pos().x(); }
void setCursorPos( int position );
virtual QRectF boundingRect() const;
void setHeight( int height );
......@@ -26,13 +25,12 @@ protected:
private:
QPen m_pen;
QRectF m_boundingRect;
bool m_moveRequired;
signals:
void cursorPositionChanged( qint64 pos );
public slots:
void updateCursorPos( qint64 pos );
void setCursorPos( qint64 position );
};
#endif // GRAPHICSCURSORITEM_H
......@@ -102,3 +102,8 @@ void GraphicsMovieItem::updateTitle()
//FIXME there is a small visual refresh bug here
m_movieTitle->setPlainText( fm.elidedText( text, Qt::ElideRight, width ) );
}
void GraphicsMovieItem::setClip( Clip* clip )
{
m_clip = clip;
}
/*****************************************************************************
* GraphicsTrack.hpp: Graphically represent a track in the timeline
*****************************************************************************
* Copyright (C) 2008-2009 the VLMC team
*
* Authors: Ludovic Fauvet <etix@l0cal.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef GRAPHICSTRACK_HPP
#define GRAPHICSTRACK_HPP
#include <QGraphicsWidget>
#include <QPainter>
class GraphicsTrack : public QGraphicsWidget
{
Q_OBJECT
public:
enum { Type = UserType + 2 };
enum MediaType
{
Video,
Audio
};
GraphicsTrack( MediaType type, quint32 trackNumber, QGraphicsItem* parent = 0 ) : QGraphicsWidget( parent )
{
m_type = type;
m_trackNumber = trackNumber;
}
quint32 trackNumber()
{
return m_trackNumber;
}
virtual int type() const { return Type; }
protected:
virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem*, QWidget* = 0 )
{
if ( m_type == Video )
painter->setBrush( Qt::green );
else
painter->setBrush( Qt::blue );
painter->setPen( Qt::transparent );
painter->drawRect( rect() );
}
private:
MediaType m_type;
quint32 m_trackNumber;
};
#endif // GRAPHICSTRACK_HPP
......@@ -82,7 +82,7 @@ void LibraryWidget::removeMedia( const QUuid& uuid )
ListViewMediaItem* item;
foreach (item, *m_clips)
{
if ( item->getClip()->getUuid() == uuid )
if ( item->getClip()->getParent()->getUuid() == uuid )
{
switch( item->getFileType() )
{
......
......@@ -82,7 +82,9 @@ void MediaListWidget::mouseMoveEvent( QMouseEvent* event )
ListViewMediaItem* item = static_cast<ListViewMediaItem*>( currentItem() );
QMimeData* mimeData = new QMimeData;
mimeData->setData( "vlmc/uuid", item->getClip()->getUuid().toString().toAscii() );
//FIXME the second argument is a media UUID instead of a Clip
// and this is not logical... but it works.
mimeData->setData( "vlmc/uuid", item->getClip()->getParent()->getUuid().toString().toAscii() );
QDrag* drag = new QDrag( this );
drag->setMimeData( mimeData );
const QPixmap& dragPixmap = static_cast<ListViewMediaItem*>( currentItem() )->getClip()->getParent()->getSnapshot();
......
......@@ -59,7 +59,9 @@ Timeline::Timeline( QWidget *parent ) :
setDuration( 0 );
connect( m_tracksView->horizontalScrollBar(), SIGNAL( valueChanged( int ) ), m_tracksRuler, SLOT( moveRuler( int ) ) );
connect( m_tracksView, SIGNAL( durationChanged(int) ), this, SLOT( setDuration(int) ) );
connect( m_mainWorkflow, SIGNAL( clipAdded(Clip*,uint,qint64) ), this, SLOT( actionAddClip(Clip*,uint,qint64) ) );
connect( m_mainWorkflow, SIGNAL( clipMoved(QUuid, uint, qint64 ) ), this, SLOT( actionMoveClip(QUuid,uint,qint64) ) );
connect( m_mainWorkflow, SIGNAL( clipRemoved(QUuid,uint) ), this, SLOT( actionRemoveClip(QUuid,uint)) );
}
Timeline::~Timeline()
......@@ -92,9 +94,21 @@ void Timeline::setDuration( int duration )
m_tracksRuler->setDuration( duration );
}
void Timeline::actionAddClip( Clip* clip, unsigned int track, qint64 start )
{
tracksView()->addMediaItem( clip, track, start );
}
void Timeline::actionMoveClip( const QUuid& uuid, unsigned int track, qint64 time )
{
tracksView()->moveMediaItem( uuid, track, time );
tracksView()->updateDuration();
tracksRuler()->update();
}
void Timeline::actionRemoveClip( const QUuid& uuid, unsigned int track )
{
// The signal was triggered by the backend, so we do not have to
// notify it again. I guess it would be a very bad idea.
tracksView()->removeMediaItem( uuid, track, false );
}
......@@ -46,7 +46,9 @@ public:
public slots:
void changeZoom( int factor );
void setDuration( int duration );
void actionAddClip( Clip* clip, unsigned int track, qint64 start );
void actionMoveClip( const QUuid& uuid, unsigned int track, qint64 time );
void actionRemoveClip( const QUuid& uuid, unsigned int track );
protected:
virtual void changeEvent( QEvent *e );
......
......@@ -149,7 +149,7 @@ void TracksRuler::paintEvent( QPaintEvent* e )
painter.drawLine( ( int )f, BIG_MARK_X1, ( int )f, BIG_MARK_X2 );
// Draw the pointer
int cursorPos = ( int ) ( m_tracksView->cursorPos() * m_factor - offset() );
int cursorPos = qRound( m_tracksView->cursorPos() * m_factor - offset() );
QPolygon cursor( 3 );
cursor.setPoints( 3, cursorPos - 9, 11, cursorPos + 9, 11, cursorPos, 30 );
painter.setBrush( QBrush( QColor( 82, 97, 122, 150 ) ) );
......
......@@ -53,7 +53,13 @@ void TracksScene::keyPressEvent( QKeyEvent* keyEvent )
// Skip the deletion process
if ( b == QMessageBox::No ) return;
//TODO delete the item(s)
QList<QGraphicsItem*> items = selectedItems();
for (int i = 0; i < items.size(); ++i )
{
AbstractGraphicsMediaItem* item = qgraphicsitem_cast<AbstractGraphicsMediaItem*>( items.at(i) );
if ( !item ) return;
tv->removeMediaItem( item );
}
}
QGraphicsScene::keyPressEvent( keyEvent );
......
......@@ -34,6 +34,7 @@
#include "GraphicsMovieItem.h"
#include "GraphicsCursorItem.h"
#include "Commands.hpp"
#include "GraphicsTrack.hpp"
TracksView::TracksView( QGraphicsScene* scene, MainWorkflow* mainWorkflow, QWidget* parent )
: QGraphicsView( scene, parent ), m_scene( scene ), m_mainWorkflow( mainWorkflow )
......@@ -56,8 +57,7 @@ TracksView::TracksView( QGraphicsScene* scene, MainWorkflow* mainWorkflow, QWidg
setContentsMargins( 0, 0, 0, 0 );
setFrameStyle( QFrame::NoFrame );
//TODO Remove the GraphicsCursorItem parameter height (not useful anymore)
m_cursorLine = new GraphicsCursorItem( 1, QPen( QColor( 220, 30, 30 ) ) );
m_cursorLine = new GraphicsCursorItem( QPen( QColor( 220, 30, 30 ) ) );
m_scene->addItem( m_cursorLine );
......@@ -126,6 +126,29 @@ void TracksView::addAudioTrack()
m_cursorLine->setHeight( m_layout->contentsRect().height() );
}
void TracksView::addMediaItem( Clip* clip, unsigned int track, qint64 start )
{
Q_ASSERT( clip );
// Is the clip already existing in the timeline ?
//TODO: please optimize me!
QList<QGraphicsItem*> sceneItems = m_scene->items();
for ( int i = 0; i < sceneItems.size(); ++i )
{
AbstractGraphicsMediaItem* item =
dynamic_cast<AbstractGraphicsMediaItem*>( sceneItems.at( i ) );
if ( !item || item->uuid() != clip->getUuid() ) continue;
// Item already exist: goodbye!
return;
}
GraphicsMovieItem* item = new GraphicsMovieItem( clip );
item->setWidth( clip->getLength() );
item->setHeight( tracksHeight() );
item->setParentItem( getTrack( track ) );
moveMediaItem( item, track, start );
}
void TracksView::dragEnterEvent( QDragEnterEvent* event )
{
if ( event->mimeData()->hasFormat( "vlmc/uuid" ) )
......@@ -202,7 +225,7 @@ void TracksView::moveMediaItem( AbstractGraphicsMediaItem* item, int track, qint
QPointF oldPos = item->pos();
QGraphicsItem* oldParent = item->parentItem();
// Check for vertical collisions
item->setParentItem( m_layout->itemAt( m_numVideoTrack - track - 1 )->graphicsItem() );
item->setParentItem( getTrack( track ) );
bool continueSearch = true;
while ( continueSearch )
{
......@@ -225,7 +248,7 @@ void TracksView::moveMediaItem( AbstractGraphicsMediaItem* item, int track, qint
}
track -= 1;
Q_ASSERT( m_layout->itemAt( track )->graphicsItem() != NULL );
item->setParentItem( m_layout->itemAt( track )->graphicsItem() );
item->setParentItem( getTrack( track ) );
}
else if ( currentItem->trackNumber() < track )
{
......@@ -237,7 +260,7 @@ void TracksView::moveMediaItem( AbstractGraphicsMediaItem* item, int track, qint
}
track += 1;
Q_ASSERT( m_layout->itemAt( track )->graphicsItem() != NULL );
item->setParentItem( m_layout->itemAt( track )->graphicsItem() );
item->setParentItem( getTrack( track ) );
}
}
}
......@@ -267,6 +290,59 @@ void TracksView::moveMediaItem( AbstractGraphicsMediaItem* item, int track, qint
}
}
void TracksView::removeMediaItem( const QUuid& uuid, unsigned int track, bool notifyBackend )
{
Q_UNUSED( track );
//TODO When a clever API will be done to manage the tracks, we could
// use the "track" argument to limit the search into the track instead
// of the full scene.
QList<QGraphicsItem*> sceneItems = m_scene->items();
for ( int i = 0; i < sceneItems.size(); ++i )
{
AbstractGraphicsMediaItem* item =
dynamic_cast<AbstractGraphicsMediaItem*>( sceneItems.at( i ) );
if ( !item || item->uuid() != uuid ) continue;
removeMediaItem( item, notifyBackend );
}
}
void TracksView::removeMediaItem( AbstractGraphicsMediaItem* item, bool notifyBackend )
{
QList<AbstractGraphicsMediaItem*> items;
items.append( item );
removeMediaItem( items, notifyBackend );
}
void TracksView::removeMediaItem( const QList<AbstractGraphicsMediaItem*>& items, bool notifyBackend )
{
QVector<Commands::MainWorkflow::ClipActionInfo> clipsinfos;
for ( int i = 0; i < items.size(); ++i )
{
GraphicsMovieItem* movieItem = qgraphicsitem_cast<GraphicsMovieItem*>( items.at( i ) );
if ( !movieItem )
{
//TODO add support for audio tracks
qWarning() << tr( "Action not supported." );
continue;
}
Commands::MainWorkflow::ClipActionInfo ai;
ai.clip = movieItem->clip();
ai.trackNumber = movieItem->trackNumber();
ai.pos = movieItem->pos().x();
clipsinfos.append( ai );
delete movieItem;
}
if ( notifyBackend )
Commands::trigger( new Commands::MainWorkflow::RemoveClips( m_mainWorkflow,
clipsinfos ) );
}
void TracksView::dragLeaveEvent( QDragLeaveEvent* event )
{
Q_UNUSED( event )
......@@ -289,10 +365,13 @@ void TracksView::dropEvent( QDropEvent* event )
qreal mappedXPos = ( mapToScene( event->pos() ).x() + 0.5 );
m_dragItem->oldTrackNumber = m_dragItem->trackNumber();
Clip* clip = new Clip( m_dragItem->clip() );
m_dragItem->setClip( clip );
Commands::trigger( new Commands::MainWorkflow::AddClip( m_mainWorkflow,
m_dragItem->clip(),
clip,
m_dragItem->trackNumber(),
(qint64)mappedXPos ) );
m_dragItem->oldPosition = mappedXPos;
m_dragItem = NULL;
}
}
......@@ -325,22 +404,6 @@ void TracksView::drawBackground( QPainter* painter, const QRectF& rect )
painter->drawRect( ( int ) r.left(), ( int ) m_separator->y(),
( int ) r.right(),
( int ) m_separator->boundingRect().height() );
/*QColor base = palette().button().color();
QRectF r = rect;
r.setWidth( r.width() + 1 );
painter->setClipRect( r );
painter->drawLine( r.left(), 0, r.right(), 0 );
uint tracks = m_tracksCount;
for ( uint i = 0; i < tracks; ++i )
painter->drawLine( r.left(), m_tracksHeight * ( i + 1 ), r.right(), m_tracksHeight * ( i + 1 ) );
int lowerLimit = m_tracksHeight * m_tracksCount + 1;
if ( height() > lowerLimit )
painter->fillRect( QRectF ( r.left(), lowerLimit, r.width(),
height() - lowerLimit ), QBrush( base ) );*/
}
void TracksView::mouseMoveEvent( QMouseEvent* event )
......@@ -523,3 +586,16 @@ void TracksView::updateDuration()
emit durationChanged( m_projectDuration );
}
GraphicsTrack* TracksView::getTrack( unsigned int number )
{
for (int i = 0; i < m_layout->count(); ++i )
{
QGraphicsItem* gi = m_layout->itemAt( i )->graphicsItem();
GraphicsTrack* track = qgraphicsitem_cast<GraphicsTrack*>( gi );
if ( !track ) continue;
if ( track->trackNumber() == number )
return track;
}
return NULL;
}
......@@ -31,50 +31,14 @@
#include <QWheelEvent>
#include <QGraphicsSceneDragDropEvent>
#include <QApplication>
#include <QVector>
#include "GraphicsCursorItem.h"
#include "MainWorkflow.h"
#include "TrackWorkflow.h"
#include "AbstractGraphicsMediaItem.h"
class GraphicsMovieItem;
class AbstractGraphicsMediaItem;
class GraphicsTrack : public QGraphicsWidget
{
Q_OBJECT
public:
enum { Type = UserType + 2 };
enum MediaType
{
Video,
Audio
};
GraphicsTrack( MediaType type, int trackNumber, QGraphicsItem* parent = 0 ) : QGraphicsWidget( parent )
{
m_type = type;
m_trackNumber = trackNumber;
}
int trackNumber()
{
return m_trackNumber;
}
virtual int type() const { return Type; }
protected:
virtual void paint( QPainter* painter, const QStyleOptionGraphicsItem*, QWidget* = 0 )
{
if ( m_type == Video )
painter->setBrush( Qt::green );
else
painter->setBrush( Qt::blue );
painter->setPen( Qt::transparent );
painter->drawRect( rect() );
}
private:
MediaType m_type;
int m_trackNumber;
};
//class AbstractGraphicsMediaItem;