Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Kdenlive
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
261
Issues
261
List
Boards
Labels
Service Desk
Milestones
Merge Requests
16
Merge Requests
16
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Multimedia
Kdenlive
Commits
b1d63b64
Commit
b1d63b64
authored
Jan 10, 2021
by
Jean-Baptiste Mardelle
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of invent.kde.org:multimedia/kdenlive
parents
48de2321
64a60166
Pipeline
#46993
passed with stage
in 10 minutes and 44 seconds
Changes
15
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
227 additions
and
87 deletions
+227
-87
data/kdenliveeffectscategory.rc
data/kdenliveeffectscategory.rc
+1
-1
data/org.kde.kdenlive.xml
data/org.kde.kdenlive.xml
+11
-1
src/bin/model/markerlistmodel.cpp
src/bin/model/markerlistmodel.cpp
+40
-0
src/bin/model/markerlistmodel.hpp
src/bin/model/markerlistmodel.hpp
+16
-0
src/dialogs/clipcreationdialog.cpp
src/dialogs/clipcreationdialog.cpp
+18
-10
src/mainwindow.cpp
src/mainwindow.cpp
+1
-1
src/mltconnection.cpp
src/mltconnection.cpp
+5
-1
src/timeline2/model/clipmodel.cpp
src/timeline2/model/clipmodel.cpp
+39
-41
src/timeline2/model/timelinefunctions.cpp
src/timeline2/model/timelinefunctions.cpp
+5
-5
src/timeline2/model/timelinefunctions.hpp
src/timeline2/model/timelinefunctions.hpp
+1
-1
src/timeline2/model/timelinemodel.cpp
src/timeline2/model/timelinemodel.cpp
+11
-14
src/timeline2/model/trackmodel.cpp
src/timeline2/model/trackmodel.cpp
+3
-3
src/timeline2/view/qml/timeline.qml
src/timeline2/view/qml/timeline.qml
+24
-6
src/timeline2/view/timelinecontroller.cpp
src/timeline2/view/timelinecontroller.cpp
+36
-2
src/timeline2/view/timelinecontroller.h
src/timeline2/view/timelinecontroller.h
+16
-1
No files found.
data/kdenliveeffectscategory.rc
View file @
b1d63b64
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<data
name=
"effects"
version=
"0"
>
<group
list=
"chroma,frei0r.alpha0ps,frei0r.alphagrad,frei0r.alphaspot,frei0r.transparency,frei0r.mask0mate,rotoscoping,frei0r.keyspillm0pup,avfilter.despill,obscure,autotrack_rectangle,frei0r.bluescreen0r,lumakey,shape,spot_remover,frei0r.select0r,frei0r.spillsupress,frei0r.bgsubtract0r,opencv.tracker"
>
<group
list=
"chroma,frei0r.alpha0ps,frei0r.alphagrad,frei0r.alphaspot,frei0r.transparency,frei0r.mask0mate,rotoscoping,frei0r.keyspillm0pup,avfilter.despill,obscure,autotrack_rectangle,frei0r.bluescreen0r,lumakey,shape,spot_remover,frei0r.select0r,frei0r.spillsupress,frei0r.bgsubtract0r,opencv.tracker
,strobe
"
>
<text>
Alpha, Mask and Keying
</text>
</group>
<group
list=
"boxblur,frei0r.squareblur,avfilter.avgblur,avfilter.gblur,avfilter.smartblur,avfilter.boxblur,avfilter.unsharp,avfilter.sab"
>
...
...
data/org.kde.kdenlive.xml
View file @
b1d63b64
...
...
@@ -5,7 +5,7 @@
<comment
xml:lang=
"ca"
>
Document de projecte de vídeo del Kdenlive
</comment>
<comment
xml:lang=
"ca@valencia"
>
Document de projecte de vídeo del Kdenlive
</comment>
<comment
xml:lang=
"en_GB"
>
Kdenlive video project document
</comment>
<comment
xml:lang=
"es"
>
Documento de p
royecto de video de Kdenlive
</comment>
<comment
xml:lang=
"es"
>
P
royecto de video de Kdenlive
</comment>
<comment
xml:lang=
"eu"
>
Kdenlive-ko bideo-proiektuaren dokumentua
</comment>
<comment
xml:lang=
"fr"
>
Document de projet vidéo pour Kdenlive
</comment>
<comment
xml:lang=
"it"
>
Progetto video di Kdenlive
</comment>
...
...
@@ -47,6 +47,16 @@
</mime-type>
<mime-type
type=
"application/kdenlivelayout"
>
<comment>
Kdenlive application layout
</comment>
<comment
xml:lang=
"ca"
>
Disposició de l'aplicació Kdenlive
</comment>
<comment
xml:lang=
"ca@valencia"
>
Disposició de l'aplicació Kdenlive
</comment>
<comment
xml:lang=
"es"
>
Organización de paneles de Kdenlive
</comment>
<comment
xml:lang=
"eu"
>
Kdenlive aplikazioaren antolaera
</comment>
<comment
xml:lang=
"fr"
>
Mise en page de l'application Kdenlive
</comment>
<comment
xml:lang=
"nl"
>
Toepassingsindeling van Kdenlive
</comment>
<comment
xml:lang=
"pt"
>
Disposição da aplicação Kdenlive
</comment>
<comment
xml:lang=
"ru"
>
Макет приложения Kdenlive
</comment>
<comment
xml:lang=
"sv"
>
Kdenlive programlayout
</comment>
<comment
xml:lang=
"uk"
>
Компонування вікон програми Kdenlive
</comment>
<sub-class-of
type=
"text/plain"
/>
<glob
pattern=
"*.kdenlivelayout"
/>
</mime-type>
...
...
src/bin/model/markerlistmodel.cpp
View file @
b1d63b64
...
...
@@ -197,6 +197,32 @@ bool MarkerListModel::editMarker(GenTime oldPos, GenTime pos, QString comment, i
return
res
;
}
bool
MarkerListModel
::
moveMarkers
(
QList
<
CommentedTime
>
markers
,
GenTime
fromPos
,
GenTime
toPos
,
Fun
&
undo
,
Fun
&
redo
)
{
QWriteLocker
locker
(
&
m_lock
);
if
(
markers
.
length
()
<=
0
)
{
return
false
;
}
bool
res
=
false
;
for
(
const
auto
&
marker
:
markers
)
{
GenTime
oldPos
=
marker
.
time
();
QString
oldComment
=
marker
.
comment
();
int
oldType
=
marker
.
markerType
();
GenTime
newPos
=
oldPos
.
operator
+
(
toPos
.
operator
-
(
fromPos
));
res
=
removeMarker
(
oldPos
,
undo
,
redo
);
if
(
res
)
{
res
=
addMarker
(
newPos
,
oldComment
,
oldType
,
undo
,
redo
);
}
else
{
break
;
}
}
return
res
;
}
Fun
MarkerListModel
::
changeComment_lambda
(
GenTime
pos
,
const
QString
&
comment
,
int
type
)
{
QWriteLocker
locker
(
&
m_lock
);
...
...
@@ -357,6 +383,20 @@ QList<CommentedTime> MarkerListModel::getAllMarkers() const
return
markers
;
}
QList
<
CommentedTime
>
MarkerListModel
::
getMarkersInRange
(
int
start
,
int
end
)
const
{
READ_LOCK
();
QList
<
CommentedTime
>
markers
;
for
(
const
auto
&
marker
:
m_markerList
)
{
int
pos
=
marker
.
first
.
frames
(
pCore
->
getCurrentFps
());
if
(
pos
>
start
&&
(
end
==
-
1
||
pos
<
end
))
{
CommentedTime
t
(
marker
.
first
,
marker
.
second
.
first
,
marker
.
second
.
second
);
markers
<<
t
;
}
}
return
markers
;
}
std
::
vector
<
int
>
MarkerListModel
::
getSnapPoints
()
const
{
READ_LOCK
();
...
...
src/bin/model/markerlistmodel.hpp
View file @
b1d63b64
...
...
@@ -90,6 +90,16 @@ public:
*/
bool
editMarker
(
GenTime
oldPos
,
GenTime
pos
,
QString
comment
=
QString
(),
int
type
=
-
1
);
/* @brief Moves all markers from on to another position
@param markers list of markers to move
@param fromPos
@param toPos
@param undo
@param redo
*/
bool
moveMarkers
(
QList
<
CommentedTime
>
markers
,
GenTime
fromPos
,
GenTime
toPos
,
Fun
&
undo
,
Fun
&
redo
);
/* @brief This describes the available markers type and their corresponding colors */
static
std
::
array
<
QColor
,
5
>
markerTypes
;
...
...
@@ -99,6 +109,12 @@ public:
/* @brief Returns all markers in model */
QList
<
CommentedTime
>
getAllMarkers
()
const
;
/* @brief Returns all markers of model that are intersect with a given range.
* @param start is the position where start to search for markers
* @param end is the position after which markers will not be returned, set to -1 to get all markers after start
*/
QList
<
CommentedTime
>
getMarkersInRange
(
int
start
,
int
end
)
const
;
/* @brief Returns all markers positions in model */
std
::
vector
<
int
>
getSnapPoints
()
const
;
...
...
src/dialogs/clipcreationdialog.cpp
View file @
b1d63b64
...
...
@@ -457,28 +457,36 @@ void ClipCreationDialog::clipWidget(QDockWidget* m_DockClipWidget)
QString
clipFolder
=
KRecentDirs
::
dir
(
QStringLiteral
(
":KdenliveClipFolder"
));
KFileWidget
*
fileWidget
=
new
KFileWidget
(
QUrl
::
fromLocalFile
(
clipFolder
),
m_DockClipWidget
);
fileWidget
->
setMode
(
KFile
::
Files
|
KFile
::
ExistingOnly
|
KFile
::
LocalOnly
|
KFile
::
Directory
);
QString
allExtensions
=
getExtensions
().
join
(
QLatin1Char
(
' '
));
QString
dialogFilter
=
allExtensions
+
QLatin1Char
(
'|'
)
+
i18n
(
"All Supported Files"
)
+
QStringLiteral
(
"
\n
*|"
)
+
i18n
(
"All Files"
);
QPushButton
*
importseq
=
new
QPushButton
(
i18n
(
"Import image sequence"
));
// Make importseq checkable so that we can differentiate between a double click in filewidget and a click on the pushbutton
importseq
->
setCheckable
(
true
);
fileWidget
->
setCustomWidget
(
importseq
);
QObject
::
connect
(
fileWidget
,
&
KFileWidget
::
accepted
,
fileWidget
,
[
=
]
{
KFileItemList
files
=
fileWidget
->
dirOperator
()
->
selectedItems
();
QList
<
QUrl
>
urls
;
for
(
auto
&
f
:
files
)
{
urls
<<
f
.
url
();
// Required to only add file on double click and not on single click
fileWidget
->
setOperationMode
(
KFileWidget
::
Saving
);
QObject
::
connect
(
fileWidget
,
&
KFileWidget
::
accepted
,
[
fileWidget
,
importseq
]()
{
if
(
importseq
->
isChecked
())
{
// We are importing an image sequence, abort
return
;
}
fileWidget
->
accept
();
QList
<
QUrl
>
urls
=
fileWidget
->
selectedUrls
();
pCore
->
bin
()
->
droppedUrls
(
urls
);
});
QObject
::
connect
(
importseq
,
&
QPushButton
::
clicked
,
fileWidget
,
&
KFileWidget
::
slotOk
);
QObject
::
connect
(
importseq
,
&
QPushButton
::
clicked
,
fileWidget
,
&
KFileWidget
::
accepted
);
QObject
::
connect
(
importseq
,
&
QPushButton
::
clicked
,
fileWidget
,
&
KFileWidget
::
accept
);
fileWidget
->
setFilter
(
dialogFilter
);
QObject
::
connect
(
importseq
,
&
QPushButton
::
clicked
,
fileWidget
,
[
=
]{
QUrl
url
;
url
=
fileWidget
->
selectedUrl
();
fileWidget
->
slotOk
();
fileWidget
->
accepted
();
fileWidget
->
accept
();
QUrl
url
=
fileWidget
->
selectedUrl
();
QStringList
patternlist
;
QString
pattern
=
SlideshowClip
::
selectedPath
(
url
,
false
,
QString
(),
&
patternlist
);
int
count
=
patternlist
.
size
();
QString
fileName
=
url
.
fileName
().
section
(
QLatin1Char
(
'.'
),
0
,
-
2
);
importseq
->
setChecked
(
false
);
if
(
count
>=
1
)
{
while
(
fileName
.
size
()
>
0
&&
fileName
.
at
(
fileName
.
size
()
-
1
).
isDigit
())
{
fileName
.
chop
(
1
);
...
...
src/mainwindow.cpp
View file @
b1d63b64
...
...
@@ -3109,7 +3109,7 @@ void MainWindow::slotSetTool(ProjectTool tool)
QString
message
;
switch
(
tool
)
{
case
SpacerTool
:
message
=
i18n
(
"Ctrl + click to use spacer on current track only"
);
message
=
i18n
(
"Ctrl + click to use spacer on current track only
, Shift + click to move guides too. You can combine both modifiers.
"
);
break
;
case
RazorTool
:
message
=
i18n
(
"Click on a clip to cut it, Shift + move to preview cut frame"
);
...
...
src/mltconnection.cpp
View file @
b1d63b64
...
...
@@ -235,7 +235,11 @@ void MltConnection::refreshLumas()
}
else
{
format
=
f
;
}
QStringList
filesnames
=
dir
.
entryList
(
fileFilters
,
QDir
::
Files
);
QStringList
filesnames
;
QDirIterator
it
(
dir
.
absolutePath
(),
fileFilters
,
QDir
::
Files
,
QDirIterator
::
Subdirectories
);
while
(
it
.
hasNext
())
{
filesnames
.
append
(
it
.
next
());
}
if
(
MainWindow
::
m_lumaFiles
.
contains
(
format
))
{
imagefiles
=
MainWindow
::
m_lumaFiles
.
value
(
format
);
}
...
...
src/timeline2/model/clipmodel.cpp
View file @
b1d63b64
...
...
@@ -256,56 +256,54 @@ bool ClipModel::requestResize(int size, bool right, Fun &undo, Fun &redo, bool l
};
if
(
operation
())
{
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
())
{
if
(
trackDuration
>
0
)
{
// Operation changed parent track duration, update effect stack
int
newDuration
=
ptr
->
getTrackById_const
(
m_currentTrackId
)
->
trackDuration
();
if
(
logUndo
||
trackDuration
!=
newDuration
)
{
// A clip move changed the track duration, update track effects
ptr
->
getTrackById
(
m_currentTrackId
)
->
m_effectStack
->
adjustStackLength
(
true
,
0
,
trackDuration
,
0
,
newDuration
,
0
,
undo
,
redo
,
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
())
{
if
(
trackDuration
>
0
)
{
// Operation changed parent track duration, update effect stack
int
newDuration
=
ptr
->
getTrackById_const
(
m_currentTrackId
)
->
trackDuration
();
if
(
logUndo
||
trackDuration
!=
newDuration
)
{
// A clip move changed the track duration, update track effects
ptr
->
getTrackById
(
m_currentTrackId
)
->
m_effectStack
->
adjustStackLength
(
true
,
0
,
trackDuration
,
0
,
newDuration
,
0
,
undo
,
redo
,
logUndo
);
}
track_reverse
=
ptr
->
getTrackById
(
m_currentTrackId
)
->
requestClipResize_lambda
(
m_id
,
old_in
,
old_out
,
right
,
hasMix
);
}
}
reverse
=
[
this
,
old_in
,
old_out
,
track_reverse
,
logUndo
,
oldIn
,
oldOut
,
right
,
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
->
notifyChange
(
ix
,
ix
,
roles
);
if
(
logUndo
&&
!
ptr
->
getTrackById_const
(
m_currentTrackId
)
->
isAudioTrack
())
{
if
(
right
)
{
int
newOut
=
m_position
+
getOut
()
-
getIn
();
if
(
oldOut
<
newOut
)
{
emit
ptr
->
invalidateZone
(
oldOut
,
newOut
);
}
else
{
emit
ptr
->
invalidateZone
(
newOut
,
oldOut
);
}
track_reverse
=
ptr
->
getTrackById
(
m_currentTrackId
)
->
requestClipResize_lambda
(
m_id
,
old_in
,
old_out
,
right
,
hasMix
);
}
}
reverse
=
[
this
,
old_in
,
old_out
,
track_reverse
,
logUndo
,
oldIn
,
oldOut
,
right
,
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
->
notifyChange
(
ix
,
ix
,
roles
);
if
(
logUndo
&&
!
ptr
->
getTrackById_const
(
m_currentTrackId
)
->
isAudioTrack
())
{
if
(
right
)
{
int
newOut
=
m_position
+
getOut
()
-
getIn
();
if
(
oldOut
<
newOut
)
{
emit
ptr
->
invalidateZone
(
oldOut
,
newOut
);
}
else
{
if
(
oldIn
<
m_position
)
{
emit
ptr
->
invalidateZone
(
oldIn
,
m_position
);
}
else
{
emit
ptr
->
invalidateZone
(
m_position
,
oldIn
);
}
emit
ptr
->
invalidateZone
(
newOut
,
oldOut
);
}
}
else
{
if
(
oldIn
<
m_position
)
{
emit
ptr
->
invalidateZone
(
oldIn
,
m_position
);
}
else
{
emit
ptr
->
invalidateZone
(
m_position
,
oldIn
);
}
}
}
}
return
true
;
}
qDebug
()
<<
"============
\n
+++++++++++++++++
\n
REVRSE TRACK OP FAILED
\n\n
++++++++++++++++"
;
return
false
;
};
qDebug
()
<<
"----------
\n
-----------
\n
// ADJUSTING EFFECT LENGTH, LOGUNDO "
<<
logUndo
<<
", "
<<
old_in
<<
"/"
<<
inPoint
<<
", "
<<
m_producer
->
get_playtime
();
return
true
;
}
qDebug
()
<<
"============
\n
+++++++++++++++++
\n
REVRSE TRACK OP FAILED
\n\n
++++++++++++++++"
;
return
false
;
};
qDebug
()
<<
"----------
\n
-----------
\n
// ADJUSTING EFFECT LENGTH, LOGUNDO "
<<
logUndo
<<
", "
<<
old_in
<<
"/"
<<
inPoint
<<
", "
<<
m_producer
->
get_playtime
();
adjustEffectLength
(
right
,
old_in
,
inPoint
,
old_out
-
old_in
,
m_producer
->
get_playtime
(),
offset
,
reverse
,
operation
,
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
);
return
true
;
}
...
...
src/timeline2/model/timelinefunctions.cpp
View file @
b1d63b64
...
...
@@ -325,7 +325,7 @@ int TimelineFunctions::requestSpacerStartOperation(const std::shared_ptr<Timelin
return
-
1
;
}
bool
TimelineFunctions
::
requestSpacerEndOperation
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
int
itemId
,
int
startPosition
,
int
endPosition
,
int
affectedTrack
)
bool
TimelineFunctions
::
requestSpacerEndOperation
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
int
itemId
,
int
startPosition
,
int
endPosition
,
int
affectedTrack
,
Fun
&
undo
,
Fun
&
redo
)
{
// Move group back to original position
int
track
=
timeline
->
getItemTrackId
(
itemId
);
...
...
@@ -338,9 +338,6 @@ bool TimelineFunctions::requestSpacerEndOperation(const std::shared_ptr<Timeline
timeline
->
requestSubtitleMove
(
itemId
,
startPosition
,
false
,
false
);
}
std
::
unordered_set
<
int
>
clips
=
timeline
->
getGroupElements
(
itemId
);
// Start undoable command
std
::
function
<
bool
(
void
)
>
undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo
=
[]()
{
return
true
;
};
int
mainGroup
=
timeline
->
m_groups
->
getRootId
(
itemId
);
bool
final
=
false
;
bool
liftOk
=
true
;
...
...
@@ -1818,7 +1815,10 @@ bool TimelineFunctions::requestDeleteBlankAt(const std::shared_ptr<TimelineItemM
return
false
;
}
int
start
=
timeline
->
getItemPosition
(
cid
);
requestSpacerEndOperation
(
timeline
,
cid
,
start
,
start
-
spaceDuration
,
affectAllTracks
?
-
1
:
trackId
);
// Start undoable command
std
::
function
<
bool
(
void
)
>
undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo
=
[]()
{
return
true
;
};
requestSpacerEndOperation
(
timeline
,
cid
,
start
,
start
-
spaceDuration
,
affectAllTracks
?
-
1
:
trackId
,
undo
,
redo
);
return
true
;
}
...
...
src/timeline2/model/timelinefunctions.hpp
View file @
b1d63b64
...
...
@@ -86,7 +86,7 @@ struct TimelineFunctions
static
bool
requestDeleteBlankAt
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
int
trackId
,
int
position
,
bool
affectAllTracks
);
static
int
requestSpacerStartOperation
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
int
trackId
,
int
position
);
static
bool
requestSpacerEndOperation
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
int
itemId
,
int
startPosition
,
int
endPosition
,
int
affectedTrack
);
static
bool
requestSpacerEndOperation
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
int
itemId
,
int
startPosition
,
int
endPosition
,
int
affectedTrack
,
Fun
&
undo
,
Fun
&
redo
);
static
bool
extractZone
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
QVector
<
int
>
tracks
,
QPoint
zone
,
bool
liftOnly
);
static
bool
liftZone
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
int
trackId
,
QPoint
zone
,
Fun
&
undo
,
Fun
&
redo
);
static
bool
removeSpace
(
const
std
::
shared_ptr
<
TimelineItemModel
>
&
timeline
,
QPoint
zone
,
Fun
&
undo
,
Fun
&
redo
,
QVector
<
int
>
allowedTracks
=
QVector
<
int
>
(),
bool
useTargets
=
true
);
...
...
src/timeline2/model/timelinemodel.cpp
View file @
b1d63b64
...
...
@@ -688,9 +688,10 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
if
(
old_trackId
==
trackId
)
{
// We are moving a clip on same track
if
(
finalMove
&&
position
>=
mixData
.
first
.
firstClipInOut
.
second
)
{
position
+=
m_allClips
[
clipId
]
->
getMixDuration
()
-
m_allClips
[
clipId
]
->
getMixCutPosition
();
removeMixWithUndo
(
clipId
,
local_undo
,
local_redo
);
}
}
else
if
(
finalMove
)
{
}
else
{
// Clip moved to another track, delete mix
int
subPlaylist
=
m_allClips
[
clipId
]
->
getSubPlaylistIndex
();
update_playlist
=
[
this
,
clipId
,
old_trackId
,
trackId
,
finalMove
]()
{
...
...
@@ -718,6 +719,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
if
(
finalMove
&&
(
position
+
clipDuration
<=
mixData
.
second
.
secondClipInOut
.
first
))
{
// Moved outside mix zone
removeMixWithUndo
(
mixData
.
second
.
secondClipId
,
local_undo
,
local_redo
);
}
}
else
{
// Clip moved to another track, delete mix
...
...
@@ -738,11 +740,8 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
int
mixEnd
=
m_allClips
[
mixData
.
first
.
firstClipId
]
->
getPosition
()
+
m_allClips
[
mixData
.
first
.
firstClipId
]
->
getPlaytime
();
if
(
mixEnd
<
position
)
{
// Mix will be deleted, recreate on undo
bool
isAudio
=
getTrackById_const
(
old_trackId
)
->
isAudioTrack
();
update_playlist_undo
=
[
this
,
mixData
,
old_trackId
,
isAudio
]()
{
bool
result
=
getTrackById_const
(
old_trackId
)
->
createMix
(
mixData
.
first
,
isAudio
);
return
result
;
};
position
+=
m_allClips
[
mixData
.
first
.
secondClipId
]
->
getMixDuration
()
-
m_allClips
[
mixData
.
first
.
secondClipId
]
->
getMixCutPosition
();
removeMixWithUndo
(
mixData
.
first
.
secondClipId
,
local_undo
,
local_redo
);
}
}
}
...
...
@@ -752,11 +751,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
int
mixEnd
=
m_allClips
[
mixData
.
second
.
secondClipId
]
->
getPosition
();
if
(
mixEnd
>
position
+
m_allClips
[
clipId
]
->
getPlaytime
())
{
// Mix will be deleted, recreate on undo
bool
isAudio
=
getTrackById_const
(
old_trackId
)
->
isAudioTrack
();
update_playlist_undo
=
[
this
,
mixData
,
old_trackId
,
isAudio
]()
{
bool
result
=
getTrackById_const
(
old_trackId
)
->
createMix
(
mixData
.
second
,
isAudio
);
return
result
;
};
removeMixWithUndo
(
mixData
.
second
.
secondClipId
,
local_undo
,
local_redo
);
}
}
}
...
...
@@ -785,6 +780,7 @@ bool TimelineModel::requestClipMove(int clipId, int trackId, int position, bool
Q_ASSERT
(
undone
);
return
false
;
}
qDebug
()
<<
":::MOVED CLIP: "
<<
clipId
<<
" TO "
<<
position
;
sync_mix
();
update_model
();
simple_move_mix
();
...
...
@@ -2364,7 +2360,7 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
Q_ASSERT
(
undone
);
return
false
;
}
int
newStart
=
getTrackById_const
(
current_track_id
)
->
getBlankStart
(
current_in
-
1
);
int
newStart
=
getTrackById_const
(
current_track_id
)
->
getBlankStart
(
current_in
-
1
,
subPlaylist
);
delta_pos
=
qMax
(
delta_pos
,
newStart
-
current_in
);
}
}
else
{
...
...
@@ -2374,7 +2370,7 @@ bool TimelineModel::requestGroupMove(int itemId, int groupId, int delta_track, i
subPlaylist
=
m_allClips
[
item
.
first
]
->
getSubPlaylistIndex
();
}
if
(
!
getTrackById_const
(
current_track_id
)
->
isAvailable
(
moveStart
,
moveEnd
-
moveStart
,
subPlaylist
))
{
int
newStart
=
getTrackById_const
(
current_track_id
)
->
getBlankEnd
(
current_in
+
playtime
);
int
newStart
=
getTrackById_const
(
current_track_id
)
->
getBlankEnd
(
current_in
+
playtime
,
subPlaylist
);
if
(
newStart
==
current_in
+
playtime
)
{
// No move possible, abort
bool
undone
=
local_undo
();
...
...
@@ -2814,8 +2810,9 @@ int TimelineModel::requestItemResizeInfo(int itemId, int in, int out, int size,
//TODO: don't allow subtitle overlap?
success
=
true
;
}
// undo temp move
temp_undo
();
if
(
success
)
{
temp_undo
();
// undo temp move
size
=
proposed_size
;
}
}
...
...
src/timeline2/model/trackmodel.cpp
View file @
b1d63b64
...
...
@@ -1548,10 +1548,10 @@ bool TrackModel::requestRemoveMix(std::pair<int, int> clipIds, Fun &undo, Fun &r
Fun
local_undo
=
[]()
{
return
true
;
};
Fun
local_redo
=
[]()
{
return
true
;
};
if
(
auto
ptr
=
m_parent
.
lock
())
{
// Resize main clip
result
=
ptr
->
getClipPtr
(
clipIds
.
second
)
->
requestResize
(
endPos
-
secondInPos
,
false
,
local_undo
,
local_redo
,
true
,
true
);
// Resize first part clip
result
=
result
&&
ptr
->
getClipPtr
(
clipIds
.
first
)
->
requestResize
(
secondInPos
-
firstInPos
,
true
,
local_undo
,
local_redo
,
true
,
true
);
result
=
ptr
->
getClipPtr
(
clipIds
.
first
)
->
requestResize
(
secondInPos
-
firstInPos
,
true
,
local_undo
,
local_redo
,
true
,
true
);
// Resize main clip
result
=
result
&&
ptr
->
getClipPtr
(
clipIds
.
second
)
->
requestResize
(
endPos
-
secondInPos
,
false
,
local_undo
,
local_redo
,
true
,
true
);
}
if
(
result
)
{
PUSH_LAMBDA
(
local_redo
,
redo
);
...
...
src/timeline2/view/qml/timeline.qml
View file @
b1d63b64
...
...
@@ -315,6 +315,7 @@ Rectangle {
property
int
spacerFrame
:
-
1
property
int
finalSpacerFrame
:
-
1
property
int
spacerClickFrame
:
-
1
property
bool
spacerGuides
:
false
property
real
timeScale
:
timeline
.
scaleFactor
property
int
snapping
:
(
timeline
.
snap
&&
(
timeline
.
scaleFactor
<
2
*
baseUnit
))
?
Math
.
floor
(
baseUnit
/
(
timeline
.
scaleFactor
>
3
?
timeline
.
scaleFactor
/
2
:
timeline
.
scaleFactor
))
:
-
1
property
var
timelineSelection
:
timeline
.
selection
...
...
@@ -1018,13 +1019,19 @@ Rectangle {
spacerTrack
=
tracksRepeater
.
itemAt
(
Logic
.
getTrackIndexFromPos
(
y
)).
trackInternalId
}
}
if
(
mouse
.
modifiers
&
Qt
.
ShiftModifier
)
{
//spacer tool and shift modifier
spacerGuides
=
true
;
}
spacerGroup
=
timeline
.
requestSpacerStartOperation
(
spacerTrack
,
frame
)
if
(
spacerGroup
>
-
1
)
{
if
(
spacerGroup
>
-
1
||
spacerGuides
)
{
drag
.
axis
=
Drag
.
XAxis
Drag
.
active
=
true
Drag
.
proposedAction
=
Qt
.
MoveAction
spacerClickFrame
=
frame
spacerFrame
=
controller
.
getItemPosition
(
spacerGroup
)
spacerFrame
=
spacerGroup
>
-
1
?
controller
.
getItemPosition
(
spacerGroup
)
:
frame
finalSpacerFrame
=
spacerFrame
}
}
else
if
(
root
.
activeTool
===
0
||
mouse
.
y
<=
ruler
.
height
)
{
...
...
@@ -1103,7 +1110,7 @@ Rectangle {
rubberSelect
.
height
=
newY
-
rubberSelect
.
originY
}
continuousScrolling
(
newX
,
newY
)
}
else
if
((
pressedButtons
&
Qt
.
LeftButton
)
&&
!
shiftPress
)
{
}
else
if
((
pressedButtons
&
Qt
.
LeftButton
)
&&
(
!
shiftPress
||
spacerGuides
)
)
{
if
(
root
.
activeTool
===
0
||
mouse
.
y
<
ruler
.
height
)
{
proxy
.
position
=
Math
.
max
(
0
,
Math
.
min
((
scrollView
.
contentX
+
mouse
.
x
)
/
timeline
.
scaleFactor
,
timeline
.
fullDuration
-
1
))
}
else
if
(
root
.
activeTool
===
2
&&
spacerGroup
>
-
1
)
{
...
...
@@ -1112,7 +1119,10 @@ Rectangle {
var
frame
=
Math
.
round
((
mouse
.
x
+
scrollView
.
contentX
)
/
timeline
.
scaleFactor
)
+
spacerFrame
-
spacerClickFrame
finalSpacerFrame
=
controller
.
suggestItemMove
(
spacerGroup
,
track
,
frame
,
root
.
consumerPosition
,
(
mouse
.
modifiers
&
Qt
.
ShiftModifier
)
?
0
:
root
.
snapping
)[
0
]
continuousScrolling
(
mouse
.
x
+
scrollView
.
contentX
,
mouse
.
y
+
scrollView
.
contentY
)
}
else
if
(
spacerGuides
)
{
finalSpacerFrame
=
Math
.
round
((
mouse
.
x
+
scrollView
.
contentX
)
/
timeline
.
scaleFactor
)
+
spacerFrame
-
spacerClickFrame
}
scim
=
true
}
else
{
scim
=
false
...
...
@@ -1152,7 +1162,7 @@ Rectangle {
timeline
.
selectItems
(
t
,
startFrame
,
endFrame
,
mouse
.
modifiers
&
Qt
.
ControlModifier
,
selectBottomCompositions
,
selectSubs
);
}
rubberSelect
.
y
=
-
1
}
else
if
(
shiftPress
)
{
}
else
if
(
shiftPress
&&
!
spacerGuides
)
{
if
(
root
.
activeTool
==
1
)
{
// Shift click, process seek
proxy
.
position
=
Math
.
min
((
scrollView
.
contentX
+
mouse
.
x
)
/
timeline
.
scaleFactor
,
timeline
.
fullDuration
-
1
)
...
...
@@ -1169,13 +1179,21 @@ Rectangle {
}
return
}
if
(
spacerGroup
>
-
1
&&
finalSpacerFrame
>
-
1
)
{
var
frame
=
controller
.
getItemPosition
(
spacerGroup
)
timeline
.
requestSpacerEndOperation
(
spacerGroup
,
spacerFrame
,
finalSpacerFrame
,
spacerTrack
);
timeline
.
requestSpacerEndOperation
(
spacerGroup
,
spacerFrame
,
finalSpacerFrame
,
spacerTrack
,
spacerGuides
?
spacerClickFrame
:
-
1
);
}
else
if
(
spacerGuides
)
{
timeline
.
moveGuidesInRange
(
spacerClickFrame
,
-
1
,
finalSpacerFrame
-
spacerFrame
)
}
if
(
spacerGroup
>
-
1
&&
finalSpacerFrame
>
-
1
||
spacerGuides
)
{
spacerClickFrame
=
-
1
spacerFrame
=
-
1
spacerGroup
=
-
1
spacerGuides
=
false
}
scim
=
false
}
...
...
@@ -1449,7 +1467,7 @@ Rectangle {
controller
.
requestCompositionMove
(
dragProxy
.
draggedItem
,
tId
,
dragFrame
,
true
,
true
,
true
)
}
else
{
if
(
controller
.
normalEdit
())
{
controller
.
requestClipMove
(
dragProxy
.
draggedItem
,
dragProxy
.
sourceTrack
,
dragProxy
.
sourceFrame
,
moveMirrorTracks
,
tru
e
,
false
,
false
)
controller
.
requestClipMove
(
dragProxy
.
draggedItem
,
dragProxy
.
sourceTrack
,
dragProxy
.
sourceFrame
,
moveMirrorTracks
,
fals
e
,
false
,
false
)
controller
.
requestClipMove
(
dragProxy
.
draggedItem
,
tId
,
dragFrame
,
moveMirrorTracks
,
true
,
true
,
true
)
}
else
{
// Fake move, only process final move
...
...
src/timeline2/view/timelinecontroller.cpp
View file @
b1d63b64
...
...
@@ -1073,6 +1073,33 @@ void TimelineController::moveGuide(int frame, int newFrame)
guideModel
->
editMarker
(
pos
,
newPos
);
}
bool
TimelineController
::
moveGuidesInRange
(
int
start
,
int
end
,
int
offset
)
{
std
::
function
<
bool
(
void
)
>
undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo
=
[]()
{
return
true
;
};
bool
final
=
false
;
final
=
moveGuidesInRange
(
start
,
end
,
offset
,
undo
,
redo
);
if
(
final
)
{
if
(
offset
>
0
)
{
pCore
->
pushUndo
(
undo
,
redo
,
i18n
(
"Insert space"
));
}
else
{
pCore
->
pushUndo
(
undo
,
redo
,
i18n
(
"Remove space"
));
}
return
true
;
}
else
{
undo
();
}
return
false
;
}
bool
TimelineController
::
moveGuidesInRange
(
int
start
,
int
end
,
int
offset
,
Fun
&
undo
,
Fun
&
redo
)
{
GenTime
fromPos
(
start
,
pCore
->
getCurrentFps
());
GenTime
toPos
(
start
+
offset
,
pCore
->
getCurrentFps
());
QList
<
CommentedTime
>
guides
=
pCore
->
projectManager
()
->
current
()
->
getGuideModel
()
->
getMarkersInRange
(
start
,
end
);
return
pCore
->
projectManager
()
->
current
()
->
getGuideModel
()
->
moveMarkers
(
guides
,
fromPos
,
toPos
,
undo
,
redo
);
}
void
TimelineController
::
switchGuide
(
int
frame
,
bool
deleteOnly
)
{
bool
markerFound
=
false
;
...
...
@@ -1505,10 +1532,17 @@ int TimelineController::requestSpacerStartOperation(int trackId, int position)
return
itemId
;
}
bool
TimelineController
::
requestSpacerEndOperation
(
int
clipId
,
int
startPosition
,
int
endPosition
,
int
affectedTrack
)
bool
TimelineController
::
requestSpacerEndOperation
(
int
clipId
,
int
startPosition
,
int
endPosition
,
int
affectedTrack
,
int
guideStart
)
{
QMutexLocker
lk
(
&
m_metaMutex
);
bool
result
=
TimelineFunctions
::
requestSpacerEndOperation
(
m_model
,
clipId
,
startPosition
,
endPosition
,
affectedTrack
);
// Start undoable command
std
::
function
<
bool
(
void
)
>
undo
=
[]()
{
return
true
;
};
std
::
function
<
bool
(
void
)
>
redo
=
[]()
{
return
true
;
};
if
(
guideStart
>
-
1
)
{
moveGuidesInRange
(
guideStart
,
-
1
,
endPosition
-
startPosition
,
undo
,
redo
);
}
bool
result
=
TimelineFunctions
::
requestSpacerEndOperation
(
m_model
,
clipId
,
startPosition
,
endPosition
,
affectedTrack
,
undo
,
redo
);
return
result
;
}
...
...
src/timeline2/view/timelinecontroller.h
View file @
b1d63b64
...
...
@@ -299,6 +299,21 @@ public:
*/
Q_INVOKABLE
void
editGuide
(
int
frame
=
-
1
);
Q_INVOKABLE
void
moveGuide
(
int
frame
,
int
newFrame
);
/* @brief Move all guides in the given range
* @param start the start point of the range in frames
* @param end the end point of the range in frames