]> git.sesse.net Git - kdenlive/blobdiff - src/customtrackview.cpp
Do not allow removing the last keyframe by dragging it above or below the clip even...
[kdenlive] / src / customtrackview.cpp
index 429ce27297751df61c296a5711d5485ad2772a05..d6ab47535aed959d3cfc14a5cd388c9996c9db8f 100644 (file)
@@ -398,19 +398,26 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event)
                 if (!m_controlModifier && m_dragItem->type() == AVWIDGET && m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) {
                     AbstractGroupItem *parent = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
                     if (parent)
-                        parent->resizeStart((int)(snappedPos) - m_dragItemInfo.startPos.frames(m_document->fps()));
+                        parent->resizeStart((int)(snappedPos - m_dragItemInfo.startPos.frames(m_document->fps())));
                 } else {
                     m_dragItem->resizeStart((int)(snappedPos));
                 }
+                QString crop = m_document->timecode().getDisplayTimecode(m_dragItem->cropStart(), KdenliveSettings::frametimecode());
+                QString duration = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration(), KdenliveSettings::frametimecode());
+                QString offset = m_document->timecode().getDisplayTimecode(m_dragItem->cropStart() - m_dragItemInfo.cropStart, KdenliveSettings::frametimecode());
+                emit displayMessage(i18n("Crop from start:") + ' ' + crop + ' ' + i18n("Duration:") + ' ' + duration + ' ' + i18n("Offset:") + ' ' + offset, InformationMessage);
             } else if (m_operationMode == RESIZEEND && move) {
                 m_document->renderer()->pause();
                 if (!m_controlModifier && m_dragItem->type() == AVWIDGET && m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) {
                     AbstractGroupItem *parent = static_cast <AbstractGroupItem *>(m_dragItem->parentItem());
                     if (parent)
-                        parent->resizeEnd((int)(snappedPos) - m_dragItemInfo.endPos.frames(m_document->fps()));
+                        parent->resizeEnd((int)(snappedPos - m_dragItemInfo.endPos.frames(m_document->fps())));
                 } else {
                     m_dragItem->resizeEnd((int)(snappedPos));
                 }
+                QString duration = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration(), KdenliveSettings::frametimecode());
+                QString offset = m_document->timecode().getDisplayTimecode(m_dragItem->cropDuration() - m_dragItemInfo.cropDuration, KdenliveSettings::frametimecode());
+                emit displayMessage(i18n("Duration:") + ' ' + duration + ' ' + i18n("Offset:") + ' ' + offset, InformationMessage);
             } else if (m_operationMode == FADEIN && move) {
                 ((ClipItem*) m_dragItem)->setFadeIn((int)(mappedXPos - m_dragItem->startPos().frames(m_document->fps())));
             } else if (m_operationMode == FADEOUT && move) {
@@ -2338,8 +2345,12 @@ void CustomTrackView::dropEvent(QDropEvent * event)
         */
 
         m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);
-        if (items.count() > 1) groupSelectedItems(true);
-        else if (items.count() == 1) m_dragItem = static_cast <ClipItem *>(items.at(0));
+        if (items.count() > 1) {
+            groupSelectedItems(true);
+        } else if (items.count() == 1) {
+            m_dragItem = static_cast <AbstractClipItem *>(items.at(0));
+            emit clipItemSelected((ClipItem*)m_dragItem);
+        }
         event->setDropAction(Qt::MoveAction);
         event->accept();
     } else QGraphicsView::dropEvent(event);
@@ -2545,10 +2556,7 @@ void CustomTrackView::addTrack(TrackInfo type, int ix)
                 if (clip->speed() != 1.0) continue;
                 // We add a move clip command so that we get the correct producer for new track number
                 if (clip->clipType() == AV || clip->clipType() == AUDIO) {
-                    Mlt::Producer *prod;
-                    if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(clipinfo.track);
-                    else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
-                    else prod = clip->baseClip()->producer(clipinfo.track);
+                    Mlt::Producer *prod = clip->getProducer(clipinfo.track);
                     if (m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), prod) == false) {
                         // problem updating clip
                         emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", clipinfo.startPos.frames(m_document->fps()), clipinfo.track), ErrorMessage);
@@ -2575,9 +2583,10 @@ void CustomTrackView::addTrack(TrackInfo type, int ix)
     m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), maxHeight - 1);
     setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_document->tracksCount());
     viewport()->update();
