From 5aa1199079acf6eaf504803df910b31aa3b288ae Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Mon, 26 Oct 2009 09:45:00 +0000 Subject: [PATCH] Introducing timeline edit mode, starting with overwrite mode (allows to move a clip over other clips) svn path=/trunk/kdenlive/; revision=4061 --- src/abstractgroupitem.cpp | 10 +-- src/clipitem.cpp | 4 +- src/customtrackscene.cpp | 13 +++- src/customtrackscene.h | 7 +- src/customtrackview.cpp | 140 ++++++++++++++++++++++++++++++++++---- src/customtrackview.h | 5 +- src/kdenliveui.rc | 6 +- src/mainwindow.cpp | 67 ++++++++++++++++-- src/mainwindow.h | 4 +- src/razorclipcommand.cpp | 8 ++- src/razorclipcommand.h | 3 +- src/renderer.cpp | 37 +++++++--- src/renderer.h | 6 +- src/transition.cpp | 4 +- 14 files changed, 266 insertions(+), 48 deletions(-) diff --git a/src/abstractgroupitem.cpp b/src/abstractgroupitem.cpp index aed9c108..2f3f564c 100644 --- a/src/abstractgroupitem.cpp +++ b/src/abstractgroupitem.cpp @@ -196,11 +196,13 @@ QVariant AbstractGroupItem::itemChange(GraphicsItemChange change, const QVariant }*/ QPainterPath shape = clipGroupShape(newPos - pos()); - QList collindingItems = scene()->items(shape, Qt::IntersectsItemShape); - for (int i = 0; i < children.count(); i++) { - collindingItems.removeAll(children.at(i)); + QList collindingItems; + if (projectScene()->editMode() == NORMALEDIT) { + collindingItems = scene()->items(shape, Qt::IntersectsItemShape); + for (int i = 0; i < children.count(); i++) { + collindingItems.removeAll(children.at(i)); + } } - if (!collindingItems.isEmpty()) { bool forwardMove = xpos > start.x(); int offset = 0; diff --git a/src/clipitem.cpp b/src/clipitem.cpp index 7abb6815..f15929af 100644 --- a/src/clipitem.cpp +++ b/src/clipitem.cpp @@ -1186,7 +1186,9 @@ QVariant ClipItem::itemChange(GraphicsItemChange change, const QVariant &value) // Only one clip is moving QRectF sceneShape = rect(); sceneShape.translate(newPos); - QList items = scene()->items(sceneShape, Qt::IntersectsItemShape); + QList items; + if (projectScene()->editMode() == NORMALEDIT) + items = scene()->items(sceneShape, Qt::IntersectsItemShape); items.removeAll(this); bool forwardMove = newPos.x() > pos().x(); int offset = 0; diff --git a/src/customtrackscene.cpp b/src/customtrackscene.cpp index 1364d22d..1f8b40ae 100644 --- a/src/customtrackscene.cpp +++ b/src/customtrackscene.cpp @@ -25,7 +25,8 @@ CustomTrackScene::CustomTrackScene(KdenliveDoc *doc, QObject *parent) : QGraphicsScene(parent), m_document(doc), - m_scale(1.0, 1.0) + m_scale(1.0, 1.0), + m_editMode(NORMALEDIT) { } @@ -96,4 +97,14 @@ MltVideoProfile CustomTrackScene::profile() const return m_document->mltProfile(); } +void CustomTrackScene::setEditMode(EDITMODE mode) +{ + m_editMode = mode; +} + +EDITMODE CustomTrackScene::editMode() const +{ + return m_editMode; +} + #include "customtrackscene.moc" diff --git a/src/customtrackscene.h b/src/customtrackscene.h index 961927de..d0f37060 100644 --- a/src/customtrackscene.h +++ b/src/customtrackscene.h @@ -30,7 +30,9 @@ class KdenliveDoc; class MltVideoProfile; -/** This class holds all properties that need to be used by clip items */ +/** This class holds all scene properties that need to be used by clip items */ + +enum EDITMODE { NORMALEDIT = 0 , OVERWRITEEDIT = 1 , INSERTEDIT = 2 }; class CustomTrackScene : public QGraphicsScene { @@ -47,11 +49,14 @@ public: QPointF scale() const; int tracksCount() const; MltVideoProfile profile() const; + void setEditMode(EDITMODE mode); + EDITMODE editMode() const; private: KdenliveDoc *m_document; QList m_snapPoints; QPointF m_scale; + EDITMODE m_editMode; }; #endif diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index 99fd9666..f9759412 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -19,7 +19,6 @@ #include "customtrackview.h" -#include "customtrackscene.h" #include "docclipbase.h" #include "clipitem.h" #include "definitions.h" @@ -966,6 +965,7 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) return; } else if (m_operationMode == MOVE) { setCursor(Qt::ClosedHandCursor); + if (m_dragItem) m_dragItem->setZValue(10); } else if (m_operationMode == TRANSITIONSTART && event->modifiers() != Qt::ControlModifier) { ItemInfo info; info.startPos = m_dragItem->startPos(); @@ -1314,6 +1314,7 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint pos) updateSnapPoints(NULL, offsetList); m_selectionGroup->setPos(framePos); scene()->addItem(m_selectionGroup); + m_selectionGroup->setZValue(10); return true; } else if (data->hasFormat("kdenlive/producerslist")) { m_clipDrag = true; @@ -1357,6 +1358,7 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint pos) start += info.cropDuration; offsetList.append(start); ClipItem *item = new ClipItem(clip, info, m_document->fps(), 1.0, 1, false); + item->setZValue(10); item->setFlags(QGraphicsItem::ItemIsSelectable); m_selectionGroup->addToGroup(item); m_waitingThumbs.append(item); @@ -1365,6 +1367,7 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint pos) updateSnapPoints(NULL, offsetList); m_selectionGroup->setPos(framePos); scene()->addItem(m_selectionGroup); + m_selectionGroup->setZValue(10); m_thumbsTimer.start(); return true; @@ -1691,7 +1694,7 @@ void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect m_commandStack->push(command); } -void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) +ClipItem *CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut, bool execute) { if (cut) { // cut clip @@ -1700,7 +1703,7 @@ void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) emit displayMessage(i18n("Cannot find clip to cut"), ErrorMessage); kDebug() << "///////// ERROR CUTTING CLIP : (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << "-" << info.endPos.frames(25) << ")" << ", CUT: " << cutTime.frames(25); m_blockRefresh = false; - return; + return NULL; } if (item->parentItem()) { // Item is part of a group, reset group @@ -1708,7 +1711,7 @@ void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) } kDebug() << "///////// CUTTING CLIP : (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << "-" << info.endPos.frames(25) << ")" << ", CUT: " << cutTime.frames(25); - m_document->renderer()->mltCutClip(m_document->tracksCount() - info.track, cutTime); + if (execute) m_document->renderer()->mltCutClip(m_document->tracksCount() - info.track, cutTime); int cutPos = (int) cutTime.frames(m_document->fps()); ItemInfo newPos; newPos.startPos = cutTime; @@ -1737,6 +1740,7 @@ void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) item->baseClip()->addReference(); m_document->updateClip(item->baseClip()->getId()); setDocumentModified(); + return dup; //kDebug() << "///////// CUTTING CLIP RESULT: (" << item->startPos().frames(25) << "-" << item->endPos().frames(25) << "), DUP: (" << dup->startPos().frames(25) << "-" << dup->endPos().frames(25) << ")" << ", CUT: " << cutTime.frames(25); } else { // uncut clip @@ -1746,11 +1750,11 @@ void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) if (!item || !dup || item == dup) { emit displayMessage(i18n("Cannot find clip to uncut"), ErrorMessage); m_blockRefresh = false; - return; + return NULL; } if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, cutTime) == false) { emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(cutTime.frames(m_document->fps())), info.track), ErrorMessage); - return; + return NULL; } /*kDebug() << "// UNCUTTING CLIPS: ITEM 1 (" << item->startPos().frames(25) << "x" << item->endPos().frames(25) << ")"; @@ -1773,9 +1777,10 @@ void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) setDocumentModified(); } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); + return item; } - QTimer::singleShot(3000, this, SLOT(slotEnableRefresh())); + //QTimer::singleShot(3000, this, SLOT(slotEnableRefresh())); } void CustomTrackView::slotEnableRefresh() @@ -1992,8 +1997,9 @@ void CustomTrackView::dropEvent(QDropEvent * event) updateClipTypeActions(NULL); } - new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false, addCommand); + //TODO: take care of edit mode for undo item->baseClip()->addReference(); + item->setZValue(2); m_document->updateClip(item->baseClip()->getId()); ItemInfo info = item->info(); @@ -2002,9 +2008,58 @@ void CustomTrackView::dropEvent(QDropEvent * event) if (isLocked) item->setItemLocked(true); ItemInfo clipInfo = info; clipInfo.track = m_document->tracksCount() - item->track(); - if (m_document->renderer()->mltInsertClip(clipInfo, item->xml(), item->baseClip()->producer(item->track())) == -1) { + if (m_document->renderer()->mltInsertClip(clipInfo, item->xml(), item->baseClip()->producer(item->track()), m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT) == -1) { emit displayMessage(i18n("Cannot insert clip in timeline"), ErrorMessage); } + if (m_scene->editMode() == OVERWRITEEDIT) { + // if we are in overwrite or push mode, move clips accordingly + QRectF rect(clipInfo.startPos.frames(m_document->fps()), info.track * m_tracksHeight + m_tracksHeight / 2, (clipInfo.endPos - clipInfo.startPos).frames(m_document->fps()) - 1, m_tracksHeight / 2 - 2); + QList selection = m_scene->items(rect); + selection.removeAll(item); + for (int i = 0; i < selection.count(); i++) { + if (selection.at(i)->type() == AVWIDGET) { + ClipItem *clip = static_cast(selection.at(i)); + kDebug() << " - - FOUND COLLIDE CLIP: " << clip->baseClip()->getId(); + if (clip->startPos() < item->startPos()) { + if (clip->endPos() > item->endPos()) { + ItemInfo clipInfo = clip->info(); + ItemInfo dupInfo = clipInfo; + GenTime diff = item->startPos() - clip->startPos(); + dupInfo.startPos = item->startPos(); + dupInfo.cropStart += diff + GenTime(1, m_document->fps()); + dupInfo.cropDuration += GenTime() - diff; + ItemInfo newdupInfo = dupInfo; + GenTime diff2 = item->endPos() - item->startPos(); + newdupInfo.startPos = GenTime(item->endPos().frames(m_document->fps()), m_document->fps()); + newdupInfo.cropStart += diff2; + newdupInfo.cropDuration += GenTime() - diff2; + new RazorClipCommand(this, clipInfo, item->startPos(), false, addCommand); + new ResizeClipCommand(this, dupInfo, newdupInfo, false, false, addCommand); + ClipItem *dup = cutClip(clipInfo, item->startPos(), true, false); + if (dup) dup->resizeStart(item->endPos().frames(m_document->fps())); + + } else { + ItemInfo newclipInfo = clip->info(); + newclipInfo.endPos = item->startPos(); + new ResizeClipCommand(this, clip->info(), newclipInfo, false, false, addCommand); + clip->resizeEnd(item->startPos().frames(m_document->fps())); + } + } else if (clip->endPos() < item->endPos()) { + new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), clip->info(), clip->effectList(), false, true, addCommand); + scene()->removeItem(clip); + delete clip; + clip = NULL; + } else { + ItemInfo newclipInfo = clip->info(); + newclipInfo.startPos = item->endPos(); + new ResizeClipCommand(this, clip->info(), newclipInfo, false, false, addCommand); + clip->resizeStart(item->endPos().frames(m_document->fps())); + } + } + } + } + + new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false, addCommand); if (item->baseClip()->isTransparent() && getTransitionItemAtStart(info.startPos, info.track) == NULL) { // add transparency transition @@ -2613,7 +2668,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) if (m_operationMode == MOVE) { setCursor(Qt::OpenHandCursor); - + if (m_dragItem) m_dragItem->setZValue(2); if (m_dragItem->parentItem() == 0) { // we are moving one clip, easy if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) { @@ -2622,14 +2677,60 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) if (item->isAudioOnly()) prod = item->baseClip()->audioProducer(m_dragItemInfo.track); else if (item->isVideoOnly()) prod = item->baseClip()->videoProducer(); else prod = item->baseClip()->producer(m_dragItemInfo.track); - bool success = m_document->renderer()->mltMoveClip((int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItem->track()), (int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItem->startPos().frames(m_document->fps())), prod); + bool success = m_document->renderer()->mltMoveClip((int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItem->track()), (int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItem->startPos().frames(m_document->fps())), prod, m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT); if (success) { + QUndoCommand *moveCommand = new QUndoCommand(); + moveCommand->setText(i18n("Move clip")); + + if (m_scene->editMode() == OVERWRITEEDIT) { + // if we are in overwrite or push mode, move clips accordingly + QRectF rect(info.startPos.frames(m_document->fps()), info.track * m_tracksHeight + m_tracksHeight / 2, (info.endPos - info.startPos).frames(m_document->fps()) - 1, m_tracksHeight / 2 - 2); + QList selection = m_scene->items(rect); + selection.removeAll(item); + for (int i = 0; i < selection.count(); i++) { + if (selection.at(i)->type() == AVWIDGET) { + ClipItem *clip = static_cast(selection.at(i)); + if (clip->startPos() < item->startPos()) { + if (clip->endPos() > item->endPos()) { + ItemInfo clipInfo = clip->info(); + ItemInfo dupInfo = clipInfo; + GenTime diff = item->startPos() - clip->startPos(); + dupInfo.startPos = item->startPos(); + dupInfo.cropStart += diff + GenTime(1, m_document->fps()); + dupInfo.cropDuration += GenTime() - diff; + ItemInfo newdupInfo = dupInfo; + GenTime diff2 = item->endPos() - item->startPos(); + newdupInfo.startPos = GenTime(item->endPos().frames(m_document->fps()), m_document->fps()); + newdupInfo.cropStart += diff2; + newdupInfo.cropDuration += GenTime() - diff2; + new RazorClipCommand(this, clipInfo, item->startPos(), false, moveCommand); + new ResizeClipCommand(this, dupInfo, newdupInfo, false, false, moveCommand); + ClipItem *dup = cutClip(clipInfo, item->startPos(), true, false); + if (dup) dup->resizeStart(item->endPos().frames(m_document->fps())); + } else { + ItemInfo newclipInfo = clip->info(); + newclipInfo.endPos = item->startPos(); + new ResizeClipCommand(this, clip->info(), newclipInfo, false, false, moveCommand); + clip->resizeEnd(item->startPos().frames(m_document->fps())); + } + } else if (clip->endPos() < item->endPos()) { + new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), clip->info(), clip->effectList(), false, true, moveCommand); + scene()->removeItem(clip); + delete clip; + clip = NULL; + } else { + ItemInfo newclipInfo = clip->info(); + newclipInfo.startPos = item->endPos(); + new ResizeClipCommand(this, clip->info(), newclipInfo, false, false, moveCommand); + clip->resizeStart(item->endPos().frames(m_document->fps())); + } + } + } + } int tracknumber = m_document->tracksCount() - item->track() - 1; bool isLocked = m_document->trackInfoAt(tracknumber).isLocked; if (isLocked) item->setItemLocked(true); - QUndoCommand *moveCommand = new QUndoCommand(); - moveCommand->setText(i18n("Move clip")); new MoveClipCommand(this, m_dragItemInfo, info, false, moveCommand); // Also move automatic transitions (on lower track) Transition *startTransition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track); @@ -4326,6 +4427,10 @@ void CustomTrackView::copyClip() bool CustomTrackView::canBePastedTo(ItemInfo info, int type) const { + if (m_scene->editMode() != NORMALEDIT) { + // If we are in overwrite mode, always allow the move + return true; + } QRectF rect((double) info.startPos.frames(m_document->fps()), (double)(info.track * m_tracksHeight + 1), (double)(info.endPos - info.startPos).frames(m_document->fps()), (double)(m_tracksHeight - 1)); QList collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect); for (int i = 0; i < collisions.count(); i++) { @@ -5286,4 +5391,11 @@ void CustomTrackView::selectTransition(bool add, bool group) } } if (group) groupSelectedItems(); -} \ No newline at end of file +} + +void CustomTrackView::setEditMode(EDITMODE mode) +{ + m_scene->setEditMode(mode); +} + + diff --git a/src/customtrackview.h b/src/customtrackview.h index ba7bfa74..d2fe4608 100644 --- a/src/customtrackview.h +++ b/src/customtrackview.h @@ -31,12 +31,12 @@ #include "docclipbase.h" #include "guide.h" #include "effectslist.h" +#include "customtrackscene.h" class ClipItem; class AbstractClipItem; class AbstractGroupItem; class Transition; -class CustomTrackScene; class CustomTrackView : public QGraphicsView { @@ -84,7 +84,7 @@ public: void checkTrackHeight(); //QList tracksList() const; void setTool(PROJECTTOOL tool); - void cutClip(ItemInfo info, GenTime cutTime, bool cut); + ClipItem *cutClip(ItemInfo info, GenTime cutTime, bool cut, bool execute = true); void slotSeekToPreviousSnap(); void slotSeekToNextSnap(); double getSnapPointForPos(double pos); @@ -127,6 +127,7 @@ public: int selectedTrack() const; void selectClip(bool add, bool group = false); void selectTransition(bool add, bool group = false); + void setEditMode(EDITMODE mode); public slots: void setCursorPos(int pos, bool seek = true); diff --git a/src/kdenliveui.rc b/src/kdenliveui.rc index 2c4b698d..91e60ccd 100644 --- a/src/kdenliveui.rc +++ b/src/kdenliveui.rc @@ -1,6 +1,6 @@ - + Extra Toolbar @@ -46,6 +46,10 @@ Tool + + + + diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5d9b16d9..c17d6109 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -739,10 +739,41 @@ void MainWindow::setupActions() KToolBar *toolbar = new KToolBar("statusToolBar", this, Qt::BottomToolBarArea); toolbar->setMovable(false); - m_toolGroup = new QActionGroup(this); statusBar()->setStyleSheet(QString("QStatusBar QLabel {font-size:%1pt;} QStatusBar::item { border: 0px; font-size:%1pt;padding:0px; }").arg(statusBar()->font().pointSize())); QString style1 = "QToolBar { border: 0px } QToolButton { border-style: inset; border:1px solid #999999;border-radius: 3px;margin: 0px 3px;padding: 0px;} QToolButton:checked { background-color: rgba(224, 224, 0, 100); border-style: inset; border:1px solid #cc6666;border-radius: 3px;}"; + + // create edit mode buttons + KAction *normaledit = new KAction(KIcon("kdenlive-normal-edit"), i18n("Normal mode"), this); + normaledit->setShortcut(i18nc("Normal editing", "n")); + toolbar->addAction(normaledit); + normaledit->setCheckable(true); + normaledit->setChecked(true); + + m_overwriteModeTool = new KAction(KIcon("kdenlive-overwrite-edit"), i18n("Overwrite mode"), this); + m_overwriteModeTool->setShortcut(i18nc("Overwrite mode shortcut", "o")); + toolbar->addAction(m_overwriteModeTool); + m_overwriteModeTool->setCheckable(true); + m_overwriteModeTool->setChecked(false); + + m_insertModeTool = new KAction(KIcon("kdenlive-insert-edit"), i18n("Insert mode"), this); + m_insertModeTool->setShortcut(i18nc("Insert mode shortcut", "i")); + toolbar->addAction(m_insertModeTool); + m_insertModeTool->setCheckable(true); + m_insertModeTool->setChecked(false); + // not implemented yet + m_insertModeTool->setEnabled(false); + + QActionGroup *editGroup = new QActionGroup(this); + editGroup->addAction(normaledit); + editGroup->addAction(m_overwriteModeTool); + editGroup->addAction(m_insertModeTool); + editGroup->setExclusive(true); + connect(editGroup, SIGNAL(triggered(QAction *)), this, SLOT(slotChangeEdit(QAction *))); + //connect(m_overwriteModeTool, SIGNAL(toggled(bool)), this, SLOT(slotSetOverwriteMode(bool))); + + toolbar->addSeparator(); + // create tools buttons m_buttonSelectTool = new KAction(KIcon("kdenlive-select-tool"), i18n("Selection tool"), this); m_buttonSelectTool->setShortcut(i18nc("Selection tool shortcut", "s")); toolbar->addAction(m_buttonSelectTool); @@ -761,14 +792,27 @@ void MainWindow::setupActions() m_buttonSpacerTool->setCheckable(true); m_buttonSpacerTool->setChecked(false); - m_toolGroup->addAction(m_buttonSelectTool); - m_toolGroup->addAction(m_buttonRazorTool); - m_toolGroup->addAction(m_buttonSpacerTool); - m_toolGroup->setExclusive(true); + QActionGroup *toolGroup = new QActionGroup(this); + toolGroup->addAction(m_buttonSelectTool); + toolGroup->addAction(m_buttonRazorTool); + toolGroup->addAction(m_buttonSpacerTool); + toolGroup->setExclusive(true); toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); QWidget * actionWidget; int max = toolbar->iconSizeDefault() + 2; + actionWidget = toolbar->widgetForAction(normaledit); + actionWidget->setMaximumWidth(max); + actionWidget->setMaximumHeight(max - 4); + + actionWidget = toolbar->widgetForAction(m_insertModeTool); + actionWidget->setMaximumWidth(max); + actionWidget->setMaximumHeight(max - 4); + + actionWidget = toolbar->widgetForAction(m_overwriteModeTool); + actionWidget->setMaximumWidth(max); + actionWidget->setMaximumHeight(max - 4); + actionWidget = toolbar->widgetForAction(m_buttonSelectTool); actionWidget->setMaximumWidth(max); actionWidget->setMaximumHeight(max - 4); @@ -782,7 +826,7 @@ void MainWindow::setupActions() actionWidget->setMaximumHeight(max - 4); toolbar->setStyleSheet(style1); - connect(m_toolGroup, SIGNAL(triggered(QAction *)), this, SLOT(slotChangeTool(QAction *))); + connect(toolGroup, SIGNAL(triggered(QAction *)), this, SLOT(slotChangeTool(QAction *))); toolbar->addSeparator(); m_buttonFitZoom = new KAction(KIcon("zoom-fit-best"), i18n("Fit zoom to project"), this); @@ -852,6 +896,9 @@ void MainWindow::setupActions() statusBar()->addPermanentWidget(m_timecodeFormat); //statusBar()->setMaximumHeight(statusBar()->font().pointSize() * 3); + collection->addAction("normal_mode", normaledit); + collection->addAction("overwrite_mode", m_overwriteModeTool); + collection->addAction("insert_mode", m_insertModeTool); collection->addAction("select_tool", m_buttonSelectTool); collection->addAction("razor_tool", m_buttonRazorTool); collection->addAction("spacer_tool", m_buttonSpacerTool); @@ -2579,6 +2626,14 @@ void MainWindow::slotChangeTool(QAction * action) else if (action == m_buttonSpacerTool) slotSetTool(SPACERTOOL); } +void MainWindow::slotChangeEdit(QAction * action) +{ + if (!m_activeTimeline) return; + if (action == m_overwriteModeTool) m_activeTimeline->projectView()->setEditMode(OVERWRITEEDIT); + else if (action == m_insertModeTool) m_activeTimeline->projectView()->setEditMode(INSERTEDIT); + else m_activeTimeline->projectView()->setEditMode(NORMALEDIT); +} + void MainWindow::slotSetTool(PROJECTTOOL tool) { if (m_activeDocument && m_activeTimeline) { diff --git a/src/mainwindow.h b/src/mainwindow.h index 781aaa04..7cd9bc7c 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -166,11 +166,12 @@ private: KAction *m_buttonVideoThumbs; KAction *m_buttonShowMarkers; KAction *m_buttonFitZoom; + KAction *m_overwriteModeTool; + KAction *m_insertModeTool; KAction *m_buttonSelectTool; KAction *m_buttonRazorTool; KAction *m_buttonSpacerTool; KAction *m_buttonSnap; - QActionGroup *m_toolGroup; KAction *m_saveAction; KAction *m_closeAction; QSlider *m_zoomSlider; @@ -266,6 +267,7 @@ private slots: void slotActivateEffectStackView(); void slotActivateTransitionView(Transition *); void slotChangeTool(QAction * action); + void slotChangeEdit(QAction * action); void slotSetTool(PROJECTTOOL tool); void slotSnapForward(); void slotSnapRewind(); diff --git a/src/razorclipcommand.cpp b/src/razorclipcommand.cpp index 557d594a..023f39f8 100644 --- a/src/razorclipcommand.cpp +++ b/src/razorclipcommand.cpp @@ -23,11 +23,12 @@ #include -RazorClipCommand::RazorClipCommand(CustomTrackView *view, const ItemInfo info, const GenTime cutTime, QUndoCommand * parent) : +RazorClipCommand::RazorClipCommand(CustomTrackView *view, const ItemInfo info, const GenTime cutTime, bool doIt, QUndoCommand * parent) : QUndoCommand(parent), m_view(view), m_info(info), - m_cutTime(cutTime) + m_cutTime(cutTime), + m_doIt(doIt) { setText(i18n("Razor clip")); } @@ -42,6 +43,7 @@ void RazorClipCommand::undo() void RazorClipCommand::redo() { // kDebug() << "---- redoing action cut: " << m_cutTime.frames(25); - m_view->cutClip(m_info, m_cutTime, true); + if (m_doIt) m_view->cutClip(m_info, m_cutTime, true); + m_doIt = true; } diff --git a/src/razorclipcommand.h b/src/razorclipcommand.h index 4bfc9e93..c66a22c0 100644 --- a/src/razorclipcommand.h +++ b/src/razorclipcommand.h @@ -32,7 +32,7 @@ class CustomTrackView; class RazorClipCommand : public QUndoCommand { public: - RazorClipCommand(CustomTrackView *view, const ItemInfo info, const GenTime cutTime, QUndoCommand * parent = 0); + RazorClipCommand(CustomTrackView *view, const ItemInfo info, const GenTime cutTime, bool doIt = true, QUndoCommand * parent = 0); virtual void undo(); virtual void redo(); @@ -40,6 +40,7 @@ private: CustomTrackView *m_view; ItemInfo m_info; GenTime m_cutTime; + bool m_doIt; }; #endif diff --git a/src/renderer.cpp b/src/renderer.cpp index 4f6f95e2..349a6a90 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1533,7 +1533,7 @@ void Render::mltCheckLength(Mlt::Tractor *tractor) } } -int Render::mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *prod) +int Render::mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *prod, bool overwrite, bool push) { if (m_mltProducer == NULL) { kDebug() << "PLAYLIST NOT INITIALISED //////"; @@ -1561,6 +1561,7 @@ int Render::mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *pro } mlt_service_lock(service.get_service()); Mlt::Producer trackProducer(tractor.track(info.track)); + int trackDuration = trackProducer.get_playtime() - 1; Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); //kDebug()<<"/// INSERT cLIP: "<cut((int) info.cropStart.frames(m_fps), (int)(info.endPos - info.startPos + info.cropStart).frames(m_fps) - 1); - int newIndex = trackPlaylist.insert_at((int) info.startPos.frames(m_fps), clip, 1); + int cutPos = (int) info.cropStart.frames(m_fps); + int insertPos = (int) info.startPos.frames(m_fps); + int cutDuration = (int)(info.endPos - info.startPos).frames(m_fps) - 1; + Mlt::Producer *clip = prod->cut(cutPos, cutDuration + cutPos); + if (overwrite && (insertPos < trackDuration)) { + // Replace zone with blanks + //trackPlaylist.split_at(insertPos, true); + trackPlaylist.remove_region(insertPos, cutDuration + 1); + int clipIndex = trackPlaylist.get_clip_index_at(insertPos); + trackPlaylist.insert_blank(clipIndex, cutDuration); + } else if (push) { + trackPlaylist.split_at(insertPos, true); + int clipIndex = trackPlaylist.get_clip_index_at(insertPos); + trackPlaylist.insert_blank(clipIndex, cutDuration); + } + int newIndex = trackPlaylist.insert_at(insertPos, clip, 1); delete clip; /*if (QString(prod->get("transparency")).toInt() == 1) mltAddClipTransparency(info, info.track - 1, QString(prod->get("id")).toInt());*/ @@ -2733,9 +2747,9 @@ bool Render::mltResizeClipStart(ItemInfo info, GenTime diff) return true; } -bool Render::mltMoveClip(int startTrack, int endTrack, GenTime moveStart, GenTime moveEnd, Mlt::Producer *prod) +bool Render::mltMoveClip(int startTrack, int endTrack, GenTime moveStart, GenTime moveEnd, Mlt::Producer *prod, bool overwrite, bool insert) { - return mltMoveClip(startTrack, endTrack, (int) moveStart.frames(m_fps), (int) moveEnd.frames(m_fps), prod); + return mltMoveClip(startTrack, endTrack, (int) moveStart.frames(m_fps), (int) moveEnd.frames(m_fps), prod, overwrite, insert); } @@ -2779,7 +2793,7 @@ bool Render::mltUpdateClipProducer(int track, int pos, Mlt::Producer *prod) return true; } -bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEnd, Mlt::Producer *prod) +bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEnd, Mlt::Producer *prod, bool overwrite, bool insert) { m_isBlocked++; @@ -2798,7 +2812,7 @@ bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn bool checkLength = false; if (endTrack == startTrack) { Mlt::Producer *clipProducer = trackPlaylist.replace_with_blank(clipIndex); - if (!trackPlaylist.is_blank_at(moveEnd) || !clipProducer || clipProducer->is_blank()) { + if (!overwrite && (!trackPlaylist.is_blank_at(moveEnd) || !clipProducer || clipProducer->is_blank())) { // error, destination is not empty if (!trackPlaylist.is_blank_at(moveEnd)) trackPlaylist.insert_at(moveStart, clipProducer, 1); if (clipProducer) delete clipProducer; @@ -2809,6 +2823,11 @@ bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn return false; } else { trackPlaylist.consolidate_blanks(0); + if (overwrite) { + trackPlaylist.remove_region(moveEnd, clipProducer->get_playtime()); + int clipIndex = trackPlaylist.get_clip_index_at(moveEnd); + trackPlaylist.insert_blank(clipIndex, clipProducer->get_playtime() - 1); + } int newIndex = trackPlaylist.insert_at(moveEnd, clipProducer, 1); delete clipProducer; /*if (QString(clipProducer.parent().get("transparency")).toInt() == 1) { @@ -2908,7 +2927,7 @@ bool Render::mltMoveTransition(QString type, int startTrack, int newTrack, int n int currentTrack = transition.get_b_track(); int currentIn = (int) transition.get_in(); int currentOut = (int) transition.get_out(); - + if (resource == type && startTrack == currentTrack && currentIn <= old_pos && currentOut >= old_pos) { found = true; if (newTrack - startTrack != 0) { diff --git a/src/renderer.h b/src/renderer.h index c7d308ea..e1cd584b 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -169,7 +169,7 @@ Q_OBJECT public: double dar() const; /** Playlist manipulation */ - int mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *prod); + int mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *prod, bool overwrite = false, bool push = false); bool mltUpdateClip(ItemInfo info, QDomElement element, Mlt::Producer *prod); void mltCutClip(int track, GenTime position); void mltInsertSpace(QMap trackClipStartList, QMap trackTransitionStartList, int track, const GenTime duration, const GenTime timeOffset); @@ -178,8 +178,8 @@ Q_OBJECT public: bool mltResizeClipEnd(ItemInfo info, GenTime clipDuration); bool mltResizeClipStart(ItemInfo info, GenTime diff); bool mltResizeClipCrop(ItemInfo info, GenTime diff); - bool mltMoveClip(int startTrack, int endTrack, GenTime pos, GenTime moveStart, Mlt::Producer *prod); - bool mltMoveClip(int startTrack, int endTrack, int pos, int moveStart, Mlt::Producer *prod); + bool mltMoveClip(int startTrack, int endTrack, GenTime pos, GenTime moveStart, Mlt::Producer *prod, bool overwrite = false, bool insert = false); + bool mltMoveClip(int startTrack, int endTrack, int pos, int moveStart, Mlt::Producer *prod, bool overwrite = false, bool insert = false); bool mltRemoveClip(int track, GenTime position); /** Delete an effect to a clip in MLT's playlist */ bool mltRemoveEffect(int track, GenTime position, QString index, bool updateIndex, bool doRefresh = true); diff --git a/src/transition.cpp b/src/transition.cpp index 2c37ffcd..a4700c8b 100644 --- a/src/transition.cpp +++ b/src/transition.cpp @@ -207,7 +207,9 @@ QVariant Transition::itemChange(GraphicsItemChange change, const QVariant &value // Only one clip is moving QRectF sceneShape = rect(); sceneShape.translate(newPos); - QList items = scene()->items(sceneShape, Qt::IntersectsItemShape); + QList items; + if (projectScene()->editMode() == NORMALEDIT) + items = scene()->items(sceneShape, Qt::IntersectsItemShape); items.removeAll(this); if (!items.isEmpty()) { -- 2.39.2