Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Changing composition track now works with undo/redo

Reintroduce automatic track for compositions
Remove buggy track indicator for compositions
parent c5b175fa
......@@ -170,6 +170,7 @@ protected:
signals:
void modelChanged();
void compositionTrackChanged();
void replugEffect(std::shared_ptr<AssetParameterModel> asset);
void rebuildEffect(std::shared_ptr<AssetParameterModel> asset);
};
......
......@@ -527,6 +527,11 @@ QPair<int, int> Core::getCompositionATrack(int cid) const
return m_mainWindow->getCurrentTimeline()->controller()->getCompositionATrack(cid);
}
bool Core::compositionAutoTrack(int cid) const
{
return m_mainWindow->getCurrentTimeline()->controller()->compositionAutoTrack(cid);
}
void Core::setCompositionATrack(int cid, int aTrack)
{
if (!m_guiConstructed) return;
......
......@@ -156,6 +156,9 @@ public:
/** @brief Returns the composition A track (MLT index / Track id) */
QPair<int, int> getCompositionATrack(int cid) const;
void setCompositionATrack(int cid, int aTrack);
/* @brief Return true if composition's a_track is automatic (no forced track)
*/
bool compositionAutoTrack(int cid) const;
std::shared_ptr<DocUndoStack> undoStack();
double getClipSpeed(int id) const;
void invalidateItem(ObjectId itemId);
......
......@@ -143,6 +143,18 @@ int CompositionModel::getATrack() const
return a_track == -1 ? -1 : service()->get_int("a_track");
}
void CompositionModel::setForceTrack(bool force)
{
READ_LOCK();
service()->set("force_track", force ? 1 : 0);
}
int CompositionModel::getForcedTrack() const
{
QWriteLocker locker(&m_lock);
return (service()->get_int("force_track") == 0 || a_track == -1) ? -1 : service()->get_int("a_track");
}
void CompositionModel::setATrack(int trackMltPosition, int trackId)
{
QWriteLocker locker(&m_lock);
......@@ -151,6 +163,7 @@ void CompositionModel::setATrack(int trackMltPosition, int trackId)
if (a_track >= 0) {
service()->set("a_track", trackMltPosition);
}
emit compositionTrackChanged();
}
KeyframeModel *CompositionModel::getEffectKeyframeModel()
......
......@@ -65,9 +65,15 @@ public:
/* @brief Returns the id of the second track involved in the composition (a_track in mlt's vocabulary, the b_track beeing the track where the composition is
inserted)
Important: this function returns a kdenlive id, you cannot use it directly in Mlt functions. Use timelinemodel::getTrackPosition to retrieve mlt's index
*/
int getATrack() const;
/* @brief Defines the forced_track property. If true, the a_track will not change when composition
* is moved to another track. When false, the a_track will automatically change to lower video track
*/
void setForceTrack(bool force);
/* @brief Returns the id of the second track involved in the composition (a_track) or -1 if the a_track should be automatically updated when the composition changes track
*/
int getForcedTrack() const;
/* @brief Sets the id of the second track involved in the composition*/
void setATrack(int trackMltPosition, int trackId);
......
......@@ -465,3 +465,48 @@ bool TimelineFunctions::requestSplitAudio(std::shared_ptr<TimelineItemModel> tim
pCore->pushUndo(undo, redo, i18n("Split Audio"));
return true;
}
void TimelineFunctions::setCompositionATrack(std::shared_ptr<TimelineItemModel> timeline, int cid, int aTrack)
{
std::function<bool(void)> undo = []() { return true; };
std::function<bool(void)> redo = []() { return true; };
std::shared_ptr<CompositionModel>compo = timeline->getCompositionPtr(cid);
int previousATrack = compo->getATrack();
int previousAutoTrack = compo->getForcedTrack() == -1;
bool autoTrack = aTrack < 0;
if (autoTrack) {
// Automatic track compositing, find lower video track
aTrack = timeline->getPreviousVideoTrackPos(compo->getCurrentTrackId());
}
int start = timeline->getItemPosition(cid);
int end = start + timeline->getItemPlaytime(cid);
Fun local_redo = [timeline, cid, aTrack, autoTrack, start, end]() {
QScopedPointer<Mlt::Field> field(timeline->m_tractor->field());
field->lock();
timeline->getCompositionPtr(cid)->setForceTrack(!autoTrack);
timeline->getCompositionPtr(cid)->setATrack(aTrack, aTrack <= 0 ? -1 : timeline->getTrackIndexFromPosition(aTrack - 1));
field->unlock();
QModelIndex modelIndex = timeline->makeCompositionIndexFromID(cid);
timeline->dataChanged(modelIndex, modelIndex, {TimelineModel::ItemATrack});
timeline->invalidateZone(start, end);
timeline->checkRefresh(start, end);
return true;
};
Fun local_undo = [timeline, cid, previousATrack, previousAutoTrack, start, end]() {
QScopedPointer<Mlt::Field> field(timeline->m_tractor->field());
field->lock();
timeline->getCompositionPtr(cid)->setForceTrack(!previousAutoTrack);
timeline->getCompositionPtr(cid)->setATrack(previousATrack, previousATrack<= 0 ? -1 : timeline->getTrackIndexFromPosition(previousATrack - 1));
field->unlock();
QModelIndex modelIndex = timeline->makeCompositionIndexFromID(cid);
timeline->dataChanged(modelIndex, modelIndex, {TimelineModel::ItemATrack});
timeline->invalidateZone(start, end);
timeline->checkRefresh(start, end);
return true;
};
if (local_redo()) {
PUSH_LAMBDA(local_undo, undo);
PUSH_LAMBDA(local_redo, redo);
}
pCore->pushUndo(undo, redo, i18n("Change Composition Track"));
}
......@@ -66,6 +66,7 @@ struct TimelineFunctions
static bool changeClipState(std::shared_ptr<TimelineItemModel> timeline, int clipId, PlaylistState::ClipState status);
static bool changeClipState(std::shared_ptr<TimelineItemModel> timeline, int clipId, PlaylistState::ClipState status, Fun &undo, Fun &redo);
static bool requestSplitAudio(std::shared_ptr<TimelineItemModel> timeline, int clipId, int audioTarget);
static void setCompositionATrack(std::shared_ptr<TimelineItemModel> timeline, int cid, int aTrack);
};
#endif
......@@ -353,7 +353,7 @@ QVariant TimelineItemModel::data(const QModelIndex &index, int role) const
case ShowKeyframesRole:
return compo->showKeyframes();
case ItemATrack:
return compo->getATrack();
return compo->getForcedTrack();
case MarkersRole: {
QVariantList markersList;
return markersList;
......
......@@ -518,7 +518,7 @@ 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]->getATrack(), position, false, undo, redo);
bool possible = requestCompositionMove(compoId, trackId, m_allCompositions[compoId]->getForcedTrack(), position, false, undo, redo);
qDebug() << "Original move success" << possible;
if (possible) {
bool undone = undo();
......@@ -820,7 +820,7 @@ bool TimelineModel::requestGroupMove(int clipId, int groupId, int delta_track, i
ok = requestClipMove(clip, target_track, target_position, updateView, finalMove, undo, redo);
} else {
int target_position = m_allCompositions[clip]->getPosition() + delta_pos;
ok = requestCompositionMove(clip, target_track, -1, target_position, updateView, undo, redo);
ok = requestCompositionMove(clip, target_track, m_allCompositions[clip]->getForcedTrack(), target_position, updateView, undo, redo);
}
} else {
qDebug() << "// ABORTING; MOVE TRIED ON TRACK: " << target_track_position << "..\n..\n..";
......@@ -1583,7 +1583,7 @@ bool TimelineModel::requestCompositionMove(int compoId, int trackId, int positio
int min = getCompositionPosition(compoId);
int max = min + getCompositionPlaytime(compoId);
int tk = getCompositionTrackId(compoId);
bool res = requestCompositionMove(compoId, trackId, m_allCompositions[compoId]->getATrack(), position, updateView, undo, redo);
bool res = requestCompositionMove(compoId, trackId, m_allCompositions[compoId]->getForcedTrack(), position, updateView, undo, redo);
if (tk > -1) {
min = qMin(min, getCompositionPosition(compoId));
max = qMax(max, getCompositionPosition(compoId));
......
......@@ -87,12 +87,6 @@ Item {
}
}
onATrackChanged: {
if (compositionRoot.aTrack > 0 && compositionRoot.trackId > 0) {
targetTrack.y = root.getTrackYFromMltIndex(compositionRoot.aTrack) - root.getTrackYFromId(compositionRoot.trackId)
}
}
onKeyframeModelChanged: {
if (effectRow.keyframecanvas) {
effectRow.keyframecanvas.requestPaint()
......@@ -121,11 +115,6 @@ Item {
displayHeight = track.height / 2
compositionRoot.trackId = parentTrack.trackId
}
onTrackIdChanged: {
if (compositionRoot.aTrack > 0 && compositionRoot.trackId > 0) {
targetTrack.y = root.getTrackYFromMltIndex(compositionRoot.aTrack) - root.getTrackYFromId(compositionRoot.trackId)
}
}
SystemPalette { id: activePalette }
Rectangle {
......@@ -149,15 +138,14 @@ Item {
Rectangle {
// text background
id: labelRect
color: 'lightgray'
color: compositionRoot.aTrack >= 0 ? 'yellow' : 'lightgray'
opacity: 0.7
anchors.top: container.top
// + ((isAudio || !settings.timelineShowThumbnails) ? 0 : inThumbnail.width)
width: label.width + 2
height: label.height
Text {
id: label
text: clipName
text: clipName + (compositionRoot.aTrack >= 0 ? ' > ' + timeline.getTrackNameFromMltIndex(compositionRoot.aTrack) : '')
font.pixelSize: root.baseUnit
anchors {
top: labelRect.top
......@@ -386,28 +374,4 @@ Item {
}
}
}
// target track
Rectangle {
id: targetTrack
width: displayRect.width
gradient: Gradient {
GradientStop { position: 0.0; color: selected ? 'red' : 'mediumpurple' }
GradientStop { position: 1.0; color: "#00000000" }
}
visible: compositionRoot.aTrack > 0 && compositionRoot.trackId > 0
y: root.getTrackYFromMltIndex(compositionRoot.aTrack) - parentTrack.mapToItem(null, 0, 0).y + ruler.height
//y: root.getTrackYFromMltIndex(compositionRoot.aTrack) - root.getTrackYFromId(compositionRoot.trackId)
height: clabel.height + 4
Text {
id: clabel
text: timeline.getTrackNameFromMltIndex(compositionRoot.aTrack)
font.pixelSize: root.baseUnit
anchors {
top: targetTrack.top
topMargin: 2
leftMargin: 2
}
color: 'white'
}
}
}
......@@ -958,13 +958,13 @@ QPair<int, int> TimelineController::getCompositionATrack(int cid) const
void TimelineController::setCompositionATrack(int cid, int aTrack)
{
QScopedPointer<Mlt::Field> field(m_model->m_tractor->field());
field->lock();
m_model->getCompositionPtr(cid)->setATrack(aTrack, aTrack <= 0 ? -1 : m_model->getTrackIndexFromPosition(aTrack - 1));
field->unlock();
refreshItem(cid);
QModelIndex modelIndex = m_model->makeCompositionIndexFromID(cid);
m_model->dataChanged(modelIndex, modelIndex, {TimelineModel::ItemATrack});
TimelineFunctions::setCompositionATrack(m_model, cid, aTrack);
}
bool TimelineController::compositionAutoTrack(int cid) const
{
std::shared_ptr<CompositionModel> compo = m_model->getCompositionPtr(cid);
return compo && compo->getForcedTrack() == -1;
}
const QString TimelineController::getClipBinId(int clipId) const
......
......@@ -278,6 +278,9 @@ public:
*/
QPair<int, int> getCompositionATrack(int cid) const;
void setCompositionATrack(int cid, int aTrack);
/* @brief Return true if composition's a_track is automatic (no forced track)
*/
bool compositionAutoTrack(int cid) const;
const QString getClipBinId(int clipId) const;
void focusItem(int itemId);
/* @brief Create and display a split clip view to compare effect
......
......@@ -39,22 +39,25 @@ void TransitionStackView::setModel(const std::shared_ptr<AssetParameterModel> &m
{
QHBoxLayout *lay = new QHBoxLayout;
m_trackBox = new QComboBox(this);
m_trackBox->addItem(i18n("Background"), 0);
QMapIterator<int, QString> i(pCore->getVideoTrackNames());
QPair<int, int> aTrack = pCore->getCompositionATrack(model->getOwnerId().second);
m_trackBox->addItem(i18n("Automatic"), -1);
while (i.hasNext()) {
i.next();
if (i.key() != aTrack.second) {
m_trackBox->addItem(i.value(), i.key());
}
}
m_trackBox->addItem(i18n("Background"), 0);
AssetParameterView::setModel(model, range, frameSize, addSpacer);
m_trackBox->setCurrentIndex(m_trackBox->findData(aTrack.first));
if (!pCore->compositionAutoTrack(model->getOwnerId().second)) {
m_trackBox->setCurrentIndex(m_trackBox->findData(aTrack.first));
}
QLabel *title = new QLabel(i18n("Composition track: "), this);
lay->addWidget(title);
lay->addWidget(m_trackBox);
m_lay->insertLayout(0, lay);
connect(model.get(), &AssetParameterModel::compositionTrackChanged, this, &TransitionStackView::checkCompoTrack);
connect(m_trackBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTrack(int)));
connect(this, &AssetParameterView::seekToPos, [this](int pos) {
// at this point, the effects returns a pos relative to the clip. We need to convert it to a global time
......@@ -82,3 +85,13 @@ void TransitionStackView::setRange(int in, int out)
{
AssetParameterView::setRange(QPair<int, int>(in, out));
}
void TransitionStackView::checkCompoTrack()
{
bool autoTrack = pCore->compositionAutoTrack(m_model->getOwnerId().second);
QPair<int, int> aTrack = autoTrack ? QPair<int, int>(-1, -1) : pCore->getCompositionATrack(m_model->getOwnerId().second);
if (m_trackBox->currentData().toInt() != aTrack.first) {
const QSignalBlocker blocker(m_trackBox);
m_trackBox->setCurrentIndex(m_trackBox->findData(aTrack.first));
}
}
......@@ -39,6 +39,7 @@ public:
private slots:
void updateTrack(int newTrack);
void checkCompoTrack();
signals:
void seekToTransPos(int pos);
......
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