More fixes for same track composition clips move and resize

parent 8991e0ee
......@@ -571,7 +571,7 @@ bool TimelineModel::requestFakeClipMove(int clipId, int trackId, int position, b
bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool moveMirrorTracks, bool updateView, bool invalidateTimeline, bool finalMove, Fun &undo, Fun &redo, bool groupMove, QMap <int, int> moving_clips)
{
Q_UNUSED(moveMirrorTracks)
// qDebug() << "// FINAL MOVE: " << invalidateTimeline << ", UPDATE VIEW: " << updateView<<", FINAL: "<<finalMove;
//qDebug() << "//\n\nRQST CLIP MOVE\n\n//\n// FINAL MOVE: "<<finalMove<<", PLAYLIST: "<<m_allClips[clipId]->getSubPlaylistIndex();
if (trackId == -1) {
return false;
}
......@@ -649,7 +649,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
return result;
};
}
} else if (!groupMove && isTrack(old_trackId) && getTrackById_const(old_trackId)->hasMix(clipId)) {
} else if (finalMove && !groupMove && isTrack(old_trackId) && getTrackById_const(old_trackId)->hasMix(clipId)) {
// Clip has a mix
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(old_trackId)->getMixInfo(clipId);
if (mixData.first.firstClipId > -1) {
......@@ -673,12 +673,12 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
return result;
};
}
} else {
} else if (finalMove) {
// Clip moved to another track, delete mix
int subPlaylist = m_allClips[clipId]->getSubPlaylistIndex();
update_playlist = [this, clipId, subPlaylist, old_trackId, finalMove]() {
update_playlist = [this, clipId, old_trackId, finalMove]() {
m_allClips[clipId]->setMixDuration(0);
m_allClips[clipId]->setSubPlaylistIndex(subPlaylist == 0 ? 1 : 0);
m_allClips[clipId]->setSubPlaylistIndex(0);
getTrackById_const(old_trackId)->syncronizeMixes(finalMove);
return true;
};
......@@ -701,13 +701,11 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
if (finalMove && (position + clipDuration <= mixData.second.secondClipInOut.first)) {
int subPlaylist = m_allClips[mixData.second.secondClipId]->getSubPlaylistIndex();
update_playlist = [this, mixData, subPlaylist, trackId]() {
m_allClips[mixData.second.secondClipId]->setSubPlaylistIndex(subPlaylist == 0 ? 1 : 0);
bool result = getTrackById_const(trackId)->switchPlaylist(mixData.second.secondClipId, mixData.second.secondClipInOut.first, subPlaylist == 0 ? 1 : 0);
return result;
};
bool isAudio = getTrackById_const(trackId)->isAudioTrack();
update_playlist_undo = [this, mixData, subPlaylist, trackId, isAudio]() {
m_allClips[mixData.second.secondClipId]->setSubPlaylistIndex(subPlaylist);
bool result = getTrackById_const(trackId)->switchPlaylist(mixData.second.secondClipId, mixData.second.secondClipInOut.first, subPlaylist);
result = result && getTrackById_const(trackId)->createMix(mixData.second, isAudio);
return result;
......@@ -724,7 +722,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
};
}
}
} else if (groupMove && isTrack(old_trackId) && getTrackById_const(old_trackId)->hasMix(clipId) && old_trackId == trackId) {
} else if (finalMove && groupMove && isTrack(old_trackId) && getTrackById_const(old_trackId)->hasMix(clipId) && old_trackId == trackId) {
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(old_trackId)->getMixInfo(clipId);
if (mixData.first.firstClipId > -1) {
// Mix on clip start, check if mix is still in range
......@@ -796,12 +794,14 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
bool TimelineModel::mixClip(int idToMove)
{
int selectedTrack = -1;
std::unordered_set<int> initialSelection;
if (idToMove == -1) {
auto sel = getCurrentSelection();
if (sel.empty()) {
initialSelection = getCurrentSelection();
if (initialSelection.empty()) {
pCore->displayMessage(i18n("Select a clip to apply the mix"), InformationMessage, 500);
return false;
}
for (int s : sel) {
for (int s : initialSelection) {
if (!isClip(s)) {
continue;
}
......@@ -824,8 +824,21 @@ bool TimelineModel::mixClip(int idToMove)
int clipDuration = getItemPlaytime(idToMove);
std::pair<int, int> clipsToMix;
// Check if we have a clip before and/or after
int previousClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition - 1);
int nextClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition + clipDuration + 1);
int previousClip = -1;
int nextClip = -1;
// Check if clip already has a mix
if (getTrackById_const(selectedTrack)->hasStartMix(idToMove)) {
if (getTrackById_const(selectedTrack)->hasEndMix(idToMove)) {
pCore->displayMessage(i18n("Clip already mixed"), InformationMessage, 500);
return false;
}
nextClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition + clipDuration + 1);
} else if (getTrackById_const(selectedTrack)->hasEndMix(idToMove)) {
previousClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition - 1);
} else {
previousClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition - 1);
nextClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition + clipDuration + 1);
}
if (previousClip > -1 && nextClip > -1) {
// We have a clip before and a clip after, check timeline cursor position to decide where to mix
int cursor = pCore->getTimelinePosition();
......@@ -883,10 +896,17 @@ bool TimelineModel::mixClip(int idToMove)
}
}
pCore->pushUndo(undo, redo, i18n("Create mix"));
// Reselect clips
if (!initialSelection.empty()) {
requestSetSelection(initialSelection);
}
return result;
} else {
qDebug()<<"////// MIX OPERATION FAILED";
undo();
if (!initialSelection.empty()) {
requestSetSelection(initialSelection);
}
return false;
}
}
......@@ -971,6 +991,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
Q_ASSERT(m_allClips.count(clipId) > 0);
if (m_allClips[clipId]->getPosition() == position && getClipTrackId(clipId) == trackId) {
TRACE_RES(true);
qDebug()<<"=== ABORTING; NO MOVE";
return true;
}
if (m_groups->isInGroup(clipId)) {
......@@ -1059,7 +1080,6 @@ QVariantList TimelineModel::suggestClipMove(int clipId, int trackId, int positio
if (m_allClips[clipId]->getCurrentTrackId() == trackId) {
maxPos -= m_allClips[clipId]->getPlaytime();
}
qDebug()<<"=== TRYING CLIP MOVE AT: "<<position<<", MAX TK: "<<getTrackById_const(trackId)->trackDuration();
position = qMin(position, maxPos);
}
bool after = position > currentPos;
......@@ -1092,6 +1112,7 @@ QVariantList TimelineModel::suggestClipMove(int clipId, int trackId, int positio
// we check if move is possible
bool possible = (m_editMode == TimelineMode::NormalEdit) ? requestClipMove(clipId, trackId, position, moveMirrorTracks, true, false, false)
: requestFakeClipMove(clipId, trackId, position, true, false, false);
if (possible) {
TRACE_RES(position);
if (m_editMode != TimelineMode::NormalEdit) {
......@@ -1258,7 +1279,6 @@ QVariantList TimelineModel::suggestCompositionMove(int compoId, int trackId, int
}
// we check if move is possible
bool possible = requestCompositionMove(compoId, trackId, position, true, false);
qDebug() << "Original move success" << possible;
if (possible) {
TRACE_RES(position);
return {position, trackId};
......@@ -1607,7 +1627,6 @@ bool TimelineModel::requestClipInsertion(const QString &binClipId, int trackId,
}
} else {
std::shared_ptr<ProjectClip> binClip = pCore->projectItemModel()->getClipByBinID(bid);
qDebug() << "++++++++++++++++++\n\nCLIP INSERT TYPE 2 on TID: "<<trackId<<"\n\n+++++++++++++++++++";
if (dropType == PlaylistState::Disabled) {
dropType = getTrackById_const(trackId)->trackType();
} else if (dropType != getTrackById_const(trackId)->trackType()) {
......@@ -2122,8 +2141,11 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
int current_in = item.second;
int playtime = getClipPlaytime(item.first);
int target_position = current_in + delta_pos;
int subPlaylist = m_allClips[item.first]->getSubPlaylistIndex();
int subPlaylist = -1;
if (delta_pos < 0) {
if (getTrackById_const(current_track_id)->hasStartMix(item.first)) {
subPlaylist = m_allClips[item.first]->getSubPlaylistIndex();
}
if (!getTrackById_const(current_track_id)->isAvailable(target_position, -delta_pos, subPlaylist)) {
if (!getTrackById_const(current_track_id)->isBlankAt(current_in - 1)) {
// No move possible, abort
......@@ -2137,6 +2159,9 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
} else {
int moveEnd = target_position + playtime;
int moveStart = qMax(current_in + playtime, target_position);
if (getTrackById_const(current_track_id)->hasEndMix(item.first)) {
subPlaylist = m_allClips[item.first]->getSubPlaylistIndex();
}
if (!getTrackById_const(current_track_id)->isAvailable(moveStart, moveEnd - moveStart, subPlaylist)) {
int newStart = getTrackById_const(current_track_id)->getBlankEnd(current_in + playtime);
if (newStart == current_in + playtime) {
......@@ -2153,7 +2178,6 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
for (const std::pair<int, int> &item : sorted_clips) {
int current_track_id = getClipTrackId(item.first);
if (!allowedTracks.isEmpty() && !allowedTracks.contains(current_track_id)) {
qDebug()<<"°°°°°°°°°°°°ABORTING CLIP MOVE: "<<item.first;
continue;
}
int current_in = item.second;
......@@ -2608,9 +2632,6 @@ int TimelineModel::requestItemSpeedChange(int itemId, int size, bool right, int
int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logUndo, int snapDistance, bool allowSingleResize)
{
if (logUndo) {
qDebug() << "---------------------\n---------------------\nRESIZE W/UNDO CALLED\n++++++++++++++++\n++++";
}
QWriteLocker locker(&m_lock);
TRACE(itemId, size, right, logUndo, snapDistance, allowSingleResize)
Q_ASSERT(isItem(itemId));
......@@ -2683,7 +2704,6 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
resizeMix = true;
}
if (logUndo && resizeMix && isClip(id)) {
qDebug()<<"=== RESIZING PROCESS MIX";
int tid = getItemTrackId(id);
if (tid > -1) {
if (right) {
......
......@@ -137,6 +137,7 @@ bool TrackModel::switchPlaylist(int clipId, int position, int playlist)
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);
return index != -1;
}
return false;
......@@ -195,6 +196,10 @@ Fun TrackModel::requestClipInsertion_lambda(int clipId, int position, bool updat
qDebug() << "Error : Clip Insertion failed because timeline is not available anymore";
return false;
};
if (!finalMove && !hasMix(clipId) && (!m_playlists[0].is_blank_at(position) || !m_playlists[1].is_blank_at(position))) {
qDebug()<<"==== WARNING INVALID MOVE";
return []() { return false; };
}
if (target_clip >= count && m_playlists[target_playlist].is_blank_at(position)) {
// In that case, we append after, in the first playlist
return [this, position, clipId, end_function, finalMove, groupMove, target_playlist]() {
......@@ -699,14 +704,14 @@ int TrackModel::getId() const
return m_id;
}
int TrackModel::getClipByPosition(int position)
int TrackModel::getClipByPosition(int position, int playlist)
{
READ_LOCK();
QSharedPointer<Mlt::Producer> prod(nullptr);
if (m_playlists[0].count() > 0) {
if ((playlist == 0 || playlist == -1) && m_playlists[0].count() > 0) {
prod = QSharedPointer<Mlt::Producer>(m_playlists[0].get_clip_at(position));
}
if ((!prod || prod->is_blank()) && m_playlists[1].count() > 0) {
if (playlist != 0 && (!prod || prod->is_blank()) && m_playlists[1].count() > 0) {
prod = QSharedPointer<Mlt::Producer>(m_playlists[1].get_clip_at(position));
}
if (!prod || prod->is_blank()) {
......@@ -1402,6 +1407,17 @@ void TrackModel::unlock()
bool TrackModel::isAvailable(int position, int duration, int playlist)
{
if (playlist == -1) {
// Check on both playlists
for (auto &m_playlist : m_playlists) {
int start_clip = m_playlist.get_clip_index_at(position);
int end_clip = m_playlist.get_clip_index_at(position + duration - 1);
if (start_clip != end_clip || !m_playlist.is_blank(start_clip)) {
return false;
}
}
return true;
}
int start_clip = m_playlists[playlist].get_clip_index_at(position);
int end_clip = m_playlists[playlist].get_clip_index_at(position + duration - 1);
if (start_clip != end_clip) {
......@@ -1420,6 +1436,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
int firstClipDuration;
int source_track;
int mixPosition;
int dest_track = 1;
qDebug()<<"=========MIXING CLIPS: "<<clipIds;
if (auto ptr = m_parent.lock()) {
// The clip that will be moved to playlist 1
......@@ -1430,18 +1447,60 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
std::shared_ptr<ClipModel> firstClip(ptr->getClipPtr(clipIds.first));
firstClipDuration = firstClip->getPlaytime();
mixPosition = secondClipPos - mixDuration;
if (firstClip->getSubPlaylistIndex() == 1) {
dest_track = 0;
}
} else {
// Error, timeline unavailable
return false;
}
int dest_track = 1;
if (source_track == 1) {
dest_track = 0;
}
// Rearrange subsequent mixes
Fun rearrange_playlists = []() { return true; };
Fun rearrange_playlists_undo = []() { return true; };
if (source_track != dest_track && hasEndMix(clipIds.second)) {
// A list of clip ids x playlists
QMap<int, int> rearrangedPlaylists;
int ix = 0;
int moveId = m_mixList.value(clipIds.second, -1);
while (moveId > -1) {
rearrangedPlaylists.insert(moveId, ix % 2 ? 1 - dest_track : dest_track);
if (hasEndMix(moveId)) {
moveId = m_mixList.value(moveId, -1);
} else {
break;
}
ix++;
}
rearrange_playlists = [this, rearrangedPlaylists]() {
bool result = true;
QMapIterator<int, int> i(rearrangedPlaylists);
i.toBack();
while (i.hasPrevious()) {
i.previous();
result = switchPlaylist(i.key(), m_allClips[i.key()]->getPosition(), i.value());
if (!result) {
break;
}
}
return true;
};
rearrange_playlists_undo = [this, rearrangedPlaylists]() {
bool result = true;
QMapIterator<int, int> i(rearrangedPlaylists);
i.toBack();
while (i.hasPrevious()) {
i.previous();
result = switchPlaylist(i.key(), m_allClips[i.key()]->getPosition(), 1 - i.value());
if (!result) {
break;
}
}
return true;
};
}
// Create mix compositing
Fun build_mix = [clipIds, mixPosition, mixDuration, this]() {
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);
......@@ -1449,11 +1508,17 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
if (isAudioTrack()) {
std::shared_ptr<Mlt::Transition> t(new Mlt::Transition(*ptr->getProfile(), "mix"));
t->set_in_and_out(mixPosition, mixPosition + 2 * mixDuration);
if (dest_track == 0) {
t->set("reverse", 1);
}
m_track->plant_transition(*t.get(), 0, 1);
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);
if (dest_track == 0) {
t->set("reverse", 1);
}
m_track->plant_transition(*t.get(), 0, 1);
m_sameCompositions[clipIds.second] = t;
}
......@@ -1482,10 +1547,11 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
auto operation = requestClipDeletion_lambda(clipIds.second, updateView, finalMove, groupMove, finalMove);
bool res = operation();
if (res) {
Fun replay = [this, clipIds, dest_track, firstClipDuration, secondClipDuration, mixDuration, build_mix, secondClipPos, updateView, finalMove, groupMove]() {
Fun replay = [this, clipIds, dest_track, firstClipDuration, secondClipDuration, mixDuration, build_mix, secondClipPos, updateView, finalMove, groupMove, rearrange_playlists]() {
if (auto ptr = m_parent.lock()) {
ptr->getClipPtr(clipIds.second)->setSubPlaylistIndex(dest_track);
}
rearrange_playlists();
build_mix();
auto op = requestClipInsertion_lambda(clipIds.second, secondClipPos, updateView, finalMove, groupMove);
bool result = op();
......@@ -1502,7 +1568,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
return result;
};
Fun reverse = [this, clipIds, source_track, secondClipDuration, firstClipDuration, destroy_mix, secondClipPos, updateView, finalMove, groupMove, operation]() {
Fun reverse = [this, clipIds, source_track, secondClipDuration, firstClipDuration, destroy_mix, secondClipPos, updateView, finalMove, groupMove, operation, rearrange_playlists_undo]() {
destroy_mix();
std::function<bool(void)> local_undo = []() { return true; };
std::function<bool(void)> local_redo = []() { return true; };
......@@ -1516,6 +1582,7 @@ bool TrackModel::requestClipMix(std::pair<int, int> clipIds, int mixDuration, bo
}
auto op = requestClipInsertion_lambda(clipIds.second, secondClipPos, updateView, finalMove, groupMove);
op();
rearrange_playlists_undo();
return true;
};
res = res && replay();
......@@ -1612,14 +1679,21 @@ bool TrackModel::createMix(MixInfo info, bool isAudio)
//int out = in + info.firstClipInOut.second - info.secondClipInOut.first;
int out = in + movedClip->getMixDuration();
movedClip->setMixDuration(out - in);
bool reverse = movedClip->getSubPlaylistIndex() == 0;
if (isAudio) {
std::shared_ptr<Mlt::Transition> t(new Mlt::Transition(*ptr->getProfile(), "mix"));
t->set_in_and_out(in, out);
if (reverse) {
t->set("reverse", 1);
}
m_track->plant_transition(*t.get(), 0, 1);
m_sameCompositions[info.secondClipId] = t;
} else {
std::shared_ptr<Mlt::Transition> t(new Mlt::Transition(*ptr->getProfile(), "luma"));
t->set_in_and_out(in, out);
if (reverse) {
t->set("reverse", 1);
}
m_track->plant_transition(*t.get(), 0, 1);
m_sameCompositions[info.secondClipId] = t;
}
......@@ -1637,18 +1711,24 @@ bool TrackModel::createMix(std::pair<int, int> clipIds, std::pair<int, int> mixD
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> movedClip(ptr->getClipPtr(clipIds.second));
movedClip->setMixDuration(mixData.second);
qDebug()<<"==== CREATING MIX WITH DURATION:"<<mixData.second;
QModelIndex ix = ptr->makeClipIndexFromID(clipIds.second);
emit ptr->dataChanged(ix, ix, {TimelineModel::MixRole});
bool reverse = movedClip->getSubPlaylistIndex() == 0;
// Insert mix transition
if (isAudioTrack()) {
std::shared_ptr<Mlt::Transition> t(new Mlt::Transition(*ptr->getProfile(), "mix"));
t->set_in_and_out(mixData.first, mixData.first + mixData.second);
if (reverse) {
t->set("reverse", 1);
}
m_track->plant_transition(*t.get(), 0, 1);
m_sameCompositions[clipIds.second] = t;
} else {
std::shared_ptr<Mlt::Transition> t(new Mlt::Transition(*ptr->getProfile(), "luma"));
t->set_in_and_out(mixData.first, mixData.first + mixData.second);
if (reverse) {
t->set("reverse", 1);
}
m_track->plant_transition(*t.get(), 0, 1);
m_sameCompositions[clipIds.second] = t;
}
......@@ -1740,11 +1820,11 @@ bool TrackModel::hasEndMix(int cid) const
bool TrackModel::loadMix(Mlt::Transition &t)
{
//TODO: manage case where both mix clips would start at same position
int in = t.get_in();
int out = t.get_out();
int cid1 = getClipByPosition(in);
int cid2 = getClipByPosition(out);
bool reverse = t.get_int("reverse") == 1;
int cid1 = getClipByPosition(in, reverse ? 1 : 0);
int cid2 = getClipByPosition(out, reverse ? 0 : 1);
std::shared_ptr<Mlt::Transition>tr(&t);
m_sameCompositions[cid2] = tr;
m_mixList.insert(cid1, cid2);
......
......@@ -262,7 +262,7 @@ protected:
int getBlankEnd(int position, int track);
/* @brief Returns the clip id on this track at position requested, or -1 if no clip */
int getClipByPosition(int position);
int getClipByPosition(int position, int playlist = -1);
/* @brief Returns the composition id on this track starting position requested, or -1 if not found */
int getCompositionByPosition(int position);
......
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