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

Fix copy/paste of clips with same track transitions

parent afff6143
Pipeline #80361 canceled with stage
......@@ -1300,6 +1300,7 @@ QDomElement ClipModel::toXml(QDomDocument &document)
container.setAttribute(QStringLiteral("out"), getOut());
container.setAttribute(QStringLiteral("position"), getPosition());
container.setAttribute(QStringLiteral("state"), m_currentState);
container.setAttribute(QStringLiteral("playlist"), m_subPlaylistIndex);
if (auto ptr = m_parent.lock()) {
int trackId = ptr->getTrackPosition(m_currentTrackId);
container.setAttribute(QStringLiteral("track"), trackId);
......
......@@ -1453,11 +1453,17 @@ QString TimelineFunctions::copyClips(const std::shared_ptr<TimelineItemModel> &t
offset = timeline->getItemPosition(id);
}
if (timeline->isClip(id)) {
container.appendChild(timeline->m_allClips[id]->toXml(copiedItems));
QDomElement clipXml = timeline->m_allClips[id]->toXml(copiedItems);
container.appendChild(clipXml);
const QString bid = timeline->m_allClips[id]->binId();
if (!binIds.contains(bid)) {
binIds << bid;
}
int tid = timeline->getItemTrackId(id);
if (timeline->getTrackById_const(tid)->hasStartMix(id)) {
QDomElement mix = timeline->getTrackById_const(tid)->mixXml(copiedItems, id);
clipXml.appendChild(mix);
}
} else if (timeline->isComposition(id)) {
container.appendChild(timeline->m_allCompositions[id]->toXml(copiedItems));
} else if (timeline->isSubTitle(id)) {
......@@ -1810,6 +1816,7 @@ bool TimelineFunctions::pasteTimelineClips(const std::shared_ptr<TimelineItemMod
int offset = copiedItems.documentElement().attribute(QStringLiteral("offset")).toInt();
bool res = true;
std::unordered_map<int, int> correspondingIds;
QDomElement documentMixes = copiedItems.createElement(QStringLiteral("mixes"));
for (int i = 0; i < clips.count(); i++) {
QDomElement prod = clips.at(i).toElement();
QString originalId = prod.attribute(QStringLiteral("binid"));
......@@ -1847,21 +1854,21 @@ bool TimelineFunctions::pasteTimelineClips(const std::shared_ptr<TimelineItemMod
// This is a timeremap
timeline->m_allClips[newId]->useTimeRemapProducer(true, timeline_undo, timeline_redo);
if (timeline->m_allClips[newId]->m_producer->parent().type() == mlt_service_chain_type) {
Mlt::Chain fromChain(timeline->m_allClips[newId]->m_producer->parent());
int count = fromChain.link_count();
for (int i = 0; i < count; i++) {
QScopedPointer<Mlt::Link> fromLink(fromChain.link(i));
if (fromLink && fromLink->is_valid() && fromLink->get("mlt_service")) {
if (fromLink->get("mlt_service") == QLatin1String("timeremap")) {
// Found a timeremap effect, read params
fromLink->set("map", prod.attribute(QStringLiteral("timemap")).toUtf8().constData());
fromLink->set("pitch", prod.attribute(QStringLiteral("timepitch")).toInt());
fromLink->set("image_mode", prod.attribute(QStringLiteral("timeblend")).toUtf8().constData());
break;
Mlt::Chain fromChain(timeline->m_allClips[newId]->m_producer->parent());
int count = fromChain.link_count();
for (int i = 0; i < count; i++) {
QScopedPointer<Mlt::Link> fromLink(fromChain.link(i));
if (fromLink && fromLink->is_valid() && fromLink->get("mlt_service")) {
if (fromLink->get("mlt_service") == QLatin1String("timeremap")) {
// Found a timeremap effect, read params
fromLink->set("map", prod.attribute(QStringLiteral("timemap")).toUtf8().constData());
fromLink->set("pitch", prod.attribute(QStringLiteral("timepitch")).toInt());
fromLink->set("image_mode", prod.attribute(QStringLiteral("timeblend")).toUtf8().constData());
break;
}
}
}
}
}
}
if (timeline->m_allClips[newId]->m_endlessResize) {
......@@ -1872,6 +1879,10 @@ bool TimelineFunctions::pasteTimelineClips(const std::shared_ptr<TimelineItemMod
}
timeline->m_allClips[newId]->setInOut(in, out);
int targetId = prod.attribute(QStringLiteral("id")).toInt();
int targetPlaylist = prod.attribute(QStringLiteral("playlist")).toInt();
if (targetPlaylist > 0) {
timeline->m_allClips[newId]->setSubPlaylistIndex(targetPlaylist, curTrackId);
}
correspondingIds[targetId] = newId;
res = res && timeline->getTrackById(curTrackId)->requestClipInsertion(newId, position + pos, true, true, timeline_undo, timeline_redo);
// paste effects
......@@ -1882,6 +1893,40 @@ bool TimelineFunctions::pasteTimelineClips(const std::shared_ptr<TimelineItemMod
qDebug()<<"=== COULD NOT PASTE CLIP: "<<newId<<" ON TRACK: "<<curTrackId<<" AT: "<<position;
break;
}
// Mixes (same track transitions)
if (prod.hasChildNodes()) {
QDomNodeList mixes = prod.elementsByTagName(QLatin1String("mix"));
if (!mixes.isEmpty()) {
QDomElement mix = mixes.at(0).toElement();
if (mix.tagName() == QLatin1String("mix")) {
mix.setAttribute(QStringLiteral("tid"), curTrackId);
documentMixes.appendChild(mix);
}
}
}
}
// Process mix insertion
QDomNodeList mixes = documentMixes.childNodes();
for (int k = 0; k < mixes.count(); k++) {
QDomElement mix = mixes.at(k).toElement();
int originalFirstClipId = mix.attribute(QLatin1String("firstClip")).toInt();
int originalSecondClipId = mix.attribute(QLatin1String("secondClip")).toInt();
if (correspondingIds.count(originalFirstClipId) > 0 && correspondingIds.count(originalSecondClipId) > 0) {
QVector<QPair<QString, QVariant>> params;
QDomNodeList paramsXml = mix.elementsByTagName(QLatin1String("param"));
for (int j = 0; j < paramsXml.count(); j++) {
QDomElement e = paramsXml.at(j).toElement();
params.append({e.attribute(QLatin1String("name")), e.text()});
}
std::pair<QString,QVector<QPair<QString, QVariant>>> mixParams = {mix.attribute(QLatin1String("asset")),params};
MixInfo mixData;
mixData.firstClipId = correspondingIds[originalFirstClipId];
mixData.secondClipId = correspondingIds[originalSecondClipId];
mixData.firstClipInOut.second = mix.attribute(QLatin1String("mixEnd")).toInt();
mixData.secondClipInOut.first = mix.attribute(QLatin1String("mixStart")).toInt();
mixData.mixOffset = mix.attribute(QLatin1String("mixOffset")).toInt();
timeline->getTrackById_const(mix.attribute(QLatin1String("tid")).toInt())->createMix(mixData, mixParams, true);
}
}
// Compositions
if (res) {
......
......@@ -2077,7 +2077,7 @@ bool TrackModel::createMix(MixInfo info, std::pair<QString,QVector<QPair<QString
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();
int mixCutPos = info.mixOffset; //movedClip->getMixCutPosition();
t->set_in_and_out(in, out);
t->set("kdenlive:mixcut", mixCutPos);
t->set("kdenlive_id", assetId.toUtf8().constData());
......@@ -2293,6 +2293,34 @@ bool TrackModel::hasEndMix(int cid) const
return m_mixList.contains(cid);
}
QDomElement TrackModel::mixXml(QDomDocument &document, int cid) const
{
QDomElement container = document.createElement(QStringLiteral("mix"));
int firstClipId = m_mixList.key(cid);
container.setAttribute(QStringLiteral("firstClip"), firstClipId);
container.setAttribute(QStringLiteral("secondClip"), cid);
if (auto ptr = m_parent.lock()) {
std::shared_ptr<ClipModel> clip = ptr->getClipPtr(firstClipId);
container.setAttribute(QStringLiteral("firstClipPosition"), clip->getPosition());
}
std::shared_ptr<AssetParameterModel> asset = m_sameCompositions.at(cid);
const QString assetId = m_sameCompositions.at(cid)->getAssetId();
QVector<QPair<QString, QVariant>> params = m_sameCompositions.at(cid)->getAllParameters();
container.setAttribute(QStringLiteral("asset"), assetId);
for (const auto &p : qAsConst(params)) {
QDomElement para = document.createElement(QStringLiteral("param"));
para.setAttribute(QStringLiteral("name"), p.first);
QDomText val = document.createTextNode(p.second.toString());
para.appendChild(val);
container.appendChild(para);
}
std::pair<MixInfo, MixInfo> mixData = getMixInfo(cid);
container.setAttribute(QStringLiteral("mixStart"), mixData.first.secondClipInOut.first);
container.setAttribute(QStringLiteral("mixEnd"), mixData.first.firstClipInOut.second);
container.setAttribute(QStringLiteral("mixOffset"), mixData.first.mixOffset);
return container;
}
bool TrackModel::loadMix(Mlt::Transition *t)
{
int in = t->get_in();
......
......@@ -330,6 +330,8 @@ protected:
bool hasStartMix(int cid) const;
/** @brief Returns true if this clip has a mix at end */
bool hasEndMix(int cid) const;
/** @brief Returns all mix info as xml */
QDomElement mixXml(QDomDocument &document, int cid) const;
public slots:
/** Delete the current track and all its associated clips */
......
Supports Markdown
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