Commit 24aac434 by luyikei

Workflow: Commands: Implement transition API

parent d5cf70b5
......@@ -36,6 +36,7 @@
#include "AbstractUndoStack.h"
#include "Backend/IFilter.h"
#include "Library/Library.h"
#include "Transition/Transition.h"
#ifdef HAVE_GUI
# include "Gui/timeline/MarkerManager.h"
......@@ -570,6 +571,172 @@ Commands::Effect::Remove::internalUndo()
m_helper->setTarget( m_target.get() );
}
Commands::Transition::Add::Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, Workflow::TrackType type )
: m_identifier( identifier )
, m_begin( begin )
, m_end( end )
, m_trackId( trackId )
, m_trackAId( 0 )
, m_trackBId( 0 )
, m_type( type )
, m_workflow( workflow )
{
retranslate();
}
Commands::Transition::Add::Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId,
Workflow::TrackType type )
: m_identifier( identifier )
, m_begin( begin )
, m_end( end )
, m_trackAId( trackAId )
, m_trackBId( trackBId )
, m_type( type )
, m_workflow( workflow )
{
retranslate();
}
void
Commands::Transition::Add::internalRedo()
{
if ( m_uuid.isNull() == true )
{
if ( m_trackBId > 0 )
m_uuid = m_workflow->addTransitionBetweenTracks( m_identifier, m_begin, m_end, m_trackAId, m_trackBId, m_type );
else
m_uuid = m_workflow->addTransition( m_identifier, m_begin, m_end, m_trackId, m_type );
}
else
m_workflow->addTransition( m_transitionInstance );
}
void
Commands::Transition::Add::internalUndo()
{
m_transitionInstance = m_workflow->removeTransition( m_uuid );
}
void
Commands::Transition::Add::retranslate()
{
setText( tr( "Adding transition" ) );
}
const QUuid&
Commands::Transition::Add::uuid()
{
return m_uuid;
}
Commands::Transition::Move::Move( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, qint64 begin, qint64 end )
: m_uuid( uuid )
, m_begin( begin )
, m_end( end )
, m_workflow( workflow )
{
auto transitionInstance = m_workflow->transition( uuid );
if ( transitionInstance == nullptr )
invalidate();
else
{
m_oldBegin = transitionInstance->transition->begin();
m_oldEnd = transitionInstance->transition->end();
}
retranslate();
}
void
Commands::Transition::Move::internalRedo()
{
bool ret = m_workflow->moveTransition( m_uuid, m_begin, m_end );
if ( ret == false )
invalidate();
}
void
Commands::Transition::Move::internalUndo()
{
bool ret = m_workflow->moveTransition( m_uuid, m_oldBegin, m_oldEnd );
if ( ret == false )
invalidate();
}
void
Commands::Transition::Move::retranslate()
{
setText( tr( "Moving transition" ) );
}
Commands::Transition::MoveBetweenTracks::MoveBetweenTracks( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, quint32 trackAId, quint32 trackBId )
: m_uuid( uuid )
, m_trackAId( trackAId )
, m_trackBId( trackBId )
, m_workflow( workflow )
{
auto transitionInstance = m_workflow->transition( uuid );
if ( transitionInstance == nullptr )
invalidate();
else
{
m_oldTrackAId = transitionInstance->trackAId;
m_oldTrackBId = transitionInstance->trackBId;
}
retranslate();
}
void
Commands::Transition::MoveBetweenTracks::internalRedo()
{
bool ret = m_workflow->moveTransitionBetweenTracks( m_uuid, m_trackAId, m_trackBId );
if ( ret == false )
invalidate();
}
void
Commands::Transition::MoveBetweenTracks::internalUndo()
{
bool ret = m_workflow->moveTransitionBetweenTracks( m_uuid, m_oldTrackAId, m_oldTrackBId );
if ( ret == false )
invalidate();
}
void
Commands::Transition::MoveBetweenTracks::retranslate()
{
setText( tr( "Moving transition" ) );
}
Commands::Transition::Remove::Remove( std::shared_ptr<SequenceWorkflow> const& workflow, const QUuid& uuid )
: m_uuid( uuid )
, m_workflow( workflow )
{
retranslate();
}
void
Commands::Transition::Remove::internalRedo()
{
m_transitionInstance = m_workflow->removeTransition( m_uuid );
}
void
Commands::Transition::Remove::internalUndo()
{
m_workflow->addTransition( m_transitionInstance );
}
void Commands::Transition::Remove::retranslate()
{
setText( tr( "Removing transition" ) );
}
#ifdef HAVE_GUI
Commands::Marker::Add::Add( QSharedPointer<MarkerManager> markerManager, quint64 pos )
: m_markerManager( markerManager )
......
......@@ -37,13 +37,14 @@
#include <memory>
class Clip;
class EffectHelper;
class Transition;
class MarkerManager;
namespace Backend
{
class IInput;
}
class EffectHelper;
class MarkerManager;
namespace Commands
{
......@@ -281,6 +282,84 @@ namespace Commands
};
}
namespace Transition
{
class Add : public Generic
{
public:
Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, Workflow::TrackType type );
Add( std::shared_ptr<SequenceWorkflow> const& workflow,
const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId, Workflow::TrackType type );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
const QUuid& uuid();
private:
QString m_identifier;
qint64 m_begin;
qint64 m_end;
quint32 m_trackId;
quint32 m_trackAId;
quint32 m_trackBId;
Workflow::TrackType m_type;
QUuid m_uuid;
QSharedPointer<SequenceWorkflow::TransitionInstance> m_transitionInstance;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
class Move : public Generic
{
public:
Move( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, qint64 begin, qint64 end );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
private:
QUuid m_uuid;
qint64 m_begin;
qint64 m_end;
qint64 m_oldBegin;
qint64 m_oldEnd;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
class MoveBetweenTracks : public Generic
{
public:
MoveBetweenTracks( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid, quint32 trackAId, quint32 trackBId );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
private:
QUuid m_uuid;
quint32 m_trackAId;
quint32 m_trackBId;
quint32 m_oldTrackAId;
quint32 m_oldTrackBId;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
class Remove : public Generic
{
public:
Remove( std::shared_ptr<SequenceWorkflow> const& workflow,
const QUuid& uuid );
virtual void internalRedo();
virtual void internalUndo();
virtual void retranslate();
private:
QUuid m_uuid;
QSharedPointer<SequenceWorkflow::TransitionInstance> m_transitionInstance;
std::shared_ptr<SequenceWorkflow> m_workflow;
};
}
#ifdef HAVE_GUI
// Gui commands
namespace Marker
......
......@@ -49,6 +49,7 @@
#include "Tools/VlmcDebug.h"
#include "Tools/RendererEventWatcher.h"
#include "Tools/OutputEventWatcher.h"
#include "Transition/Transition.h"
#include "Workflow/Types.h"
#include <QJsonArray>
......@@ -67,6 +68,9 @@ MainWorkflow::MainWorkflow( Settings* projectSettings, int trackCount ) :
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipUnlinked, this, &MainWorkflow::clipUnlinked );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipMoved, this, &MainWorkflow::clipMoved );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::clipResized, this, &MainWorkflow::clipResized );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::transitionAdded, this, &MainWorkflow::transitionAdded );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::transitionMoved, this, &MainWorkflow::transitionMoved );
connect( m_sequenceWorkflow.get(), &SequenceWorkflow::transitionRemoved, this, &MainWorkflow::transitionRemoved );
m_renderer->setInput( m_sequenceWorkflow->input() );
connect( m_renderer->eventWatcher().data(), &RendererEventWatcher::lengthChanged, this, &MainWorkflow::lengthChanged );
......@@ -244,6 +248,15 @@ MainWorkflow::libraryClipInfo( const QString& uuid )
return QJsonObject::fromVariantHash( h );
}
QJsonObject
MainWorkflow::transitionInfo( const QString& uuid )
{
auto t = m_sequenceWorkflow->transition( uuid );
if ( !t )
return {};
return QJsonObject::fromVariantHash( t->toVariant().toHash() );
}
void
MainWorkflow::moveClip( const QString& uuid, quint32 trackId, qint64 startFrame )
{
......@@ -305,6 +318,43 @@ MainWorkflow::addEffect( const QString &clipUuid, const QString &effectId )
return QStringLiteral( "" );
}
QString
MainWorkflow::addTransition( const QString& identifier, qint64 begin, qint64 end, quint32 trackId, const QString& type )
{
auto trackType = type == QStringLiteral( "Video" ) ? Workflow::VideoTrack : Workflow::AudioTrack;
auto command = new Commands::Transition::Add( m_sequenceWorkflow, identifier, begin, end, trackId, trackType );
trigger( command );
return command->uuid().toString();
}
QString
MainWorkflow::addTransitionBetweenTracks( const QString& identifier, qint64 begin, qint64 end, quint32 trackAId, quint32 trackBId,
const QString& type )
{
auto trackType = type == QStringLiteral( "Video" ) ? Workflow::VideoTrack : Workflow::AudioTrack;
auto command = new Commands::Transition::Add( m_sequenceWorkflow, identifier, begin, end, trackAId, trackBId, trackType );
trigger( command );
return command->uuid().toString();
}
void
MainWorkflow::moveTransition( const QUuid& uuid, qint64 begin, qint64 end )
{
trigger( new Commands::Transition::Move( m_sequenceWorkflow, uuid, begin, end ) );
}
void
MainWorkflow::moveTransitionBetweenTracks( const QUuid& uuid, quint32 trackAId, quint32 trackBId )
{
trigger( new Commands::Transition::MoveBetweenTracks( m_sequenceWorkflow, uuid, trackAId, trackBId ) );
}
void
MainWorkflow::removeTransition( const QUuid& uuid )
{
trigger( new Commands::Transition::Remove( m_sequenceWorkflow, uuid ) );
}
bool
MainWorkflow::startRenderToFile( const QString &outputFileName, quint32 width, quint32 height,
double fps, const QString &ar, quint32 vbitrate, quint32 abitrate,
......
......@@ -129,6 +129,9 @@ class MainWorkflow : public QObject
QJsonObject libraryClipInfo( const QString& uuid );
Q_INVOKABLE
QJsonObject transitionInfo( const QString& uuid );
Q_INVOKABLE
void moveClip( const QString& uuid, quint32 trackId, qint64 startFrame );
Q_INVOKABLE
......@@ -150,6 +153,23 @@ class MainWorkflow : public QObject
Q_INVOKABLE
QString addEffect( const QString& clipUuid, const QString& effectId );
Q_INVOKABLE
QString addTransition( const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, const QString& type );
Q_INVOKABLE
QString addTransitionBetweenTracks( const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId, const QString& type );
Q_INVOKABLE
void moveTransition( const QUuid& uuid, qint64 begin, qint64 end );
Q_INVOKABLE
void moveTransitionBetweenTracks( const QUuid& uuid, quint32 trackAId, quint32 trackBId );
Q_INVOKABLE
void removeTransition( const QUuid& uuid );
bool startRenderToFile( const QString& outputFileName, quint32 width, quint32 height,
double fps, const QString& ar, quint32 vbitrate, quint32 abitrate,
quint32 nbChannels, quint32 sampleRate );
......@@ -247,6 +267,10 @@ class MainWorkflow : public QObject
void clipLinked( const QString& uuidA, const QString& uuidB );
void clipUnlinked( const QString& uuidA, const QString& uuidB );
void transitionAdded( const QString& uuid );
void transitionMoved( const QString& uuid );
void transitionRemoved( const QString& uuid );
void effectsUpdated( const QString& clipUuid );
};
......
......@@ -35,6 +35,7 @@
#include "Library/Library.h"
#include "Tools/VlmcDebug.h"
#include "Media/Media.h"
#include "Transition/Transition.h"
SequenceWorkflow::SequenceWorkflow( size_t trackCount )
: m_multitrack( new Backend::MLT::MLTMultiTrack )
......@@ -216,9 +217,108 @@ SequenceWorkflow::unlinkClips( const QUuid& uuidA, const QUuid& uuidB )
return ret;
}
QUuid
SequenceWorkflow::addTransition( const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, Workflow::TrackType type )
{
auto t = track( trackId, type == Workflow::AudioTrack );
auto transition = QSharedPointer<Transition>::create( identifier, begin, end, type );
t->addTransition( transition );
m_transitions.insert( transition->uuid(), QSharedPointer<TransitionInstance>::create( transition, trackId, 0, true ) );
emit transitionAdded( transition->uuid().toString() );
return transition->uuid();
}
QUuid
SequenceWorkflow::addTransitionBetweenTracks( const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId,
Workflow::TrackType type )
{
auto transition = QSharedPointer<Transition>::create( identifier, begin, end, type );
m_transitions.insert( transition->uuid(), QSharedPointer<TransitionInstance>::create( transition, trackAId, trackBId, false ) );
transition->apply( *m_multitrack, trackAId, trackBId );
emit transitionAdded( transition->uuid().toString() );
return transition->uuid();
}
bool
SequenceWorkflow::addTransition( QSharedPointer<TransitionInstance> transitionInstance )
{
auto transition = transitionInstance->transition;
auto t = track( transitionInstance->trackAId, transition->type() == Workflow::AudioTrack );
m_transitions.insert( transition->uuid(), transitionInstance );
emit transitionAdded( transition->uuid().toString() );
return t->addTransition( transition );
}
bool
SequenceWorkflow::moveTransition( const QUuid& uuid, qint64 begin, qint64 end )
{
auto it = m_transitions.find( uuid );
if ( it == m_transitions.end() )
return false;
auto transitionInstance = it.value();
auto transition = transitionInstance->transition;
if ( transition->begin() == begin && transition->end() == end )
return true;
if ( transitionInstance->isInTrack == true )
{
auto t = track( transitionInstance->trackAId, transition->type() == Workflow::AudioTrack );
emit transitionMoved( uuid.toString() );
return t->moveTransition( uuid, begin, end );
}
else
{
transition->setBoundaries( begin, end );
emit transitionMoved( uuid.toString() );
return true;
}
}
bool
SequenceWorkflow::moveTransitionBetweenTracks( const QUuid& uuid, quint32 trackAId, quint32 trackBId )
{
auto it = m_transitions.find( uuid );
if ( it == m_transitions.end() )
return false;
auto transitionInstance = it.value();
if ( transitionInstance->isInTrack == true )
return false; // Not allowed
auto transition = transitionInstance->transition;
if ( transitionInstance->trackAId == trackAId && transitionInstance->trackBId == trackBId )
return true;
transition->setTracks( trackAId, trackBId );
transitionInstance->trackAId = trackAId;
transitionInstance->trackBId = trackBId;
emit transitionMoved( uuid.toString() );
return true;
}
QSharedPointer<SequenceWorkflow::TransitionInstance>
SequenceWorkflow::removeTransition( const QUuid& uuid )
{
auto it = m_transitions.find( uuid );
if ( it == m_transitions.end() )
return {};
auto transitionInstance = it.value();
if ( transitionInstance->isInTrack == true )
{
auto transition = transitionInstance->transition;
auto t = track( transitionInstance->trackAId, transition->type() == Workflow::AudioTrack );
t->removeTransition( uuid );
}
m_transitions.erase( it );
emit transitionRemoved( uuid.toString() );
return transitionInstance;
}
QVariant
SequenceWorkflow::toVariant() const
{
QVariantList transitions;
for ( const auto& t : m_transitions )
transitions << t->toVariant();
QVariantList l;
for ( auto it = m_clips.begin(); it != m_clips.end(); ++it )
{
......@@ -237,13 +337,26 @@ SequenceWorkflow::toVariant() const
h["linkedClips"] = linkedClipList;
l << h;
}
QVariantHash h{ { "clips", l }, { "filters", EffectHelper::toVariant( m_multitrack ) } };
QVariantHash h{ { "transitions", transitions }, { "clips", l },
{ "filters", EffectHelper::toVariant( m_multitrack.get() ) } };
return h;
}
void
SequenceWorkflow::loadFromVariant( const QVariant& variant )
{
for ( auto& var : variant.toMap()["transitions"].toList() )
{
auto m = var.toMap();
bool inTrack = m["isInTrack"].toBool();
if ( inTrack == true )
addTransition( m["identifier"].toString(), m["begin"].toLongLong(), m["end"].toLongLong(),
m["trackId"].toUInt(), m["audio"].toBool() ? Workflow::AudioTrack : Workflow::VideoTrack );
else
addTransitionBetweenTracks( m["identifier"].toString(), m["begin"].toLongLong(), m["end"].toLongLong(),
m["trackAId"].toUInt(), m["trackBId"].toUInt(), m["audio"].toBool() ? Workflow::AudioTrack : Workflow::VideoTrack );
}
for ( auto& var : variant.toMap()["clips"].toList() )
{
auto m = var.toMap();
......@@ -294,6 +407,15 @@ SequenceWorkflow::clip( const QUuid& uuid )
return it.value();
}
QSharedPointer<SequenceWorkflow::TransitionInstance>
SequenceWorkflow::transition( const QUuid& uuid )
{
auto it = m_transitions.find( uuid );
if ( it == m_transitions.end() )
return {};
return it.value();
}
quint32
SequenceWorkflow::trackId( const QUuid& uuid )
{
......@@ -354,3 +476,30 @@ SequenceWorkflow::ClipInstance::duplicateClipForResize( qint64 begin, qint64 end
m_hasClonedClip = true;
return true;
}
SequenceWorkflow::TransitionInstance::TransitionInstance( QSharedPointer<Transition> transition,
quint32 trackAId, quint32 trackBId, bool isInTrack )
: transition( transition )
, trackAId( trackAId )
, trackBId( trackBId )
, isInTrack( isInTrack )
{
}
QVariant
SequenceWorkflow::TransitionInstance::toVariant() const
{
auto h = transition->toVariant().toHash();
h["isInTrack"] = isInTrack;
if ( isInTrack == true )
{
h["trackId"] = trackAId;
}
else
{
h["trackAId"] = trackAId;
h["trackBId"] = trackBId;
}
return h;
}
......@@ -33,6 +33,7 @@
#include "Types.h"
class Track;
class Transition;
namespace Backend
{
......@@ -82,6 +83,18 @@ class SequenceWorkflow : public QObject
bool m_hasClonedClip;
};
struct TransitionInstance
{
TransitionInstance() = default;
TransitionInstance( QSharedPointer<Transition> transition, quint32 trackAId, quint32 trackBId, bool isInTrack );
QSharedPointer<Transition> transition;
quint32 trackAId;
quint32 trackBId;
bool isInTrack; // If it's in a track, the transition is between clips.
QVariant toVariant() const;
};
/**
* @brief addClip Adds a clip to the sequence workflow
* @param clip A library clip's UUID
......@@ -102,11 +115,21 @@ class SequenceWorkflow : public QObject
bool linkClips( const QUuid& uuidA, const QUuid& uuidB );
bool unlinkClips( const QUuid& uuidA, const QUuid& uuidB );
QUuid addTransition( const QString& identifier, qint64 begin, qint64 end,
quint32 trackId, Workflow::TrackType type );
QUuid addTransitionBetweenTracks( const QString& identifier, qint64 begin, qint64 end,
quint32 trackAId, quint32 trackBId, Workflow::TrackType type );
bool addTransition( QSharedPointer<TransitionInstance> transition );
bool moveTransition( const QUuid& uuid, qint64 begin, qint64 end );
bool moveTransitionBetweenTracks( const QUuid& uuid, quint32 trackAId, quint32 trackBId );
QSharedPointer<TransitionInstance> removeTransition( const QUuid& uuid );
QVariant toVariant() const;
void loadFromVariant( const QVariant& variant );
void clear();
QSharedPointer<ClipInstance> clip( const QUuid& uuid );
QSharedPointer<TransitionInstance> transition( const QUuid& uuid );
quint32 trackId( const QUuid& uuid );
qint64 position( const QUuid& uuid );
......@@ -118,6 +141,7 @@ class SequenceWorkflow : public QObject
inline QSharedPointer<Track> track( quint32 trackId, bool audio );
QMap<QUuid, QSharedPointer<ClipInstance>> m_clips;
QMap<QUuid, QSharedPointer<TransitionInstance>> m_transitions;
QList<QSharedPointer<Track>> m_tracks[Workflow::NbTrackType];
QList<std::shared_ptr<Backend::IMultiTrack>> m_multiTracks;
......@@ -131,6 +155,10 @@ class SequenceWorkflow : public QObject
void clipUnlinked( QString, QString );
void clipMoved( QString );
void clipResized( QString );
void transitionAdded( const QString& uuid );
void transitionMoved( const QString& uuid );
void transitionRemoved( const QString& uuid );
};
#endif // SEQUENCEWORKFLOW_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