Nicer visual for mix, fix resizing grouped mix didn't update grouped mix cut position.

Allow easy add of a mix by double clicking a clip's resize handle
parent 1432dd62
......@@ -805,7 +805,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
return true;
}
bool TimelineModel::mixClip(int idToMove)
bool TimelineModel::mixClip(int idToMove, int delta)
{
int selectedTrack = -1;
std::unordered_set<int> initialSelection = getCurrentSelection();
......@@ -835,20 +835,24 @@ bool TimelineModel::mixClip(int idToMove)
int nextClip = -1;
previousClip = -1;
// Check if clip already has a mix
if (getTrackById_const(selectedTrack)->hasStartMix(s)) {
if (delta > -1 && getTrackById_const(selectedTrack)->hasStartMix(s)) {
if (getTrackById_const(selectedTrack)->hasEndMix(s)) {
continue;
}
nextClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition + clipDuration + 1);
} else if (getTrackById_const(selectedTrack)->hasEndMix(s)) {
} else if (delta < 1 && getTrackById_const(selectedTrack)->hasEndMix(s)) {
previousClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition - 1);
if (previousClip > -1 && getTrackById_const(selectedTrack)->hasEndMix(previousClip)) {
// Could happen if 2 clips before are mixed to full length
previousClip = -1;
}
} else {
previousClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition - 1);
nextClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition + clipDuration + 1);
if (delta < 1) {
previousClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition - 1);
}
if (delta > -1) {
nextClip = getTrackById_const(selectedTrack)->getClipByPosition(mixPosition + clipDuration + 1);
}
}
if (previousClip > -1 && nextClip > -1) {
// We have a clip before and a clip after, check timeline cursor position to decide where to mix
......@@ -2863,6 +2867,26 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
PUSH_LAMBDA(sync_end_mix_undo2, sync_end_mix_undo);
}
PUSH_LAMBDA(sync_mix_undo, undo);
} else {
// Mix was resized, update cut position
int currentMixDuration = m_allClips[mixData.second.secondClipId]->getMixDuration();
int currentMixCut = m_allClips[mixData.second.secondClipId]->getMixCutPosition();
Fun adjust_mix2 = [this, tid, mixData, currentMixCut, id]() {
MixInfo secondMixData = getTrackById_const(tid)->getMixInfo(id).second;
int offset = mixData.second.firstClipInOut.second - secondMixData.firstClipInOut.second;
getTrackById_const(tid)->setMixDuration(secondMixData.secondClipId, secondMixData.firstClipInOut.second - secondMixData.secondClipInOut.first, currentMixCut - offset);
QModelIndex ix = makeClipIndexFromID(secondMixData.secondClipId);
emit dataChanged(ix, ix, {TimelineModel::MixRole,TimelineModel::MixCutRole});
return true;
};
Fun adjust_mix_undo = [this, tid, mixData, currentMixCut, currentMixDuration]() {
getTrackById_const(tid)->setMixDuration(mixData.second.secondClipId, currentMixDuration, currentMixCut);
QModelIndex ix = makeClipIndexFromID(mixData.second.secondClipId);
emit dataChanged(ix, ix, {TimelineModel::MixRole,TimelineModel::MixCutRole});
return true;
};
PUSH_LAMBDA(adjust_mix2, adjust_mix);
PUSH_LAMBDA(adjust_mix_undo, undo);
}
}
} else if (getTrackById_const(tid)->hasStartMix(id)) {
......
......@@ -700,8 +700,8 @@ public:
void prepareClose();
/** @brief Import project's master effects */
void importMasterEffects(std::weak_ptr<Mlt::Service> service);
/** @brief Create a mix selection with currently selected clip */
bool mixClip(int idToMove = -1);
/** @brief Create a mix selection with currently selected clip. If delta = -1, mix with previous clip, +1 with next clip and 0 will check cursor position*/
bool mixClip(int idToMove = -1, int delta = 0);
Q_INVOKABLE bool resizeStartMix(int cid, int duration);
protected:
......
......@@ -20,6 +20,7 @@ import QtQuick 2.11
import QtQuick.Controls 2.4
import Kdenlive.Controls 1.0
import QtQml.Models 2.11
import QtQuick.Shapes 1.11
import QtQuick.Window 2.2
import 'Timeline.js' as Logic
import com.enums 1.0
......@@ -314,7 +315,7 @@ Rectangle {
// Thumbs container
id: thumbsLoader
anchors.fill: parent
anchors.leftMargin: parentTrack.isAudio ? 0 : clipRoot.border.width
anchors.leftMargin: parentTrack.isAudio ? 0 : clipRoot.border.width + mixContainer.width
anchors.rightMargin: parentTrack.isAudio ? 0 : clipRoot.border.width
anchors.topMargin: clipRoot.border.width
anchors.bottomMargin: clipRoot.border.width
......@@ -341,20 +342,36 @@ Rectangle {
width: clipRoot.mixDuration * clipRoot.timeScale
Rectangle {
id: mixBackground
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
color: "mediumpurple"
Shape {
anchors.fill: mixBackground
anchors.margins: border.width
asynchronous: true
opacity: 0.4
ShapePath {
fillColor: clipRoot.color
strokeColor: "transparent"
PathLine {x: 0; y: mixBackground.height}
PathLine {x: mixBackground.width; y: mixBackground.height}
PathLine {x: mixBackground.width; y: 0}
PathLine {x: 0; y: mixBackground.height}
}
ShapePath {
fillColor: "#fff"
strokeColor: "transparent"
PathLine {x: 0; y: 0}
PathLine {x: mixBackground.width; y: mixBackground.height}
PathLine {x: mixBackground.width; y: 0}
}
}
opacity: mixArea.containsMouse || root.selectedMix == clipRoot.clipId ? 1 : 0.5
opacity: mixArea.containsMouse || trimInMixArea.pressed || trimInMixArea.containsMouse || root.selectedMix == clipRoot.clipId ? 1 : 0.7
border.color: root.selectedMix == clipRoot.clipId ? root.selectionColor : "transparent"
border.width: 2
MouseArea {
......@@ -364,7 +381,6 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
console.log('MIX CLICKED: ', clipRoot.clipId)
controller.requestMixSelection(clipRoot.clipId);
}
}
......@@ -375,7 +391,7 @@ Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 2
color: "#000"
color: "indigo"
}
MouseArea {
// Left resize handle
......@@ -409,6 +425,7 @@ Rectangle {
}
anchors.left = parent.left
parent.anchors.right = mixContainer.right
mixBackground.anchors.bottom = mixContainer.bottom
mixOut.opacity = 0.5
mixCutPos.anchors.right = mixCutPos.parent.right
}
......@@ -421,6 +438,12 @@ Rectangle {
//TODO: resize mix's other clip
//clipRoot.trimmingIn(clipRoot, newDuration, mouse, shiftTrim, controlTrim)
}
if (x < mixCutPos.x) {
// This will delete the mix
mixBackground.anchors.bottom = mixContainer.top
} else {
mixBackground.anchors.bottom = mixContainer.bottom
}
}
}
onEntered: {
......@@ -429,15 +452,16 @@ Rectangle {
}
}
onExited: {
mixOut.opacity = 0.5
if (!pressed) {
mixOut.opacity = 0
}
}
Rectangle {
id: mixOut
anchors.left: parent.left
width: clipRoot.border.width
height: parent.height
color: 'blue'
opacity: 0.5
height: mixContainer.height
color: 'darkorchid'
opacity: 0
Drag.active: trimInMixArea.drag.active
Drag.proposedAction: Qt.MoveAction
visible: trimInMixArea.pressed || (root.activeTool === 0 && !mouseArea.drag.active && parent.enabled)
......@@ -555,6 +579,9 @@ Rectangle {
sizeChanged = false
}
}
onDoubleClicked: {
timeline.mixClip(clipRoot.clipId, -1)
}
onPositionChanged: {
if (mouse.buttons === Qt.LeftButton) {
var currentFrame = Math.round((clipRoot.x + (x + clipRoot.border.width)) / timeScale)
......@@ -644,6 +671,9 @@ Rectangle {
sizeChanged = false
}
}
onDoubleClicked: {
timeline.mixClip(clipRoot.clipId, 1)
}
onPositionChanged: {
if (mouse.buttons === Qt.LeftButton) {
var newDuration = Math.round((x + width) / timeScale)
......@@ -715,6 +745,7 @@ Rectangle {
Item {
// Clipping container for clip names
anchors.fill: parent
anchors.leftMargin: mixContainer.width
clip: true
Rectangle {
// Clip name background
......@@ -1078,7 +1109,7 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
drag.target: fadeInMouseArea
drag.minimumX: - 2*root.baseUnit
drag.minimumX: - Math.ceil(width / 2)
drag.maximumX: container.width - width / 2
drag.axis: Drag.XAxis
drag.smoothed: false
......@@ -1099,22 +1130,13 @@ Rectangle {
onReleased: {
root.autoScrolling = timeline.autoScroll
fadeInTriangle.opacity = 0.4
if (startFadeIn == 0 && x < 0) {
timeline.mixClip(clipRoot.clipId)
} else {
timeline.adjustFade(clipRoot.clipId, 'fadein', clipRoot.fadeIn, startFadeIn)
}
timeline.adjustFade(clipRoot.clipId, 'fadein', clipRoot.fadeIn, startFadeIn)
bubbleHelp.hide()
anchors.left = container.left
}
onPositionChanged: {
if (mouse.buttons === Qt.LeftButton) {
var delta = Math.round((x + width / 2) / timeScale)
if (delta < root.baseUnit) {
fadeInControl.radius = 0
} else {
fadeInControl.radius = fadeInControl.width / 2
}
var duration = Math.max(0, delta)
duration = Math.min(duration, clipRoot.clipDuration - 1)
if (duration != clipRoot.fadeIn) {
......
......@@ -3682,8 +3682,8 @@ void TimelineController::addTracks(int videoTracks, int audioTracks)
}
}
void TimelineController::mixClip(int cid)
void TimelineController::mixClip(int cid, int delta)
{
m_model->mixClip(cid);
m_model->mixClip(cid, delta);
}
......@@ -560,8 +560,8 @@ public:
void addTracks(int videoTracks, int audioTracks);
/** @brief Get in/out of currently selected items */
QPoint selectionInOut() const;
/** @brief Create same track transition between clips */
Q_INVOKABLE void mixClip(int cid = -1);
/** @brief Create a mix transition with currently selected clip. If delta = -1, mix with previous clip, +1 with next clip and 0 will check cursor position*/
Q_INVOKABLE void mixClip(int cid = -1, int delta = 0);
public slots:
void resetView();
......
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