More tests and fixes for same track transitions

parent 1e3707f1
......@@ -100,7 +100,7 @@ QDomDocument ClipCreator::getXmlFromUrl(const QString &path)
QDomElement prod;
qDebug()<<"=== GOT DROPPED MIME: "<<type.name();
if (type.name().startsWith(QLatin1String("image/"))) {
int duration = pCore->currentDoc()->getFramePos(KdenliveSettings::image_duration());
int duration = pCore->getDurationFromString(KdenliveSettings::image_duration());
prod = createProducer(xml, ClipType::Image, path, QString(), duration, QString());
} else if (type.inherits(QStringLiteral("application/x-kdenlivetitle"))) {
// opening a title file
......@@ -202,7 +202,7 @@ QString ClipCreator::createTitleTemplate(const QString &path, const QString &tex
// Duration not found, we fall-back to defaults
if (duration == 0) {
duration = pCore->currentDoc()->getFramePos(KdenliveSettings::title_duration());
duration = pCore->getDurationFromString(KdenliveSettings::title_duration());
}
auto prod = createProducer(xml, ClipType::TextTemplate, path, name, duration, QString());
if (!text.isEmpty()) {
......
......@@ -845,11 +845,7 @@ QString Core::getTimelineClipBinId(int cid)
int Core::getDurationFromString(const QString &time)
{
if (!m_guiConstructed) {
return 0;
}
const QString duration = currentDoc()->timecode().reformatSeparators(time);
return currentDoc()->timecode().getFrameCount(duration);
return m_timecode.getFrameCount(time);
}
void Core::processInvalidFilter(const QString service, const QString id, const QString message)
......
......@@ -316,7 +316,7 @@ bool LoadJob::startJob()
if (producerLength > 0) {
duration = producerLength;
} else {
duration = pCore->currentDoc()->getFramePos(KdenliveSettings::title_duration());
duration = pCore->getDurationFromString(KdenliveSettings::title_duration());
}
}
if (producerLength <= 0) {
......@@ -340,7 +340,7 @@ bool LoadJob::startJob()
producerLength = pLength.toInt(&ok);
}
if (producerLength <= 0) {
producerLength = pCore->currentDoc()->getFramePos(KdenliveSettings::title_duration());
producerLength = pCore->getDurationFromString(KdenliveSettings::title_duration());
}
m_producer = loadResource(m_resource, QStringLiteral("qml:"));
m_producer->set("length", producerLength);
......
......@@ -80,6 +80,11 @@
<label>Default image sequence frame duration.</label>
<default>00:00:03:00</default>
</entry>
<entry name="mix_duration" type="String">
<label>Default mix transition duration.</label>
<default>00:00:01:00</default>
</entry>
<entry name="autoimagesequence" type="Bool">
<label>Automatically import image sequences.</label>
......
......@@ -699,14 +699,21 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
};
if (old_trackId == trackId) {
if (finalMove && (position + clipDuration <= mixData.second.secondClipInOut.first)) {
// Moved outside mix zone
bool switchPlaylist = !getTrackById_const(trackId)->hasStartMix(clipId);
int subPlaylist = m_allClips[mixData.second.secondClipId]->getSubPlaylistIndex();
update_playlist = [this, mixData, subPlaylist, trackId]() {
bool result = getTrackById_const(trackId)->switchPlaylist(mixData.second.secondClipId, mixData.second.secondClipInOut.first, subPlaylist == 0 ? 1 : 0);
return result;
};
if (switchPlaylist) {
update_playlist = [this, mixData, subPlaylist, trackId]() {
bool result = getTrackById_const(trackId)->switchPlaylist(mixData.second.secondClipId, mixData.second.secondClipInOut.first, subPlaylist, 0);
return result;
};
}
bool isAudio = getTrackById_const(trackId)->isAudioTrack();
update_playlist_undo = [this, mixData, subPlaylist, trackId, isAudio]() {
bool result = getTrackById_const(trackId)->switchPlaylist(mixData.second.secondClipId, mixData.second.secondClipInOut.first, subPlaylist);
update_playlist_undo = [this, mixData, subPlaylist, trackId, isAudio, switchPlaylist]() {
bool result = true;
if (switchPlaylist) {
result = getTrackById_const(trackId)->switchPlaylist(mixData.second.secondClipId, mixData.second.secondClipInOut.first, 0, subPlaylist);
}
result = result && getTrackById_const(trackId)->createMix(mixData.second, isAudio);
return result;
};
......@@ -926,14 +933,14 @@ bool TimelineModel::requestClipMix(std::pair<int, int> clipIds, int trackId, int
// Move on same track, simply inform the view
updateView = false;
notifyViewOnly = true;
int mixDuration = 8;
int mixDuration = pCore->getDurationFromString(KdenliveSettings::mix_duration());
update_model = [clipIds, this, trackId, position, invalidateTimeline, mixDuration]() {
QModelIndex modelIndex = makeClipIndexFromID(clipIds.second);
notifyChange(modelIndex, modelIndex, {StartRole,DurationRole});
QModelIndex modelIndex2 = makeClipIndexFromID(clipIds.first);
notifyChange(modelIndex2, modelIndex2, {DurationRole});
if (invalidateTimeline && !getTrackById_const(trackId)->isAudioTrack()) {
emit invalidateZone(position - mixDuration, position + mixDuration);
emit invalidateZone(position - mixDuration / 2, position + mixDuration);
}
return true;
};
......@@ -2647,6 +2654,8 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Fun sync_mix = []() { return true; };
Fun sync_end_mix = []() { return true; };
Fun sync_end_mix_undo = []() { return true; };
Fun sync_mix_undo = []() { return true; };
std::unordered_set<int> all_items;
QList <int> tracksWithMixes;
......@@ -2659,10 +2668,21 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
tracksWithMixes << tid;
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(itemId);
if (in + size <= mixData.second.secondClipInOut.first) {
// Clip resized outside of mix zone, mix will be deleted
bool switchPlaylist = getTrackById_const(tid)->hasEndMix(mixData.second.secondClipId) == false && m_allClips[mixData.second.secondClipId]->getSubPlaylistIndex() == 1;
Fun sync_mix_undo = [this, tid, mixData]() {
getTrackById_const(tid)->createMix(mixData.second, getTrackById_const(tid)->isAudioTrack());
return true;
};
// Move second clip to first playlist again
if (switchPlaylist) {
sync_end_mix = [this, tid, mixData]() {
return getTrackById_const(tid)->switchPlaylist(mixData.second.secondClipId, mixData.second.secondClipInOut.first, 1, 0);
};
sync_end_mix_undo = [this, tid, mixData]() {
return getTrackById_const(tid)->switchPlaylist(mixData.second.secondClipId, m_allClips[mixData.second.secondClipId]->getPosition(), 0, 1);
};
}
PUSH_LAMBDA(sync_mix_undo, undo);
}
}
......@@ -2772,9 +2792,12 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
}
if (result && logUndo) {
if (isClip(itemId)) {
sync_end_mix();
sync_mix();
PUSH_LAMBDA(sync_end_mix, redo);
PUSH_LAMBDA(sync_mix, redo);
PUSH_UNDO(undo, redo, i18n("Resize clip"))
PUSH_LAMBDA(undo, sync_end_mix_undo);
PUSH_UNDO(sync_end_mix_undo, redo, i18n("Resize clip"))
} else {
PUSH_UNDO(undo, redo, i18n("Resize composition"))
}
......
......@@ -128,16 +128,19 @@ int TrackModel::getClipsCount()
return count;
}
bool TrackModel::switchPlaylist(int clipId, int position, int playlist)
bool TrackModel::switchPlaylist(int clipId, int position, int sourcePlaylist, int destPlaylist)
{
QWriteLocker locker(&m_lock);
int source_playlist = playlist == 1 ? 0 : 1;
int target_clip = m_playlists[source_playlist].get_clip_index_at(position);
std::unique_ptr<Mlt::Producer> prod(m_playlists[source_playlist].replace_with_blank(target_clip));
if (sourcePlaylist == destPlaylist) {
return true;
}
Q_ASSERT(!m_playlists[sourcePlaylist].is_blank_at(position) && m_playlists[destPlaylist].is_blank_at(position));
int target_clip = m_playlists[sourcePlaylist].get_clip_index_at(position);
std::unique_ptr<Mlt::Producer> prod(m_playlists[sourcePlaylist].replace_with_blank(target_clip));
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(clipId);
int index = m_playlists[playlist].insert_at(position, *clip, 1);
clip->setSubPlaylistIndex(playlist);
int index = m_playlists[destPlaylist].insert_at(position, *clip, 1);
clip->setSubPlaylistIndex(destPlaylist);
return index != -1;
}
return false;
......@@ -1003,6 +1006,7 @@ std::pair<int, int> TrackModel::getClipIndexAt(int position, int playlist)
if (!m_playlists[playlist].is_blank_at(position)) {
return {playlist, m_playlists[playlist].get_clip_index_at(position)};
}
qDebug()<<"=== CANNOT FIND CLIP ON PLAYLIST: "<<playlist<<" AT POSITION: "<<position<<", TID: "<<m_id;
Q_ASSERT(false);
return {-1, -1};
}
......@@ -1446,7 +1450,10 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
source_track = secondClip->getSubPlaylistIndex();
std::shared_ptr<ClipModel> firstClip(ptr->getClipPtr(clipIds.first));
firstClipDuration = firstClip->getPlaytime();
mixPosition = secondClipPos - mixDuration;
// Ensure mix is not longer than clip
mixPosition = qMax(firstClip->getPosition(), secondClipPos - mixDuration / 2);
int maxPos = qMin(secondClipPos + secondClipDuration, secondClipPos + mixDuration - (mixDuration / 2));
mixDuration = qMin(mixDuration, maxPos - mixPosition);
if (firstClip->getSubPlaylistIndex() == 1) {
dest_track = 0;
}
......@@ -1478,7 +1485,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
i.toBack();
while (i.hasPrevious()) {
i.previous();
result = switchPlaylist(i.key(), m_allClips[i.key()]->getPosition(), i.value());
result = switchPlaylist(i.key(), m_allClips[i.key()]->getPosition(), m_allClips[i.key()]->getSubPlaylistIndex(), i.value());
if (!result) {
break;
}
......@@ -1491,7 +1498,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
i.toBack();
while (i.hasPrevious()) {
i.previous();
result = switchPlaylist(i.key(), m_allClips[i.key()]->getPosition(), 1 - i.value());
result = switchPlaylist(i.key(), m_allClips[i.key()]->getPosition(), m_allClips[i.key()]->getSubPlaylistIndex(), 1 - i.value());
if (!result) {
break;
}
......@@ -1503,11 +1510,11 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
Fun build_mix = [clipIds, mixPosition, mixDuration, dest_track, this]() {
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> movedClip(ptr->getClipPtr(clipIds.second));
movedClip->setMixDuration(mixDuration * 2);
movedClip->setMixDuration(mixDuration);
// Insert mix transition
if (isAudioTrack()) {
std::shared_ptr<Mlt::Transition> t(new Mlt::Transition(*ptr->getProfile(), "mix"));
t->set_in_and_out(mixPosition, mixPosition + 2 * mixDuration);
t->set_in_and_out(mixPosition, mixPosition + mixDuration);
if (dest_track == 0) {
t->set("reverse", 1);
}
......@@ -1515,7 +1522,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
m_sameCompositions[clipIds.second] = t;
} else {
std::shared_ptr<Mlt::Transition> t(new Mlt::Transition(*ptr->getProfile(), "luma"));
t->set_in_and_out(mixPosition, mixPosition + 2 * mixDuration);
t->set_in_and_out(mixPosition, mixPosition + mixDuration);
if (dest_track == 0) {
t->set("reverse", 1);
}
......@@ -1559,8 +1566,8 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
std::function<bool(void)> local_undo = []() { return true; };
std::function<bool(void)> local_redo = []() { return true; };
if (auto ptr = m_parent.lock()) {
result = ptr->getClipPtr(clipIds.second)->requestResize(secondClipDuration + mixDuration, false, local_undo, local_redo, false);
result = ptr->getClipPtr(clipIds.first)->requestResize(firstClipDuration + mixDuration, true, local_undo, local_redo, false);
result = ptr->getClipPtr(clipIds.second)->requestResize(secondClipDuration + mixDuration / 2, false, local_undo, local_redo, false);
result = ptr->getClipPtr(clipIds.first)->requestResize(firstClipDuration + mixDuration / 2, true, local_undo, local_redo, false);
QModelIndex ix = ptr->makeClipIndexFromID(clipIds.second);
emit ptr->dataChanged(ix, ix, {TimelineModel::StartRole,TimelineModel::MixRole});
}
......
......@@ -131,7 +131,7 @@ public:
bool createMix(MixInfo info, bool isAudio);
void syncronizeMixes(bool finalMove);
/** @brief Switch a clip from one playlist to the other */
bool switchPlaylist(int clipId, int position, int playlist);
bool switchPlaylist(int clipId, int position, int sourcePlaylist, int destPlaylist);
/** @brief Load a same track transition from project */
bool loadMix(Mlt::Transition &t);
......
......@@ -382,10 +382,10 @@ int TimelineController::insertNewComposition(int tid, int clipId, int offset, co
{
int id;
int minimumPos = clipId > -1 ? m_model->getClipPosition(clipId) : offset;
int clip_duration = clipId > -1 ? m_model->getClipPlaytime(clipId) : pCore->currentDoc()->getFramePos(KdenliveSettings::transition_duration());
int clip_duration = clipId > -1 ? m_model->getClipPlaytime(clipId) : pCore->getDurationFromString(KdenliveSettings::transition_duration());
int endPos = minimumPos + clip_duration;
int position = minimumPos;
int duration = qMin(clip_duration, pCore->currentDoc()->getFramePos(KdenliveSettings::transition_duration()));
int duration = qMin(clip_duration, pCore->getDurationFromString(KdenliveSettings::transition_duration()));
int lowerVideoTrackId = m_model->getPreviousVideoTrackIndex(tid);
bool revert = offset > clip_duration / 2;
int bottomId = 0;
......@@ -425,13 +425,13 @@ int TimelineController::insertNewComposition(int tid, int clipId, int offset, co
}
}
}
int defaultLength = pCore->currentDoc()->getFramePos(KdenliveSettings::transition_duration());
int defaultLength = pCore->getDurationFromString(KdenliveSettings::transition_duration());
bool isShortComposition = TransitionsRepository::get()->getType(transitionId) == AssetListType::AssetType::VideoShortComposition;
if (duration < 0 || (isShortComposition && duration > 1.5 * defaultLength)) {
duration = defaultLength;
} else if (duration <= 1) {
// if suggested composition duration is lower than 4 frames, use default
duration = pCore->currentDoc()->getFramePos(KdenliveSettings::transition_duration());
duration = pCore->getDurationFromString(KdenliveSettings::transition_duration());
if (minimumPos + clip_duration - position < 3) {
position = minimumPos + clip_duration - duration;
}
......@@ -461,7 +461,7 @@ int TimelineController::insertNewComposition(int tid, int clipId, int offset, co
int TimelineController::insertComposition(int tid, int position, const QString &transitionId, bool logUndo)
{
int id;
int duration = pCore->currentDoc()->getFramePos(KdenliveSettings::transition_duration());
int duration = pCore->getDurationFromString(KdenliveSettings::transition_duration());
if (!m_model->requestCompositionInsertion(transitionId, tid, position, duration, nullptr, id, logUndo)) {
id = -1;
}
......@@ -1527,7 +1527,7 @@ void TimelineController::adjustFade(int cid, const QString &effectId, int durati
{
if (initialDuration == -2) {
// Add default fade
duration = pCore->currentDoc()->getFramePos(KdenliveSettings::fade_duration());
duration = pCore->getDurationFromString(KdenliveSettings::fade_duration());
initialDuration = 0;
}
if (duration <= 0) {
......
......@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>629</width>
<height>636</height>
<width>646</width>
<height>735</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
......@@ -61,6 +61,23 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Title clips</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Transitions</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="kcfg_title_duration"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
......@@ -71,13 +88,16 @@
<item row="0" column="1">
<widget class="QLineEdit" name="kcfg_color_duration"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<item row="2" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Title clips</string>
<string>Fades</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="kcfg_transition_duration"/>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
......@@ -85,34 +105,24 @@
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="kcfg_image_duration"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="kcfg_title_duration"/>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="kcfg_sequence_duration"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="kcfg_transition_duration"/>
<item row="2" column="3">
<widget class="QLineEdit" name="kcfg_fade_duration"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Transitions</string>
</property>
</widget>
<item row="0" column="3">
<widget class="QLineEdit" name="kcfg_image_duration"/>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_6">
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Fades</string>
<string>Mixes</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLineEdit" name="kcfg_fade_duration"/>
<item row="3" column="1">
<widget class="QLineEdit" name="kcfg_mix_duration"/>
</item>
</layout>
</widget>
......
......@@ -125,6 +125,8 @@ TEST_CASE("Simple Mix", "[SameTrackMix]")
SECTION("Create mix on color clips and move main (right side) clip")
{
// CID 3 length=20, pos=500, CID4 length=20, pos=520
// Default mix duration = 25 frames (12 before / 13 after)
state0();
REQUIRE(timeline->mixClip(cid4));
state2();
......@@ -220,6 +222,9 @@ TEST_CASE("Simple Mix", "[SameTrackMix]")
SECTION("Create mix and move AV clips")
{
// CID 1 length=10, pos=100, CID2 length=10, pos=110
// Default mix duration = 25 frames (12 before / 13 after)
// Resize clip, should resize the mix
state0();
REQUIRE(timeline->mixClip(cid2));
state1();
......@@ -235,10 +240,36 @@ TEST_CASE("Simple Mix", "[SameTrackMix]")
REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
undoStack->undo();
state1();
/*// Undo mix
// Undo mix
undoStack->undo();
state0();
}
SECTION("Create mix on color clip and resize")
{
state0();
REQUIRE(timeline->mixClip(cid4));
state2();
// CID 3 length=20, pos=500, CID4 length=20, pos=520
// Default mix duration = 25 frames (12 before / 13 after)
// Resize clip, should resize the mix
REQUIRE(timeline->requestItemResize(cid3, 16, true) == 16);
REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
undoStack->undo();
state0();*/
state2();
// Resize clip outside mix zone, should delete the mix
REQUIRE(timeline->requestItemResize(cid3, 4, true) == 4);
REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
undoStack->undo();
//state2();
undoStack->undo();
state0();
}
binModel->clean();
pCore->m_projectManager = nullptr;
Logger::print_trace();
......
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