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

fix timeline corruption:

* Major update to item drag in timeline
* Fix composition move in groups
* Refactor timeline preview (in progress)
parent 22b3cabb
......@@ -1585,8 +1585,8 @@ void Bin::slotItemDoubleClicked(const QModelIndex &ix, const QPoint pos)
}
if (ix.isValid()) {
QRect IconRect = m_itemView->visualRect(ix);
IconRect.setSize(m_itemView->iconSize());
if (!pos.isNull() && ((ix.column() == 2 && item->itemType() == AbstractProjectItem::ClipItem) || !IconRect.contains(pos))) {
IconRect.setWidth((double)IconRect.height() / m_itemView->iconSize().height() * m_itemView->iconSize().width());
if (!pos.isNull() && ((ix.column() == 2 && item->itemType() == AbstractProjectItem::ClipItem) || (!IconRect.contains(pos) && pos.y() < (IconRect.y() + IconRect.height()/2)))) {
// User clicked outside icon, trigger rename
m_itemView->edit(ix);
return;
......
......@@ -1401,7 +1401,7 @@ const QString GLWidget::sceneList(const QString &root, const QString &fullPath)
{
QString playlist;
qCDebug(KDENLIVE_LOG) << " * * *Setting document xml root: " << root;
Mlt::Consumer xmlConsumer(*m_monitorProfile, fullPath.isEmpty() ? "xml:kdenlive_playlist" : fullPath.toUtf8().constData());
Mlt::Consumer xmlConsumer(*m_monitorProfile, "xml", fullPath.isEmpty() ? "kdenlive_playlist" : fullPath.toUtf8().constData());
if (!root.isEmpty()) {
xmlConsumer.set("root", root.toUtf8().constData());
}
......
......@@ -181,13 +181,19 @@ bool ClipModel::requestResize(int size, bool right, Fun &undo, Fun &redo, bool l
};
if (operation()) {
// Now, we are in the state in which the timeline should be when we try to revert current action. So we can build the reverse action from here
auto ptr = m_parent.lock();
if (m_currentTrackId != -1 && ptr) {
if (m_currentTrackId != -1) {
QVector<int> roles{TimelineModel::DurationRole};
if (!right) {
roles.push_back(TimelineModel::StartRole); roles.push_back(TimelineModel::InPointRole);
} else {
roles.push_back(TimelineModel::OutPointRole);
}
if (auto ptr = m_parent.lock()) {
QModelIndex ix = ptr->makeClipIndexFromID(m_id);
ptr->dataChanged(ix, ix, {TimelineModel::InPointRole});
//TODO: integrate in undo
ptr->dataChanged(ix, ix, roles);
track_reverse = ptr->getTrackById(m_currentTrackId)->requestClipResize_lambda(m_id, old_in, old_out, right);
}
track_reverse = ptr->getTrackById(m_currentTrackId)->requestClipResize_lambda(m_id, old_in, old_out, right);
}
Fun reverse = [this, old_in, old_out, track_reverse]() {
if (track_reverse()) {
......
......@@ -109,6 +109,14 @@ bool CompositionModel::requestResize(int size, bool right, Fun &undo, Fun &redo,
if (operation()) {
// Now, we are in the state in which the timeline should be when we try to revert current action. So we can build the reverse action from here
auto ptr = m_parent.lock();
// we send a list of roles to be updated
QVector<int> roles{TimelineModel::DurationRole};
if (!right) {
roles.push_back(TimelineModel::StartRole);
}
QModelIndex ix = ptr->makeCompositionIndexFromID(m_id);
//TODO: integrate in undo
ptr->dataChanged(ix, ix, roles);
if (m_currentTrackId != -1 && ptr) {
track_reverse = ptr->getTrackById(m_currentTrackId)->requestCompositionResize_lambda(m_id, old_in, old_out);
}
......@@ -186,7 +194,9 @@ void CompositionModel::setATrack(int trackMltPosition, int trackId)
if (a_track >= 0) {
service()->set("a_track", trackMltPosition);
}
emit compositionTrackChanged();
if (m_currentTrackId != -1) {
emit compositionTrackChanged();
}
}
KeyframeModel *CompositionModel::getEffectKeyframeModel()
......
......@@ -186,12 +186,17 @@ int TimelineFunctions::requestSpacerStartOperation(std::shared_ptr<TimelineItemM
return -1;
}
bool TimelineFunctions::requestSpacerEndOperation(std::shared_ptr<TimelineItemModel> timeline, int clipId, int startPosition, int endPosition)
bool TimelineFunctions::requestSpacerEndOperation(std::shared_ptr<TimelineItemModel> timeline, int itemId, int startPosition, int endPosition)
{
// Move group back to original position
int track = timeline->getItemTrackId(clipId);
timeline->requestClipMove(clipId, track, startPosition, false, false);
std::unordered_set<int> clips = timeline->getGroupElements(clipId);
int track = timeline->getItemTrackId(itemId);
bool isClip = timeline->isClip(itemId);
if (isClip) {
timeline->requestClipMove(itemId, track, startPosition, false, false);
} else {
timeline->requestCompositionMove(itemId, track, startPosition, false, false);
}
std::unordered_set<int> clips = timeline->getGroupElements(itemId);
// break group
pCore->clearSelection();
// Start undoable command
......@@ -201,14 +206,18 @@ bool TimelineFunctions::requestSpacerEndOperation(std::shared_ptr<TimelineItemMo
bool final = false;
if (res > -1) {
if (clips.size() > 1) {
final = timeline->requestGroupMove(clipId, res, 0, endPosition - startPosition, true, true, undo, redo);
final = timeline->requestGroupMove(itemId, res, 0, endPosition - startPosition, true, true, undo, redo);
} else {
// only 1 clip to be moved
final = timeline->requestClipMove(clipId, track, endPosition, true, true, undo, redo);
if (isClip) {
final = timeline->requestClipMove(itemId, track, endPosition, true, true, undo, redo);
} else {
final = timeline->requestCompositionMove(itemId, track, -1, endPosition, true, undo, redo);
}
}
}
if (final && clips.size() > 1) {
final = timeline->requestClipUngroup(clipId, undo, redo);
final = timeline->requestClipUngroup(itemId, undo, redo);
}
if (final) {
pCore->pushUndo(undo, redo, i18n("Insert space"));
......
......@@ -64,7 +64,7 @@ struct TimelineFunctions
QList<int> &clipIds, bool logUndo, bool refreshView);
static int requestSpacerStartOperation(std::shared_ptr<TimelineItemModel> timeline, int trackId, int position);
static bool requestSpacerEndOperation(std::shared_ptr<TimelineItemModel> timeline, int clipId, int startPosition, int endPosition);
static bool requestSpacerEndOperation(std::shared_ptr<TimelineItemModel> timeline, int itemId, int startPosition, int endPosition);
static bool extractZone(std::shared_ptr<TimelineItemModel> timeline, QVector<int> tracks, QPoint zone, bool liftOnly);
static bool liftZone(std::shared_ptr<TimelineItemModel> timeline, int trackId, QPoint zone, Fun &undo, Fun &redo);
static bool removeSpace(std::shared_ptr<TimelineItemModel> timeline, int trackId, QPoint zone, Fun &undo, Fun &redo);
......
......@@ -73,13 +73,18 @@ QModelIndex TimelineItemModel::index(int row, int column, const QModelIndex &par
int clipId = getTrackById_const(trackId)->getClipByRow(row);
if (clipId != -1) {
result = createIndex(row, 0, quintptr(clipId));
} else {
} else if (row < getTrackClipsCount(trackId) + getTrackCompositionsCount(trackId)) {
int compoId = getTrackById_const(trackId)->getCompositionByRow(row);
if (compoId != -1) {
result = createIndex(row, 0, quintptr(compoId));
}
} else {
// Invalid index requested
Q_ASSERT(false);
}
} else if (row < getTracksCount() && row >= 0) {
// Get sort order
row = getTracksCount() - 1 - row;
auto it = m_allTracks.cbegin();
std::advance(it, row);
int trackId = (*it)->getId();
......@@ -118,6 +123,8 @@ QModelIndex TimelineItemModel::makeTrackIndexFromID(int trackId) const
Q_ASSERT(m_iteratorTable.count(trackId) > 0);
auto it = m_iteratorTable.at(trackId);
int ind = (int)std::distance<decltype(m_allTracks.cbegin())>(m_allTracks.begin(), it);
// Get sort order
ind = getTracksCount() - 1 - ind;
return index(ind);
}
......@@ -171,6 +178,7 @@ QHash<int, QByteArray> TimelineItemModel::roleNames() const
roles[ResourceRole] = "resource";
roles[ServiceRole] = "mlt_service";
roles[BinIdRole] = "binId";
roles[TrackIdRole] = "trackId";
roles[IsBlankRole] = "blank";
roles[StartRole] = "start";
roles[DurationRole] = "duration";
......@@ -223,7 +231,7 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
if (isTrack(id)) {
return getTrackSortValue(id, KdenliveSettings::audiotracksbelow());
}
return id;
return QVariant();
}
if (isClip(id)) {
// qDebug() << "REQUESTING DATA "<<roleNames()[role]<<index;
......@@ -253,6 +261,8 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
}
case BinIdRole:
return clip->binId();
case TrackIdRole:
return clip->getCurrentTrackId();
case ServiceRole:
return clip->getProperty("mlt_service");
break;
......@@ -360,6 +370,8 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
return false;
case StartRole:
return compo->getPosition();
case TrackIdRole:
return compo->getCurrentTrackId();
case DurationRole:
return compo->getPlaytime();
case GroupedRole:
......
......@@ -386,21 +386,43 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
std::function<bool(void)> local_redo = []() { return true; };
bool ok = true;
int old_trackId = getClipTrackId(clipId);
bool notifyViewOnly = false;
bool localUpdateView = updateView;
qDebug()<<"MOVING CLIP FROM: "<<old_trackId<<" == "<<trackId;
Fun update_model = []() { return true; };
if (old_trackId == trackId) {
// Move on same track, simply inform the view
localUpdateView = false;
notifyViewOnly = true;
update_model = [clipId, this]() {
QModelIndex modelIndex = makeClipIndexFromID(clipId);
qDebug()<<"// UPDATING START POS FOR CLIP: "<<getClipPosition(clipId);
notifyChange(modelIndex, modelIndex, {StartRole});
return true;
};
}
if (old_trackId != -1) {
ok = getTrackById(old_trackId)->requestClipDeletion(clipId, updateView, invalidateTimeline, local_undo, local_redo);
if (notifyViewOnly) {
PUSH_LAMBDA(update_model, local_undo);
}
ok = getTrackById(old_trackId)->requestClipDeletion(clipId, localUpdateView, invalidateTimeline, local_undo, local_redo);
if (!ok) {
bool undone = local_undo();
Q_ASSERT(undone);
return false;
}
}
ok = getTrackById(trackId)->requestClipInsertion(clipId, position, updateView, invalidateTimeline, local_undo, local_redo);
ok = getTrackById(trackId)->requestClipInsertion(clipId, position, localUpdateView, invalidateTimeline, local_undo, local_redo);
if (!ok) {
// qDebug()<<"-------------\n\nINSERTION FAILED, REVERTING\n\n-------------------";
bool undone = local_undo();
Q_ASSERT(undone);
return false;
}
update_model();
if (notifyViewOnly) {
PUSH_LAMBDA(update_model, local_redo);
}
UPDATE_UNDO_REDO(local_redo, local_undo, undo, redo);
return true;
}
......@@ -466,6 +488,14 @@ bool TimelineModel::requestClipMoveAttempt(int clipId, int trackId, int position
return res;
}
int TimelineModel::suggestItemMove(int itemId, int trackId, int position, int snapDistance)
{
if (isClip(itemId)) {
return suggestClipMove(itemId, trackId, position, snapDistance);
}
return suggestCompositionMove(itemId, trackId, position, snapDistance);
}
int TimelineModel::suggestClipMove(int clipId, int trackId, int position, int snapDistance, bool allowViewUpdate)
{
#ifdef LOGGING
......@@ -475,7 +505,8 @@ int TimelineModel::suggestClipMove(int clipId, int trackId, int position, int sn
Q_ASSERT(isClip(clipId));
Q_ASSERT(isTrack(trackId));
int currentPos = getClipPosition(clipId);
if (currentPos == position) {
int sourceTrackId = getClipTrackId(clipId);
if (currentPos == position && sourceTrackId == trackId) {
return position;
}
bool after = position > currentPos;
......@@ -503,18 +534,26 @@ int TimelineModel::suggestClipMove(int clipId, int trackId, int position, int sn
}
}
// we check if move is possible
bool possible;
if (allowViewUpdate) {
possible = requestClipMove(clipId, trackId, position, false, false, false);
} else {
bool possible = requestClipMove(clipId, trackId, position, true, false, false);
/*} else {
possible = requestClipMoveAttempt(clipId, trackId, position);
}
}*/
if (possible) {
return position;
}
// Find best possible move
if (!m_groups->isInGroup(clipId)) {
// Easy
//int currentTrackId = getClipTrackId(clipId);
// Try same track move
trackId = sourceTrackId;
possible = requestClipMove(clipId, trackId, position, true, false, false);
if (!possible) {
qDebug() << "CANNOT MOVE CLIP : "<<clipId<<" ON TK: "<<trackId<<", AT POS: "<<position;
} else {
return position;
}
int blank_length = getTrackById(trackId)->getBlankSizeNearClip(clipId, after);
qDebug() << "Found blank" << blank_length;
if (blank_length < INT_MAX) {
......@@ -524,13 +563,9 @@ int TimelineModel::suggestClipMove(int clipId, int trackId, int position, int sn
position = currentPos - blank_length;
}
} else {
return false;
}
if (allowViewUpdate) {
possible = requestClipMove(clipId, trackId, position, false, false, false);
} else {
possible = requestClipMoveAttempt(clipId, trackId, position);
return currentPos;
}
possible = requestClipMove(clipId, trackId, position, true, false, false);
return possible ? position : currentPos;
}
// find best pos for groups
......@@ -582,6 +617,8 @@ int TimelineModel::suggestClipMove(int clipId, int trackId, int position, int sn
}
}
}
/*
+ * This returns erratic results, moving clips to 0.
if (blank_length != 0) {
int updatedPos = currentPos + (after ? blank_length : -blank_length);
if (allowViewUpdate) {
......@@ -592,7 +629,7 @@ int TimelineModel::suggestClipMove(int clipId, int trackId, int position, int sn
if (possible) {
return updatedPos;
}
}
}*/
return currentPos;
}
......@@ -606,7 +643,7 @@ int TimelineModel::suggestCompositionMove(int compoId, int trackId, int position
Q_ASSERT(isTrack(trackId));
int currentPos = getCompositionPosition(compoId);
int currentTrack = getCompositionTrackId(compoId);
if (currentPos == position || currentTrack != trackId) {
if (currentPos == position && currentTrack == trackId) {
return position;
}
......@@ -638,16 +675,12 @@ int TimelineModel::suggestCompositionMove(int compoId, int trackId, int position
}
}
// we check if move is possible
Fun undo = []() { return true; };
Fun redo = []() { return true; };
bool possible = requestCompositionMove(compoId, trackId, m_allCompositions[compoId]->getForcedTrack(), position, false, undo, redo);
bool possible = requestCompositionMove(compoId, trackId, position, true, false);
qDebug() << "Original move success" << possible;
if (possible) {
bool undone = undo();
Q_ASSERT(undone);
return position;
}
bool after = position > currentPos;
/*bool after = position > currentPos;
int blank_length = getTrackById(trackId)->getBlankSizeNearComposition(compoId, after);
qDebug() << "Found blank" << blank_length;
if (blank_length < INT_MAX) {
......@@ -656,7 +689,8 @@ int TimelineModel::suggestCompositionMove(int compoId, int trackId, int position
}
return currentPos - blank_length;
}
return position;
return position;*/
return currentPos;
}
bool TimelineModel::requestClipCreation(const QString &binClipId, int &id, PlaylistState::ClipState state, Fun &undo, Fun &redo)
......@@ -941,6 +975,7 @@ bool TimelineModel::requestGroupMove(int clipId, int groupId, int delta_track, i
Q_ASSERT(m_allGroups.count(groupId) > 0);
bool ok = true;
auto all_items = m_groups->getLeaves(groupId);
Q_ASSERT(all_items.size() > 1);
Fun local_undo = []() { return true; };
Fun local_redo = []() { return true; };
......@@ -955,18 +990,41 @@ bool TimelineModel::requestGroupMove(int clipId, int groupId, int delta_track, i
// Moving groups is a two stage process: first we remove the clips from the tracks, and then try to insert them back at their calculated new positions.
// This way, we ensure that no conflict will arise with clips inside the group being moved
Fun update_model = []() { return true; };
// Check if there is a track move
bool updatePositionOnly = false;
if (delta_track == 0 && updateView) {
updateView = false;
allowViewRefresh = false;
updatePositionOnly = true;
update_model = [sorted_clips, this]() {
QModelIndex modelIndex;
QVector<int> roles{StartRole};
for (int item : sorted_clips) {
if (isClip(item)) {
modelIndex = makeClipIndexFromID(item);
} else {
modelIndex = makeCompositionIndexFromID(item);
}
notifyChange(modelIndex, modelIndex, roles);
}
return true;
};
}
// First, remove clips
std::unordered_map<int, int> old_track_ids, old_position, old_forced_track;
for (int item : sorted_clips) {
int old_trackId = getItemTrackId(item);
old_track_ids[item] = old_trackId;
if (old_trackId != -1) {
bool updateThisView = (item == clipId) ? updateView : allowViewRefresh;
bool updateThisView = allowViewRefresh;
if (isClip(item)) {
ok = ok && getTrackById(old_trackId)->requestClipDeletion(item, updateThisView, finalMove, local_undo, local_redo);
old_position[item] = m_allClips[item]->getPosition();
} else {
ok = ok && getTrackById(old_trackId)->requestCompositionDeletion(item, updateThisView, local_undo, local_redo);
//ok = ok && getTrackById(old_trackId)->requestCompositionDeletion(item, updateThisView, local_undo, local_redo);
old_position[item] = m_allCompositions[item]->getPosition();
old_forced_track[item] = m_allCompositions[item]->getForcedTrack();
}
......@@ -996,7 +1054,7 @@ bool TimelineModel::requestGroupMove(int clipId, int groupId, int delta_track, i
int current_track_position = getTrackPosition(current_track_id);
int d = getTrackById(current_track_id)->isAudioTrack() ? audio_delta : video_delta;
int target_track_position = current_track_position + d;
bool updateThisView = (item == clipId) ? updateView : allowViewRefresh;
bool updateThisView = allowViewRefresh;
if (target_track_position >= 0 && target_track_position < getTracksCount()) {
auto it = m_allTracks.cbegin();
......@@ -1018,6 +1076,11 @@ bool TimelineModel::requestGroupMove(int clipId, int groupId, int delta_track, i
return false;
}
}
if (updatePositionOnly) {
update_model();
PUSH_LAMBDA(update_model, local_redo);
PUSH_LAMBDA(update_model, local_undo);
}
UPDATE_UNDO_REDO(local_redo, local_undo, undo, redo);
return true;
}
......@@ -1276,23 +1339,6 @@ bool TimelineModel::requestClipUngroup(int id, bool logUndo)
Fun tmp_redo = []() { return true; };
requestClipUngroup(id, tmp_undo, tmp_redo);
m_temporarySelectionGroup = -1;
// Parse children to find groups
std::unordered_set<int> groups;
for (int item : leaves) {
if (m_groups->getLeaves(item).size() > 0) {
if (groups.count(item) <= 0) {
leaves.insert(item);
}
}
}
// destroy groups
for (int leave : leaves) {
result = requestClipUngroup(leave, undo, redo);
if (!result) {
break;
}
}
} else {
result = requestClipUngroup(id, undo, redo);
}
......@@ -1787,9 +1833,10 @@ int TimelineModel::getItemPlaytime(int itemId) const
return getCompositionPlaytime(itemId);
}
int TimelineModel::getTrackCompositionsCount(int compoId) const
int TimelineModel::getTrackCompositionsCount(int trackId) const
{
return getTrackById_const(compoId)->getCompositionsCount();
Q_ASSERT(isTrack(trackId));
return getTrackById_const(trackId)->getCompositionsCount();
}
bool TimelineModel::requestCompositionMove(int compoId, int trackId, int position, bool updateView, bool logUndo)
......@@ -1840,7 +1887,7 @@ bool TimelineModel::requestCompositionMove(int compoId, int trackId, int composi
Q_ASSERT(isComposition(compoId));
Q_ASSERT(isTrack(trackId));
if (compositionTrack == -1 || (compositionTrack > 0 && trackId == getTrackIndexFromPosition(compositionTrack - 1))) {
qDebug() << "// compo track: " << trackId << ", PREVIOUS TK: " << getPreviousVideoTrackPos(trackId);
//qDebug() << "// compo track: " << trackId << ", PREVIOUS TK: " << getPreviousVideoTrackPos(trackId);
compositionTrack = getPreviousVideoTrackPos(trackId);
}
if (compositionTrack == -1) {
......@@ -1855,6 +1902,18 @@ bool TimelineModel::requestCompositionMove(int compoId, int trackId, int composi
Fun local_redo = []() { return true; };
bool ok = true;
int old_trackId = getCompositionTrackId(compoId);
bool notifyViewOnly = false;
Fun update_model = []() { return true; };
if (old_trackId == trackId) {
// Move on same track, only send view update
updateView = false;
notifyViewOnly = true;
update_model = [compoId, this]() {
QModelIndex modelIndex = makeCompositionIndexFromID(compoId);
notifyChange(modelIndex, modelIndex, {StartRole});
return true;
};
}
if (old_trackId != -1) {
Fun delete_operation = []() { return true; };
Fun delete_reverse = []() { return true; };
......@@ -1874,6 +1933,9 @@ bool TimelineModel::requestCompositionMove(int compoId, int trackId, int composi
if (!ok) qDebug() << "Move failed because of first delete operation";
if (ok) {
if (notifyViewOnly) {
PUSH_LAMBDA(update_model, local_undo);
}
UPDATE_UNDO_REDO(delete_operation, delete_reverse, local_undo, local_redo);
ok = getTrackById(old_trackId)->requestCompositionDeletion(compoId, updateView, local_undo, local_redo);
}
......@@ -1904,6 +1966,9 @@ bool TimelineModel::requestCompositionMove(int compoId, int trackId, int composi
ok = insert_operation();
if (!ok) qDebug() << "Move failed because of second insert operation";
if (ok) {
if (notifyViewOnly) {
PUSH_LAMBDA(update_model, local_redo);
}
UPDATE_UNDO_REDO(insert_operation, insert_reverse, local_undo, local_redo);
}
}
......@@ -1912,6 +1977,7 @@ bool TimelineModel::requestCompositionMove(int compoId, int trackId, int composi
Q_ASSERT(undone);
return false;
}
update_model();
UPDATE_UNDO_REDO(local_redo, local_undo, undo, redo);
return true;
}
......@@ -1990,9 +2056,7 @@ bool TimelineModel::replantCompositions(int currentCompo, bool updateView)
field->unlock();
if (updateView) {
QModelIndex modelIndex = makeCompositionIndexFromID(currentCompo);
QVector<int> roles;
roles.push_back(ItemATrack);
notifyChange(modelIndex, modelIndex, roles);
notifyChange(modelIndex, modelIndex, {ItemATrack});
}
return true;
}
......
......@@ -123,6 +123,7 @@ public:
IsBlankRole, /// clip only
StartRole, /// clip only
BinIdRole, /// clip only
TrackIdRole,
MarkersRole, /// clip only
StatusRole, /// clip only
TypeRole, /// clip only
......@@ -190,13 +191,13 @@ public:
Q_INVOKABLE int getCompositionTrackId(int compoId) const;
/* @brief Convenience function that calls either of the previous ones based on item type*/
int getItemTrackId(int itemId) const;
Q_INVOKABLE int getItemTrackId(int itemId) const;
Q_INVOKABLE int getCompositionPosition(int compoId) const;
int getCompositionPlaytime(int compoId) const;
/* Returns an item position, item can be clip or composition */
int getItemPosition(int itemId) const;
Q_INVOKABLE int getItemPosition(int itemId) const;
/* Returns an item duration, item can be clip or composition */
int getItemPlaytime(int itemId) const;
......@@ -345,6 +346,7 @@ public:
of the clip
@param dontRefreshMasterClip when false, no view refresh is attempted
*/
Q_INVOKABLE int suggestItemMove(int itemId, int trackId, int position, int snapDistance = -1);
Q_INVOKABLE int suggestClipMove(int clipId, int trackId, int position, int snapDistance = -1, bool allowViewUpdate = true);
Q_INVOKABLE int suggestCompositionMove(int compoId, int trackId, int position, int snapDistance = -1);
......
......@@ -958,7 +958,7 @@ int TrackModel::getCompositionByRow(int row) const
if (row < (int)m_allClips.size()) {
return -1;
}
// Q_ASSERT(row <= (int)m_allClips.size() + m_allCompositions.size());
Q_ASSERT(row <= (int)m_allClips.size() + m_allCompositions.size());
auto it = m_allCompositions.cbegin();
std::advance(it, row - (int)m_allClips.size());
return (*it).first;
......
......@@ -37,12 +37,18 @@ PreviewManager::PreviewManager(TimelineController *controller, Mlt::Tractor *tra
, m_tractor(tractor)
, m_previewTrack(nullptr)
, m_overlayTrack(nullptr)
, m_previewProfile(new Mlt::Profile(*m_tractor->profile()))
, m_previewTrackIndex(-1)
, m_initialized(false)
, m_abortPreview(false)
{
m_previewGatherTimer.setSingleShot(true);
m_previewGatherTimer.setInterval(200);
m_previewProfile->set_width(1024);
int height = 1024 / m_previewProfile->dar();