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

Make same track transition correcty resize on clip resize

parent 38a21d0e
......@@ -2365,6 +2365,29 @@ void TimelineModel::processGroupResize(QVariantList startPos, QVariantList endPo
if (!mixTracks.contains(tid)) {
mixTracks << tid;
}
if (right) {
if (getTrackById_const(tid)->hasEndMix(id)) {
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(id);
QPair<int, int> endPos = endData.value(id);
if (endPos.first + endPos.second <= mixData.second.secondClipInOut.first) {
Fun sync_mix_undo = [this, tid, mixData]() {
getTrackById_const(tid)->createMix(mixData.second, getTrackById_const(tid)->isAudioTrack());
return true;
};
PUSH_LAMBDA(sync_mix_undo, undo);
}
}
} else if (getTrackById_const(tid)->hasStartMix(id)) {
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(id);
QPair<int, int> endPos = endData.value(id);
if (endPos.first >= mixData.first.firstClipInOut.second) {
Fun sync_mix_undo = [this, tid, mixData]() {
getTrackById_const(tid)->createMix(mixData.first, getTrackById_const(tid)->isAudioTrack());
return true;
};
PUSH_LAMBDA(sync_mix_undo, undo);
}
}
}
}
}
......@@ -2508,14 +2531,20 @@ int TimelineModel::requestItemResizeInfo(int itemId, int in, int out, int size,
Fun temp_redo = []() { return true; };
int trackId = getItemTrackId(itemId);
if (right && size > out - in && isClip(itemId)) {
int playlist = m_allClips[itemId]->getSubPlaylistIndex();
int playlist = -1;
if (getTrackById_const(trackId)->hasEndMix(itemId)) {
playlist = m_allClips[itemId]->getSubPlaylistIndex();
}
int targetPos = in + size - 1;
if (!getTrackById_const(trackId)->isBlankAt(targetPos, playlist)) {
size = getTrackById_const(trackId)->getBlankEnd(out + 1, playlist) - in;
}
} else if (!right && size > (out - in) && isClip(itemId)) {
int targetPos = out - size;
int playlist = m_allClips[itemId]->getSubPlaylistIndex();
int playlist = -1;
if (getTrackById_const(trackId)->hasStartMix(itemId)) {
playlist = m_allClips[itemId]->getSubPlaylistIndex();
}
if (!getTrackById_const(trackId)->isBlankAt(targetPos, playlist)) {
size = out - getTrackById_const(trackId)->getBlankStart(in - 1, playlist);
}
......@@ -2590,32 +2619,46 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
return -1;
}
int in = getItemPosition(itemId);
int out = in + getItemPlaytime(itemId);
int offset = getItemPlaytime(itemId);
int out = in + offset;
size = requestItemResizeInfo(itemId, in, out, size, right, snapDistance);
offset -= size;
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Fun sync_mix = []() { return true; };
Fun sync_mix_undo = []() { return true; };
std::unordered_set<int> all_items;
QList <int> tracksWithMixes;
all_items.insert(itemId);
if (isClip(itemId) && logUndo) {
if (logUndo && isClip(itemId)) {
int tid = getItemTrackId(itemId);
if (tid > -1) {
if (right) {
if (getTrackById_const(tid)->hasEndMix(itemId)) {
sync_mix = [this, tid, logUndo]() {
getTrackById_const(tid)->syncronizeMixes(logUndo);
tracksWithMixes << tid;
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(itemId);
if (in + size <= mixData.second.secondClipInOut.first) {
Fun sync_mix_undo = [this, tid, mixData]() {
getTrackById_const(tid)->createMix(mixData.second, getTrackById_const(tid)->isAudioTrack());
return true;
};
PUSH_LAMBDA(sync_mix_undo, undo);
}
}
} else if (getTrackById_const(tid)->hasStartMix(itemId)) {
tracksWithMixes << tid;
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(itemId);
if (out - size >= mixData.first.firstClipInOut.second) {
Fun sync_mix_undo = [this, tid, mixData]() {
getTrackById_const(tid)->createMix(mixData.first, getTrackById_const(tid)->isAudioTrack());
return true;
};
PUSH_LAMBDA(sync_mix_undo, undo);
}
} else if (getTrackById_const(tid)->hasStartMix(itemId)) {
sync_mix = [this, tid, logUndo]() {
getTrackById_const(tid)->syncronizeMixes(logUndo);
return true;
};
}
}
}
PUSH_LAMBDA(sync_mix, undo);
if (!allowSingleResize && m_groups->isInGroup(itemId)) {
int groupId = m_groups->getRootId(itemId);
std::unordered_set<int> items = m_groups->getLeaves(groupId);
......@@ -2629,19 +2672,65 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
}
int start = getItemPosition(id);
int end = start + getItemPlaytime(id);
bool resizeMix = false;
if (right) {
if (out == end) {
all_items.insert(id);
resizeMix = true;
}
} else if (start == in) {
all_items.insert(id);
resizeMix = true;
}
if (logUndo && resizeMix && isClip(id)) {
qDebug()<<"=== RESIZING PROCESS MIX";
int tid = getItemTrackId(id);
if (tid > -1) {
if (right) {
if (getTrackById_const(tid)->hasEndMix(id)) {
if (!tracksWithMixes.contains(tid)) {
tracksWithMixes << tid;
}
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(id);
if (end - offset <= mixData.second.secondClipInOut.first) {
Fun sync_mix_undo = [this, tid, mixData]() {
getTrackById_const(tid)->createMix(mixData.second, getTrackById_const(tid)->isAudioTrack());
return true;
};
PUSH_LAMBDA(sync_mix_undo, undo);
}
}
} else if (getTrackById_const(tid)->hasStartMix(id)) {
if (!tracksWithMixes.contains(tid)) {
tracksWithMixes << tid;
}
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(id);
if (start - offset >= mixData.first.firstClipInOut.second) {
Fun sync_mix_undo = [this, tid, mixData]() {
getTrackById_const(tid)->createMix(mixData.first, getTrackById_const(tid)->isAudioTrack());
return true;
};
PUSH_LAMBDA(sync_mix_undo, undo);
}
}
}
}
}
}
if (logUndo && !tracksWithMixes.isEmpty()) {
sync_mix = [this, tracksWithMixes]() {
for (auto &t : tracksWithMixes) {
getTrackById_const(t)->syncronizeMixes(true);
}
return true;
};
}
bool result = true;
int finalPos = right ? in + size : out - size;
int finalSize;
int resizedCount = 0;
PUSH_LAMBDA(sync_mix, undo);
PUSH_LAMBDA(sync_mix_undo, undo);
for (int id : all_items) {
int tid = getItemTrackId(id);
if (tid > -1 && getTrackById_const(tid)->isLocked()) {
......@@ -2688,19 +2777,19 @@ bool TimelineModel::requestItemResize(int itemId, int size, bool right, bool log
if (tid > -1) {
if (right) {
if (getTrackById_const(tid)->hasEndMix(itemId)) {
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(itemId);
hasMix = true;
/*std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(itemId);
int mixDuration = mixData.second.firstClipInOut.second - (mixData.second.secondClipInOut.second - size);
m_allClips[mixData.second.secondClipId]->setMixDuration(mixDuration);
hasMix = true;
QModelIndex ix = makeClipIndexFromID(mixData.second.secondClipId);
emit dataChanged(ix, ix, {TimelineModel::MixRole});
emit dataChanged(ix, ix, {TimelineModel::MixRole});*/
}
} else if (getTrackById_const(tid)->hasStartMix(itemId)) {
hasMix = true;
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(itemId);
// We have a mix at clip start
int mixDuration = mixData.first.firstClipInOut.second - (mixData.first.secondClipInOut.second - size);
m_allClips[itemId]->setMixDuration(mixDuration);
hasMix = true;
m_allClips[itemId]->setMixDuration(qMax(1, mixDuration));
QModelIndex ix = makeClipIndexFromID(itemId);
emit dataChanged(ix, ix, {TimelineModel::MixRole});
}
......@@ -4586,3 +4675,20 @@ void TimelineModel::plantMix(int tid, Mlt::Transition &t)
getTrackById_const(tid)->getTrackService()->plant_transition(t, 0, 1);
getTrackById_const(tid)->loadMix(t);
}
bool TimelineModel::resizeStartMix(int cid, int duration)
{
Q_ASSERT(isClip(cid));
int tid = m_allClips[cid]->getCurrentTrackId();
if (tid > -1) {
std::pair<MixInfo, MixInfo> mixData = getTrackById_const(tid)->getMixInfo(cid);
if (mixData.first.firstClipId > -1) {
int clipToResize = mixData.first.firstClipId;
Q_ASSERT(isClip(clipToResize));
int updatedDuration = m_allClips[cid]->getPosition() + duration - m_allClips[clipToResize]->getPosition();
int result = requestItemResize(clipToResize, updatedDuration, true, true, 0, false);
return result > -1;
}
}
return false;
}
......@@ -694,6 +694,7 @@ public:
void importMasterEffects(std::weak_ptr<Mlt::Service> service);
/** @brief Create a mix selection with currently selected clip */
bool mixClip(int idToMove = -1);
Q_INVOKABLE bool resizeStartMix(int cid, int duration);
protected:
/* @brief Register a new track. This is a call-back meant to be called from TrackModel
......
......@@ -1045,6 +1045,9 @@ int TrackModel::getBlankStart(int position)
int TrackModel::getBlankStart(int position, int track)
{
if (track == -1) {
return getBlankStart(position);
}
READ_LOCK();
int result = 0;
if (!m_playlists[track].is_blank_at(position)) {
......@@ -1060,6 +1063,9 @@ int TrackModel::getBlankStart(int position, int track)
int TrackModel::getBlankEnd(int position, int track)
{
if (track == -1) {
return getBlankEnd(position);
}
READ_LOCK();
// Q_ASSERT(m_playlists[track].is_blank_at(position));
if (!m_playlists[track].is_blank_at(position)) {
......
......@@ -331,20 +331,110 @@ Rectangle {
//clip: true
property bool showDetails: (!clipRoot.selected || !effectRow.visible) && container.height > 2.2 * labelRect.height
Rectangle {
Item {
// Mix indicator
id: mixContainer
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: clipRoot.mixDuration * timeScale
color: 'red'
//opacity: 0.5
Text {
text: clipRoot.mixDuration
anchors {
bottom: parent.bottom
width: clipRoot.mixDuration * clipRoot.timeScale
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
visible: clipRoot.mixDuration > 0
gradient: Gradient {
GradientStop { position: 0.0; color: "transparent" }
GradientStop { position: 1.0; color: "red" }
}
Text {
anchors.bottom: parent.bottom
text: clipRoot.mixDuration
}
opacity: 0.7
MouseArea {
// Left resize handle
id: trimInMixArea
anchors.left: parent.left
anchors.leftMargin: clipRoot.mixDuration * clipRoot.timeScale
height: parent.height
width: root.baseUnit / 2
visible: root.activeTool === 0
property int previousMix
enabled: !isLocked && (pressed || clipRoot.width > 3 * width)
hoverEnabled: true
drag.target: trimInMixArea
drag.axis: Drag.XAxis
drag.smoothed: false
property bool sizeChanged: false
cursorShape: (containsMouse ? Qt.SizeHorCursor : Qt.ClosedHandCursor);
onPressed: {
previousMix = clipRoot.mixDuration
root.autoScrolling = false
mixOut.opacity = 1
anchors.left = undefined
parent.anchors.right = undefined
}
onReleased: {
controller.resizeStartMix(clipRoot.clipId, Math.round(Math.max(0, x) / clipRoot.timeScale))
root.autoScrolling = timeline.autoScroll
if (sizeChanged) {
sizeChanged = false
}
anchors.left = parent.left
parent.anchors.right = mixContainer.right
mixOut.opacity = 0.5
}
onPositionChanged: {
if (mouse.buttons === Qt.LeftButton) {
var currentFrame = Math.round(x / clipRoot.timeScale)
if (currentFrame != previousMix) {
parent.width = currentFrame * clipRoot.timeScale
sizeChanged = true
//TODO: resize mix's other clip
//clipRoot.trimmingIn(clipRoot, newDuration, mouse, shiftTrim, controlTrim)
}
}
}
onEntered: {
if (!pressed) {
mixOut.opacity = 1
}
}
onExited: {
mixOut.opacity = 0.5
}
Rectangle {
id: mixOut
anchors.left: parent.left
width: clipRoot.border.width
height: parent.height
color: 'blue'
opacity: 0.5
Drag.active: trimInMixArea.drag.active
Drag.proposedAction: Qt.MoveAction
visible: trimInMixArea.pressed || (root.activeTool === 0 && !mouseArea.drag.active && parent.enabled)
ToolTip {
visible: trimInMixArea.containsMouse && !trimInMixArea.pressed
delay: 1000
timeout: 5000
background: Rectangle {
color: activePalette.alternateBase
border.color: activePalette.light
}
contentItem: Label {
color: activePalette.text
font: miniFont
text: i18n("Mix:%1", timeline.simplifiedTC(clipRoot.mixDuration))
}
}
}
}
}
}
Repeater {
......
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