X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fcustomtrackview.cpp;h=9f513bd57af88eea16de7ef1d53f550582050396;hb=7caecc149e65907e4a57c8115c7cac12042e9308;hp=97f32b704727549b385c7af35c8e28da508c9271;hpb=228b8f4201c32557c62fe1dd1a31aeba127d2e00;p=kdenlive diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index 97f32b70..9f513bd5 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -61,7 +61,13 @@ #include "ui_keyframedialog_ui.h" #include "clipdurationdialog.h" #include "abstractgroupitem.h" - +#include "insertspacecommand.h" +#include "spacerdialog.h" +#include "addtrackcommand.h" +#include "changetrackcommand.h" +#include "movegroupcommand.h" +#include "ui_addtrack_ui.h" +#include "initeffects.h" //TODO: // disable animation if user asked it in KDE's global settings @@ -86,13 +92,17 @@ CustomTrackView::CustomTrackView(KdenliveDoc *doc, CustomTrackScene* projectscen m_tipPen.setColor(border); m_tipPen.setWidth(3); setContentsMargins(0, 0, 0, 0); - if (projectscene) { - m_cursorLine = projectscene->addLine(0, 0, 0, m_tracksHeight); - m_cursorLine->setZValue(1000); - } + const int maxWidth = m_tracksHeight * m_document->tracksCount(); + setSceneRect(0, 0, sceneRect().width(), maxWidth); + verticalScrollBar()->setMaximum(maxWidth); + m_cursorLine = projectscene->addLine(0, 0, 0, maxWidth); + m_cursorLine->setZValue(1000); KIcon razorIcon("edit-cut"); m_razorCursor = QCursor(razorIcon.pixmap(22, 22)); + + KIcon spacerIcon("kdenlive-spacer-tool"); + m_spacerCursor = QCursor(spacerIcon.pixmap(22, 22)); verticalScrollBar()->setTracking(true); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotRefreshGuides())); connect(&m_scrollTimer, SIGNAL(timeout()), this, SLOT(slotCheckMouseScrolling())); @@ -112,15 +122,18 @@ void CustomTrackView::setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transi m_timelineContextMenu = timeline; m_timelineContextClipMenu = clip; m_timelineContextTransitionMenu = transition; + QList list = m_timelineContextTransitionMenu->actions(); + for (int i = 0; i < list.count(); i++) + if (list.at(i)->data().toString() == "auto") m_autoTransition = list.at(i); } void CustomTrackView::checkAutoScroll() { m_autoScroll = KdenliveSettings::autoscroll(); } -QList CustomTrackView::tracksList() const { +/*sQList CustomTrackView::tracksList() const { return m_scene->m_tracksList; -} +}*/ void CustomTrackView::checkTrackHeight() { if (m_tracksHeight == KdenliveSettings::trackheight()) return; @@ -129,6 +142,8 @@ void CustomTrackView::checkTrackHeight() { QList itemList = items(); ClipItem *item; Transition *transitionitem; + bool snap = KdenliveSettings::snaptopoints(); + KdenliveSettings::setSnaptopoints(false); for (int i = 0; i < itemList.count(); i++) { if (itemList.at(i)->type() == AVWIDGET) { item = (ClipItem*) itemList.at(i); @@ -141,16 +156,17 @@ void CustomTrackView::checkTrackHeight() { transitionitem->setPos((qreal) transitionitem->startPos().frames(m_document->fps()), (qreal) transitionitem->track() * m_tracksHeight + m_tracksHeight / 3 * 2); } } - m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_scene->m_tracksList.count()); + m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_document->tracksCount()); for (int i = 0; i < m_guides.count(); i++) { QLineF l = m_guides.at(i)->line(); - l.setP2(QPointF(l.x2(), m_tracksHeight * m_scene->m_tracksList.count())); + l.setP2(QPointF(l.x2(), m_tracksHeight * m_document->tracksCount())); m_guides.at(i)->setLine(l); } - setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_scene->m_tracksList.count()); - verticalScrollBar()->setMaximum(m_tracksHeight * m_scene->m_tracksList.count()); + setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_document->tracksCount()); +// verticalScrollBar()->setMaximum(m_tracksHeight * m_document->tracksCount()); + KdenliveSettings::setSnaptopoints(snap); update(); } @@ -179,10 +195,10 @@ void CustomTrackView::wheelEvent(QWheelEvent * e) { } int CustomTrackView::getPreviousVideoTrack(int track) { - track = m_scene->m_tracksList.count() - track - 1; + track = m_document->tracksCount() - track - 1; track --; for (int i = track; i > -1; i--) { - if (m_scene->m_tracksList.at(i).type == VIDEOTRACK) return i + 1; + if (m_document->trackInfoAt(i).type == VIDEOTRACK) return i + 1; } return 0; } @@ -221,10 +237,17 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event) { int mappedXPos = (int)(mapToScene(event->pos()).x() + 0.5); emit mousePosition(mappedXPos); if (event->buttons() & Qt::MidButton) return; + if ((event->modifiers() == Qt::ControlModifier && m_tool != SPACERTOOL) || event->modifiers() == Qt::ShiftModifier) { + QGraphicsView::mouseMoveEvent(event); + m_moveOpMode = NONE; + return; + } + if (event->buttons() != Qt::NoButton) { + bool move = (event->pos() - m_clickEvent).manhattanLength() >= QApplication::startDragDistance(); if (m_dragItem && m_tool == SELECTTOOL) { - if (m_operationMode == MOVE) { - if ((event->pos() - m_clickEvent).manhattanLength() >= QApplication::startDragDistance()) QGraphicsView::mouseMoveEvent(event); + if (m_operationMode == MOVE && move) { + QGraphicsView::mouseMoveEvent(event); // If mouse is at a border of the view, scroll if (pos < 5) { m_scrollOffset = -30; @@ -234,17 +257,17 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event) { m_scrollTimer.start(); } else if (m_scrollTimer.isActive()) m_scrollTimer.stop(); - } else if (m_operationMode == RESIZESTART) { + } else if (m_operationMode == RESIZESTART && move) { double snappedPos = getSnapPointForPos(mappedXPos); m_dragItem->resizeStart((int)(snappedPos)); - } else if (m_operationMode == RESIZEEND) { + } else if (m_operationMode == RESIZEEND && move) { double snappedPos = getSnapPointForPos(mappedXPos); m_dragItem->resizeEnd((int)(snappedPos)); - } else if (m_operationMode == FADEIN) { + } else if (m_operationMode == FADEIN && move) { ((ClipItem*) m_dragItem)->setFadeIn((int)(mappedXPos - m_dragItem->startPos().frames(m_document->fps()))); - } else if (m_operationMode == FADEOUT) { + } else if (m_operationMode == FADEOUT && move) { ((ClipItem*) m_dragItem)->setFadeOut((int)(m_dragItem->endPos().frames(m_document->fps()) - mappedXPos)); - } else if (m_operationMode == KEYFRAME) { + } else if (m_operationMode == KEYFRAME && move) { GenTime keyFramePos = GenTime(mappedXPos, m_document->fps()) - m_dragItem->startPos() + m_dragItem->cropStart(); double pos = mapToScene(event->pos()).toPoint().y(); QRectF br = m_dragItem->sceneBoundingRect(); @@ -265,6 +288,10 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event) { m_visualTip = NULL; QGraphicsView::mouseMoveEvent(event); return; + } else if (m_operationMode == SPACER && move) { + // spacer tool + int mappedClick = (int)(mapToScene(m_clickEvent).x() + 0.5); + m_selectionGroup->setPos(mappedXPos + (((int) m_selectionGroup->boundingRect().topLeft().x() + 0.5) - mappedClick) , m_selectionGroup->pos().y()); } } @@ -272,6 +299,9 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event) { setCursor(m_razorCursor); //QGraphicsView::mouseMoveEvent(event); //return; + } else if (m_tool == SPACERTOOL) { + setCursor(m_spacerCursor); + return; } QList itemList = items(event->pos()); @@ -495,16 +525,18 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { if (event->button() == Qt::MidButton) { m_document->renderer()->switchPlay(); m_blockRefresh = false; + m_operationMode = NONE; return; } // check item under mouse QList collisionList = items(event->pos()); - if (event->modifiers() == Qt::ControlModifier && collisionList.count() == 0) { + if (event->modifiers() == Qt::ControlModifier && m_tool != SPACERTOOL && collisionList.count() == 0) { setDragMode(QGraphicsView::ScrollHandDrag); QGraphicsView::mousePressEvent(event); m_blockRefresh = false; + m_operationMode = NONE; return; } @@ -512,6 +544,7 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { setDragMode(QGraphicsView::RubberBandDrag); QGraphicsView::mousePressEvent(event); m_blockRefresh = false; + m_operationMode = RUBBERSELECTION; return; } @@ -524,10 +557,7 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { m_operationMode = MOVEGUIDE; // deselect all clips so that only the guide will move m_scene->clearSelection(); - if (m_selectionGroup) { - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = NULL; - } + resetSelectionGroup(); updateSnapPoints(NULL); QGraphicsView::mousePressEvent(event); return; @@ -545,37 +575,60 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { i++; } + if (m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) { + // update transition menu action + m_autoTransition->setChecked(static_cast(m_dragItem)->isAutomatic()); + m_autoTransition->setEnabled(true); + } else m_autoTransition->setEnabled(false); + // context menu requested if (event->button() == Qt::RightButton) { if (m_dragItem) { if (!m_dragItem->isSelected()) { + resetSelectionGroup(false); m_scene->clearSelection(); - if (m_selectionGroup) { - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = NULL; - } m_dragItem->setSelected(true); } } m_operationMode = NONE; displayContextMenu(event->globalPos(), m_dragItem); - m_menuPosition = event->pos(); + m_menuPosition = m_clickEvent; m_dragItem = NULL; event->accept(); return; } // No item under click - if (m_dragItem == NULL) { - if (m_selectionGroup) { - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = NULL; - } + if (m_dragItem == NULL || m_tool == SPACERTOOL) { + resetSelectionGroup(); setCursor(Qt::ArrowCursor); m_scene->clearSelection(); - setCursorPos((int)(mapToScene(event->x(), 0).x())); event->accept(); emit clipItemSelected(NULL); + if (m_tool == SPACERTOOL) { + QList selection; + if (event->modifiers() == Qt::ControlModifier) { + // Ctrl + click, select all items on track after click position + int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight); + selection = items(m_clickEvent.x(), track * m_tracksHeight + 1, sceneRect().width() - m_clickEvent.x(), m_tracksHeight - 2); + } else { + // Select all items on all tracks after click position + selection = items(event->pos().x(), 1, sceneRect().width() - event->pos().x(), sceneRect().height()); + } + m_selectionGroup = new AbstractGroupItem(m_document->fps()); + scene()->addItem(m_selectionGroup); + + for (int i = 0; i < selection.count(); i++) { + if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) { + m_selectionGroup->addToGroup(selection.at(i)); + selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable); + } + } + QPointF top = m_selectionGroup->boundingRect().topLeft(); + m_selectionGroup->setPos(top); + m_selectionGroup->translate(-top.x(), -top.y() + 1); + m_operationMode = SPACER; + } else setCursorPos((int)(mapToScene(event->x(), 0).x())); return; } @@ -596,32 +649,19 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { return; } updateSnapPoints(m_dragItem); - if (m_dragItem && m_dragItem->type() == AVWIDGET) emit clipItemSelected((ClipItem*) m_dragItem); + if (m_dragItem->type() == AVWIDGET) emit clipItemSelected((ClipItem*) m_dragItem); else emit clipItemSelected(NULL); - if (m_selectionGroup) { - // delete selection group - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = NULL; - } - - if (m_dragItem && m_operationMode == NONE) QGraphicsView::mousePressEvent(event); - - QList selection = m_scene->selectedItems(); - if (selection.count() > 1) { - m_selectionGroup = new AbstractGroupItem(m_document->fps()); - scene()->addItem(m_selectionGroup); - for (int i = 0; i < selection.count(); i++) { - if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) - m_selectionGroup->addToGroup(selection.at(i)); - } - QPointF top = m_selectionGroup->boundingRect().topLeft(); - const int width = m_selectionGroup->boundingRect().width(); - const int height = m_selectionGroup->boundingRect().height(); - m_selectionGroup->setPos(top); - m_selectionGroup->translate(-top.x(), -top.y() + 1); - m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()); - m_selectionGroupInfo.track = m_selectionGroup->track(); + if (event->modifiers() != Qt::ControlModifier && (m_dragItem->group() || m_dragItem->isSelected())) { + // If clicked item is selected, allow move + event->accept(); + if (m_selectionGroup) m_selectionGroup->setSelected(true); + if (m_operationMode == NONE) QGraphicsView::mousePressEvent(event); + } else { + resetSelectionGroup(); + if (event->modifiers() != Qt::ControlModifier) m_scene->clearSelection(); + m_dragItem->setSelected(!m_dragItem->isSelected()); + groupSelectedItems(); } m_clickPoint = QPoint((int)(mapToScene(event->pos()).x() - m_dragItem->startPos().frames(m_document->fps())), (int)(event->pos().y() - m_dragItem->pos().y())); @@ -667,7 +707,7 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { info.track = m_dragItem->track(); int transitiontrack = getPreviousVideoTrack(info.track); ClipItem *transitionClip = NULL; - if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack); + if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack); if (transitionClip && transitionClip->endPos() < m_dragItem->endPos()) { info.endPos = transitionClip->endPos(); } else info.endPos = info.startPos + GenTime(65, m_document->fps()); @@ -679,7 +719,7 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { info.track = m_dragItem->track(); int transitiontrack = getPreviousVideoTrack(info.track); ClipItem *transitionClip = NULL; - if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack); + if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack); if (transitionClip && transitionClip->startPos() > m_dragItem->startPos()) { info.startPos = transitionClip->startPos(); } else info.startPos = info.endPos - GenTime(65, m_document->fps()); @@ -687,6 +727,9 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { QDomElement transition = MainWindow::transitions.getEffectByName("Luma").cloneNode().toElement(); EffectsList::setParameter(transition, "reverse", "1"); slotAddTransition((ClipItem *) m_dragItem, info, transitiontrack, transition); + } else if ((m_operationMode == RESIZESTART || m_operationMode == RESIZEEND) && m_selectionGroup) { + resetSelectionGroup(false); + m_dragItem->setSelected(true); } m_blockRefresh = false; @@ -694,7 +737,53 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event) { //QGraphicsView::mousePressEvent(event); } +void CustomTrackView::resetSelectionGroup(bool selectItems) { + if (m_selectionGroup) { + // delete selection group + bool snap = KdenliveSettings::snaptopoints(); + KdenliveSettings::setSnaptopoints(false); + QList children = m_selectionGroup->childItems(); + for (int i = 0; i < children.count(); i++) { + children.at(i)->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + children.at(i)->setSelected(selectItems); + } + scene()->destroyItemGroup(m_selectionGroup); + m_selectionGroup = NULL; + KdenliveSettings::setSnaptopoints(snap); + } +} + +void CustomTrackView::groupSelectedItems() { + if (m_selectionGroup) { + kDebug() << "///// ERROR, TRYING TO OVERRIDE EXISTING GROUP"; + return; + } + QList selection = m_scene->selectedItems(); + if (selection.count() > 1) { + m_selectionGroup = new AbstractGroupItem(m_document->fps()); + scene()->addItem(m_selectionGroup); + for (int i = 0; i < selection.count(); i++) { + if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) { + m_selectionGroup->addToGroup(selection.at(i)); + selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable); + } + } + + if (m_selectionGroup) { + bool snap = KdenliveSettings::snaptopoints(); + KdenliveSettings::setSnaptopoints(false); + QPointF top = m_selectionGroup->sceneBoundingRect().topLeft(); + m_selectionGroup->translate(-top.x(), -top.y() + 1); + m_selectionGroup->setPos(top); + m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()); + m_selectionGroupInfo.track = m_selectionGroup->track(); + KdenliveSettings::setSnaptopoints(snap); + } + } else resetSelectionGroup(); +} + void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event) { + kDebug() << "++++++++++++ DBL CLK"; if (m_dragItem && m_dragItem->hasKeyFrames()) { if (m_moveOpMode == KEYFRAME) { // user double clicked on a keyframe, open edit dialog @@ -713,7 +802,7 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event) { QString next = item->keyframes(item->selectedEffectIndex()); EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false); m_commandStack->push(command); - updateEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex()); + updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex()); } } else { @@ -726,7 +815,7 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event) { QString next = item->keyframes(item->selectedEffectIndex()); EditKeyFrameCommand *command = new EditKeyFrameCommand(this, m_dragItem->track(), m_dragItem->startPos(), item->selectedEffectIndex(), previous, next, false); m_commandStack->push(command); - updateEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex()); + updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex()); } } else if (m_dragItem) { ClipDurationDialog d(m_dragItem, m_document->timecode(), this); @@ -778,7 +867,7 @@ void CustomTrackView::editKeyFrame(const GenTime pos, const int track, const int ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), track); if (clip) { clip->setKeyframes(index, keyframes); - updateEffect(m_scene->m_tracksList.count() - clip->track(), clip->startPos(), clip->effectAt(index), index); + updateEffect(m_document->tracksCount() - clip->track(), clip->startPos(), clip->effectAt(index), index); } else emit displayMessage(i18n("Cannot find clip with keyframe"), ErrorMessage); } @@ -795,10 +884,7 @@ void CustomTrackView::activateMonitor() { void CustomTrackView::dragEnterEvent(QDragEnterEvent * event) { if (event->mimeData()->hasFormat("kdenlive/clip")) { - if (m_selectionGroup) { - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = NULL; - } + resetSelectionGroup(); QStringList list = QString(event->mimeData()->data("kdenlive/clip")).split(";"); m_selectionGroup = new AbstractGroupItem(m_document->fps()); @@ -819,10 +905,7 @@ void CustomTrackView::dragEnterEvent(QDragEnterEvent * event) { } else if (event->mimeData()->hasFormat("kdenlive/producerslist")) { QStringList ids = QString(event->mimeData()->data("kdenlive/producerslist")).split(";"); m_scene->clearSelection(); - if (m_selectionGroup) { - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = NULL; - } + resetSelectionGroup(false); m_selectionGroup = new AbstractGroupItem(m_document->fps()); QPoint pos = QPoint(); @@ -876,7 +959,7 @@ bool CustomTrackView::insertPossible(AbstractGroupItem *group, const QPoint &pos } void CustomTrackView::slotRefreshEffects(ClipItem *clip) { - int track = m_scene->m_tracksList.count() - clip->track(); + int track = m_document->tracksCount() - clip->track(); GenTime pos = clip->startPos(); if (!m_document->renderer()->mltRemoveEffect(track, pos, "-1", false)) { emit displayMessage(i18n("Problem deleting effect"), ErrorMessage); @@ -891,10 +974,9 @@ void CustomTrackView::slotRefreshEffects(ClipItem *clip) { } void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect) { - ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track); + ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track); if (clip) { - QHash effectParams = clip->addEffect(effect); - if (!m_document->renderer()->mltAddEffect(track, pos, effectParams)) + if (!m_document->renderer()->mltAddEffect(track, pos, clip->addEffect(effect))) emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage); emit clipItemSelected(clip); } else emit displayMessage(i18n("Cannot find clip to add effect"), ErrorMessage); @@ -906,7 +988,7 @@ void CustomTrackView::deleteEffect(int track, GenTime pos, QDomElement effect) { emit displayMessage(i18n("Problem deleting effect"), ErrorMessage); return; } - ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track); + ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track); if (clip) { clip->deleteEffect(index); emit clipItemSelected(clip); @@ -926,7 +1008,12 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track) if (itemList.at(i)->type() == AVWIDGET) { ClipItem *item = (ClipItem *)itemList.at(i); item->initEffect(effect); - AddEffectCommand *command = new AddEffectCommand(this, m_scene->m_tracksList.count() - item->track(), item->startPos(), effect, true); + if (effect.attribute("tag") == "ladspa") { + QString ladpsaFile = m_document->getLadspaFile(); + initEffects::ladspaEffectFile(ladpsaFile, effect.attribute("ladspaid").toInt(), getLadspaParams(effect)); + effect.setAttribute("src", ladpsaFile); + } + AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), effect, true); m_commandStack->push(command); } } @@ -934,26 +1021,30 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track) } void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect) { - AddEffectCommand *command = new AddEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), effect, false); + AddEffectCommand *command = new AddEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, false); m_commandStack->push(command); m_document->setModified(true); } void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement effect, int ix, bool triggeredByUser) { - ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track); + ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track); if (clip) { - QHash effectParams = clip->getEffectArgs(effect); + EffectsParameterList effectParams = clip->getEffectArgs(effect); + if (effect.attribute("tag") == "ladspa") { + // Update the ladspa affect file + initEffects::ladspaEffectFile(effect.attribute("src"), effect.attribute("ladspaid").toInt(), getLadspaParams(effect)); + } // check if we are trying to reset a keyframe effect - if (effectParams.contains("keyframes") && effectParams.value("keyframes").isEmpty()) { + if (effectParams.hasParam("keyframes") && effectParams.paramValue("keyframes").isEmpty()) { clip->initEffect(effect); clip->setEffectAt(ix, effect); effectParams = clip->getEffectArgs(effect); } - if (effectParams.value("disabled") == "1") { - if (m_document->renderer()->mltRemoveEffect(track, pos, effectParams.value("kdenlive_ix"))) { + if (effectParams.paramValue("disabled") == "1") { + if (m_document->renderer()->mltRemoveEffect(track, pos, effectParams.paramValue("kdenlive_ix"))) { kDebug() << "////// DISABLING EFFECT: " << index << ", CURRENTLA: " << clip->selectedEffectIndex(); } else emit displayMessage(i18n("Problem deleting effect"), ErrorMessage); - } else if (!m_document->renderer()->mltEditEffect(m_scene->m_tracksList.count() - clip->track(), clip->startPos(), effectParams)) + } else if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - clip->track(), clip->startPos(), effectParams)) emit displayMessage(i18n("Problem editing effect"), ErrorMessage); clip->setEffectAt(ix, effect); @@ -964,11 +1055,11 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement effect, i if (effect.attribute("tag") == "volume") { // A fade effect was modified, update the clip if (effect.attribute("id") == "fadein") { - int pos = effectParams.value("out").toInt() - effectParams.value("in").toInt(); + int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt(); clip->setFadeIn(pos); } if (effect.attribute("id") == "fadeout") { - int pos = effectParams.value("out").toInt() - effectParams.value("in").toInt(); + int pos = effectParams.paramValue("out").toInt() - effectParams.paramValue("in").toInt(); clip->setFadeOut(pos); } @@ -978,7 +1069,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement effect, i } void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos) { - ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_scene->m_tracksList.count() - track); + ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, m_document->tracksCount() - track); if (clip) { m_document->renderer()->mltMoveEffect(track, pos, oldPos, newPos); QDomElement act = clip->effectAt(newPos - 1).cloneNode().toElement(); @@ -994,19 +1085,19 @@ void CustomTrackView::slotChangeEffectState(ClipItem *clip, int effectPos, bool QDomElement effect = clip->effectAt(effectPos); QDomElement oldEffect = effect.cloneNode().toElement(); effect.setAttribute("disabled", disable); - EditEffectCommand *command = new EditEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true); + EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldEffect, effect, effectPos, true); m_commandStack->push(command); m_document->setModified(true); } void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int currentPos, int newPos) { - MoveEffectCommand *command = new MoveEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), currentPos, newPos, true); + MoveEffectCommand *command = new MoveEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), currentPos, newPos, true); m_commandStack->push(command); m_document->setModified(true); } void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect, QDomElement effect, int ix) { - EditEffectCommand *command = new EditEffectCommand(this, m_scene->m_tracksList.count() - clip->track(), clip->startPos(), oldeffect, effect, ix, true); + EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true); m_commandStack->push(command); } @@ -1022,7 +1113,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_scene->m_tracksList.count() - info.track, cutTime); + m_document->renderer()->mltCutClip(m_document->tracksCount() - info.track, cutTime); int cutPos = (int) cutTime.frames(m_document->fps()); ItemInfo newPos; newPos.startPos = cutTime; @@ -1049,6 +1140,10 @@ void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) { m_blockRefresh = false; return; } + 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; + } kDebug() << "// UNCUTTING CLIPS: ITEM 1 (" << item->startPos().frames(25) << "x" << item->endPos().frames(25) << ")"; kDebug() << "// UNCUTTING CLIPS: ITEM 2 (" << dup->startPos().frames(25) << "x" << dup->endPos().frames(25) << ")"; @@ -1061,10 +1156,9 @@ void CustomTrackView::cutClip(ItemInfo info, GenTime cutTime, bool cut) { m_document->updateClip(dup->baseClip()->getId()); scene()->removeItem(dup); delete dup; - m_document->renderer()->mltRemoveClip(m_scene->m_tracksList.count() - info.track, cutTime); ItemInfo clipinfo = item->info(); - clipinfo.track = m_scene->m_tracksList.count() - clipinfo.track; + clipinfo.track = m_document->tracksCount() - clipinfo.track; bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, info.endPos - info.startPos); if (success) { item->resizeEnd((int) info.endPos.frames(m_document->fps())); @@ -1092,14 +1186,14 @@ void CustomTrackView::slotAddTransitionToSelectedClips(QDomElement transition) { if (pos < item->startPos() + item->duration() / 2) { // add transition to clip start info.startPos = item->startPos(); - if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack); + if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.startPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack); if (transitionClip && transitionClip->endPos() < item->endPos()) { info.endPos = transitionClip->endPos(); } else info.endPos = info.startPos + GenTime(65, m_document->fps()); } else { // add transition to clip end info.endPos = item->endPos(); - if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_scene->m_tracksList.count() - transitiontrack); + if (transitiontrack != 0) transitionClip = getClipItemAt((int) info.endPos.frames(m_document->fps()), m_document->tracksCount() - transitiontrack); if (transitionClip && transitionClip->startPos() > item->startPos()) { info.startPos = transitionClip->startPos(); } else info.startPos = info.endPos - GenTime(65, m_document->fps()); @@ -1127,11 +1221,11 @@ void CustomTrackView::slotAddTransition(ClipItem* clip, ItemInfo transitionInfo, } void CustomTrackView::addTransition(ItemInfo transitionInfo, int endTrack, QDomElement params) { - Transition *tr = new Transition(transitionInfo, endTrack, m_document->fps(), params); + Transition *tr = new Transition(transitionInfo, endTrack, m_document->fps(), params, true); scene()->addItem(tr); //kDebug() << "---- ADDING transition " << params.attribute("value"); - m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_scene->m_tracksList.count() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML()); + m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML()); m_document->setModified(true); } @@ -1141,7 +1235,7 @@ void CustomTrackView::deleteTransition(ItemInfo transitionInfo, int endTrack, QD emit displayMessage(i18n("Select clip to delete"), ErrorMessage); return; } - m_document->renderer()->mltDeleteTransition(item->transitionTag(), endTrack, m_scene->m_tracksList.count() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, item->toXML()); + m_document->renderer()->mltDeleteTransition(item->transitionTag(), endTrack, m_document->tracksCount() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, item->toXML()); if (m_dragItem == item) m_dragItem = NULL; delete item; emit transitionItemSelected(NULL); @@ -1160,7 +1254,7 @@ void CustomTrackView::slotTransitionTrackUpdated(Transition *tr, int track) { track = getPreviousVideoTrack(tr->track()); tr->setForcedTrack(false, track); } else { - tr->setForcedTrack(true, m_scene->m_tracksList.count() + 1 - track); + tr->setForcedTrack(true, m_document->tracksCount() + 1 - track); } EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, tr->toXML(), true); m_commandStack->push(command); @@ -1173,7 +1267,7 @@ void CustomTrackView::updateTransition(int track, GenTime pos, QDomElement oldTr kWarning() << "Unable to find transition at pos :" << pos.frames(m_document->fps()) << ", ON track: " << track; return; } - m_document->renderer()->mltUpdateTransition(oldTransition.attribute("tag"), transition.attribute("tag"), transition.attribute("transition_btrack").toInt(), m_scene->m_tracksList.count() - transition.attribute("transition_atrack").toInt(), item->startPos(), item->endPos(), transition); + m_document->renderer()->mltUpdateTransition(oldTransition.attribute("tag"), transition.attribute("tag"), transition.attribute("transition_btrack").toInt(), m_document->tracksCount() - transition.attribute("transition_atrack").toInt(), item->startPos(), item->endPos(), transition); item->setTransitionParameters(transition); if (updateTransitionWidget) emit transitionItemSelected(item, true); m_document->setModified(true); @@ -1207,11 +1301,8 @@ void CustomTrackView::dragLeaveEvent(QDragLeaveEvent * event) { void CustomTrackView::dropEvent(QDropEvent * event) { if (m_selectionGroup) { QList items = m_selectionGroup->childItems(); + resetSelectionGroup(); m_scene->clearSelection(); - if (m_selectionGroup) { - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = NULL; - } for (int i = 0; i < items.count(); i++) { ClipItem *item = static_cast (items.at(i)); AddTimelineClipCommand *command = new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, false); @@ -1225,9 +1316,9 @@ void CustomTrackView::dropEvent(QDropEvent * event) { int endTrack = getPreviousVideoTrack(info.track); Transition *tr = new Transition(info, endTrack, m_document->fps(), MainWindow::transitions.getEffectByTag("composite", "alphatransparency"), true); scene()->addItem(tr); - m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML()); + m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML()); } - info.track = m_scene->m_tracksList.count() - item->track(); + info.track = m_document->tracksCount() - item->track(); m_document->renderer()->mltInsertClip(info, item->xml(), item->baseClip()->producer(item->track())); item->setSelected(true); } @@ -1261,32 +1352,289 @@ int CustomTrackView::duration() const { return m_projectDuration; } -void CustomTrackView::addTrack(TrackInfo type) { - m_scene->m_tracksList << type; - m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_scene->m_tracksList.count()); - setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_scene->m_tracksList.count()); - verticalScrollBar()->setMaximum(m_tracksHeight * m_scene->m_tracksList.count()); +void CustomTrackView::addTrack(TrackInfo type, int ix) { + if (ix == -1) m_document->insertTrack(ix, type); + else { + m_document->insertTrack(m_document->tracksCount() - ix, type); + // insert track in MLT playlist + m_document->renderer()->mltInsertTrack(m_document->tracksCount() - ix, type.type == VIDEOTRACK); + + double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2; + QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY); + QList selection = m_scene->items(r); + resetSelectionGroup(); + + m_selectionGroup = new AbstractGroupItem(m_document->fps()); + scene()->addItem(m_selectionGroup); + for (int i = 0; i < selection.count(); i++) { + if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) + m_selectionGroup->addToGroup(selection.at(i)); + selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable); + } + // Move graphic items + m_selectionGroup->translate(0, m_tracksHeight); + + // adjust track number + QList children = m_selectionGroup->childItems(); + for (int i = 0; i < children.count(); i++) { + AbstractClipItem *item = static_cast (children.at(i)); + item->updateItem(); + ItemInfo clipinfo = item->info(); + if (item->type() == AVWIDGET) { + ClipItem *clip = static_cast (item); + // We add a move clip command so that we get the correct producer for new track number + if (clip->clipType() == AV || clip->clipType() == AUDIO) { + m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), clip->baseClip()->producer(clipinfo.track)); + kDebug() << "// UPDATING CLIP TO TRACK PROD: " << clipinfo.track; + } + } else if (item->type() == TRANSITIONWIDGET) { + Transition *tr = static_cast (item); + int track = tr->transitionEndTrack(); + if (track >= ix) { + tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track)); + } + } + } + resetSelectionGroup(false); + + } + int maxHeight = m_tracksHeight * m_document->tracksCount(); + for (int i = 0; i < m_guides.count(); i++) { + QLineF l = m_guides.at(i)->line(); + l.setP2(QPointF(l.x2(), maxHeight)); + m_guides.at(i)->setLine(l); + } + m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight); + setSceneRect(0, 0, sceneRect().width(), maxHeight); + QTimer::singleShot(300, this, SIGNAL(trackHeightChanged())); + viewport()->update(); //setFixedHeight(50 * m_tracksCount); } -void CustomTrackView::removeTrack() { - // TODO: implement track deletion - //m_tracksCount--; - m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), m_tracksHeight * m_scene->m_tracksList.count()); +void CustomTrackView::removeTrack(int ix) { + // Delete track in MLT playlist + m_document->renderer()->mltDeleteTrack(m_document->tracksCount() - ix); + m_document->deleteTrack(m_document->tracksCount() - ix - 1); + + double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2; + QRectF r(0, startY, sceneRect().width(), sceneRect().height() - startY); + QList selection = m_scene->items(r); + + resetSelectionGroup(); + + m_selectionGroup = new AbstractGroupItem(m_document->fps()); + scene()->addItem(m_selectionGroup); + for (int i = 0; i < selection.count(); i++) { + if (selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET) { + m_selectionGroup->addToGroup(selection.at(i)); + selection.at(i)->setFlags(QGraphicsItem::ItemIsSelectable); + } + } + // Move graphic items + qreal ydiff = 0 - (int) m_tracksHeight; + m_selectionGroup->translate(0, ydiff); + + // adjust track number + QList children = m_selectionGroup->childItems(); + //kDebug() << "// FOUND CLIPS TO MOVE: " << children.count(); + for (int i = 0; i < children.count(); i++) { + if (children.at(i)->type() == AVWIDGET) { + ClipItem *clip = static_cast (children.at(i)); + clip->updateItem(); + ItemInfo clipinfo = clip->info(); + kDebug() << "// CLIP TRK IS: " << clipinfo.track; + // We add a move clip command so that we get the correct producer for new track number + if (clip->clipType() == AV || clip->clipType() == AUDIO) + m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), clip->baseClip()->producer(clipinfo.track)); + } else if (children.at(i)->type() == TRANSITIONWIDGET) { + Transition *tr = static_cast (children.at(i)); + tr->updateItem(); + int track = tr->transitionEndTrack(); + if (track >= ix) { + ItemInfo clipinfo = tr->info(); + tr->updateTransitionEndTrack(getPreviousVideoTrack(clipinfo.track)); + } + } + } + resetSelectionGroup(false); + + int maxHeight = m_tracksHeight * m_document->tracksCount(); + for (int i = 0; i < m_guides.count(); i++) { + QLineF l = m_guides.at(i)->line(); + l.setP2(QPointF(l.x2(), maxHeight)); + m_guides.at(i)->setLine(l); + } + m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight); + setSceneRect(0, 0, sceneRect().width(), maxHeight); + QTimer::singleShot(300, this, SIGNAL(trackHeightChanged())); + viewport()->update(); +} + +void CustomTrackView::changeTrack(int ix, TrackInfo type) { + int tracknumber = m_document->tracksCount() - ix; + m_document->setTrackType(tracknumber - 1, type); + m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind); + QTimer::singleShot(300, this, SIGNAL(trackHeightChanged())); + viewport()->update(); } void CustomTrackView::slotSwitchTrackAudio(int ix) { - int tracknumber = m_scene->m_tracksList.count() - ix; - kDebug() << "///// MUTING TRK: " << ix << "; PL NUM: " << tracknumber; - m_scene->m_tracksList[tracknumber - 1].isMute = !m_scene->m_tracksList.at(tracknumber - 1).isMute; - m_document->renderer()->mltChangeTrackState(tracknumber, m_scene->m_tracksList.at(tracknumber - 1).isMute, m_scene->m_tracksList.at(tracknumber - 1).isBlind); + /*for (int i = 0; i < m_document->tracksCount(); i++) + kDebug() << "TRK " << i << " STATE: " << m_document->trackInfoAt(i).isMute << m_document->trackInfoAt(i).isBlind;*/ + + int tracknumber = m_document->tracksCount() - ix; + + m_document->switchTrackAudio(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isMute); + kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber - 1).isMute << m_document->trackInfoAt(tracknumber - 1).isBlind; + m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind); + m_document->setModified(true); } void CustomTrackView::slotSwitchTrackVideo(int ix) { - int tracknumber = m_scene->m_tracksList.count() - ix; - m_scene->m_tracksList[tracknumber - 1].isBlind = !m_scene->m_tracksList.at(tracknumber - 1).isBlind; - m_document->renderer()->mltChangeTrackState(tracknumber, m_scene->m_tracksList.at(tracknumber - 1).isMute, m_scene->m_tracksList.at(tracknumber - 1).isBlind); + int tracknumber = m_document->tracksCount() - ix; + m_document->switchTrackVideo(tracknumber - 1, !m_document->trackInfoAt(tracknumber - 1).isBlind); + m_document->renderer()->mltChangeTrackState(tracknumber, m_document->trackInfoAt(tracknumber - 1).isMute, m_document->trackInfoAt(tracknumber - 1).isBlind); + m_document->setModified(true); +} + +void CustomTrackView::slotRemoveSpace() { + GenTime pos; + int track = 0; + if (m_menuPosition.isNull()) { + pos = GenTime(cursorPos(), m_document->fps()); + bool ok; + track = QInputDialog::getInteger(this, i18n("Remove Space"), i18n("Track"), 0, 0, m_document->tracksCount() - 1, 1, &ok); + if (!ok) return; + } else { + pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps()); + track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight); + } + ClipItem *item = getClipItemAt(pos, track); + if (item) { + emit displayMessage(i18n("You must be in an empty space to remove space (time=%1, track:%2)", m_document->timecode().getTimecodeFromFrames(mapToScene(m_menuPosition).x()), track), ErrorMessage); + return; + } + int length = m_document->renderer()->mltGetSpaceLength(pos, m_document->tracksCount() - track, true); + //kDebug() << "// GOT LENGT; " << length; + if (length <= 0) { + emit displayMessage(i18n("You must be in an empty space to remove space (time=%1, track:%2)", m_document->timecode().getTimecodeFromFrames(mapToScene(m_menuPosition).x()), track), ErrorMessage); + return; + } + + QRectF r(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2, sceneRect().width() - pos.frames(m_document->fps()), m_tracksHeight / 2 - 1); + QList items = m_scene->items(r); + + QList clipsToMove = QList (); + QList transitionsToMove = QList (); + + for (int i = 0; i < items.count(); i++) { + if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) { + AbstractClipItem *item = static_cast (items.at(i)); + ItemInfo info = item->info(); + if (item->type() == AVWIDGET) { + clipsToMove.append(info); + } else if (item->type() == TRANSITIONWIDGET) { + transitionsToMove.append(info); + } + } + } + + InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, GenTime(-length, m_document->fps()), true); + m_commandStack->push(command); +} + +void CustomTrackView::slotInsertSpace() { + GenTime pos; + int track = 0; + if (m_menuPosition.isNull()) { + pos = GenTime(cursorPos(), m_document->fps()); + } else { + pos = GenTime((int)(mapToScene(m_menuPosition).x()), m_document->fps()); + track = (int)(mapToScene(m_menuPosition).y() / m_tracksHeight) + 1; + } + SpacerDialog d(GenTime(65, m_document->fps()), m_document->timecode(), track, m_document->tracksCount(), this); + if (d.exec() != QDialog::Accepted) return; + GenTime spaceDuration = d.selectedDuration(); + track = d.selectedTrack(); + ClipItem *item = getClipItemAt(pos, track); + if (item) pos = item->startPos(); + + int minh = 0; + int maxh = sceneRect().height(); + if (track != -1) { + minh = track * m_tracksHeight + m_tracksHeight / 2; + maxh = m_tracksHeight / 2 - 1; + } + + QRectF r(pos.frames(m_document->fps()), minh, sceneRect().width() - pos.frames(m_document->fps()), maxh); + QList items = m_scene->items(r); + + QList clipsToMove = QList (); + QList transitionsToMove = QList (); + + for (int i = 0; i < items.count(); i++) { + if (items.at(i)->type() == AVWIDGET || items.at(i)->type() == TRANSITIONWIDGET) { + AbstractClipItem *item = static_cast (items.at(i)); + ItemInfo info = item->info(); + if (item->type() == AVWIDGET) { + clipsToMove.append(info); + } else if (item->type() == TRANSITIONWIDGET) { + transitionsToMove.append(info); + } + } + } + + InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, spaceDuration, true); + m_commandStack->push(command); +} + +void CustomTrackView::insertSpace(QList clipsToMove, QList transToMove, int track, const GenTime duration, const GenTime offset) { + int diff = duration.frames(m_document->fps()); + resetSelectionGroup(); + m_selectionGroup = new AbstractGroupItem(m_document->fps()); + scene()->addItem(m_selectionGroup); + ClipItem *clip; + Transition *transition; + + kDebug() << "/// STARTING SPACE INSERT"; + + + // Create lists with start pos for each track + QMap trackClipStartList; + QMap trackTransitionStartList; + + for (int i = 1; i < m_document->tracksCount() + 1; i++) { + trackClipStartList[i] = -1; + trackTransitionStartList[i] = -1; + } + + if (!clipsToMove.isEmpty()) for (int i = 0; i < clipsToMove.count(); i++) { + kDebug() << "/// FETCHING CLIP: " << i; + clip = getClipItemAtStart(clipsToMove.at(i).startPos + offset, clipsToMove.at(i).track); + if (clip) { + m_selectionGroup->addToGroup(clip); + if (trackClipStartList.value(m_document->tracksCount() - clipsToMove.at(i).track) == -1 || clipsToMove.at(i).startPos.frames(m_document->fps()) < trackClipStartList.value(m_document->tracksCount() - clipsToMove.at(i).track)) + trackClipStartList[m_document->tracksCount() - clipsToMove.at(i).track] = clipsToMove.at(i).startPos.frames(m_document->fps()); + clip->setFlags(QGraphicsItem::ItemIsSelectable); + } else emit displayMessage(i18n("Cannot move clip at position %1, track %2", m_document->timecode().getTimecodeFromFrames(clipsToMove.at(i).startPos.frames(m_document->fps())), clipsToMove.at(i).track), ErrorMessage); + } + if (!transToMove.isEmpty()) for (int i = 0; i < transToMove.count(); i++) { + kDebug() << "/// FETCHING TRANS: " << i; + transition = getTransitionItemAtStart(transToMove.at(i).startPos + offset, transToMove.at(i).track); + if (transition) { + m_selectionGroup->addToGroup(transition); + if (trackTransitionStartList.value(m_document->tracksCount() - transToMove.at(i).track) == -1 || transToMove.at(i).startPos.frames(m_document->fps()) < trackTransitionStartList.value(m_document->tracksCount() - transToMove.at(i).track)) + trackTransitionStartList[m_document->tracksCount() - transToMove.at(i).track] = transToMove.at(i).startPos.frames(m_document->fps()); + transition->setFlags(QGraphicsItem::ItemIsSelectable); + } else emit displayMessage(i18n("Cannot move transition at position %1, track %2", m_document->timecode().getTimecodeFromFrames(transToMove.at(i).startPos.frames(m_document->fps())), transToMove.at(i).track), ErrorMessage); + } + kDebug() << "/// STARTING SPACE DONE"; + m_selectionGroup->translate(diff, 0); + resetSelectionGroup(false); + kDebug() << "/// STARTING SPACE DONE2"; + if (track != -1) track = m_document->tracksCount() - track; + m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, duration, offset); } void CustomTrackView::deleteClip(const QString &clipId) { @@ -1325,23 +1673,23 @@ void CustomTrackView::moveCursorPos(int delta) { m_cursorPos += delta; m_cursorLine->setPos(m_cursorPos, 0); m_document->renderer()->seek(GenTime(m_cursorPos, m_document->fps())); - //if (m_autoScroll && m_scale < 50) checkScrolling(); +} + +void CustomTrackView::initCursorPos(int pos) { + emit cursorMoved((int)(m_cursorPos), (int)(pos)); + m_cursorPos = pos; + m_cursorLine->setPos(pos, 0); + checkScrolling(); } void CustomTrackView::checkScrolling() { int vert = verticalScrollBar()->value(); int hor = cursorPos(); ensureVisible(hor, vert + 10, 2, 2, 50, 0); - //centerOn(QPointF(cursorPos(), m_tracksHeight)); - /*QRect rectInView = viewport()->rect(); - int delta = rectInView.width() / 3; - int max = rectInView.right() + horizontalScrollBar()->value() - delta; - //kDebug() << "CURSOR POS: "<= max) horizontalScrollBar()->setValue((int)(horizontalScrollBar()->value() + 1 + m_scale));*/ } void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { - m_moveOpMode = NONE; + if (m_moveOpMode == SEEK) m_moveOpMode = NONE; QGraphicsView::mouseReleaseEvent(event); if (m_scrollTimer.isActive()) m_scrollTimer.stop(); if (event->button() == Qt::MidButton) { @@ -1358,7 +1706,61 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { m_dragGuide = NULL; m_dragItem = NULL; return; + } else if (m_operationMode == SPACER) { + int endClick = (int)(mapToScene(event->pos()).x() + 0.5); + int mappedClick = (int)(mapToScene(m_clickEvent).x() + 0.5); + int track = (int)(mapToScene(m_clickEvent).y() / m_tracksHeight); + if (m_selectionGroup->sceneBoundingRect().height() > m_tracksHeight) { + // We are moving all tracks + track = -1; + } + + int startPos = (int) m_selectionGroup->boundingRect().topLeft().x(); + int diff = ((int) m_selectionGroup->pos().x()) - startPos; + //kDebug()<<"//////// SPACER DIFF: "<boundingRect().topLeft(); + if (diff != 0) { + QList items = m_selectionGroup->childItems(); + + QList clipsToMove = QList (); + QList transitionsToMove = QList (); + + // Create lists with start pos for each track + QMap trackClipStartList; + QMap trackTransitionStartList; + + for (int i = 1; i < m_document->tracksCount() + 1; i++) { + trackClipStartList[i] = -1; + trackTransitionStartList[i] = -1; + } + + for (int i = 0; i < items.count(); i++) { + AbstractClipItem *item = static_cast (items.at(i)); + ItemInfo info = item->info(); + if (item->type() == AVWIDGET) { + clipsToMove.append(info); + if (trackClipStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackClipStartList.value(m_document->tracksCount() - info.track)) + trackClipStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps()); + } else if (item->type() == TRANSITIONWIDGET) { + transitionsToMove.append(info); + if (trackClipStartList.value(m_document->tracksCount() - info.track) == -1 || info.startPos.frames(m_document->fps()) < trackTransitionStartList.value(m_document->tracksCount() - info.track)) + trackTransitionStartList[m_document->tracksCount() - info.track] = info.startPos.frames(m_document->fps()); + } + } + + InsertSpaceCommand *command = new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, GenTime(diff, m_document->fps()), false); + m_commandStack->push(command); + if (track != -1) track = m_document->tracksCount() - track; + m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, GenTime(diff, m_document->fps()), GenTime()); + } + resetSelectionGroup(false); + m_operationMode = NONE; + } else if (m_operationMode == RUBBERSELECTION) { + kDebug() << "// END RUBBER SELECT"; + resetSelectionGroup(); + groupSelectedItems(); + m_operationMode = NONE; } + if (m_dragItem == NULL && m_selectionGroup == NULL) { emit transitionItemSelected(NULL); return; @@ -1373,24 +1775,81 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { // we are moving one clip, easy if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) { ClipItem *item = static_cast (m_dragItem); - bool success = m_document->renderer()->mltMoveClip((int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItem->track()), (int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItem->startPos().frames(m_document->fps())), item->baseClip()->producer(info.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())), item->baseClip()->producer(info.track)); if (success) { - MoveClipCommand *command = new MoveClipCommand(this, m_dragItemInfo, info, false); - m_commandStack->push(command); - if (item->baseClip()->isTransparent()) { - // Also move automatic transition - Transition *tr = getTransitionItemAt((int) m_dragItemInfo.startPos.frames(m_document->fps()), m_dragItemInfo.track); + 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 *tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track); + if (tr && tr->isAutomatic()) { + ItemInfo trInfo = tr->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.track = info.track; + newTrInfo.startPos = m_dragItem->startPos(); + if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtEnd(newTrInfo.endPos, m_document->tracksCount() - tr->transitionEndTrack())) { + // transition end should stay the same + } else { + // transition end should be adjusted to clip + newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos); + } + new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand); + } + if (tr == NULL || tr->endPos() < m_dragItemInfo.endPos) { + // Check if there is a transition at clip end + tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track); if (tr && tr->isAutomatic()) { - tr->updateTransitionEndTrack(getPreviousVideoTrack(info.track)); - m_document->renderer()->mltMoveTransition(tr->transitionTag(), m_scene->m_tracksList.count() - m_dragItemInfo.track, m_scene->m_tracksList.count() - info.track, tr->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos); - tr->setPos((int) info.startPos.frames(m_document->fps()), (int)(info.track * m_tracksHeight + 1)); + ItemInfo trInfo = tr->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.track = info.track; + newTrInfo.endPos = m_dragItem->endPos(); + if (m_dragItemInfo.track == info.track && !item->baseClip()->isTransparent() && getClipItemAtStart(trInfo.startPos, m_document->tracksCount() - tr->transitionEndTrack())) { + // transition start should stay the same + } else { + // transition start should be moved + newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos); + } + new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand); } } + // Also move automatic transitions (on upper track) + tr = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1); + if (m_dragItemInfo.track == info.track && tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) { + ItemInfo trInfo = tr->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.startPos = m_dragItem->startPos(); + ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1); + if (!upperClip || !upperClip->baseClip()->isTransparent()) { + if (!getClipItemAtEnd(newTrInfo.endPos, tr->track())) { + // transition end should be adjusted to clip on upper track + newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos); + } + new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand); + } + } + if (m_dragItemInfo.track == info.track && (tr == NULL || tr->endPos() < m_dragItemInfo.endPos)) { + // Check if there is a transition at clip end + tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1); + if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) { + ItemInfo trInfo = tr->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.endPos = m_dragItem->endPos(); + ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1); + if (!upperClip || !upperClip->baseClip()->isTransparent()) { + if (!getClipItemAtStart(trInfo.startPos, tr->track())) { + // transition start should be moved + newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos); + } + new MoveTransitionCommand(this, trInfo, newTrInfo, true, moveCommand); + } + } + } + m_commandStack->push(moveCommand); } else { // undo last move and emit error message MoveClipCommand *command = new MoveClipCommand(this, info, m_dragItemInfo, true); m_commandStack->push(command); - emit displayMessage(i18n("Cannot move clip to position %1seconds", QString::number(m_dragItemInfo.startPos.seconds(), 'g', 2)), ErrorMessage); + emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(m_dragItemInfo.startPos.frames(m_document->fps()))), ErrorMessage); } } if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) { @@ -1398,7 +1857,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { m_commandStack->push(command); Transition *transition = (Transition *) m_dragItem; transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track())); - m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItem->track()), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos); + m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItem->track()), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos); } } else { // Moving several clips. We need to delete them and readd them to new position, @@ -1406,51 +1865,62 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { QList items = m_selectionGroup->childItems(); + QList clipsToMove = QList (); + QList transitionsToMove = QList (); + GenTime timeOffset = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()) - m_selectionGroupInfo.startPos; const int trackOffset = m_selectionGroup->track() - m_selectionGroupInfo.track; - //kDebug() << "&DROPPED GRPOUP:" << timeOffset.frames(25) << "x" << trackOffset; if (timeOffset != GenTime() || trackOffset != 0) { QUndoCommand *moveClips = new QUndoCommand(); - moveClips->setText("Move clips"); + moveClips->setText(i18n("Move group")); // remove items in MLT playlist for (int i = 0; i < items.count(); i++) { AbstractClipItem *item = static_cast (items.at(i)); ItemInfo info = item->info(); - /*info.startPos = info.startPos - timeOffset; - info.endPos = info.endPos - timeOffset; - info.track = info.track - trackOffset;*/ - //kDebug() << "REM CLP:" << i << ", START:" << info.startPos.frames(25); if (item->type() == AVWIDGET) { - ClipItem *clip = static_cast (item); - new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), false, true, moveClips); - m_document->renderer()->mltRemoveClip(m_scene->m_tracksList.count() - info.track, info.startPos); + if (m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) { + // error, clip cannot be removed from playlist + emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage); + } else { + clipsToMove.append(info); + } } else { + transitionsToMove.append(info); Transition *tr = static_cast (item); - new AddTransitionCommand(this, info, tr->transitionEndTrack(), tr->toXML(), false, true, moveClips); - m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML()); + m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML()); } } for (int i = 0; i < items.count(); i++) { // re-add items in correct place AbstractClipItem *item = static_cast (items.at(i)); + item->updateItem(); ItemInfo info = item->info(); - info.startPos = info.startPos + timeOffset; - info.endPos = info.endPos + timeOffset; - info.track = info.track + trackOffset; if (item->type() == AVWIDGET) { ClipItem *clip = static_cast (item); - new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), info, clip->effectList(), false, false, moveClips); - info.track = m_scene->m_tracksList.count() - info.track; + info.track = m_document->tracksCount() - info.track; m_document->renderer()->mltInsertClip(info, clip->xml(), clip->baseClip()->producer(info.track)); } else { Transition *tr = static_cast (item); - ItemInfo transitionInfo = tr->info(); - new AddTransitionCommand(this, info, tr->transitionEndTrack(), tr->toXML(), false, false, moveClips); - m_document->renderer()->mltAddTransition(tr->transitionTag(), tr->transitionEndTrack() + trackOffset, m_scene->m_tracksList.count() - transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, tr->toXML()); + int newTrack = tr->transitionEndTrack(); + if (!tr->forcedTrack()) { + newTrack += trackOffset; + if (newTrack < 0 || newTrack > m_document->tracksCount()) newTrack = getPreviousVideoTrack(info.track); + } + tr->updateTransitionEndTrack(newTrack); + m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML()); } } + + new MoveGroupCommand(this, clipsToMove, transitionsToMove, timeOffset, trackOffset, false, moveClips); m_commandStack->push(moveClips); + + QPointF top = m_selectionGroup->sceneBoundingRect().topLeft(); + //QPointF oldpos = m_selectionGroup->scenePos(); + //kDebug()<<"SELECTION GRP POS: "<scenePos()<<", TOP: "<setPos(top); + m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()); + m_selectionGroupInfo.track = m_selectionGroup->track(); } } @@ -1458,12 +1928,34 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { // resize start if (m_dragItem->type() == AVWIDGET) { ItemInfo resizeinfo = m_dragItemInfo; - resizeinfo.track = m_scene->m_tracksList.count() - resizeinfo.track; + resizeinfo.track = m_document->tracksCount() - resizeinfo.track; bool success = m_document->renderer()->mltResizeClipStart(resizeinfo, m_dragItem->startPos() - m_dragItemInfo.startPos); if (success) { + QUndoCommand *resizeCommand = new QUndoCommand(); + resizeCommand->setText(i18n("Resize clip")); + + // Check if there is an automatic transition on that clip (lower track) + Transition *transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track); + if (transition && transition->isAutomatic()) { + ItemInfo trInfo = transition->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.startPos = m_dragItem->startPos(); + new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand); + } + // Check if there is an automatic transition on that clip (upper track) + transition = getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1); + if (transition && transition->isAutomatic() && (m_document->tracksCount() - transition->transitionEndTrack()) == m_dragItemInfo.track) { + ItemInfo trInfo = transition->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.startPos = m_dragItem->startPos(); + ClipItem * upperClip = getClipItemAt(m_dragItemInfo.startPos, m_dragItemInfo.track - 1); + if (!upperClip || !upperClip->baseClip()->isTransparent()) { + new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand); + } + } updateClipFade(static_cast (m_dragItem)); - ResizeClipCommand *command = new ResizeClipCommand(this, m_dragItemInfo, info, false); - m_commandStack->push(command); + new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand); + m_commandStack->push(resizeCommand); } else { m_dragItem->resizeStart((int) m_dragItemInfo.startPos.frames(m_document->fps())); emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); @@ -1472,7 +1964,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false); m_commandStack->push(command); Transition *transition = static_cast (m_dragItem); - m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), 0, m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos); + m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItemInfo.track), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos); } //m_document->renderer()->doRefresh(); @@ -1480,11 +1972,35 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { // resize end if (m_dragItem->type() == AVWIDGET) { ItemInfo resizeinfo = info; - resizeinfo.track = m_scene->m_tracksList.count() - resizeinfo.track; + resizeinfo.track = m_document->tracksCount() - resizeinfo.track; bool success = m_document->renderer()->mltResizeClipEnd(resizeinfo, resizeinfo.endPos - resizeinfo.startPos); if (success) { - ResizeClipCommand *command = new ResizeClipCommand(this, m_dragItemInfo, info, false); - m_commandStack->push(command); + QUndoCommand *resizeCommand = new QUndoCommand(); + resizeCommand->setText(i18n("Resize clip")); + + // Check if there is an automatic transition on that clip (lower track) + Transition *tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track); + if (tr && tr->isAutomatic()) { + ItemInfo trInfo = tr->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.endPos = m_dragItem->endPos(); + new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand); + } + + // Check if there is an automatic transition on that clip (upper track) + tr = getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1); + if (tr && tr->isAutomatic() && (m_document->tracksCount() - tr->transitionEndTrack()) == m_dragItemInfo.track) { + ItemInfo trInfo = tr->info(); + ItemInfo newTrInfo = trInfo; + newTrInfo.endPos = m_dragItem->endPos(); + ClipItem * upperClip = getClipItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track - 1); + if (!upperClip || !upperClip->baseClip()->isTransparent()) { + new MoveTransitionCommand(this, trInfo, newTrInfo, true, resizeCommand); + } + } + + new ResizeClipCommand(this, m_dragItemInfo, info, false, resizeCommand); + m_commandStack->push(resizeCommand); updateClipFade(static_cast (m_dragItem), true); } else { m_dragItem->resizeEnd((int) m_dragItemInfo.endPos.frames(m_document->fps())); @@ -1494,7 +2010,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false); m_commandStack->push(command); Transition *transition = static_cast (m_dragItem); - m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), (int)(m_scene->m_tracksList.count() - m_dragItemInfo.track), 0, m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos); + m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - m_dragItemInfo.track), 0, m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos); } //m_document->renderer()->doRefresh(); } else if (m_operationMode == FADEIN) { @@ -1551,7 +2067,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { QString next = item->keyframes(item->selectedEffectIndex()); EditKeyFrameCommand *command = new EditKeyFrameCommand(this, item->track(), item->startPos(), item->selectedEffectIndex(), previous, next, false); m_commandStack->push(command); - updateEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex()); + updateEffect(m_document->tracksCount() - item->track(), item->startPos(), item->selectedEffect(), item->selectedEffectIndex()); } emit transitionItemSelected((m_dragItem && m_dragItem->type() == TRANSITIONWIDGET) ? static_cast (m_dragItem) : NULL); @@ -1561,8 +2077,9 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { void CustomTrackView::deleteClip(ItemInfo info) { ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track); - if (!item) { - kDebug() << "----------------  ERROR, CANNOT find clip to delete at...";// << rect.x(); + + if (!item || m_document->renderer()->mltRemoveClip(m_document->tracksCount() - info.track, info.startPos) == false) { + emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), info.track), ErrorMessage); return; } if (item->isSelected()) emit clipItemSelected(NULL); @@ -1573,7 +2090,7 @@ void CustomTrackView::deleteClip(ItemInfo info) { // also remove automatic transition Transition *tr = getTransitionItemAt((int) info.startPos.frames(m_document->fps()), info.track); if (tr && tr->isAutomatic()) { - m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML()); + m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML()); scene()->removeItem(tr); delete tr; } @@ -1581,7 +2098,6 @@ void CustomTrackView::deleteClip(ItemInfo info) { scene()->removeItem(item); if (m_dragItem == item) m_dragItem = NULL; delete item; - m_document->renderer()->mltRemoveClip(m_scene->m_tracksList.count() - info.track, info.startPos); m_document->renderer()->doRefresh(); } @@ -1631,16 +2147,16 @@ void CustomTrackView::changeClipSpeed() { } void CustomTrackView::doChangeClipSpeed(ItemInfo info, const double speed, const double oldspeed, const QString &id) { - DocClipBase *baseclip = m_document->clipManager()->getClipById(id); ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track); - info.track = m_scene->m_tracksList.count() - item->track(); + info.track = m_document->tracksCount() - item->track(); int endPos = m_document->renderer()->mltChangeClipSpeed(info, speed, oldspeed, baseclip->producer()); //kDebug() << "//CH CLIP SPEED: " << speed << "x" << oldspeed << ", END POS: " << endPos; item->setSpeed(speed); item->updateRectGeometry(); if (item->cropDuration().frames(m_document->fps()) > endPos) item->AbstractClipItem::resizeEnd(info.startPos.frames(m_document->fps()) + endPos, speed); + m_document->setModified(true); } void CustomTrackView::cutSelectedClips() { @@ -1671,12 +2187,12 @@ void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo i int endTrack = getPreviousVideoTrack(info.track); Transition *tr = new Transition(info, endTrack, m_document->fps(), MainWindow::transitions.getEffectByTag("composite", "alphatransparency"), true); scene()->addItem(tr); - m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_scene->m_tracksList.count() - info.track, info.startPos, info.endPos, tr->toXML()); + m_document->renderer()->mltAddTransition(tr->transitionTag(), endTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML()); } baseclip->addReference(); m_document->updateClip(baseclip->getId()); - info.track = m_scene->m_tracksList.count() - info.track; + info.track = m_document->tracksCount() - info.track; m_document->renderer()->mltInsertClip(info, xml, baseclip->producer(info.track)); for (int i = 0; i < item->effectsCount(); i++) { m_document->renderer()->mltAddEffect(info.track, info.startPos, item->getEffectArgs(item->effectAt(i)), false); @@ -1693,17 +2209,44 @@ void CustomTrackView::slotUpdateClip(const QString &clipId) { if (clip->clipProducer() == clipId) { clip->refreshClip(); ItemInfo info = clip->info(); - info.track = m_scene->m_tracksList.count() - clip->track(); + info.track = m_document->tracksCount() - clip->track(); m_document->renderer()->mltUpdateClip(info, clip->xml(), clip->baseClip()->producer()); } } } } +ClipItem *CustomTrackView::getClipItemAtEnd(GenTime pos, int track) { + int framepos = (int)(pos.frames(m_document->fps())); + QList list = scene()->items(QPointF(framepos - 1, track * m_tracksHeight + m_tracksHeight / 2)); + ClipItem *clip = NULL; + for (int i = 0; i < list.size(); i++) { + if (list.at(i)->type() == AVWIDGET) { + ClipItem *test = static_cast (list.at(i)); + if (test->endPos() == pos) clip = test; + break; + } + } + return clip; +} + +ClipItem *CustomTrackView::getClipItemAtStart(GenTime pos, int track) { + QList list = scene()->items(QPointF(pos.frames(m_document->fps()), track * m_tracksHeight + m_tracksHeight / 2)); + ClipItem *clip = NULL; + for (int i = 0; i < list.size(); i++) { + if (list.at(i)->type() == AVWIDGET) { + ClipItem *test = static_cast (list.at(i)); + if (test->startPos() == pos) clip = test; + break; + } + } + return clip; +} + ClipItem *CustomTrackView::getClipItemAt(int pos, int track) { QList list = scene()->items(QPointF(pos , track * m_tracksHeight + m_tracksHeight / 2)); ClipItem *clip = NULL; - for (int i = 0; i < list.size(); ++i) { + for (int i = 0; i < list.size(); i++) { if (list.at(i)->type() == AVWIDGET) { clip = static_cast (list.at(i)); break; @@ -1720,7 +2263,7 @@ ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track) { Transition *CustomTrackView::getTransitionItemAt(int pos, int track) { QList list = scene()->items(QPointF(pos, (track + 1) * m_tracksHeight)); Transition *clip = NULL; - for (int i = 0; i < list.size(); ++i) { + for (int i = 0; i < list.size(); i++) { if (list.at(i)->type() == TRANSITIONWIDGET) { clip = static_cast (list.at(i)); break; @@ -1734,42 +2277,145 @@ Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track) { return getTransitionItemAt(framepos, track); } +Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track) { + int framepos = (int)(pos.frames(m_document->fps())); + QList list = scene()->items(QPointF(framepos - 1, (track + 1) * m_tracksHeight)); + Transition *clip = NULL; + for (int i = 0; i < list.size(); i++) { + if (list.at(i)->type() == TRANSITIONWIDGET) { + Transition *test = static_cast (list.at(i)); + if (test->endPos() == pos) clip = test; + break; + } + } + return clip; +} + +Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track) { + QList list = scene()->items(QPointF(pos.frames(m_document->fps()), (track + 1) * m_tracksHeight)); + Transition *clip = NULL; + for (int i = 0; i < list.size(); ++i) { + if (list.at(i)->type() == TRANSITIONWIDGET) { + Transition *test = static_cast (list.at(i)); + if (test->startPos() == pos) clip = test; + break; + } + } + return clip; +} + void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end) { + if (m_selectionGroup) resetSelectionGroup(false); ClipItem *item = getClipItemAt((int) start.startPos.frames(m_document->fps()) + 1, start.track); if (!item) { - emit displayMessage(i18n("Cannot move clip at time: %1s on track %2", QString::number(start.startPos.seconds(), 'g', 2), start.track), ErrorMessage); - kDebug() << "----------------  ERROR, CANNOT find clip to move at.. ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2; + emit displayMessage(i18n("Cannot move clip at time: %1 on track %2", m_document->timecode().getTimecodeFromFrames(start.startPos.frames(m_document->fps())), start.track), ErrorMessage); + kDebug() << "----------------  ERROR, CANNOT find clip to move at.. "; return; } - //kDebug() << "----------------  Move CLIP FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << startPos.y() << " TO " << endPos.y(); - - bool success = m_document->renderer()->mltMoveClip((int)(m_scene->m_tracksList.count() - start.track), (int)(m_scene->m_tracksList.count() - end.track), (int) start.startPos.frames(m_document->fps()), (int)end.startPos.frames(m_document->fps()), item->baseClip()->producer(end.track)); + bool success = m_document->renderer()->mltMoveClip((int)(m_document->tracksCount() - start.track), (int)(m_document->tracksCount() - end.track), (int) start.startPos.frames(m_document->fps()), (int)end.startPos.frames(m_document->fps()), item->baseClip()->producer(end.track)); if (success) { + bool snap = KdenliveSettings::snaptopoints(); + KdenliveSettings::setSnaptopoints(false); item->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1)); + m_scene->clearSelection(); + item->setSelected(true); if (item->baseClip()->isTransparent()) { // Also move automatic transition Transition *tr = getTransitionItemAt((int) start.startPos.frames(m_document->fps()), start.track); if (tr && tr->isAutomatic()) { tr->updateTransitionEndTrack(getPreviousVideoTrack(end.track)); - m_document->renderer()->mltMoveTransition(tr->transitionTag(), m_scene->m_tracksList.count() - start.track, m_scene->m_tracksList.count() - end.track, tr->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos); + m_document->renderer()->mltMoveTransition(tr->transitionTag(), m_document->tracksCount() - start.track, m_document->tracksCount() - end.track, tr->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos); tr->setPos((int) end.startPos.frames(m_document->fps()), (int)(end.track * m_tracksHeight + 1)); } } + KdenliveSettings::setSnaptopoints(snap); } else { // undo last move and emit error message - emit displayMessage(i18n("Cannot move clip to position %1seconds", QString::number(end.startPos.seconds(), 'g', 2)), ErrorMessage); + emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(end.startPos.frames(m_document->fps()))), ErrorMessage); + } + kDebug() << " // MOVED CLIP TO: " << end.startPos.frames(25) << ", ITEM START: " << item->startPos().frames(25); +} + +void CustomTrackView::moveGroup(QList startClip, QList startTransition, const GenTime offset, const int trackOffset, bool reverseMove) { + // Group Items + kDebug() << "// GROUP MOVE; OFFSET: " << offset.frames(25) << ", TK OFF: " << trackOffset; + resetSelectionGroup(); + m_scene->clearSelection(); + for (int i = 0; i < startClip.count(); i++) { + if (reverseMove) { + startClip[i].startPos = startClip.at(i).startPos - offset; + startClip[i].track = startClip.at(i).track - trackOffset; + } + ClipItem *clip = getClipItemAt(startClip.at(i).startPos, startClip.at(i).track); + if (clip) { + clip->setSelected(true); + m_document->renderer()->mltRemoveClip(m_document->tracksCount() - startClip.at(i).track, startClip.at(i).startPos); + } + } + for (int i = 0; i < startTransition.count(); i++) { + if (reverseMove) { + startTransition[i].startPos = startTransition.at(i).startPos - offset; + startTransition[i].track = startTransition.at(i).track - trackOffset; + } + Transition *tr = getTransitionItemAt(startTransition.at(i).startPos, startTransition.at(i).track); + if (tr) { + tr->setSelected(true); + m_document->renderer()->mltDeleteTransition(tr->transitionTag(), tr->transitionEndTrack(), m_document->tracksCount() - startTransition.at(i).track, startTransition.at(i).startPos, startTransition.at(i).endPos, tr->toXML()); + } + } + groupSelectedItems(); + if (m_selectionGroup) { + QPointF pos = m_selectionGroup->pos(); + qreal posx = pos.x() + offset.frames(m_document->fps()); + qreal posy = pos.y() + trackOffset * (qreal) m_tracksHeight; + bool snap = KdenliveSettings::snaptopoints(); + KdenliveSettings::setSnaptopoints(false); + + m_selectionGroup->setPos(posx, posy); + + QPointF top = m_selectionGroup->sceneBoundingRect().topLeft(); + m_selectionGroup->setPos(top); + m_selectionGroupInfo.startPos = GenTime(m_selectionGroup->scenePos().x(), m_document->fps()); + m_selectionGroupInfo.track = m_selectionGroup->track(); + + QList children = m_selectionGroup->childItems(); + for (int i = 0; i < children.count(); i++) { + // re-add items in correct place + AbstractClipItem *item = static_cast (children.at(i)); + item->updateItem(); + ItemInfo info = item->info(); + if (item->type() == AVWIDGET) { + ClipItem *clip = static_cast (item); + info.track = m_document->tracksCount() - info.track; + m_document->renderer()->mltInsertClip(info, clip->xml(), clip->baseClip()->producer(info.track)); + } else { + Transition *tr = static_cast (item); + int newTrack = tr->transitionEndTrack(); + kDebug() << "/// TRANSITION CURR TRK: " << newTrack; + if (!tr->forcedTrack()) { + newTrack += trackOffset; + if (newTrack < 0 || newTrack > m_document->tracksCount()) newTrack = getPreviousVideoTrack(info.track); + } + tr->updateTransitionEndTrack(newTrack); + kDebug() << "/// TRANSITION UPDATED TRK: " << newTrack; + m_document->renderer()->mltAddTransition(tr->transitionTag(), newTrack, m_document->tracksCount() - info.track, info.startPos, info.endPos, tr->toXML()); + } + } + KdenliveSettings::setSnaptopoints(snap); } + } void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end) { Transition *item = getTransitionItemAt((int)start.startPos.frames(m_document->fps()), start.track); if (!item) { - emit displayMessage(i18n("Cannot move transition at time: %1s on track %2", start.startPos.seconds(), start.track), ErrorMessage); + emit displayMessage(i18n("Cannot move transition at time: %1 on track %2", m_document->timecode().getTimecodeFromFrames(start.startPos.frames(m_document->fps())), start.track), ErrorMessage); kDebug() << "----------------  ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2; return; } //kDebug() << "----------------  Move TRANSITION FROM: " << startPos.x() << ", END:" << endPos.x() << ",TRACKS: " << oldtrack << " TO " << newtrack; - + bool snap = KdenliveSettings::snaptopoints(); + KdenliveSettings::setSnaptopoints(false); //kDebug()<<"/// RESIZE TRANS START: ("<< startPos.x()<<"x"<< startPos.y()<<") / ("<resizeStart((int) end.startPos.frames(m_document->fps())); - } else { + } else if (end.startPos == start.startPos) { // Transition end resize; item->resizeEnd((int) end.endPos.frames(m_document->fps())); + } else { + // Move & resize + item->setPos((int) end.startPos.frames(m_document->fps()), (end.track) * m_tracksHeight + 1); + item->resizeStart((int) end.startPos.frames(m_document->fps())); + item->resizeEnd((int) end.endPos.frames(m_document->fps())); } //item->moveTransition(GenTime((int) (endPos.x() - startPos.x()), m_document->fps())); + KdenliveSettings::setSnaptopoints(snap); item->updateTransitionEndTrack(getPreviousVideoTrack(end.track)); - m_document->renderer()->mltMoveTransition(item->transitionTag(), m_scene->m_tracksList.count() - start.track, m_scene->m_tracksList.count() - end.track, item->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos); + m_document->renderer()->mltMoveTransition(item->transitionTag(), m_document->tracksCount() - start.track, m_document->tracksCount() - end.track, item->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos); } void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) { @@ -1794,13 +2446,15 @@ void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) { else offset = -1;*/ ClipItem *item = getClipItemAt((int)(start.startPos.frames(m_document->fps()) + offset), start.track); if (!item) { - emit displayMessage(i18n("Cannot move clip at time: %1s on track %2", start.startPos.seconds(), start.track), ErrorMessage); + emit displayMessage(i18n("Cannot move clip at time: %1 on track %2", m_document->timecode().getTimecodeFromFrames(start.startPos.frames(m_document->fps())), start.track), ErrorMessage); kDebug() << "----------------  ERROR, CANNOT find clip to resize at... "; // << startPos; return; } + bool snap = KdenliveSettings::snaptopoints(); + KdenliveSettings::setSnaptopoints(false); if (resizeClipStart) { ItemInfo clipinfo = item->info(); - clipinfo.track = m_scene->m_tracksList.count() - clipinfo.track; + clipinfo.track = m_document->tracksCount() - clipinfo.track; bool success = m_document->renderer()->mltResizeClipStart(clipinfo, end.startPos - item->startPos()); if (success) { item->resizeStart((int) end.startPos.frames(m_document->fps())); @@ -1808,7 +2462,7 @@ void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) { } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); } else { ItemInfo clipinfo = item->info(); - clipinfo.track = m_scene->m_tracksList.count() - clipinfo.track; + clipinfo.track = m_document->tracksCount() - clipinfo.track; bool success = m_document->renderer()->mltResizeClipEnd(clipinfo, end.endPos - clipinfo.startPos); if (success) { item->resizeEnd((int) end.endPos.frames(m_document->fps())); @@ -1816,6 +2470,7 @@ void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) { } else emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); } m_document->renderer()->doRefresh(); + KdenliveSettings::setSnaptopoints(snap); } void CustomTrackView::updateClipFade(ClipItem * item, bool updateFadeOut) { @@ -1835,8 +2490,7 @@ void CustomTrackView::updateClipFade(ClipItem * item, bool updateFadeOut) { end += start; EffectsList::setParameter(oldeffect, "in", QString::number(start)); EffectsList::setParameter(oldeffect, "out", QString::number(end)); - QHash effectParams = item->getEffectArgs(oldeffect); - if (!m_document->renderer()->mltEditEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), effectParams)) + if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect))) emit displayMessage(i18n("Problem editing effect"), ErrorMessage); // if fade effect is displayed, update the effect edit widget with new clip duration if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos); @@ -1857,8 +2511,7 @@ void CustomTrackView::updateClipFade(ClipItem * item, bool updateFadeOut) { start = end - start; EffectsList::setParameter(oldeffect, "in", QString::number(start)); EffectsList::setParameter(oldeffect, "out", QString::number(end)); - QHash effectParams = item->getEffectArgs(oldeffect); - if (!m_document->renderer()->mltEditEffect(m_scene->m_tracksList.count() - item->track(), item->startPos(), effectParams)) + if (!m_document->renderer()->mltEditEffect(m_document->tracksCount() - item->track(), item->startPos(), item->getEffectArgs(oldeffect))) emit displayMessage(i18n("Problem editing effect"), ErrorMessage); // if fade effect is displayed, update the effect edit widget with new clip duration if (item->isSelected() && effectPos == item->selectedEffectIndex()) emit clipItemSelected(item, effectPos); @@ -1947,88 +2600,30 @@ void CustomTrackView::clipStart() { void CustomTrackView::clipEnd() { ClipItem *item = getMainActiveClip(); if (item != NULL) { - setCursorPos((int) item->endPos().frames(m_document->fps())); + setCursorPos((int) item->endPos().frames(m_document->fps()) - 1); checkScrolling(); } } -void CustomTrackView::slotAddClipMarker() { - QList itemList = scene()->selectedItems(); - if (itemList.count() != 1) { - emit displayMessage(i18n("Cannot add marker if more than one clip is selected"), ErrorMessage); - kDebug() << "// CANNOT ADD MARKER IF MORE TAN ONE CLIP IS SELECTED...."; - return; - } - AbstractClipItem *item = (AbstractClipItem *)itemList.at(0); - if (item->type() != AVWIDGET) return; - GenTime pos = GenTime(m_cursorPos, m_document->fps()); - if (item->startPos() > pos || item->endPos() < pos) return; - ClipItem *clip = (ClipItem *) item; - QString id = clip->baseClip()->getId(); - GenTime position = pos - item->startPos() + item->cropStart(); - CommentedTime marker(position, i18n("Marker")); - MarkerDialog d(clip->baseClip(), marker, m_document->timecode(), this); - if (d.exec() == QDialog::Accepted) { - slotAddClipMarker(id, d.newMarker().time(), d.newMarker().comment()); - } -} - void CustomTrackView::slotAddClipMarker(const QString &id, GenTime t, QString c) { QString oldcomment = m_document->clipManager()->getClipById(id)->markerComment(t); AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, c, id, t, true); m_commandStack->push(command); } -void CustomTrackView::slotDeleteClipMarker() { - QList itemList = scene()->selectedItems(); - if (itemList.count() != 1) { - emit displayMessage(i18n("Cannot delete marker if more than one clip is selected"), ErrorMessage); - kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED...."; - return; - } - AbstractClipItem *item = (AbstractClipItem *)itemList.at(0); - if (item->type() != AVWIDGET) { - emit displayMessage(i18n("No clip selected"), ErrorMessage); - return; - } - GenTime pos = GenTime(m_cursorPos, m_document->fps()); - if (item->startPos() > pos || item->endPos() < pos) { - emit displayMessage(i18n("No selected clip at cursor time"), ErrorMessage); - return; - } - ClipItem *clip = (ClipItem *) item; - QString id = clip->baseClip()->getId(); - GenTime position = pos - item->startPos() + item->cropStart(); - QString comment = clip->baseClip()->markerComment(position); - if (comment.isEmpty()) { - emit displayMessage(i18n("No marker found at cursor time"), ErrorMessage); - return; - } +void CustomTrackView::slotDeleteClipMarker(const QString &comment, const QString &id, const GenTime &position) { AddMarkerCommand *command = new AddMarkerCommand(this, comment, QString(), id, position, true); m_commandStack->push(command); } -void CustomTrackView::slotDeleteAllClipMarkers() { - QList itemList = scene()->selectedItems(); - if (itemList.count() != 1) { - emit displayMessage(i18n("Cannot delete marker if more than one clip is selected"), ErrorMessage); - kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED...."; - return; - } - AbstractClipItem *item = (AbstractClipItem *)itemList.at(0); - if (item->type() != AVWIDGET) { - emit displayMessage(i18n("No clip selected"), ErrorMessage); - return; - } - - ClipItem *clip = static_cast (item); - QList markers = clip->baseClip()->commentedSnapMarkers(); +void CustomTrackView::slotDeleteAllClipMarkers(const QString &id) { + DocClipBase *base = m_document->clipManager()->getClipById(id); + QList markers = base->commentedSnapMarkers(); if (markers.isEmpty()) { emit displayMessage(i18n("Clip has no markers"), ErrorMessage); return; } - QString id = clip->baseClip()->getId(); QUndoCommand *deleteMarkers = new QUndoCommand(); deleteMarkers->setText("Delete clip markers"); @@ -2038,49 +2633,6 @@ void CustomTrackView::slotDeleteAllClipMarkers() { m_commandStack->push(deleteMarkers); } -void CustomTrackView::slotEditClipMarker() { - QList itemList = scene()->selectedItems(); - if (itemList.count() != 1) { - emit displayMessage(i18n("Cannot edit marker if more than one clip is selected"), ErrorMessage); - kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED...."; - return; - } - AbstractClipItem *item = (AbstractClipItem *)itemList.at(0); - if (item->type() != AVWIDGET) { - emit displayMessage(i18n("No clip at cursor time"), ErrorMessage); - return; - } - GenTime pos = GenTime(m_cursorPos, m_document->fps()); - if (item->startPos() > pos || item->endPos() < pos) { - emit displayMessage(i18n("No selected clip at cursor time"), ErrorMessage); - return; - } - ClipItem *clip = (ClipItem *) item; - QString id = clip->baseClip()->getId(); - GenTime position = pos - item->startPos() + item->cropStart(); - QString oldcomment = clip->baseClip()->markerComment(position); - if (oldcomment.isEmpty()) { - emit displayMessage(i18n("No marker found at cursor time"), ErrorMessage); - return; - } - - CommentedTime marker(position, oldcomment); - MarkerDialog d(clip->baseClip(), marker, m_document->timecode(), this); - if (d.exec() == QDialog::Accepted) { - if (d.newMarker().time() == position) { - // marker position was not changed, only text - AddMarkerCommand *command = new AddMarkerCommand(this, oldcomment, d.newMarker().comment(), id, position, true); - m_commandStack->push(command); - } else { - // marker text and position were changed, remove previous marker and add new one - AddMarkerCommand *command1 = new AddMarkerCommand(this, oldcomment, QString(), id, position, true); - AddMarkerCommand *command2 = new AddMarkerCommand(this, QString(), d.newMarker().comment(), id, d.newMarker().time(), true); - m_commandStack->push(command1); - m_commandStack->push(command2); - } - } -} - void CustomTrackView::addMarker(const QString &id, const GenTime &pos, const QString comment) { DocClipBase *base = m_document->clipManager()->getClipById(id); if (!comment.isEmpty()) base->addSnapMarker(pos, comment); @@ -2124,11 +2676,11 @@ void CustomTrackView::editGuide(const GenTime oldPos, const GenTime pos, const Q bool CustomTrackView::addGuide(const GenTime pos, const QString &comment) { for (int i = 0; i < m_guides.count(); i++) { if (m_guides.at(i)->position() == pos) { - emit displayMessage(i18n("A guide already exists at that position"), ErrorMessage); + emit displayMessage(i18n("A guide already exists at position %1", m_document->timecode().getTimecodeFromFrames(pos.frames(m_document->fps()))), ErrorMessage); return false; } } - Guide *g = new Guide(this, pos, comment, m_document->fps(), m_tracksHeight * m_scene->m_tracksList.count()); + Guide *g = new Guide(this, pos, comment, m_document->fps(), m_tracksHeight * m_document->tracksCount()); scene()->addItem(g); m_guides.append(g); qSort(m_guides.begin(), m_guides.end(), sortGuidesList); @@ -2138,7 +2690,7 @@ bool CustomTrackView::addGuide(const GenTime pos, const QString &comment) { void CustomTrackView::slotAddGuide() { CommentedTime marker(GenTime(m_cursorPos, m_document->fps()), i18n("Guide")); - MarkerDialog d(NULL, marker, m_document->timecode(), this); + MarkerDialog d(NULL, marker, m_document->timecode(), i18n("Add Guide"), this); if (d.exec() != QDialog::Accepted) return; if (addGuide(d.newMarker().time(), d.newMarker().comment())) { EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), d.newMarker().time(), d.newMarker().comment(), false); @@ -2160,7 +2712,7 @@ void CustomTrackView::slotEditGuide() { } void CustomTrackView::slotEditGuide(CommentedTime guide) { - MarkerDialog d(NULL, guide, m_document->timecode(), this); + MarkerDialog d(NULL, guide, m_document->timecode(), i18n("Edit Guide"), this); if (d.exec() == QDialog::Accepted) { EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d.newMarker().time(), d.newMarker().comment(), true); m_commandStack->push(command); @@ -2249,14 +2801,14 @@ void CustomTrackView::drawBackground(QPainter * painter, const QRectF & rect) { r.setWidth(r.width() + 1); painter->setClipRect(r); painter->drawLine(r.left(), 0, r.right(), 0); - uint max = m_scene->m_tracksList.count(); + uint max = m_document->tracksCount(); for (uint i = 0; i < max;i++) { /*if (max - i - 1 == m_selectedTrack) painter->fillRect(r.left(), m_tracksHeight * i + 1, r.right() - r.left() + 1, m_tracksHeight - 1, QBrush(QColor(211, 205, 147))); else*/ - if (m_scene->m_tracksList.at(max - i - 1).type == AUDIOTRACK) painter->fillRect(r.left(), m_tracksHeight * i + 1, r.right() - r.left() + 1, m_tracksHeight - 1, QBrush(QColor(240, 240, 255))); + if (m_document->trackInfoAt(max - i - 1).type == AUDIOTRACK) painter->fillRect(r.left(), m_tracksHeight * i + 1, r.right() - r.left() + 1, m_tracksHeight - 1, QBrush(QColor(240, 240, 255))); painter->drawLine(r.left(), m_tracksHeight * (i + 1), r.right(), m_tracksHeight * (i + 1)); } - int lowerLimit = m_tracksHeight * m_scene->m_tracksList.count() + 1; + int lowerLimit = m_tracksHeight * m_document->tracksCount() + 1; if (height() > lowerLimit) painter->fillRect(QRectF(r.left(), lowerLimit, r.width(), height() - lowerLimit), QBrush(base)); } @@ -2453,7 +3005,7 @@ void CustomTrackView::pasteClipEffects() { if (clips.at(i)->type() == AVWIDGET) { ClipItem *item = static_cast < ClipItem *>(clips.at(i)); for (int i = 0; i < clip->effectsCount(); i++) { - new AddEffectCommand(this, m_scene->m_tracksList.count() - item->track(), item->startPos(), clip->effectAt(i), true, paste); + new AddEffectCommand(this, m_document->tracksCount() - item->track(), item->startPos(), clip->effectAt(i), true, paste); } } } @@ -2462,7 +3014,7 @@ void CustomTrackView::pasteClipEffects() { ClipItem *CustomTrackView::getClipUnderCursor() const { - QRectF rect((double) m_cursorPos, 0.0, 1.0, (double)(m_tracksHeight * m_scene->m_tracksList.count())); + QRectF rect((double) m_cursorPos, 0.0, 1.0, (double)(m_tracksHeight * m_document->tracksCount())); QList collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect); for (int i = 0; i < collisions.count(); i++) { if (collisions.at(i)->type() == AVWIDGET) { @@ -2488,7 +3040,7 @@ ClipItem *CustomTrackView::getMainActiveClip() const { return NULL; } -ClipItem *CustomTrackView::getActiveClipUnderCursor() const { +ClipItem *CustomTrackView::getActiveClipUnderCursor(bool allowOutsideCursor) const { QList clips = scene()->selectedItems(); if (clips.isEmpty()) { return getClipUnderCursor(); @@ -2499,7 +3051,7 @@ ClipItem *CustomTrackView::getActiveClipUnderCursor() const { if (clips.at(i)->type() != AVWIDGET) clips.removeAt(i); else i++; } - if (clips.count() == 1) return static_cast < ClipItem *>(clips.at(0)); + if (clips.count() == 1 && allowOutsideCursor) return static_cast < ClipItem *>(clips.at(0)); for (int i = 0; i < clips.count(); ++i) { if (clips.at(i)->type() == AVWIDGET) item = static_cast < ClipItem *>(clips.at(i)); @@ -2510,7 +3062,7 @@ ClipItem *CustomTrackView::getActiveClipUnderCursor() const { } void CustomTrackView::setInPoint() { - ClipItem *clip = getActiveClipUnderCursor(); + ClipItem *clip = getActiveClipUnderCursor(true); if (clip == NULL) { emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage); return; @@ -2518,12 +3070,23 @@ void CustomTrackView::setInPoint() { ItemInfo startInfo = clip->info(); ItemInfo endInfo = clip->info(); endInfo.startPos = GenTime(m_cursorPos, m_document->fps()); + if (endInfo.startPos >= startInfo.endPos) { + // Check for invalid resize + emit displayMessage(i18n("Invalid action"), ErrorMessage); + return; + } else if (endInfo.startPos < startInfo.startPos) { + int length = m_document->renderer()->mltGetSpaceLength(endInfo.startPos, m_document->tracksCount() - startInfo.track, false); + if (length < (startInfo.startPos - endInfo.startPos).frames(m_document->fps())) { + emit displayMessage(i18n("Invalid action"), ErrorMessage); + return; + } + } ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true); m_commandStack->push(command); } void CustomTrackView::setOutPoint() { - ClipItem *clip = getActiveClipUnderCursor(); + ClipItem *clip = getActiveClipUnderCursor(true); if (clip == NULL) { emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage); return; @@ -2531,21 +3094,229 @@ void CustomTrackView::setOutPoint() { ItemInfo startInfo = clip->info(); ItemInfo endInfo = clip->info(); endInfo.endPos = GenTime(m_cursorPos, m_document->fps()); + if (endInfo.endPos <= startInfo.startPos) { + // Check for invalid resize + emit displayMessage(i18n("Invalid action"), ErrorMessage); + return; + } else if (endInfo.endPos > startInfo.endPos) { + int length = m_document->renderer()->mltGetSpaceLength(endInfo.endPos, m_document->tracksCount() - startInfo.track, false); + if (length < (endInfo.endPos - startInfo.endPos).frames(m_document->fps())) { + emit displayMessage(i18n("Invalid action"), ErrorMessage); + return; + } + } + + + ResizeClipCommand *command = new ResizeClipCommand(this, startInfo, endInfo, true); m_commandStack->push(command); } void CustomTrackView::slotUpdateAllThumbs() { QList itemList = items(); + //if (itemList.isEmpty()) return; ClipItem *item; - Transition *transitionitem; + QString thumbBase = m_document->projectFolder().path() + "/thumbs/"; for (int i = 0; i < itemList.count(); i++) { if (itemList.at(i)->type() == AVWIDGET) { item = static_cast (itemList.at(i)); + if (item->clipType() != COLOR) { + // Check if we have a cached thumbnail + if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) { + QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png"; + if (QFile::exists(thumb)) { + QPixmap pix(thumb); + item->slotSetStartThumb(pix); + item->slotSetEndThumb(pix); + } + } else { + QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_'; + QString endThumb = startThumb; + startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png"); + endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png"); + if (QFile::exists(startThumb)) { + QPixmap pix(startThumb); + item->slotSetStartThumb(pix); + } + if (QFile::exists(endThumb)) { + QPixmap pix(endThumb); + item->slotSetEndThumb(pix); + } + } + } item->refreshClip(); qApp->processEvents(); } } + viewport()->update(); +} + +void CustomTrackView::saveThumbnails() { + QList itemList = items(); + ClipItem *item; + QString thumbBase = m_document->projectFolder().path() + "/thumbs/"; + for (int i = 0; i < itemList.count(); i++) { + if (itemList.at(i)->type() == AVWIDGET) { + item = static_cast (itemList.at(i)); + if (item->clipType() != COLOR) { + // Check if we have a cached thumbnail + if (item->clipType() == IMAGE || item->clipType() == TEXT || item->clipType() == AUDIO) { + QString thumb = thumbBase + item->baseClip()->getClipHash() + "_0.png"; + if (!QFile::exists(thumb)) { + QPixmap pix(item->startThumb()); + pix.save(thumb); + } + } else { + QString startThumb = thumbBase + item->baseClip()->getClipHash() + '_'; + QString endThumb = startThumb; + startThumb.append(QString::number(item->cropStart().frames(m_document->fps())) + ".png"); + endThumb.append(QString::number((item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1) + ".png"); + if (!QFile::exists(startThumb)) { + QPixmap pix(item->startThumb()); + pix.save(startThumb); + } + if (!QFile::exists(endThumb)) { + QPixmap pix(item->endThumb()); + pix.save(endThumb); + } + } + } + } + } +} + + +void CustomTrackView::slotInsertTrack(int ix) { + kDebug() << "// INSERTING TRK: " << ix; + QDialog d(parentWidget()); + Ui::AddTrack_UI view; + view.setupUi(&d); + view.track_nb->setMaximum(m_document->tracksCount() - 1); + view.track_nb->setValue(ix); + d.setWindowTitle(i18n("Insert Track")); + + if (d.exec() == QDialog::Accepted) { + ix = view.track_nb->value(); + if (view.before_select->currentIndex() == 1) { + ix++; + } + TrackInfo info; + if (view.video_track->isChecked()) { + info.type = VIDEOTRACK; + info.isMute = false; + info.isBlind = false; + } else { + info.type = AUDIOTRACK; + info.isMute = false; + info.isBlind = true; + } + AddTrackCommand *addTrack = new AddTrackCommand(this, ix, info, true, true); + m_commandStack->push(addTrack); + m_document->setModified(true); + } +} + +void CustomTrackView::slotDeleteTrack(int ix) { + bool ok; + ix = QInputDialog::getInteger(this, i18n("Remove Track"), i18n("Track"), ix, 0, m_document->tracksCount() - 1, 1, &ok); + if (ok) { + TrackInfo info = m_document->trackInfoAt(m_document->tracksCount() - ix - 1); + deleteTimelineTrack(ix, info); + m_document->setModified(true); + /*AddTrackCommand* command = new AddTrackCommand(this, ix, info, false, true); + m_commandStack->push(command);*/ + } +} + +void CustomTrackView::slotChangeTrack(int ix) { + QDialog d(parentWidget()); + Ui::AddTrack_UI view; + view.setupUi(&d); + view.label->setText(i18n("Change track")); + view.before_select->setHidden(true); + view.track_nb->setMaximum(m_document->tracksCount() - 1); + view.track_nb->setValue(ix); + d.setWindowTitle(i18n("Change Track Type")); + + if (d.exec() == QDialog::Accepted) { + TrackInfo info; + if (view.video_track->isChecked()) { + info.type = VIDEOTRACK; + info.isMute = false; + info.isBlind = false; + } else { + info.type = AUDIOTRACK; + info.isMute = false; + info.isBlind = true; + } + changeTimelineTrack(ix, info); + m_document->setModified(true); + } +} + + +void CustomTrackView::deleteTimelineTrack(int ix, TrackInfo trackinfo) { + double startY = ix * m_tracksHeight + 1 + m_tracksHeight / 2; + QRectF r(0, startY, sceneRect().width(), m_tracksHeight / 2 - 1); + QList selection = m_scene->items(r); + QUndoCommand *deleteTrack = new QUndoCommand(); + deleteTrack->setText("Delete track"); + + // Delete all clips in selected track + for (int i = 0; i < selection.count(); i++) { + if (selection.at(i)->type() == AVWIDGET) { + ClipItem *item = static_cast (selection.at(i)); + new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), item->effectList(), false, true, deleteTrack); + m_scene->removeItem(item); + delete item; + item = NULL; + } else if (selection.at(i)->type() == TRANSITIONWIDGET) { + Transition *item = static_cast (selection.at(i)); + new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, false, deleteTrack); + m_scene->removeItem(item); + delete item; + item = NULL; + } + } + + new AddTrackCommand(this, ix, trackinfo, false, true, deleteTrack); + m_commandStack->push(deleteTrack); +} + +void CustomTrackView::changeTimelineTrack(int ix, TrackInfo trackinfo) { + TrackInfo oldinfo = m_document->trackInfoAt(m_document->tracksCount() - ix); + ChangeTrackCommand *changeTrack = new ChangeTrackCommand(this, ix, oldinfo, trackinfo, true); + m_commandStack->push(changeTrack); +} + +void CustomTrackView::autoTransition() { + QList itemList = scene()->selectedItems(); + if (itemList.count() != 1 || itemList.at(0)->type() != TRANSITIONWIDGET) { + emit displayMessage(i18n("You must select one transition for this action"), ErrorMessage); + return; + } + Transition *tr = static_cast (itemList.at(0)); + tr->setAutomatic(!tr->isAutomatic()); + QDomElement transition = tr->toXML(); + m_document->renderer()->mltUpdateTransition(transition.attribute("tag"), transition.attribute("tag"), transition.attribute("transition_btrack").toInt(), m_document->tracksCount() - transition.attribute("transition_atrack").toInt(), tr->startPos(), tr->endPos(), transition); +} + + +QStringList CustomTrackView::getLadspaParams(QDomElement effect) const { + QStringList result; + QDomNodeList params = effect.elementsByTagName("parameter"); + for (int i = 0; i < params.count(); i++) { + QDomElement e = params.item(i).toElement(); + if (!e.isNull() && e.attribute("type") == "constant") { + if (e.hasAttribute("factor")) { + double factor = e.attribute("factor").toDouble(); + double value = e.attribute("value").toDouble(); + value = value / factor; + result.append(QString::number(value)); + } else result.append(e.attribute("value")); + } + } + return result; } #include "customtrackview.moc"