-    emit tracksChanged();
     //QTimer::singleShot(500, this, SIGNAL(trackHeightChanged()));
     //setFixedHeight(50 * m_tracksCount);
+
+    updateTrackNames(ix, true);
 }
 
 void CustomTrackView::removeTrack(int ix)
@@ -2619,10 +2628,7 @@ void CustomTrackView::removeTrack(int ix)
             ItemInfo clipinfo = clip->info();
             // We add a move clip command so that we get the correct producer for new track number
             if (clip->clipType() == AV || clip->clipType() == AUDIO) {
-                Mlt::Producer *prod;
-                if (clip->isAudioOnly()) prod = clip->baseClip()->audioProducer(clipinfo.track);
-                else if (clip->isVideoOnly()) prod = clip->baseClip()->videoProducer();
-                else prod = clip->baseClip()->producer(clipinfo.track);
+                Mlt::Producer *prod = clip->getProducer(clipinfo.track);
                 if (!m_document->renderer()->mltUpdateClipProducer((int)(m_document->tracksCount() - clipinfo.track), clipinfo.startPos.frames(m_document->fps()), prod)) {
                     emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", clipinfo.startPos.frames(m_document->fps()), clipinfo.track), ErrorMessage);
                 }
@@ -2650,7 +2656,8 @@ void CustomTrackView::removeTrack(int ix)
 
     m_selectedTrack = qMin(m_selectedTrack, m_document->tracksCount() - 1);
     viewport()->update();
-    emit tracksChanged();
+
+    updateTrackNames(ix, false);
     //QTimer::singleShot(500, this, SIGNAL(trackHeightChanged()));
 }
 
@@ -2662,8 +2669,8 @@ void CustomTrackView::configTracks(QList < TrackInfo > trackInfos)
         lockTrack(m_document->tracksCount() - i - 1, m_document->trackInfoAt(i).isLocked, false);
     }
 
-    QTimer::singleShot(300, this, SIGNAL(trackHeightChanged()));
     viewport()->update();
+    emit trackHeightChanged();
 }
 
 void CustomTrackView::slotSwitchTrackAudio(int ix)
