Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Multimedia
Kdenlive
Commits
8991e0ee
Commit
8991e0ee
authored
Sep 14, 2020
by
Jean-Baptiste Mardelle
Browse files
Make same track transition correcty resize on clip resize
parent
38a21d0e
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/timeline2/model/timelinemodel.cpp
View file @
8991e0ee
...
...
@@ -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
;
}
src/timeline2/model/timelinemodel.hpp
View file @
8991e0ee
...
...
@@ -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
...
...
src/timeline2/model/trackmodel.cpp
View file @
8991e0ee
...
...
@@ -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
))
{
...
...
src/timeline2/view/qml/Clip.qml
View file @
8991e0ee
...
...
@@ -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
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment