Commit 9c198b20 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Fix cannot move grouped clips with mix.

Fixes #1120
parent 465e6dbb
......@@ -34,7 +34,6 @@
#include "kdenlivesettings.h"
#include "snapmodel.hpp"
#include "timelinefunctions.hpp"
#include "trackmodel.hpp"
#include <QDebug>
#include <QThread>
......@@ -618,7 +617,7 @@ bool TimelineModel::requestFakeClipMove(int clipId, int trackId, int position, b
return false;
}
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)
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, std::pair<MixInfo,MixInfo>mixData)
{
Q_UNUSED(moveMirrorTracks)
if (trackId == -1) {
......@@ -661,14 +660,19 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
};
}
Fun sync_mix = []() { return true; };
Fun update_playlist = []() { return true; };
Fun update_playlist_undo = []() { return true; };
Fun simple_move_mix = []() { return true; };
Fun simple_restore_mix = []() { return true; };
if (old_trackId == -1 && isTrack(previous_track) && getTrackById_const(previous_track)->hasMix(clipId) && previous_track != trackId) {
QList<int> allowedClipMixes;
bool hadMix = mixData.first.firstClipId > -1 || mixData.second.secondClipId > -1;
if (old_trackId == -1 && isTrack(previous_track) && hadMix && previous_track != trackId) {
// Clip is moved to another track
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(previous_track)->getMixInfo(clipId);
bool mixGroupMove = false;
if (mixData.first.firstClipId > 0) {
allowedClipMixes << mixData.first.firstClipId;
}
if (mixData.second.firstClipId > 0) {
allowedClipMixes << mixData.second.secondClipId;
}
if (m_groups->isInGroup(clipId)) {
int parentGroup = m_groups->getRootId(clipId);
if (parentGroup > -1) {
......@@ -680,31 +684,35 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
}
if (mixGroupMove) {
// We are moving a group on another track, delete and re-add
bool isAudio = getTrackById_const(previous_track)->isAudioTrack();
simple_move_mix = [this, previous_track, trackId, finalMove, mixData, isAudio]() {
std::pair<QString,QVector<QPair<QString, QVariant>>> mixParams = getTrackById_const(previous_track)->getMixParams(mixData.first.secondClipId);
simple_move_mix = [this, previous_track, trackId, finalMove, mixData, mixParams]() {
// Get mix properties
std::pair<QString,QVector<QPair<QString, QVariant>>> mixParams = getTrackById_const(previous_track)->getMixParams(mixData.first.secondClipId);
// Remove mix on old track
getTrackById_const(previous_track)->syncronizeMixes(finalMove);
bool result = getTrackById_const(trackId)->createMix(mixData.first, isAudio);
// Insert mix on new track
bool result = getTrackById_const(trackId)->createMix(mixData.first, mixParams, finalMove);
return result;
};
simple_restore_mix = [this, previous_track, trackId, finalMove, mixData, isAudio]() {
bool result = true;
if (finalMove) {
result = getTrackById_const(previous_track)->createMix(mixData.first, isAudio);
getTrackById_const(trackId)->syncronizeMixes(finalMove);
//getTrackById_const(previous_track)->syncronizeMixes(finalMove);
}
simple_restore_mix = [this, previous_track, trackId, finalMove, mixData, mixParams]() {
getTrackById_const(trackId)->syncronizeMixes(finalMove);
bool result = getTrackById_const(previous_track)->createMix(mixData.first, mixParams, finalMove);
return result;
};
}
} else if (finalMove && !groupMove && isTrack(old_trackId) && getTrackById_const(old_trackId)->hasMix(clipId)) {
} else if (finalMove && !groupMove && isTrack(old_trackId) && hadMix) {
// Clip has a mix
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(old_trackId)->getMixInfo(clipId);
if (mixData.first.firstClipId > -1) {
if (old_trackId == trackId) {
// We are moving a clip on same track
if (finalMove && position >= mixData.first.firstClipInOut.second) {
position += m_allClips[clipId]->getMixDuration() - m_allClips[clipId]->getMixCutPosition();
removeMixWithUndo(clipId, local_undo, local_redo);
if (mixData.first.firstClipId > 0) {
if (moving_clips.contains(mixData.first.firstClipId)) {
allowedClipMixes << mixData.first.firstClipId;
}
}
}
} else {
// Clip moved to another track, delete mix
......@@ -713,6 +721,11 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
}
if (mixData.second.firstClipId > -1) {
// We have a mix at clip end
if (mixData.second.firstClipId > 0) {
if (moving_clips.contains(mixData.second.firstClipId)) {
allowedClipMixes << mixData.second.secondClipId;
}
}
int clipDuration = mixData.second.firstClipInOut.second - mixData.second.firstClipInOut.first;
sync_mix = [this, old_trackId, finalMove]() {
getTrackById_const(old_trackId)->syncronizeMixes(finalMove);
......@@ -722,7 +735,6 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
if (finalMove && (position + clipDuration <= mixData.second.secondClipInOut.first)) {
// Moved outside mix zone
removeMixWithUndo(mixData.second.secondClipId, local_undo, local_redo);
}
} else {
// Clip moved to another track, delete mix
......@@ -731,8 +743,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
removeMixWithUndo(mixData.second.secondClipId, local_undo, local_redo);
}
}
} 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);
} else if (finalMove && groupMove && isTrack(old_trackId) && hadMix && old_trackId == trackId) {
if (mixData.first.firstClipId > -1) {
// Mix on clip start, check if mix is still in range
if (!moving_clips.contains(mixData.first.firstClipId)) {
......@@ -742,6 +753,8 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
position += m_allClips[mixData.first.secondClipId]->getMixDuration() - m_allClips[mixData.first.secondClipId]->getMixCutPosition();
removeMixWithUndo(mixData.first.secondClipId, local_undo, local_redo);
}
} else {
allowedClipMixes << mixData.first.firstClipId;
}
}
if (mixData.second.firstClipId > -1) {
......@@ -752,10 +765,11 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
// Mix will be deleted, recreate on undo
removeMixWithUndo(mixData.second.secondClipId, local_undo, local_redo);
}
} else {
allowedClipMixes << mixData.second.secondClipId;
}
}
}
PUSH_LAMBDA(simple_restore_mix, local_undo);
if (finalMove) {
PUSH_LAMBDA(sync_mix, local_undo);
}
......@@ -763,26 +777,24 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
if (notifyViewOnly) {
PUSH_LAMBDA(update_model, local_undo);
}
ok = getTrackById(old_trackId)->requestClipDeletion(clipId, updateView, finalMove, local_undo, local_redo, groupMove, false);
ok = getTrackById(old_trackId)->requestClipDeletion(clipId, updateView, finalMove, local_undo, local_redo, groupMove, false, allowedClipMixes);
if (!ok) {
bool undone = local_undo();
Q_ASSERT(undone);
return false;
}
}
update_playlist();
UPDATE_UNDO_REDO(update_playlist, update_playlist_undo, local_undo, local_redo);
ok = getTrackById(trackId)->requestClipInsertion(clipId, position, updateView, finalMove, local_undo, local_redo, groupMove);
ok = ok && getTrackById(trackId)->requestClipInsertion(clipId, position, updateView, finalMove, local_undo, local_redo, groupMove, allowedClipMixes);
if (!ok) {
qWarning() << "clip insertion failed";
bool undone = local_undo();
Q_ASSERT(undone);
return false;
}
qDebug()<<":::MOVED CLIP: "<<clipId<<" TO "<<position;
sync_mix();
update_model();
simple_move_mix();
PUSH_LAMBDA(simple_restore_mix, local_undo);
PUSH_LAMBDA(simple_move_mix, local_redo);
if (finalMove) {
PUSH_LAMBDA(sync_mix, local_redo);
......@@ -797,7 +809,6 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
bool TimelineModel::mixClip(int idToMove, int delta)
{
int selectedTrack = -1;
qDebug()<<"==== REQUEST CLIP MIX STEP 1";
std::unordered_set<int> initialSelection = getCurrentSelection();
if (idToMove == -1 && initialSelection.empty()) {
pCore->displayMessage(i18n("Select a clip to apply the mix"), ErrorMessage, 500);
......@@ -2142,6 +2153,8 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
// Separate clips from compositions to sort and check source tracks
QMap<std::pair<int, int>, int> mixesToDelete;
// Mixes might be deleted while moving clips to another track, so store them before attempting a move
QMap<int, std::pair<MixInfo, MixInfo>> mixDataArray;
for (int affectedItemId : all_items) {
if (delta_track != 0 && !isSubTitle(affectedItemId)) {
// Check if an upper / lower move is possible
......@@ -2159,8 +2172,9 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
int current_track_id = getClipTrackId(affectedItemId);
// Check if we have a mix in the group
if (getTrackById_const(current_track_id)->hasMix(affectedItemId)) {
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(current_track_id)->getMixInfo(affectedItemId);
mixDataArray.insert(affectedItemId, mixData);
if (delta_track != 0) {
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(current_track_id)->getMixInfo(affectedItemId);
if (mixData.first.firstClipId > -1 && all_items.find(mixData.first.firstClipId) == all_items.end()) {
// First part of the mix is not moving, delete start mix
mixesToDelete.insert({mixData.first.firstClipId,affectedItemId}, current_track_id);
......@@ -2180,7 +2194,6 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
sorted_subtitles.emplace_back(affectedItemId, m_allSubtitles.at(affectedItemId));
}
}
if (!sorted_subtitles.empty() && m_subtitleModel->isLocked()) {
// Group with a locked subtitle, abort
return false;
......@@ -2416,15 +2429,15 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
}
int current_in = item.second;
int target_position = current_in + delta_pos;
ok = requestClipMove(item.first, current_track_id, target_position, moveMirrorTracks, updateThisView, finalMove, finalMove, local_undo, local_redo, true, oldTrackIds);
ok = requestClipMove(item.first, current_track_id, target_position, moveMirrorTracks, updateThisView, finalMove, finalMove, local_undo, local_redo, true, oldTrackIds, mixDataArray.contains(item.first) ? mixDataArray.value(item.first) : std::pair<MixInfo,MixInfo>());
if (!ok) {
qWarning() << "failed moving clip on track" << current_track_id;
qWarning() << "failed moving clip on track " << current_track_id;
break;
}
}
sync_mix();
PUSH_LAMBDA(sync_mix, local_redo);
if (ok) {
sync_mix();
PUSH_LAMBDA(sync_mix, local_redo);
for (const std::pair<int, std::pair<int, int>> &item : sorted_compositions) {
int current_track_id = getItemTrackId(item.first);
if (!allowedTracks.isEmpty() && !allowedTracks.contains(current_track_id)) {
......@@ -2459,7 +2472,7 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
std::advance(it, target_track_position);
int target_track = (*it)->getId();
int target_position = old_position[item.first] + delta_pos;
ok = ok && requestClipMove(item.first, target_track, target_position, moveMirrorTracks, updateThisView, finalMove, finalMove, local_undo, local_redo, true, oldTrackIds);
ok = ok && requestClipMove(item.first, target_track, target_position, moveMirrorTracks, updateThisView, finalMove, finalMove, local_undo, local_redo, true, oldTrackIds, mixDataArray.contains(item.first) ? mixDataArray.value(item.first) : std::pair<MixInfo,MixInfo>());
} else {
ok = false;
}
......
......@@ -24,6 +24,7 @@
#include "definitions.h"
#include "undohelper.hpp"
#include "trackmodel.hpp"
#include <QAbstractItemModel>
#include <QReadWriteLock>
#include <cassert>
......@@ -385,7 +386,7 @@ public:
/* Same function, but accumulates undo and redo, and doesn't check
for group*/
bool requestClipMove(int clipId, int trackId, int position, bool moveMirrorTracks, bool updateView, bool invalidateTimeline, bool finalMove, Fun &undo, Fun &redo, bool groupMove = false, QMap <int, int> moving_clips = QMap <int, int>());
bool requestClipMove(int clipId, int trackId, int position, bool moveMirrorTracks, bool updateView, bool invalidateTimeline, bool finalMove, Fun &undo, Fun &redo, bool groupMove = false, QMap <int, int> moving_clips = QMap <int, int>(), std::pair<MixInfo, MixInfo>mixData = {});
bool requestCompositionMove(int transid, int trackId, int compositionTrack, int position, bool updateView, bool finalMove, Fun &undo, Fun &redo);
/** @brief When timeline edit mode is insert or overwrite, we fake the move (as it will overlap existing clips, and only process the real move on drop */
......
......@@ -155,19 +155,20 @@ bool TrackModel::switchPlaylist(int clipId, int position, int sourcePlaylist, in
return false;
}
Fun TrackModel::requestClipInsertion_lambda(int clipId, int position, bool updateView, bool finalMove, bool groupMove)
Fun TrackModel::requestClipInsertion_lambda(int clipId, int position, bool updateView, bool finalMove, bool groupMove, QList<int> allowedClipMixes)
{
QWriteLocker locker(&m_lock);
qDebug()<<"== PROCESSING INSERT OF : "<<clipId;
// By default, insertion occurs in topmost track
int target_playlist = 0;
int length = -1;
if (auto ptr = m_parent.lock()) {
Q_ASSERT(ptr->getClipPtr(clipId)->getCurrentTrackId() == -1);
target_playlist = ptr->getClipPtr(clipId)->getSubPlaylistIndex();
length = ptr->getClipPtr(clipId)->getPlaytime();
/*if (target_playlist == 1 && ptr->getClipPtr(clipId)->getMixDuration() == 0) {
target_playlist = 0;
}*/
qDebug()<<"==== GOT TRARGET PLAYLIST: "<<target_playlist;
//qDebug()<<"==== GOT TRARGET PLAYLIST: "<<target_playlist;
} else {
qDebug() << "impossible to get parent timeline";
Q_ASSERT(false);
......@@ -208,9 +209,28 @@ 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 (!finalMove && !hasMix(clipId)) {
if (allowedClipMixes.isEmpty()) {
if (!m_playlists[0].is_blank_at(position) || !m_playlists[1].is_blank_at(position)) {
// Track is not empty
return []() { return false; };
}
} else {
// This is a group move with a mix, some clips are allowed
if (!m_playlists[target_playlist].is_blank_at(position)) {
// Track is not empty
return []() { return false; };
}
// Check if there are clips on the other playlist, and if they are in the allowed list
std::unordered_set<int> collisions = getClipsInRange(position, position + length);
qDebug()<<"==== DETECTING COLLISIONS AT: "<<position<<" to "<<(position+length)<<" COUNT: "<<collisions.size();
for (int c : collisions) {
if (!allowedClipMixes.contains(c)) {
// Track is not empty
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
......@@ -235,11 +255,6 @@ Fun TrackModel::requestClipInsertion_lambda(int clipId, int position, bool updat
}
if (m_playlists[target_playlist].is_blank_at(position)) {
int blank_end = getBlankEnd(position, target_playlist);
int length = -1;
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(clipId);
length = clip->getPlaytime();
}
if (blank_end >= position + length) {
return [this, position, clipId, end_function, target_playlist]() {
if (isLocked()) return false;
......@@ -261,7 +276,7 @@ Fun TrackModel::requestClipInsertion_lambda(int clipId, int position, bool updat
return []() { return false; };
}
bool TrackModel::requestClipInsertion(int clipId, int position, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove)
bool TrackModel::requestClipInsertion(int clipId, int position, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove, QList<int> allowedClipMixes)
{
QWriteLocker locker(&m_lock);
if (isLocked()) {
......@@ -289,7 +304,7 @@ bool TrackModel::requestClipInsertion(int clipId, int position, bool updateView,
res = clip->setClipState(isAudioTrack() ? PlaylistState::AudioOnly : PlaylistState::VideoOnly, local_undo, local_redo);
}
int duration = trackDuration();
auto operation = requestClipInsertion_lambda(clipId, position, updateView, finalMove, groupMove);
auto operation = requestClipInsertion_lambda(clipId, position, updateView, finalMove, groupMove, allowedClipMixes);
res = res && operation();
if (res) {
if (finalMove && duration != trackDuration()) {
......@@ -426,7 +441,7 @@ Fun TrackModel::requestClipDeletion_lambda(int clipId, bool updateView, bool fin
};
}
bool TrackModel::requestClipDeletion(int clipId, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove, bool finalDeletion)
bool TrackModel::requestClipDeletion(int clipId, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove, bool finalDeletion, QList<int> allowedClipMixes)
{
QWriteLocker locker(&m_lock);
Q_ASSERT(m_allClips.count(clipId) > 0);
......@@ -446,7 +461,7 @@ bool TrackModel::requestClipDeletion(int clipId, bool updateView, bool finalMove
// A clip move changed the track duration, update track effects
m_effectStack->adjustStackLength(true, 0, duration, 0, trackDuration(), 0, undo, redo, true);
}
auto reverse = requestClipInsertion_lambda(clipId, old_position, updateView, finalMove, groupMove);
auto reverse = requestClipInsertion_lambda(clipId, old_position, updateView, finalMove, groupMove, allowedClipMixes);
UPDATE_UNDO_REDO(operation, reverse, undo, redo);
return true;
}
......@@ -2040,6 +2055,52 @@ bool TrackModel::deleteMix(int clipId, bool final, bool notify)
return false;
}
bool TrackModel::createMix(MixInfo info, std::pair<QString,QVector<QPair<QString, QVariant>>> params, bool finalMove)
{
if (m_sameCompositions.count(info.secondClipId) > 0) {
// Clip already has a mix
return false;
}
if (auto ptr = m_parent.lock()) {
// Insert mix transition
std::shared_ptr<ClipModel> movedClip(ptr->getClipPtr(info.secondClipId));
int in = movedClip->getPosition();
//int out = in + info.firstClipInOut.second - info.secondClipInOut.first;
int out = in + movedClip->getMixDuration();
movedClip->setMixDuration(out - in);
std::unique_ptr<Mlt::Transition> t;
const QString assetId = params.first;
t = std::make_unique<Mlt::Transition>(*ptr->getProfile(), assetId.toUtf8().constData());
int mixCutPos = movedClip->getMixCutPosition();
t->set_in_and_out(in, out);
t->set("kdenlive:mixcut", mixCutPos);
t->set("kdenlive_id", assetId.toUtf8().constData());
m_track->plant_transition(*t.get(), 0, 1);
QDomElement xml = TransitionsRepository::get()->getXml(assetId);
QDomNodeList xmlParams = xml.elementsByTagName(QStringLiteral("parameter"));
for (int i = 0; i < xmlParams.count(); ++i) {
QDomElement currentParameter = xmlParams.item(i).toElement();
QString paramName = currentParameter.attribute(QStringLiteral("name"));
for (const auto &p : qAsConst(params.second)) {
if (p.first == paramName) {
currentParameter.setAttribute(QStringLiteral("value"), p.second.toString());
break;
}
}
}
std::shared_ptr<AssetParameterModel> asset(new AssetParameterModel(std::move(t), xml, assetId, {ObjectType::TimelineMix, info.secondClipId}, QString()));
m_sameCompositions[info.secondClipId] = asset;
m_mixList.insert(info.firstClipId, info.secondClipId);
if (finalMove) {
QModelIndex ix2 = ptr->makeClipIndexFromID(info.secondClipId);
emit ptr->dataChanged(ix2, ix2, {TimelineModel::MixRole,TimelineModel::MixCutRole});
}
return true;
}
return false;
}
bool TrackModel::createMix(MixInfo info, bool isAudio)
{
if (m_sameCompositions.count(info.secondClipId) > 0) {
......@@ -2270,6 +2331,14 @@ bool TrackModel::reAssignEndMix(int currentId, int newId)
return true;
}
std::pair<QString,QVector<QPair<QString, QVariant>>> TrackModel::getMixParams(int cid)
{
Q_ASSERT(m_sameCompositions.count(cid) > 0);
const QString assetId = m_sameCompositions[cid]->getAssetId();
QVector<QPair<QString, QVariant>> params = m_sameCompositions[cid]->getAllParameters();
return {assetId,params};
}
void TrackModel::switchMix(int cid, const QString composition, Fun &undo, Fun &redo)
{
// First remove existing mix
......
......@@ -41,8 +41,8 @@ class AssetParameterModel;
class MixInfo
{
public:
int firstClipId;
int secondClipId;
int firstClipId = -1;
int secondClipId = -1;
std::pair<int, int> firstClipInOut;
std::pair<int, int> secondClipInOut;
std::pair<int, int> mixInOut;
......@@ -130,10 +130,13 @@ public:
bool deleteMix(int clipId, bool final, bool notify = true);
/** @brief Create a mix composition using clip ids */
bool createMix(std::pair<int, int> clipIds, std::pair<int, int> mixData);
bool createMix(MixInfo info, std::pair<QString,QVector<QPair<QString, QVariant>>> params, bool finalMove);
/** @brief Create a mix composition using mix info */
bool createMix(MixInfo info, bool isAudio);
/** @brief Change id of first clip in a mix (in case of clip cut) */
bool reAssignEndMix(int currentId, int newId);
/** @brief Get all necessary infos to clone a mix */
std::pair<QString,QVector<QPair<QString, QVariant>>> getMixParams(int cid);
void switchMix(int cid, const QString composition, Fun &undo, Fun &redo);
/** @brief Ensure we don't have unsynced mixes in the playlist (mixes without owner clip) */
void syncronizeMixes(bool finalMove);
......@@ -176,9 +179,9 @@ protected:
@param undo Lambda function containing the current undo stack. Will be updated with current operation
@param redo Lambda function containing the current redo queue. Will be updated with current operation
*/
bool requestClipInsertion(int clipId, int position, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove = false);
bool requestClipInsertion(int clipId, int position, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove = false, QList<int> allowedClipMixes = {});
/** @brief This function returns a lambda that performs the requested operation */
Fun requestClipInsertion_lambda(int clipId, int position, bool updateView, bool finalMove, bool groupMove = false);
Fun requestClipInsertion_lambda(int clipId, int position, bool updateView, bool finalMove, bool groupMove = false, QList<int> allowedClipMixes = {});
/** @brief Performs an deletion of the given clip.
Returns true if the operation succeeded, and otherwise, the track is not modified.
......@@ -191,7 +194,7 @@ protected:
@param groupMove If true, this is part of a larger operation and some operations like checking track duration will not be performed and have to be performed separately
@param finalDeletion If true, the clip will be deselected (should be false if this is a clip move doing delete/insert)
*/
bool requestClipDeletion(int clipId, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove, bool finalDeletion);
bool requestClipDeletion(int clipId, bool updateView, bool finalMove, Fun &undo, Fun &redo, bool groupMove, bool finalDeletion, QList<int> allowedClipMixes = {});
/** @brief This function returns a lambda that performs the requested operation */
Fun requestClipDeletion_lambda(int clipId, bool updateView, bool finalMove, bool groupMove, bool finalDeletion);
......
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