@@ -2695,15 +2702,61 @@ void CustomTrackView::lockTrack(int ix, bool lock, bool requestUpdate)
     QList<QGraphicsItem *> selection = m_scene->items(0, ix * m_tracksHeight + m_tracksHeight / 2, sceneRect().width(), m_tracksHeight / 2 - 2);
 
     for (int i = 0; i < selection.count(); i++) {
-        if (selection.at(i)->type() != AVWIDGET && selection.at(i)->type() != TRANSITIONWIDGET) continue;
-        if (selection.at(i)->isSelected()) {
-            if (selection.at(i)->type() == AVWIDGET) emit clipItemSelected(NULL);
-            else emit transitionItemSelected(NULL);
+        if (selection.at(i)->type() == GROUPWIDGET && (AbstractGroupItem *)selection.at(i) != m_selectionGroup) {
+            if (selection.at(i)->parentItem() && m_selectionGroup) {
+                selection.removeAll((QGraphicsItem*)m_selectionGroup);
+                resetSelectionGroup();
+            }
+
+            bool changeGroupLock = true;
+            bool hasClipOnTrack = false;
+            QList <QGraphicsItem *> children =  selection.at(i)->childItems();
+            for (int j = 0; j < children.count(); ++j) {
+                if (children.at(j)->isSelected()) {
+                    if (children.at(j)->type() == AVWIDGET)
+                        emit clipItemSelected(NULL);
+                    else if (children.at(j)->type() == TRANSITIONWIDGET)
+                        emit transitionItemSelected(NULL);
+                    else
+                        continue;
+                }
+
+                AbstractClipItem * child = static_cast <AbstractClipItem *>(children.at(j));
+                if (child == m_dragItem)
+                    m_dragItem = NULL;
+
+                // only unlock group, if it is not locked by another track too
+                if (!lock && child->track() != ix && m_document->trackInfoAt(m_document->tracksCount() - child->track() - 1).isLocked)
+                    changeGroupLock = false;
+                
+                // only (un-)lock if at least one clip is on the track
+                if (child->track() == ix)
+                    hasClipOnTrack = true;
+            }
+            if (changeGroupLock && hasClipOnTrack)
+                ((AbstractGroupItem*)selection.at(i))->setItemLocked(lock);
+        } else if((selection.at(i)->type() == AVWIDGET || selection.at(i)->type() == TRANSITIONWIDGET)) {
+            if (selection.at(i)->parentItem()) {
+                if (selection.at(i)->parentItem() == m_selectionGroup) {
+                    selection.removeAll((QGraphicsItem*)m_selectionGroup);
+                    resetSelectionGroup();
+                } else {
+                    // groups are handled separately
+                    continue;
+                }
+            }
+
+            if (selection.at(i)->isSelected()) {
+                if (selection.at(i)->type() == AVWIDGET)
+                    emit clipItemSelected(NULL);
+                else
+                    emit transitionItemSelected(NULL);
+            }
+            clip = static_cast <AbstractClipItem *>(selection.at(i));
+            clip->setItemLocked(lock);
+            if (clip == m_dragItem)
+                m_dragItem = NULL;
         }
-        clip = static_cast <AbstractClipItem *>(selection.at(i));
-        clip->setItemLocked(lock);
-        if (clip == m_dragItem)
-            m_dragItem = NULL;
     }
     kDebug() << "NEXT TRK STATE: " << m_document->trackInfoAt(tracknumber).isLocked;
     viewport()->update();
@@ -3097,10 +3150,7 @@ 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 <ClipItem *>(m_dragItem);
-                Mlt::Producer *prod;
-                if (item->isAudioOnly()) prod = item->baseClip()->audioProducer(info.track);
-                else if (item->isVideoOnly()) prod = item->baseClip()->videoProducer();
-                else prod = item->baseClip()->producer(info.track);
+                Mlt::Producer *prod = item->getProducer(info.track);
                 bool success = m_document->renderer()->mltMoveClip((int)(m_document->tracksCount() - m_dragItemInfo.track), (int)(m_document->tracksCount() - info.track), (int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(info.startPos.frames(m_document->fps())), prod, m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT);
 
                 if (success) {
@@ -3301,15 +3351,8 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
                     if (item->type() == AVWIDGET) {
                         ClipItem *clip = static_cast <ClipItem*>(item);
                         info.track = m_document->tracksCount() - info.track;
-                        Mlt::Producer *prod;
                         adjustTimelineClips(m_scene->editMode(), clip, ItemInfo(), moveGroup);
-                        if (clip->isAudioOnly())
-                            prod = clip->baseClip()->audioProducer(info.track);
-                        else if (clip->isVideoOnly())
-                            prod = clip->baseClip()->videoProducer();
-                        else
-                            prod = clip->baseClip()->producer(info.track);
-                        m_document->renderer()->mltInsertClip(info, clip->xml(), prod, m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT);
+                        m_document->renderer()->mltInsertClip(info, clip->xml(), clip->getProducer(info.track), m_scene->editMode() == OVERWRITEEDIT, m_scene->editMode() == INSERTEDIT);
                         for (int i = 0; i < clip->effectsCount(); i++) {
                             m_document->renderer()->mltAddEffect(info.track, info.startPos, getEffectArgs(clip->effectAt(i)), false);
                         }
@@ -3508,7 +3551,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
         int start = item->cropStart().frames(m_document->fps());
         int end = (item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1;
 
-        if ((val < -50 || val > 150) && item->editedKeyFramePos() != start && item->editedKeyFramePos() != end) {
+        if ((val < -50 || val > 150) && item->editedKeyFramePos() != start && item->editedKeyFramePos() != end && item->keyFrameNumber() > 1) {
             //delete keyframe
             item->movedKeyframe(item->getEffectAt(item->selectedEffectIndex()), item->selectedKeyFramePos(), -1, 0);
         } else {
@@ -3686,7 +3729,9 @@ void CustomTrackView::changeClipSpeed()
 
 void CustomTrackView::doChangeClipSpeed(ItemInfo info, ItemInfo speedIndependantInfo, const double speed, const double oldspeed, int strobe, const QString &id)
 {
-    DocClipBase *baseclip = m_document->clipManager()->getClipById(id);
+    Q_UNUSED(id);
+    //DocClipBase *baseclip = m_document->clipManager()->getClipById(id);
+
     ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()), info.track);
     if (!item) {
         kDebug() << "ERROR: Cannot find clip for speed change";
@@ -3694,22 +3739,17 @@ void CustomTrackView::doChangeClipSpeed(ItemInfo info, ItemInfo speedIndependant
         return;
     }
     info.track = m_document->tracksCount() - item->track();
-    int endPos;
-    if (item->isVideoOnly())
-        endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->videoProducer());
-    else if (item->isAudioOnly())
-        endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->audioProducer(item->track()));
-    else
-        endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, baseclip->producer());
+    int endPos = m_document->renderer()->mltChangeClipSpeed(info, speedIndependantInfo, speed, oldspeed, strobe, item->getProducer(item->track(), false));
     if (endPos >= 0) {
         item->setSpeed(speed, strobe);
         item->updateRectGeometry();
-        if (item->cropDuration().frames(m_document->fps()) != endPos) {
+        if (item->cropDuration().frames(m_document->fps()) != endPos)
             item->resizeEnd((int) info.startPos.frames(m_document->fps()) + endPos - 1);
-        }
         updatePositionEffects(item, info);
         setDocumentModified();
-    } else emit displayMessage(i18n("Invalid clip"), ErrorMessage);
+    } else {
+        emit displayMessage(i18n("Invalid clip"), ErrorMessage);
+    }
 }
 
 void CustomTrackView::cutSelectedClips()
@@ -3936,17 +3976,15 @@ void CustomTrackView::addClip(QDomElement xml, const QString &clipId, ItemInfo i
     baseclip->addReference();
     m_document->updateClip(baseclip->getId());
     info.track = m_document->tracksCount() - info.track;
-    Mlt::Producer *prod;
-    if (item->isAudioOnly()) prod = baseclip->audioProducer(info.track);
-    else if (item->isVideoOnly()) prod = baseclip->videoProducer();
-    else prod = baseclip->producer(info.track);
-    m_document->renderer()->mltInsertClip(info, xml, prod, overwrite, push);
+    m_document->renderer()->mltInsertClip(info, xml, item->getProducer(info.track), overwrite, push);
     for (int i = 0; i < item->effectsCount(); i++) {
         m_document->renderer()->mltAddEffect(info.track, info.startPos, getEffectArgs(item->effectAt(i)), false);
     }
     setDocumentModified();
-    if (refresh) m_document->renderer()->doRefresh();
-    if (!baseclip->isPlaceHolder()) m_waitingThumbs.append(item);
+    if (refresh)
+        m_document->renderer()->doRefresh();
+    if (!baseclip->isPlaceHolder())
+        m_waitingThumbs.append(item);
     m_thumbsTimer.start();
 }
 
@@ -4083,10 +4121,7 @@ void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end, bool re
         kDebug() << "----------------  ERROR, CANNOT find clip to move at.. ";
         return;
     }
-    Mlt::Producer *prod;
-    if (item->isAudioOnly()) prod = item->baseClip()->audioProducer(end.track);
-    else if (item->isVideoOnly()) prod = item->baseClip()->videoProducer();
-    else prod = item->baseClip()->producer(end.track);
+    Mlt::Producer *prod = item->getProducer(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()), prod);
     if (success) {
@@ -4210,14 +4245,7 @@ void CustomTrackView::moveGroup(QList <ItemInfo> startClip, QList <ItemInfo> sta
             if (item->type() == AVWIDGET) {
                 ClipItem *clip = static_cast <ClipItem*>(item);
                 info.track = m_document->tracksCount() - info.track;
-                Mlt::Producer *prod;
-                if (clip->isAudioOnly())
-                    prod = clip->baseClip()->audioProducer(info.track);
-                else if (clip->isVideoOnly())
-                    prod = clip->baseClip()->videoProducer();
-                else
-                    prod = clip->baseClip()->producer(info.track);
-                m_document->renderer()->mltInsertClip(info, clip->xml(), prod);
+                m_document->renderer()->mltInsertClip(info, clip->xml(), clip->getProducer(info.track));
                 for (int i = 0; i < clip->effectsCount(); i++) {
                     m_document->renderer()->mltAddEffect(info.track, info.startPos, getEffectArgs(clip->effectAt(i)), false);
                 }
@@ -4908,13 +4936,18 @@ bool CustomTrackView::addGuide(const GenTime pos, const QString &comment)
     return true;
 }
 
-void CustomTrackView::slotAddGuide()
+void CustomTrackView::slotAddGuide(bool dialog)
 {
     CommentedTime marker(GenTime(m_cursorPos, m_document->fps()), i18n("Guide"));
-    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);
+    if (dialog) {
+        MarkerDialog d(NULL, marker, m_document->timecode(), i18n("Add Guide"), this);
+        if (d.exec() != QDialog::Accepted) return;
+        marker.setComment(d.newMarker().comment());
+    } else {
+        marker.setComment(m_document->timecode().getDisplayTimecodeFromFrames(m_cursorPos, false));
+    }
+    if (addGuide(marker.time(), marker.comment())) {
+        EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), marker.time(), marker.comment(), false);
         m_commandStack->push(command);
     }
 }
