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
32423ba3
Commit
32423ba3
authored
Jun 14, 2019
by
Jean-Baptiste Mardelle
Browse files
Initial implementation of clip speed change on Ctrl + resize
parent
738b8e13
Pipeline
#4319
passed with stage
in 18 minutes and 39 seconds
Changes
8
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/timeline2/model/clipmodel.cpp
View file @
32423ba3
...
...
@@ -152,11 +152,13 @@ bool ClipModel::requestResize(int size, bool right, Fun &undo, Fun &redo, bool l
int
out
=
m_producer
->
get_out
();
int
old_in
=
in
,
old_out
=
out
;
// check if there is enough space on the chosen side
if
(
!
right
&&
in
+
delta
<
0
&&
!
m_endlessResize
)
{
return
false
;
}
if
(
!
m_endlessResize
&&
right
&&
(
out
-
delta
>=
m_producer
->
get_length
()))
{
return
false
;
if
(
!
m_endlessResize
)
{
if
(
!
right
&&
in
+
delta
<
0
)
{
return
false
;
}
if
(
right
&&
(
out
-
delta
>=
m_producer
->
get_length
()))
{
return
false
;
}
}
if
(
right
)
{
out
-=
delta
;
...
...
@@ -212,28 +214,30 @@ bool ClipModel::requestResize(int size, bool right, Fun &undo, Fun &redo, bool l
return
false
;
};
if
(
operation
())
{
// Now, we are in the state in which the timeline should be when we try to revert current action. So we can build the reverse action from here
if
(
m_currentTrackId
!=
-
1
)
{
if
(
auto
ptr
=
m_parent
.
lock
())
{
track_reverse
=
ptr
->
getTrackById
(
m_currentTrackId
)
->
requestClipResize_lambda
(
m_id
,
old_in
,
old_out
,
right
);
Fun
reverse
=
[]()
{
return
true
;
};
if
(
logUndo
)
{
// Now, we are in the state in which the timeline should be when we try to revert current action. So we can build the reverse action from here
if
(
m_currentTrackId
!=
-
1
)
{
if
(
auto
ptr
=
m_parent
.
lock
())
{
track_reverse
=
ptr
->
getTrackById
(
m_currentTrackId
)
->
requestClipResize_lambda
(
m_id
,
old_in
,
old_out
,
right
);
}
}
}
Fun
reverse
=
[
this
,
old_in
,
old_out
,
track_reverse
,
roles
]
()
{
if
(
track_reverse
())
{
setInOut
(
old_in
,
old_out
);
if
(
m_currentTrackId
>
-
1
)
{
if
(
auto
ptr
=
m_parent
.
lock
())
{
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
m_id
);
ptr
->
dataChanged
(
ix
,
ix
,
roles
);
reverse
=
[
this
,
old_in
,
old_out
,
track_reverse
,
roles
]()
{
if
(
track_reverse
(
)
)
{
setInOut
(
old_in
,
old_out
);
if
(
m_currentTrackId
>
-
1
)
{
if
(
auto
ptr
=
m_parent
.
lock
()
)
{
QModelIndex
ix
=
ptr
->
makeClipIndexFromID
(
m_id
);
ptr
->
dataChanged
(
ix
,
ix
,
roles
);
}
}
return
true
;
}
return
true
;
}
return
false
;
};
qDebug
()
<<
"----------
\n
-----------
\n
// ADJUSTING EFFECT LENGTH, LOGUNDO "
<<
logUndo
<<
", "
<<
old_in
<<
"/"
<<
inPoint
<<
", "
return
false
;
};
qDebug
()
<<
"----------
\n
-----------
\n
// ADJUSTING EFFECT LENGTH, LOGUNDO "
<<
logUndo
<<
", "
<<
old_in
<<
"/"
<<
inPoint
<<
", "
<<
m_producer
->
get_playtime
();
if
(
logUndo
)
{
adjustEffectLength
(
right
,
old_in
,
inPoint
,
old_out
-
old_in
,
m_producer
->
get_playtime
(),
offset
,
reverse
,
operation
,
logUndo
);
}
UPDATE_UNDO_REDO
(
operation
,
reverse
,
undo
,
redo
);
...
...
@@ -411,7 +415,7 @@ void ClipModel::refreshProducerFromBin()
refreshProducerFromBin
(
m_currentState
);
}
bool
ClipModel
::
useTimewarpProducer
(
double
speed
,
Fun
&
undo
,
Fun
&
redo
)
bool
ClipModel
::
useTimewarpProducer
(
double
speed
,
bool
changeDuration
,
Fun
&
undo
,
Fun
&
redo
)
{
if
(
m_endlessResize
)
{
// no timewarp for endless producers
...
...
@@ -430,7 +434,7 @@ bool ClipModel::useTimewarpProducer(double speed, Fun &undo, Fun &redo)
int
oldIn
=
getIn
();
auto
operation
=
useTimewarpProducer_lambda
(
speed
);
auto
reverse
=
useTimewarpProducer_lambda
(
previousSpeed
);
if
(
oldOut
>=
newDuration
)
{
if
(
changeDuration
&&
oldOut
>=
newDuration
)
{
// in that case, we are going to shrink the clip when changing the producer. We must undo that when reloading the old producer
reverse
=
[
reverse
,
oldIn
,
oldOut
,
this
]()
{
bool
res
=
reverse
();
...
...
@@ -443,10 +447,12 @@ bool ClipModel::useTimewarpProducer(double speed, Fun &undo, Fun &redo)
if
(
operation
())
{
UPDATE_UNDO_REDO
(
operation
,
reverse
,
local_undo
,
local_redo
);
// When calculating duration, result can be a few frames longer than possible duration so adjust
bool
res
=
requestResize
(
qMin
(
newDuration
,
getMaxDuration
()),
true
,
local_undo
,
local_redo
,
true
);
if
(
!
res
)
{
local_undo
();
return
false
;
if
(
changeDuration
)
{
bool
res
=
requestResize
(
qMin
(
newDuration
,
getMaxDuration
()),
true
,
local_undo
,
local_redo
,
true
);
if
(
!
res
)
{
local_undo
();
return
false
;
}
}
UPDATE_UNDO_REDO
(
local_redo
,
local_undo
,
undo
,
redo
);
return
true
;
...
...
src/timeline2/model/clipmodel.hpp
View file @
32423ba3
...
...
@@ -183,7 +183,7 @@ protected:
/* @brief This functions replaces the current producer with a slowmotion one
It also resizes the producer so that set of frames contained in the clip is the same
*/
bool
useTimewarpProducer
(
double
speed
,
Fun
&
undo
,
Fun
&
redo
);
bool
useTimewarpProducer
(
double
speed
,
bool
changeDuration
,
Fun
&
undo
,
Fun
&
redo
);
// @brief Lambda that merely changes the speed (in and out are untouched)
Fun
useTimewarpProducer_lambda
(
double
speed
);
...
...
src/timeline2/model/timelinemodel.cpp
View file @
32423ba3
...
...
@@ -96,7 +96,7 @@ RTTR_REGISTRATION
// .method("requestCompositionInsertion", select_overload<bool(const QString &, int, int, int, std::unique_ptr<Mlt::Properties>, int &, bool)>(
// &TimelineModel::requestCompositionInsertion))(
// parameter_names("transitionId", "trackId", "position", "length", "transProps", "id", "logUndo"))
.
method
(
"requestClipTimeWarp"
,
select_overload
<
bool
(
int
,
double
)
>
(
&
TimelineModel
::
requestClipTimeWarp
))(
parameter_names
(
"clipId"
,
"speed"
));
.
method
(
"requestClipTimeWarp"
,
select_overload
<
bool
(
int
,
double
,
bool
)
>
(
&
TimelineModel
::
requestClipTimeWarp
))(
parameter_names
(
"clipId"
,
"speed"
,
"changeDuration"
));
}
int
TimelineModel
::
next_id
=
0
;
...
...
@@ -1665,20 +1665,83 @@ const std::vector<int> TimelineModel::getBoundaries(int itemId)
return
boundaries
;
}
int
TimelineModel
::
request
Item
Resize
(
int
itemId
,
int
size
,
bool
right
,
bool
logUndo
,
int
snapDistance
,
bool
allowSingleResize
)
int
TimelineModel
::
request
Clip
Resize
AndTimeWarp
(
int
itemId
,
int
size
,
bool
right
,
int
snapDistance
,
bool
allowSingleResize
,
double
speed
)
{
if
(
logUndo
)
{
qDebug
()
<<
"---------------------
\n
---------------------
\n
RESIZE W/UNDO CALLED
\n
++++++++++++++++
\n
++++"
;
}
QWriteLocker
locker
(
&
m_lock
);
TRACE
(
itemId
,
size
,
right
,
logUndo
,
snapDistance
,
allowSingleResize
);
Q_ASSERT
(
is
Item
(
itemId
));
TRACE
(
itemId
,
size
,
right
,
true
,
snapDistance
,
allowSingleResize
);
Q_ASSERT
(
is
Clip
(
itemId
));
if
(
size
<=
0
)
{
TRACE_RES
(
-
1
);
return
-
1
;
}
int
in
=
getItemPosition
(
itemId
);
int
out
=
in
+
getItemPlaytime
(
itemId
);
//size = requestItemResizeInfo(itemId, in, out, size, right, snapDistance);
Fun
undo
=
[]()
{
return
true
;
};
Fun
redo
=
[]()
{
return
true
;
};
std
::
unordered_set
<
int
>
all_items
;
if
(
!
allowSingleResize
&&
m_groups
->
isInGroup
(
itemId
))
{
int
groupId
=
m_groups
->
getRootId
(
itemId
);
std
::
unordered_set
<
int
>
items
;
if
(
m_groups
->
getType
(
groupId
)
==
GroupType
::
AVSplit
)
{
// Only resize group elements if it is an avsplit
items
=
m_groups
->
getLeaves
(
groupId
);
}
else
{
all_items
.
insert
(
itemId
);
}
for
(
int
id
:
items
)
{
if
(
id
==
itemId
)
{
all_items
.
insert
(
id
);
continue
;
}
int
start
=
getItemPosition
(
id
);
int
end
=
in
+
getItemPlaytime
(
id
);
if
(
right
)
{
if
(
out
==
end
)
{
all_items
.
insert
(
id
);
}
}
else
if
(
start
==
in
)
{
all_items
.
insert
(
id
);
}
}
}
else
{
all_items
.
insert
(
itemId
);
}
bool
result
=
true
;
for
(
int
id
:
all_items
)
{
int
tid
=
getItemTrackId
(
id
);
if
(
tid
>
-
1
&&
getTrackById_const
(
tid
)
->
isLocked
())
{
continue
;
}
// First delete clip, then timewarp, resize and reinsert
int
pos
=
getItemPosition
(
id
);
if
(
!
right
)
{
pos
+=
getItemPlaytime
(
id
)
-
size
;
}
result
=
getTrackById
(
tid
)
->
requestClipDeletion
(
id
,
true
,
true
,
undo
,
redo
,
false
,
true
);
result
=
result
&&
requestClipTimeWarp
(
id
,
speed
,
false
,
undo
,
redo
);
result
=
result
&&
requestItemResize
(
id
,
size
,
true
,
true
,
undo
,
redo
);
result
=
result
&&
getTrackById
(
tid
)
->
requestClipInsertion
(
id
,
pos
,
true
,
true
,
undo
,
redo
);
if
(
!
result
)
{
break
;
}
}
if
(
!
result
)
{
bool
undone
=
undo
();
Q_ASSERT
(
undone
);
TRACE_RES
(
-
1
);
return
-
1
;
}
if
(
result
)
{
PUSH_UNDO
(
undo
,
redo
,
i18n
(
"Resize clip speed"
));
}
int
res
=
result
?
size
:
-
1
;
TRACE_RES
(
res
);
return
res
;
}
int
TimelineModel
::
requestItemResizeInfo
(
int
itemId
,
int
in
,
int
out
,
int
size
,
bool
right
,
int
snapDistance
)
{
if
(
snapDistance
>
0
&&
getItemTrackId
(
itemId
)
!=
-
1
)
{
Fun
temp_undo
=
[]()
{
return
true
;
};
Fun
temp_redo
=
[]()
{
return
true
;
};
...
...
@@ -1713,6 +1776,24 @@ int TimelineModel::requestItemResize(int itemId, int size, bool right, bool logU
}
}
}
return
size
;
}
int
TimelineModel
::
requestItemResize
(
int
itemId
,
int
size
,
bool
right
,
bool
logUndo
,
int
snapDistance
,
bool
allowSingleResize
)
{
if
(
logUndo
)
{
qDebug
()
<<
"---------------------
\n
---------------------
\n
RESIZE W/UNDO CALLED
\n
++++++++++++++++
\n
++++"
;
}
QWriteLocker
locker
(
&
m_lock
);
TRACE
(
itemId
,
size
,
right
,
logUndo
,
snapDistance
,
allowSingleResize
);
Q_ASSERT
(
isItem
(
itemId
));
if
(
size
<=
0
)
{
TRACE_RES
(
-
1
);
return
-
1
;
}
int
in
=
getItemPosition
(
itemId
);
int
out
=
in
+
getItemPlaytime
(
itemId
);
size
=
requestItemResizeInfo
(
itemId
,
in
,
out
,
size
,
right
,
snapDistance
);
Fun
undo
=
[]()
{
return
true
;
};
Fun
redo
=
[]()
{
return
true
;
};
std
::
unordered_set
<
int
>
all_items
;
...
...
@@ -3013,7 +3094,7 @@ void TimelineModel::requestClipUpdate(int clipId, const QVector<int> &roles)
notifyChange
(
modelIndex
,
modelIndex
,
roles
);
}
bool
TimelineModel
::
requestClipTimeWarp
(
int
clipId
,
double
speed
,
Fun
&
undo
,
Fun
&
redo
)
bool
TimelineModel
::
requestClipTimeWarp
(
int
clipId
,
double
speed
,
bool
changeDuration
,
Fun
&
undo
,
Fun
&
redo
)
{
QWriteLocker
locker
(
&
m_lock
);
if
(
qFuzzyCompare
(
speed
,
m_allClips
[
clipId
]
->
getSpeed
()))
{
...
...
@@ -3029,7 +3110,7 @@ bool TimelineModel::requestClipTimeWarp(int clipId, double speed, Fun &undo, Fun
success
=
success
&&
getTrackById
(
trackId
)
->
requestClipDeletion
(
clipId
,
true
,
true
,
local_undo
,
local_redo
,
false
,
false
);
}
if
(
success
)
{
success
=
m_allClips
[
clipId
]
->
useTimewarpProducer
(
speed
,
local_undo
,
local_redo
);
success
=
m_allClips
[
clipId
]
->
useTimewarpProducer
(
speed
,
changeDuration
,
local_undo
,
local_redo
);
}
if
(
trackId
!=
-
1
)
{
success
=
success
&&
getTrackById
(
trackId
)
->
requestClipInsertion
(
clipId
,
oldPos
,
true
,
true
,
local_undo
,
local_redo
);
...
...
@@ -3042,7 +3123,7 @@ bool TimelineModel::requestClipTimeWarp(int clipId, double speed, Fun &undo, Fun
return
success
;
}
bool
TimelineModel
::
requestClipTimeWarp
(
int
clipId
,
double
speed
)
bool
TimelineModel
::
requestClipTimeWarp
(
int
clipId
,
double
speed
,
bool
changeDuration
)
{
QWriteLocker
locker
(
&
m_lock
);
TRACE
(
clipId
,
speed
);
...
...
@@ -3055,10 +3136,10 @@ bool TimelineModel::requestClipTimeWarp(int clipId, double speed)
// Check if clip has a split partner
int
splitId
=
m_groups
->
getSplitPartner
(
clipId
);
if
(
splitId
>
-
1
)
{
result
=
requestClipTimeWarp
(
splitId
,
speed
/
100.0
,
undo
,
redo
);
result
=
requestClipTimeWarp
(
splitId
,
speed
/
100.0
,
changeDuration
,
undo
,
redo
);
}
if
(
result
)
{
result
=
requestClipTimeWarp
(
clipId
,
speed
/
100.0
,
undo
,
redo
);
result
=
requestClipTimeWarp
(
clipId
,
speed
/
100.0
,
changeDuration
,
undo
,
redo
);
}
if
(
!
result
)
{
pCore
->
displayMessage
(
i18n
(
"Change speed failed"
),
ErrorMessage
);
...
...
@@ -3068,7 +3149,7 @@ bool TimelineModel::requestClipTimeWarp(int clipId, double speed)
}
}
else
{
// If clip is not inserted on a track, we just change the producer
result
=
m_allClips
[
clipId
]
->
useTimewarpProducer
(
speed
,
undo
,
redo
);
result
=
m_allClips
[
clipId
]
->
useTimewarpProducer
(
speed
,
changeDuration
,
undo
,
redo
);
}
if
(
result
)
{
PUSH_UNDO
(
undo
,
redo
,
i18n
(
"Change clip speed"
));
...
...
src/timeline2/model/timelinemodel.hpp
View file @
32423ba3
...
...
@@ -466,6 +466,8 @@ public:
Q_INVOKABLE
const
QVariantList
getGroupData
(
int
itemId
);
Q_INVOKABLE
void
processGroupResize
(
QVariantList
startPos
,
QVariantList
endPos
,
bool
right
);
Q_INVOKABLE
int
requestClipResizeAndTimeWarp
(
int
itemId
,
int
size
,
bool
right
,
int
snapDistance
,
bool
allowSingleResize
,
double
speed
);
/* @brief Group together a set of ids
The ids are either a group ids or clip ids. The involved clip must already be inserted in a track
This action is undoable
...
...
@@ -536,6 +538,11 @@ protected:
@returns best snap position or -1 if no snap point is near
*/
int
getBestSnapPos
(
int
pos
,
int
length
,
const
std
::
vector
<
int
>
&
pts
=
std
::
vector
<
int
>
(),
int
cursorPosition
=
0
,
int
snapDistance
=
-
1
);
/* @brief Returns the best possible size for a clip on resize
*/
int
requestItemResizeInfo
(
int
itemId
,
int
in
,
int
out
,
int
size
,
bool
right
,
int
snapDistance
);
/* @brief Returns a list of in/out of all items in the group of itemId
*/
const
std
::
vector
<
int
>
getBoundaries
(
int
itemId
);
...
...
@@ -621,10 +628,10 @@ public:
This functions create an undo object and also apply the effect to the corresponding audio if there is any.
Returns true on success, false otherwise (and nothing is modified)
*/
bool
requestClipTimeWarp
(
int
clipId
,
double
speed
);
Q_INVOKABLE
bool
requestClipTimeWarp
(
int
clipId
,
double
speed
,
bool
changeDuration
);
/* @brief Same function as above, but doesn't check for paired audio and accumulate undo/redo
*/
bool
requestClipTimeWarp
(
int
clipId
,
double
speed
,
Fun
&
undo
,
Fun
&
redo
);
bool
requestClipTimeWarp
(
int
clipId
,
double
speed
,
bool
changeDuration
,
Fun
&
undo
,
Fun
&
redo
);
void
replugClip
(
int
clipId
);
...
...
src/timeline2/view/qml/Clip.qml
View file @
32423ba3
...
...
@@ -75,11 +75,11 @@ Rectangle {
width
:
clipDuration
*
timeScale
;
opacity
:
dragProxyArea
.
drag
.
active
&&
dragProxy
.
draggedItem
==
clipId
?
0.8
:
1.0
signal
trimmingIn
(
var
clip
,
real
newDuration
,
var
mouse
,
bool
shiftTrim
)
signal
trimmedIn
(
var
clip
,
bool
shiftTrim
)
signal
trimmingIn
(
var
clip
,
real
newDuration
,
var
mouse
,
bool
shiftTrim
,
bool
controlTrim
)
signal
trimmedIn
(
var
clip
,
bool
shiftTrim
,
bool
controlTrim
)
signal
initGroupTrim
(
var
clip
)
signal
trimmingOut
(
var
clip
,
real
newDuration
,
var
mouse
,
bool
shiftTrim
)
signal
trimmedOut
(
var
clip
,
bool
shiftTrim
)
signal
trimmingOut
(
var
clip
,
real
newDuration
,
var
mouse
,
bool
shiftTrim
,
bool
controlTrim
)
signal
trimmedOut
(
var
clip
,
bool
shiftTrim
,
bool
controlTrim
)
onIsGrabbedChanged
:
{
if
(
clipRoot
.
isGrabbed
)
{
...
...
@@ -815,6 +815,7 @@ Rectangle {
drag.axis
:
Drag
.
XAxis
drag.smoothed
:
false
property
bool
shiftTrim
:
false
property
bool
controlTrim
:
false
property
bool
sizeChanged
:
false
cursorShape
:
(
containsMouse
?
Qt
.
SizeHorCursor
:
Qt
.
ClosedHandCursor
);
onPressed
:
{
...
...
@@ -823,6 +824,7 @@ Rectangle {
clipRoot
.
originalDuration
=
clipDuration
parent
.
anchors
.
left
=
undefined
shiftTrim
=
mouse
.
modifiers
&
Qt
.
ShiftModifier
controlTrim
=
mouse
.
modifiers
&
Qt
.
ControlModifier
if
(
!
shiftTrim
&&
clipRoot
.
grouped
)
{
clipRoot
.
initGroupTrim
(
clipRoot
)
}
...
...
@@ -832,7 +834,7 @@ Rectangle {
root
.
stopScrolling
=
false
parent
.
anchors
.
left
=
clipRoot
.
left
if
(
sizeChanged
)
{
clipRoot
.
trimmedIn
(
clipRoot
,
shiftTrim
)
clipRoot
.
trimmedIn
(
clipRoot
,
shiftTrim
,
controlTrim
)
sizeChanged
=
false
}
}
...
...
@@ -845,7 +847,7 @@ Rectangle {
}
var
newDuration
=
clipDuration
-
delta
sizeChanged
=
true
clipRoot
.
trimmingIn
(
clipRoot
,
newDuration
,
mouse
,
shiftTrim
)
clipRoot
.
trimmingIn
(
clipRoot
,
newDuration
,
mouse
,
shiftTrim
,
controlTrim
)
}
}
}
...
...
@@ -877,6 +879,7 @@ Rectangle {
anchors.fill
:
parent
hoverEnabled
:
true
property
bool
shiftTrim
:
false
property
bool
controlTrim
:
false
property
bool
sizeChanged
:
false
cursorShape
:
(
containsMouse
?
Qt
.
SizeHorCursor
:
Qt
.
ClosedHandCursor
);
drag.target
:
parent
...
...
@@ -888,6 +891,7 @@ Rectangle {
clipRoot
.
originalDuration
=
clipDuration
parent
.
anchors
.
right
=
undefined
shiftTrim
=
mouse
.
modifiers
&
Qt
.
ShiftModifier
controlTrim
=
mouse
.
modifiers
&
Qt
.
ControlModifier
if
(
!
shiftTrim
&&
clipRoot
.
grouped
)
{
clipRoot
.
initGroupTrim
(
clipRoot
)
}
...
...
@@ -897,7 +901,7 @@ Rectangle {
root
.
stopScrolling
=
false
parent
.
anchors
.
right
=
clipRoot
.
right
if
(
sizeChanged
)
{
clipRoot
.
trimmedOut
(
clipRoot
,
shiftTrim
)
clipRoot
.
trimmedOut
(
clipRoot
,
shiftTrim
,
controlTrim
)
sizeChanged
=
false
}
}
...
...
@@ -906,7 +910,7 @@ Rectangle {
var
newDuration
=
Math
.
round
((
parent
.
x
+
parent
.
width
)
/
timeScale
)
if
(
newDuration
!=
clipDuration
)
{
sizeChanged
=
true
clipRoot
.
trimmingOut
(
clipRoot
,
newDuration
,
mouse
,
shiftTrim
)
clipRoot
.
trimmingOut
(
clipRoot
,
newDuration
,
mouse
,
shiftTrim
,
controlTrim
)
}
}
}
...
...
src/timeline2/view/qml/Track.qml
View file @
32423ba3
...
...
@@ -270,6 +270,15 @@ Column{
clip
.
groupTrimData
=
controller
.
getGroupData
(
clip
.
clipId
)
}
onTrimmingIn
:
{
if
(
controlTrim
)
{
newDuration
=
Math
.
max
(
1
,
newDuration
)
speedController
.
x
=
clip
.
x
+
clip
.
width
-
newDuration
*
trackRoot
.
timeScale
speedController
.
width
=
newDuration
*
trackRoot
.
timeScale
speedController
.
lastValidDuration
=
newDuration
speedController
.
speedText
=
(
100
*
clip
.
originalDuration
*
clip
.
speed
/
speedController
.
lastValidDuration
).
toFixed
(
2
)
+
'
%
'
speedController
.
visible
=
true
return
}
var
new_duration
=
controller
.
requestItemResize
(
clip
.
clipId
,
newDuration
,
false
,
false
,
root
.
snapping
,
shiftTrim
)
if
(
new_duration
>
0
)
{
clip
.
lastValidDuration
=
new_duration
...
...
@@ -285,10 +294,18 @@ Column{
}
onTrimmedIn
:
{
bubbleHelp
.
hide
()
if
(
shiftTrim
||
clip
.
groupTrimData
==
undefined
)
{
if
(
controlTrim
)
{
speedController
.
visible
=
false
}
if
(
shiftTrim
||
clip
.
groupTrimData
==
undefined
||
controlTrim
)
{
// We only resize one element
controller
.
requestItemResize
(
clip
.
clipId
,
clip
.
originalDuration
,
false
,
false
,
0
,
shiftTrim
)
controller
.
requestItemResize
(
clip
.
clipId
,
clip
.
lastValidDuration
,
false
,
true
,
0
,
shiftTrim
)
if
(
controlTrim
)
{
// Update speed
controller
.
requestClipResizeAndTimeWarp
(
clip
.
clipId
,
speedController
.
lastValidDuration
,
false
,
root
.
snapping
,
shiftTrim
,
clip
.
originalDuration
*
clip
.
speed
/
speedController
.
lastValidDuration
)
}
else
{
controller
.
requestItemResize
(
clip
.
clipId
,
clip
.
lastValidDuration
,
false
,
true
,
0
,
shiftTrim
)
}
}
else
{
var
updatedGroupData
=
controller
.
getGroupData
(
clip
.
clipId
)
controller
.
processGroupResize
(
clip
.
groupTrimData
,
updatedGroupData
,
false
)
...
...
@@ -296,6 +313,15 @@ Column{
clip
.
groupTrimData
=
undefined
}
onTrimmingOut
:
{
if
(
controlTrim
)
{
speedController
.
x
=
clip
.
x
newDuration
=
Math
.
max
(
1
,
newDuration
)
speedController
.
width
=
newDuration
*
trackRoot
.
timeScale
speedController
.
lastValidDuration
=
newDuration
speedController
.
speedText
=
(
100
*
clip
.
originalDuration
*
clip
.
speed
/
speedController
.
lastValidDuration
).
toFixed
(
2
)
+
'
%
'
speedController
.
visible
=
true
return
}
var
new_duration
=
controller
.
requestItemResize
(
clip
.
clipId
,
newDuration
,
true
,
false
,
root
.
snapping
,
shiftTrim
)
if
(
new_duration
>
0
)
{
clip
.
lastValidDuration
=
new_duration
...
...
@@ -310,9 +336,17 @@ Column{
}
onTrimmedOut
:
{
bubbleHelp
.
hide
()
if
(
shiftTrim
||
clip
.
groupTrimData
==
undefined
)
{
if
(
controlTrim
)
{
speedController
.
visible
=
false
}
if
(
shiftTrim
||
clip
.
groupTrimData
==
undefined
||
controlTrim
)
{
controller
.
requestItemResize
(
clip
.
clipId
,
clip
.
originalDuration
,
true
,
false
,
0
,
shiftTrim
)
controller
.
requestItemResize
(
clip
.
clipId
,
clip
.
lastValidDuration
,
true
,
true
,
0
,
shiftTrim
)
if
(
controlTrim
)
{
// Update speed
controller
.
requestClipResizeAndTimeWarp
(
clip
.
clipId
,
speedController
.
lastValidDuration
,
true
,
root
.
snapping
,
shiftTrim
,
clip
.
originalDuration
*
clip
.
speed
/
speedController
.
lastValidDuration
)
}
else
{
controller
.
requestItemResize
(
clip
.
clipId
,
clip
.
lastValidDuration
,
true
,
true
,
0
,
shiftTrim
)
}
}
else
{
var
updatedGroupData
=
controller
.
getGroupData
(
clip
.
clipId
)
controller
.
processGroupResize
(
clip
.
groupTrimData
,
updatedGroupData
,
true
)
...
...
@@ -366,4 +400,23 @@ Column{
}
}
}
Rectangle
{
id
:
speedController
color
:
'
#aaff0000
'
visible
:
false
height
:
root
.
baseUnit
*
3
property
int
lastValidDuration
:
0
property
string
speedText
:
'
100%
'
Text
{
id
:
speedLabel
text
:
i18n
(
"
Adjusting speed:
\n
"
)
+
speedController
.
speedText
font.pixelSize
:
root
.
baseUnit
*
1.2
anchors.fill
:
parent
verticalAlignment
:
Text
.
AlignVCenter
horizontalAlignment
:
Text
.
AlignHCenter
color
:
'
white
'
style
:
Text
.
Outline
styleColor
:
'
black
'
}
}
}
src/timeline2/view/timelinecontroller.cpp
View file @
32423ba3
...
...
@@ -1515,7 +1515,7 @@ void TimelineController::changeItemSpeed(int clipId, double speed)
speed
=
d
->
getValue
();
qDebug
()
<<
"requesting speed "
<<
speed
;
}
m_model
->
requestClipTimeWarp
(
clipId
,
speed
);
m_model
->
requestClipTimeWarp
(
clipId
,
speed
,
true
);
}
void
TimelineController
::
switchCompositing
(
int
mode
)
...
...
tests/timewarptest.cpp
View file @
32423ba3
...
...
@@ -59,7 +59,7 @@ TEST_CASE("Test of timewarping", "[Timewarp]")
std
::
function
<
bool
(
void
)
>
undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo
=
[]()
{
return
true
;
};
REQUIRE
(
timeline
->
requestClipTimeWarp
(
cid3
,
0.1
,
undo
,
redo
));
REQUIRE
(
timeline
->
requestClipTimeWarp
(
cid3
,
0.1
,
true
,
undo
,
redo
));
CHECK_UPDATE
(
TimelineModel
::
SpeedRole
);
REQUIRE
(
timeline
->
getClipSpeed
(
cid3
)
==
0.1
);
...
...
@@ -81,7 +81,7 @@ TEST_CASE("Test of timewarping", "[Timewarp]")
std
::
function
<
bool
(
void
)
>
undo2
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo2
=
[]()
{
return
true
;
};
REQUIRE
(
timeline
->
requestClipTimeWarp
(
cid3
,
1.2
,
undo2
,
redo2
));
REQUIRE
(
timeline
->
requestClipTimeWarp
(
cid3
,
1.2
,
true
,
undo2
,
redo2
));
CHECK_UPDATE
(
TimelineModel
::
SpeedRole
);
REQUIRE
(
timeline
->
getClipSpeed
(
cid3
)
==
1.2
);
...
...
@@ -102,7 +102,7 @@ TEST_CASE("Test of timewarping", "[Timewarp]")
int
curLength
=
timeline
->
getClipPlaytime
(
cid3
);
// This is the limit, should work
REQUIRE
(
timeline
->
requestClipTimeWarp
(
cid3
,
double
(
curLength
),
undo2
,
redo2
));
REQUIRE
(
timeline
->
requestClipTimeWarp
(
cid3
,
double
(
curLength
),
true
,
undo2
,
redo2
));
CHECK_UPDATE
(
TimelineModel
::
SpeedRole
);
REQUIRE
(
timeline
->
getClipSpeed
(
cid3
)
==
double
(
curLength
));
...
...
@@ -110,7 +110,7 @@ TEST_CASE("Test of timewarping", "[Timewarp]")
// This is the higher than the limit, should not work
// (we have some error margin in duration rounding, multiply by 10)
REQUIRE_FALSE
(
timeline
->
requestClipTimeWarp
(
cid3
,
double
(
curLength
)
*
10
,
undo2
,
redo2
));
REQUIRE_FALSE
(
timeline
->
requestClipTimeWarp
(
cid3
,
double
(
curLength
)
*
10
,
true
,
undo2
,
redo2
));
}
binModel
->
clean
();
pCore
->
m_projectManager
=
nullptr
;
...
...
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