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

Add multicam tool allowing to lift tracks by clicking in the project monitor's track view

parent 995f6071
Pipeline #78215 canceled with stage
......@@ -140,7 +140,8 @@ enum ProjectTool {
RippleTool = 3,
RollTool = 4,
SlipTool = 5,
SlideTool = 6
SlideTool = 6,
MulticamTool = 7
};
Q_ENUM_NS(ProjectTool)
}
......
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<kpartgui name="kdenlive" version="203" translationDomain="kdenlive">
<kpartgui name="kdenlive" version="204" translationDomain="kdenlive">
<MenuBar>
<Menu name="file" >
<Action name="file_save"/>
......@@ -57,6 +57,7 @@
<Action name="razor_tool" />
<Action name="spacer_tool" />
<Action name="slip_tool" />
<Action name="multicam_tool" />
</Menu>
<Menu name="clip" ><text>&amp;Clip</text>
......
......@@ -149,6 +149,7 @@ static QString defaultStyle(const char *fallback = nullptr)
MainWindow::MainWindow(QWidget *parent)
: KXmlGuiWindow(parent)
, m_activeTool(ToolType::SelectTool)
{
}
......@@ -1225,6 +1226,10 @@ void MainWindow::setupActions()
m_buttonSlipTool->setCheckable(true);
m_buttonSlipTool->setChecked(false);
m_buttonMulticamTool = new QAction(QIcon::fromTheme(QStringLiteral("view-split-left-right")), i18n("Multicam tool"), this);
m_buttonMulticamTool->setCheckable(true);
m_buttonMulticamTool->setChecked(false);
/* TODO Implement Slide
// TODO icon available (and properly working) in KF 5.86
m_buttonSlideTool = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-slide")), i18n("Slide tool"), this);
......@@ -1239,6 +1244,7 @@ void MainWindow::setupActions()
//toolGroup->addAction(m_buttonRollTool);
toolGroup->addAction(m_buttonSlipTool);
//toolGroup->addAction(m_buttonSlideTool);
toolGroup->addAction(m_buttonMulticamTool);
toolGroup->setExclusive(true);
......@@ -1347,7 +1353,8 @@ void MainWindow::setupActions()
m_trimLabel = new QLabel(QString(), this);
m_trimLabel->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
m_trimLabel->setAlignment(Qt::AlignHCenter);
//m_trimLabel->setStyleSheet(QStringLiteral("QLabel { background-color :red; }"));
m_trimLabel->setFixedWidth(m_trimLabel->fontMetrics().boundingRect(i18n("Multicam")).width() + 8);
m_trimLabel->setStyleSheet(QStringLiteral("QLabel { padding-left: 2; padding-right: 2; background-color :%1; }").arg(palette().midlight().color().name()));
toolbar->addWidget(m_trimLabel);
......@@ -1383,6 +1390,7 @@ void MainWindow::setupActions()
//addAction(QStringLiteral("ripple_tool"), m_buttonRippleTool);
//addAction(QStringLiteral("roll_tool"), m_buttonRollTool);
addAction(QStringLiteral("slip_tool"), m_buttonSlipTool);
addAction(QStringLiteral("multicam_tool"), m_buttonMulticamTool);
//addAction(QStringLiteral("slide_tool"), m_buttonSlideTool);
addAction(QStringLiteral("automatic_transition"), m_buttonTimelineTags);
......@@ -3192,20 +3200,34 @@ void MainWindow::slotClipEnd()
void MainWindow::slotChangeTool(QAction *action)
{
if (m_activeTool == ToolType::MulticamTool) {
// End multicam operation
pCore->monitorManager()->switchMultiTrackView(false);
pCore->monitorManager()->slotStopMultiTrackMode();
}
if (action == m_buttonSelectTool) {
slotSetTool(ToolType::SelectTool);
m_activeTool = ToolType::SelectTool;
} else if (action == m_buttonRazorTool) {
slotSetTool(ToolType::RazorTool);
m_activeTool = ToolType::RazorTool;
} else if (action == m_buttonSpacerTool) {
slotSetTool(ToolType::SpacerTool);
m_activeTool = ToolType::SpacerTool;
} if (action == m_buttonRippleTool) {
slotSetTool(ToolType::RippleTool);
m_activeTool = ToolType::RippleTool;
} if (action == m_buttonRollTool) {
slotSetTool(ToolType::RollTool);
m_activeTool = ToolType::RollTool;
} if (action == m_buttonSlipTool) {
slotSetTool(ToolType::SlipTool);
m_activeTool = ToolType::SlipTool;
} if (action == m_buttonSlideTool) {
slotSetTool(ToolType::SlideTool);
m_activeTool = ToolType::SlideTool;
} if (action == m_buttonMulticamTool) {
m_activeTool = ToolType::MulticamTool;
};
slotSetTool(m_activeTool);
if (m_activeTool == ToolType::MulticamTool) {
// Start multicam operation
pCore->monitorManager()->switchMultiTrackView(true);
pCore->monitorManager()->slotStartMultiTrackMode();
}
}
......@@ -3214,17 +3236,11 @@ void MainWindow::slotChangeEdit(QAction *action)
TimelineMode::EditMode mode = TimelineMode::NormalEdit;
if (action == m_overwriteEditTool) {
mode = TimelineMode::OverwriteEdit;
m_trimLabel->setText(i18n("Overwrite"));
m_trimLabel->setStyleSheet(QStringLiteral("QLabel { padding-left: 2; padding-right: 2; background-color :darkGreen; }"));
} else if (action == m_insertEditTool) {
mode = TimelineMode::InsertEdit;
m_trimLabel->setText(i18n("Insert"));
m_trimLabel->setStyleSheet(QStringLiteral("QLabel { padding-left: 2; padding-right: 2; background-color :red; }"));
} else {
m_trimLabel->setText(QString());
m_trimLabel->setStyleSheet(QString());
}
getMainTimeline()->controller()->getModel()->setEditMode(mode);
showToolMessage();
if (mode == TimelineMode::InsertEdit) {
// Disable spacer tool in insert mode
if (m_buttonSpacerTool->isChecked()) {
......@@ -3249,15 +3265,38 @@ void MainWindow::slotSetTool(ToolType::ProjectTool tool)
void MainWindow::showToolMessage()
{
QString message;
QString toolLabel;
if (m_buttonSelectTool->isChecked()) {
message = xi18nc("@info:whatsthis", "<shortcut>Shift drag</shortcut> for rubber-band selection, <shortcut>Shift click</shortcut> for multiple selection, <shortcut>Ctrl drag</shortcut> to pan");
} else if (m_buttonRazorTool->isChecked()) {
message = xi18nc("@info:whatsthis", "<shortcut>Shift</shortcut> to preview cut frame");
toolLabel = i18n("Razor");
} else if (m_buttonSpacerTool->isChecked()) {
message = xi18nc("@info:whatsthis", "<shortcut>Ctrl</shortcut> to apply on current track only, <shortcut>Shift</shortcut> to also move guides. You can combine both modifiers.");
toolLabel = i18n("Spacer");
} else if (m_buttonSlipTool->isChecked()) {
message = xi18nc("@info:whatsthis", "<shortcut>Click</shortcut> on an item to slip, <shortcut>Shift</shortcut> to slip only current item of the group"); //TODO
toolLabel = i18n("Slip");
} else if (m_buttonMulticamTool->isChecked()) {
message = xi18nc("@info:whatsthis", "<shortcut>Click</shortcut> on a track view in the project monitor to perform a lift of all tracks except active one");
toolLabel = i18n("Multicam");
}
TimelineMode::EditMode mode = getMainTimeline()->controller()->getModel()->editMode();
if (mode != TimelineMode::NormalEdit) {
if (!toolLabel.isEmpty()) {
toolLabel.append(QStringLiteral(" | "));
}
if (mode == TimelineMode::InsertEdit) {
toolLabel.append(i18n("Insert"));
m_trimLabel->setStyleSheet(QStringLiteral("QLabel { padding-left: 2; padding-right: 2; background-color :red; }"));
} else if (mode == TimelineMode::OverwriteEdit) {
toolLabel.append(i18n("Overwrite"));
m_trimLabel->setStyleSheet(QStringLiteral("QLabel { padding-left: 2; padding-right: 2; background-color :darkGreen; }"));
}
} else {
m_trimLabel->setStyleSheet(QStringLiteral("QLabel { padding-left: 2; padding-right: 2; background-color :%1; }").arg(palette().midlight().color().name()));
}
m_trimLabel->setText(toolLabel);
m_messageLabel->setKeyMap(message);
}
......
......@@ -254,6 +254,7 @@ private:
QAction *m_buttonRollTool;
QAction *m_buttonSlipTool;
QAction *m_buttonSlideTool;
QAction *m_buttonMulticamTool;
QAction *m_buttonSnap;
QAction *m_saveAction;
QSlider *m_zoomSlider;
......@@ -270,6 +271,7 @@ private:
TimelineContainer *m_timelineToolBarContainer;
QLabel *m_trimLabel;
QActionGroup *m_scaleGroup;
ToolType::ProjectTool m_activeTool;
/** @brief initialize startup values, return true if first run. */
bool readOptions();
......
......@@ -33,11 +33,13 @@
#include "kdenlive_debug.h"
#include <QObject>
#include <dialogs/timeremap.h>
#include <timeline2/view/timelinecontroller.h>
const double MonitorManager::speedArray[6] = {1. ,1.5, 2., 3., 5.5, 10.};
MonitorManager::MonitorManager(QObject *parent)
: QObject(parent)
, m_activeMultiTrack(-1)
{
setupActions();
......@@ -341,6 +343,31 @@ void MonitorManager::slotForwardOneSecond()
}
}
void MonitorManager::slotStartMultiTrackMode()
{
m_activeMultiTrack = pCore->window()->getCurrentTimeline()->controller()->activeTrack();
pCore->window()->getCurrentTimeline()->controller()->setMulticamIn(m_projectMonitor->position());
}
void MonitorManager::slotStopMultiTrackMode()
{
if (m_activeMultiTrack == -1) {
return;
}
pCore->window()->getCurrentTimeline()->controller()->setMulticamIn(-1);
m_activeMultiTrack = -1;
}
void MonitorManager::slotPerformMultiTrackMode()
{
if (m_activeMultiTrack == -1) {
return;
}
pCore->window()->getCurrentTimeline()->controller()->processMultitrackOperation(m_activeMultiTrack, pCore->window()->getCurrentTimeline()->controller()->multicamIn);
m_activeMultiTrack = pCore->window()->getCurrentTimeline()->controller()->activeTrack();
pCore->window()->getCurrentTimeline()->controller()->setMulticamIn(m_projectMonitor->position());
}
void MonitorManager::slotStart()
{
if (m_activeMonitor == m_clipMonitor) {
......@@ -479,6 +506,10 @@ void MonitorManager::setupActions()
});
pCore->window()->addAction(QStringLiteral("monitor_multitrack"), m_multiTrack);
QAction *performMultiTrackOperation = new QAction(QIcon::fromTheme(QStringLiteral("media-playback-pause")), i18n("Perform Multitrack Operation"), this);
connect(performMultiTrackOperation, &QAction::triggered, this, &MonitorManager::slotPerformMultiTrackMode);
pCore->window()->addAction(QStringLiteral("perform_multitrack_mode"), performMultiTrackOperation);
QAction *enableEditmode = new QAction(QIcon::fromTheme(QStringLiteral("transform-crop")), i18n("Show/Hide edit mode"), this);
enableEditmode->setCheckable(true);
enableEditmode->setChecked(KdenliveSettings::showOnMonitorScene());
......@@ -718,6 +749,17 @@ bool MonitorManager::isMultiTrack() const
return false;
}
void MonitorManager::switchMultiTrackView(bool enable)
{
if (isMultiTrack()) {
if (!enable) {
m_multiTrack->trigger();
}
} else if (enable) {
m_multiTrack->trigger();
}
}
bool MonitorManager::isTrimming() const
{
if (m_projectMonitor && m_projectMonitor->m_trimmingbar) {
......
......@@ -68,6 +68,8 @@ public:
QDir getCacheFolder(CacheType type);
/** @brief Returns true if multitrack view is enabled in project monitor. */
bool isMultiTrack() const;
/** @brief Enable/disable multitrack view in project monitor. */
void switchMultiTrackView(bool enable);
/** @brief Returns true if the project monitor shows a trimming preview. */
bool isTrimming() const;
/** @brief Returns true if the project monitor is visible (and not tabbed under another dock. */
......@@ -120,6 +122,12 @@ public slots:
void slotExtractCurrentFrameToProject();
/** @brief Refresh monitor background color */
void updateBgColor();
/** @brief Start multitrack operation */
void slotStartMultiTrackMode();
/** @brief Stop multitrack operation */
void slotStopMultiTrackMode();
void slotPerformMultiTrackMode();
private slots:
/** @brief Set MLT's consumer deinterlace method */
......@@ -149,6 +157,8 @@ private:
QList<AbstractMonitor *> m_monitorsList;
KDualAction *m_muteAction;
QAction *m_multiTrack{nullptr};
/** @brief The currently active track for multitrack mode */
int m_activeMultiTrack;
signals:
/** @brief When the monitor changed, update the visible color scopes */
......
......@@ -91,12 +91,15 @@ Item {
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: root.activateTrack(index);
onClicked: {
root.activateTrack(index)
controller.triggerAction('perform_multitrack_mode')
}
}
}
}
}
SceneToolBar {
MultiScreenToolBar {
id: sceneToolBar
anchors {
right: parent.right
......
......@@ -585,6 +585,11 @@ void TimelineModel::setEditMode(TimelineMode::EditMode mode)
m_editMode = mode;
}
TimelineMode::EditMode TimelineModel::editMode() const
{
return m_editMode;
}
bool TimelineModel::normalEdit() const
{
return m_editMode == TimelineMode::NormalEdit;
......
......@@ -697,6 +697,7 @@ public:
void requestClipUpdate(int clipId, const QVector<int> &roles);
/** @brief define current edit mode (normal, insert, overwrite */
void setEditMode(TimelineMode::EditMode mode);
TimelineMode::EditMode editMode() const;
Q_INVOKABLE bool normalEdit() const;
/** @brief Returns the effectstack of a given clip. */
......
......@@ -1810,6 +1810,36 @@ Rectangle {
anchors.bottom: parent.bottom
}
}
Rectangle {
id: multicamLine
visible: root.activeTool === ProjectTool.MulticamTool && timeline.multicamIn > -1
color: 'purple'
width: 3
opacity: 1
height: tracksContainerArea.height
x: timeline.multicamIn * timeline.scaleFactor - scrollView.contentX
y: ruler.height
Rectangle {
// multicam in label
width: multilabel.contentWidth + 4
height: multilabel.contentHeight + 2
radius: height / 4
color: 'purple'
anchors {
top: parent.top
left: parent.left
}
Text {
id: multilabel
text: i18n("Multicam In")
bottomPadding: 2
leftPadding: 2
rightPadding: 2
font: miniFont
color: '#FFF'
}
}
}
}
}
......
......@@ -69,6 +69,7 @@ int TimelineController::m_duration = 0;
TimelineController::TimelineController(QObject *parent)
: QObject(parent)
, multicamIn(-1)
, m_root(nullptr)
, m_usePreview(false)
, m_audioRef(-1)
......@@ -696,7 +697,7 @@ void TimelineController::deleteMultipleTracks(int tid)
Fun undo = []() { return true; };
Fun redo = []() { return true; };
bool result = true;
QPointer<TrackDialog> d = new TrackDialog(m_model, tid, qApp->activeWindow(), true,m_activeTrack);
QPointer<TrackDialog> d = new TrackDialog(m_model, tid, qApp->activeWindow(), true, m_activeTrack);
if (tid == -1) {
tid = m_activeTrack;
}
......@@ -3952,6 +3953,20 @@ void TimelineController::slotMultitrackView(bool enable, bool refresh)
}
pCore->monitorManager()->projectMonitor()->updateMultiTrackView(ix);
});
int ix = 0;
auto it = m_model->m_allTracks.cbegin();
while (it != m_model->m_allTracks.cend()) {
int target_track = (*it)->getId();
++it;
if (target_track == m_activeTrack) {
break;
}
if (m_model->getTrackById_const(target_track)->isAudioTrack() || m_model->getTrackById_const(target_track)->isHidden()) {
continue;
}
++ix;
}
pCore->monitorManager()->projectMonitor()->updateMultiTrackView(ix);
} else {
disconnect(m_model.get(), &TimelineItemModel::trackVisibilityChanged, this, &TimelineController::updateMultiTrack);
}
......@@ -4685,3 +4700,37 @@ MixAlignment TimelineController::getMixAlign(int cid) const
{
return m_model->getMixAlign(cid);
}
void TimelineController::processMultitrackOperation(int tid, int in)
{
int out = pCore->getTimelinePosition();
if (out == in) {
// Simply change the reference track, nothing to do here
return;
}
QVector<int> tracks;
auto it = m_model->m_allTracks.cbegin();
// Lift all tracks except tid
while (it != m_model->m_allTracks.cend()) {
int target_track = (*it)->getId();
if (target_track != tid && m_model->getTrackById_const(target_track)->shouldReceiveTimelineOp()) {
tracks << target_track;
}
++it;
}
if (tracks.isEmpty()) {
pCore->displayMessage(i18n("Please activate a track for this operation by clicking on its label"), ErrorMessage);
}
TimelineFunctions::extractZone(m_model, tracks, QPoint(in, out), true);
}
void TimelineController::setMulticamIn(int pos)
{
if (multicamIn != -1) {
// remove previous snap
m_model->removeSnap(multicamIn);
}
multicamIn = pos;
m_model->addSnap(multicamIn);
emit multicamInChanged();
}
......@@ -92,6 +92,7 @@ class TimelineController : public QObject
Q_PROPERTY(bool guidesLocked READ guidesLocked NOTIFY guidesLockedChanged)
Q_PROPERTY(QPoint effectZone MEMBER m_effectZone NOTIFY effectZoneChanged)
Q_PROPERTY(int trimmingMainClip READ trimmingMainClip NOTIFY trimmingMainClipChanged)
Q_PROPERTY(int multicamIn MEMBER multicamIn NOTIFY multicamInChanged)
public:
TimelineController(QObject *parent);
......@@ -658,6 +659,8 @@ public:
int clipMaxDuration(int cid);
/** @brief Get align info for a mix. */
MixAlignment getMixAlign(int cid) const;
/** @brief Process a lift operation for multitrack operation. */
void processMultitrackOperation(int tid, int in);
public slots:
void resetView();
......@@ -697,6 +700,10 @@ private slots:
public:
/** @brief a list of actions that have to be enabled/disabled depending on the timeline selection */
QList<QAction *> clipActions;
/** @brief The in point for a multicam operation */
int multicamIn;
/** @brief Set the in point for a multicam operation and trigger necessary signals */
void setMulticamIn(int pos);
private:
QQuickItem *m_root;
......@@ -762,6 +769,7 @@ signals:
void showMarkersChanged();
void rippleChanged();
void scrubChanged();
void multicamInChanged();
void seeked(int position);
void zoneChanged();
void zoneMoved(const QPoint &zone);
......
......@@ -11,6 +11,7 @@
<file alias="kdenlivemonitorsplit.qml">monitor/view/kdenlivemonitorsplit.qml</file>
<file alias="kdenlivemonitorsplittracks.qml">monitor/view/kdenlivemonitorsplittracks.qml</file>
<file alias="SceneToolBar.qml">monitor/view/SceneToolBar.qml</file>
<file alias="MultiScreenToolBar.qml">monitor/view/MultiScreenToolBar.qml</file>
<file alias="EffectToolBar.qml">monitor/view/EffectToolBar.qml</file>
<file alias="MonitorRuler.qml">monitor/view/MonitorRuler.qml</file>
<file alias="OverlayStandard.qml">monitor/view/OverlayStandard.qml</file>
......
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