@@ -5785,6 +5818,11 @@ void CustomTrackView::doSplitAudio(const GenTime &pos, int track, bool split)
     if (split) {
         int start = pos.frames(m_document->fps());
         int freetrack = m_document->tracksCount() - track - 1;
+
+        // do not split audio when we are on an audio track
+        if (m_document->trackInfoAt(freetrack).type == AUDIOTRACK)
+            return;
+
         for (; freetrack > 0; freetrack--) {
             kDebug() << "// CHK DOC TRK:" << freetrack << ", DUR:" << m_document->renderer()->mltTrackDuration(freetrack);
             if (m_document->trackInfoAt(freetrack - 1).type == AUDIOTRACK && !m_document->trackInfoAt(freetrack - 1).isLocked) {
@@ -6453,3 +6491,41 @@ void CustomTrackView::updatePanZoom(ClipItem* item, GenTime cutPos)
     if (effects.count() > 0)
         emit clipItemSelected(item, item->selectedEffectIndex());
 }
+
+void CustomTrackView::updateTrackNames(int track, bool added)
+{
+    QList <TrackInfo> tracks = m_document->tracksList();
+    int max = tracks.count();
+    int docTrack = max - track - 1;
+
+    // count number of tracks of each type
+    int videoTracks = 0;
+    int audioTracks = 0;
+    for (int i = max - 1; i >= 0; --i) {
+        TrackInfo info = tracks.at(i);
+        if (info.type == VIDEOTRACK)
+            videoTracks++;
+        else
+            audioTracks++;
+
+        if (i <= docTrack) {
+            QString type = (info.type == VIDEOTRACK ? "Video " : "Audio ");
+            int typeNumber = (info.type == VIDEOTRACK ? videoTracks : audioTracks);
+
+            if (added) {
+                if (i == docTrack || info.trackName == type + QString::number(typeNumber - 1)) {
+                    info.trackName = type + QString::number(typeNumber);
+                    m_document->setTrackType(i, info);
+                }
+            } else {
+                if (info.trackName == type + QString::number(typeNumber + 1)) {
+                    info.trackName = type + QString::number(typeNumber);
+                    m_document->setTrackType(i, info);
+                }
+            }
+        }
+    }
+
+    emit tracksChanged();
+}
+