]> git.sesse.net Git - kdenlive/blobdiff - src/clipitem.cpp
Add subclips (dragging a zone from clip monitor to project tree)
[kdenlive] / src / clipitem.cpp
index e1f6331c7387bce9537c3b5816fcb1a1b450f258..0b657927c2b1b20d56bbf8382a52525430115bea 100644 (file)
@@ -59,19 +59,25 @@ ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, double fps, double speed, i
     setZValue(2);
     setRect(0, 0, (info.endPos - info.startPos).frames(fps) - 0.02, (double)(KdenliveSettings::trackheight() - 2));
     setPos(info.startPos.frames(fps), (double)(info.track * KdenliveSettings::trackheight()) + 1);
+
+    // set speed independant info
+    m_speedIndependantInfo = m_info;
+    m_speedIndependantInfo.cropStart = GenTime((int)(m_info.cropStart.frames(m_fps) * m_speed), m_fps);
+    m_speedIndependantInfo.cropDuration = GenTime((int)(m_info.cropDuration.frames(m_fps) * m_speed), m_fps);
+
     m_videoPix = KIcon("kdenlive-show-video").pixmap(QSize(16, 16));
     m_audioPix = KIcon("kdenlive-show-audio").pixmap(QSize(16, 16));
 
-    if (m_speed == 1.0) m_clipName = clip->name();
+    if (m_speed == 1.0) m_clipName = m_clip->name();
     else {
-        m_clipName = clip->name() + " - " + QString::number(m_speed * 100, 'f', 0) + '%';
+        m_clipName = m_clip->name() + " - " + QString::number(m_speed * 100, 'f', 0) + '%';
     }
-    m_producer = clip->getId();
-    m_clipType = clip->clipType();
+    m_producer = m_clip->getId();
+    m_clipType = m_clip->clipType();
     //m_cropStart = info.cropStart;
-    m_maxDuration = clip->maxDuration();
+    m_maxDuration = m_clip->maxDuration();
     setAcceptDrops(true);
-    m_audioThumbReady = clip->audioThumbCreated();
+    m_audioThumbReady = m_clip->audioThumbCreated();
     //setAcceptsHoverEvents(true);
     connect(this , SIGNAL(prepareAudioThumb(double, int, int, int)) , this, SLOT(slotPrepareAudioThumb(double, int, int, int)));
 
@@ -83,31 +89,26 @@ ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, double fps, double speed, i
         m_endThumbTimer.setSingleShot(true);
         connect(&m_endThumbTimer, SIGNAL(timeout()), this, SLOT(slotGetEndThumb()));
 
-        connect(this, SIGNAL(getThumb(int, int)), clip->thumbProducer(), SLOT(extractImage(int, int)));
-        //connect(this, SIGNAL(getThumb(int, int)), clip->thumbProducer(), SLOT(getVideoThumbs(int, int)));
+        connect(this, SIGNAL(getThumb(int, int)), m_clip->thumbProducer(), SLOT(extractImage(int, int)));
 
-        connect(clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap)));
-        connect(clip, SIGNAL(gotAudioData()), this, SLOT(slotGotAudioData()));
+        connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QImage)), this, SLOT(slotThumbReady(int, QImage)));
+        connect(m_clip, SIGNAL(gotAudioData()), this, SLOT(slotGotAudioData()));
         if (generateThumbs) QTimer::singleShot(200, this, SLOT(slotFetchThumbs()));
 
-        /*if (m_clip->producer()) {
-            videoThumbProducer.init(this, m_clip->producer(), KdenliveSettings::trackheight() * KdenliveSettings::project_display_ratio(), KdenliveSettings::trackheight());
-            slotFetchThumbs();
-        }*/
     } else if (m_clipType == COLOR) {
-        QString colour = clip->getProperty("colour");
+        QString colour = m_clip->getProperty("colour");
         colour = colour.replace(0, 2, "#");
         m_baseColor = QColor(colour.left(7));
     } else if (m_clipType == IMAGE || m_clipType == TEXT) {
         m_baseColor = QColor(141, 166, 215);
         if (m_clipType == TEXT) {
-            connect(this, SIGNAL(getThumb(int, int)), clip->thumbProducer(), SLOT(extractImage(int, int)));
-            connect(clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap)));
+            connect(this, SIGNAL(getThumb(int, int)), m_clip->thumbProducer(), SLOT(extractImage(int, int)));
+            connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QImage)), this, SLOT(slotThumbReady(int, QImage)));
         }
         //m_startPix = KThumb::getImage(KUrl(clip->getProperty("resource")), (int)(KdenliveSettings::trackheight() * KdenliveSettings::project_display_ratio()), KdenliveSettings::trackheight());
     } else if (m_clipType == AUDIO) {
         m_baseColor = QColor(141, 215, 166);
-        connect(clip, SIGNAL(gotAudioData()), this, SLOT(slotGotAudioData()));
+        connect(m_clip, SIGNAL(gotAudioData()), this, SLOT(slotGotAudioData()));
     }
 }
 
@@ -115,8 +116,9 @@ ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, double fps, double speed, i
 ClipItem::~ClipItem()
 {
     blockSignals(true);
+    if (scene()) scene()->removeItem(this);
     if (m_clipType == VIDEO || m_clipType == AV || m_clipType == SLIDESHOW || m_clipType == PLAYLIST) {
-        disconnect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap)));
+        disconnect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QImage)), this, SLOT(slotThumbReady(int, QImage)));
         disconnect(m_clip, SIGNAL(gotAudioData()), this, SLOT(slotGotAudioData()));
     }
     delete m_timeLine;
@@ -126,7 +128,7 @@ ClipItem *ClipItem::clone(ItemInfo info) const
 {
     ClipItem *duplicate = new ClipItem(m_clip, info, m_fps, m_speed, m_strobe);
     if (m_clipType == IMAGE || m_clipType == TEXT) duplicate->slotSetStartThumb(m_startPix);
-    else {
+    else if (m_clipType != COLOR) {
         if (info.cropStart == m_info.cropStart) duplicate->slotSetStartThumb(m_startPix);
         if (info.cropStart + (info.endPos - info.startPos) == m_info.cropStart + (m_info.endPos - m_info.startPos)) duplicate->slotSetEndThumb(m_endPix);
     }
@@ -155,13 +157,18 @@ int ClipItem::selectedEffectIndex() const
     return m_selectedEffect;
 }
 
-void ClipItem::initEffect(QDomElement effect)
+void ClipItem::initEffect(QDomElement effect, int diff)
 {
     // the kdenlive_ix int is used to identify an effect in mlt's playlist, should
     // not be changed
     if (effect.attribute("kdenlive_ix").toInt() == 0)
         effect.setAttribute("kdenlive_ix", QString::number(effectsCounter()));
-    // init keyframes if required
+
+    if (effect.attribute("id") == "freeze" && diff > 0) {
+        EffectsList::setParameter(effect, "frame", QString::number(diff));
+    }
+
+    // Init parameter value & keyframes if required
     QDomNodeList params = effect.elementsByTagName("parameter");
     for (int i = 0; i < params.count(); i++) {
         QDomElement e = params.item(i).toElement();
@@ -452,6 +459,7 @@ void ClipItem::refreshClip(bool checkDuration)
 
 void ClipItem::slotFetchThumbs()
 {
+    if (scene() == NULL || m_clipType == AUDIO || m_clipType == COLOR) return;
     if (m_clipType == IMAGE) {
         if (m_startPix.isNull()) {
             m_startPix = KThumb::getImage(KUrl(m_clip->getProperty("resource")), (int)(KdenliveSettings::trackheight() * KdenliveSettings::project_display_ratio()), KdenliveSettings::trackheight());
@@ -468,7 +476,7 @@ void ClipItem::slotFetchThumbs()
     if (m_endPix.isNull() && m_startPix.isNull()) {
         m_startThumbRequested = true;
         m_endThumbRequested = true;
-        emit getThumb((int)cropStart().frames(m_fps), (int)(cropStart() + cropDuration()).frames(m_fps) - 1);
+        emit getThumb((int)m_speedIndependantInfo.cropStart.frames(m_fps), (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1);
     } else {
         if (m_endPix.isNull()) {
             slotGetEndThumb();
@@ -477,35 +485,18 @@ void ClipItem::slotFetchThumbs()
             slotGetStartThumb();
         }
     }
-    /*
-        if (m_hasThumbs) {
-            if (m_endPix.isNull() && m_startPix.isNull()) {
-                int frame1 = (int)m_cropStart.frames(m_fps);
-                int frame2 = (int)(m_cropStart + m_cropDuration).frames(m_fps) - 1;
-                //videoThumbProducer.setThumbFrames(m_clip->producer(), frame1, frame2);
-                //videoThumbProducer.start(QThread::LowestPriority);
-            } else {
-                if (m_endPix.isNull()) slotGetEndThumb();
-                else slotGetStartThumb();
-            }
-
-        } else if (m_startPix.isNull()) slotGetStartThumb();*/
 }
 
 void ClipItem::slotGetStartThumb()
 {
     m_startThumbRequested = true;
-    emit getThumb((int)cropStart().frames(m_fps), -1);
-    //videoThumbProducer.setThumbFrames(m_clip->producer(), (int)m_cropStart.frames(m_fps),  - 1);
-    //videoThumbProducer.start(QThread::LowestPriority);
+    emit getThumb((int)m_speedIndependantInfo.cropStart.frames(m_fps), -1);
 }
 
 void ClipItem::slotGetEndThumb()
 {
     m_endThumbRequested = true;
-    emit getThumb(-1, (int)(cropStart() + cropDuration()).frames(m_fps) - 1);
-    //videoThumbProducer.setThumbFrames(m_clip->producer(), -1, (int)(m_cropStart + m_cropDuration).frames(m_fps) - 1);
-    //videoThumbProducer.start(QThread::LowestPriority);
+    emit getThumb(-1, (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1);
 }
 
 
@@ -531,19 +522,23 @@ void ClipItem::slotSetEndThumb(QImage img)
     }
 }
 
-void ClipItem::slotThumbReady(int frame, QPixmap pix)
+void ClipItem::slotThumbReady(int frame, QImage img)
 {
     if (scene() == NULL) return;
     QRectF r = boundingRect();
+    QPixmap pix = QPixmap::fromImage(img);
     double width = pix.width() / projectScene()->scale().x();
-    if (m_startThumbRequested && frame == cropStart().frames(m_fps)) {
+    if (m_startThumbRequested && frame == m_speedIndependantInfo.cropStart.frames(m_fps)) {
         m_startPix = pix;
         m_startThumbRequested = false;
         update(r.left(), r.top(), width, pix.height());
-    } else if (m_endThumbRequested && frame == (cropStart() + cropDuration()).frames(m_fps) - 1) {
+        if (m_clipType == IMAGE || m_clipType == TEXT) {
+            update(r.right() - width, r.top(), width, pix.height());
+        }
+    } else if (m_endThumbRequested && frame == (m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1) {
         m_endPix = pix;
         m_endThumbRequested = false;
-        update(r.right() - width, r.y(), width, pix.height());
+        update(r.right() - width, r.top(), width, pix.height());
     }
 }
 
@@ -629,7 +624,7 @@ void ClipItem::flashClip()
     //m_timeLine->start();
 }
 
-void ClipItem::animate(qreal value)
+void ClipItem::animate(qreal /*value*/)
 {
     QRectF r = boundingRect();
     r.setHeight(20);
@@ -769,7 +764,7 @@ void ClipItem::paint(QPainter *painter,
     QPen pen = painter->pen();
     pen.setColor(QColor(255, 255, 255, 200));
     pen.setStyle(Qt::DotLine);
-    painter->setPen(pen);
+
     for (; it != markers.end(); ++it) {
         pos = GenTime((int)((*it).time().frames(m_fps) / m_speed + 0.5), m_fps) - cropStart();
         if (pos > GenTime()) {
@@ -778,6 +773,7 @@ void ClipItem::paint(QPainter *painter,
             QLineF l2 = painter->matrix().map(l);
             //framepos = scale * pos.frames(m_fps);
             //QLineF l(framepos, 5, framepos, itemHeight - 5);
+            painter->setPen(pen);
             painter->drawLine(l2);
             if (KdenliveSettings::showmarkers()) {
                 framepos = rect().x() + pos.frames(m_fps);
@@ -1065,32 +1061,42 @@ void ClipItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
 }
 */
 
-void ClipItem::resizeStart(int posx, double /*speed*/)
+void ClipItem::resizeStart(int posx)
 {
     const int min = (startPos() - cropStart()).frames(m_fps);
     if (posx < min) posx = min;
     if (posx == startPos().frames(m_fps)) return;
     const int previous = cropStart().frames(m_fps);
-    AbstractClipItem::resizeStart(posx, m_speed);
+    AbstractClipItem::resizeStart(posx);
+
+    // set speed independant info
+    m_speedIndependantInfo = m_info;
+    m_speedIndependantInfo.cropStart = GenTime((int)(m_info.cropStart.frames(m_fps) * m_speed), m_fps);
+    m_speedIndependantInfo.cropDuration = GenTime((int)(m_info.cropDuration.frames(m_fps) * m_speed), m_fps);
+
     if ((int) cropStart().frames(m_fps) != previous) {
         if (m_hasThumbs && KdenliveSettings::videothumbnails()) {
-            /*connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap)));*/
             m_startThumbTimer.start(150);
         }
     }
 }
 
-void ClipItem::resizeEnd(int posx, double /*speed*/)
+void ClipItem::resizeEnd(int posx)
 {
     const int max = (startPos() - cropStart() + maxDuration()).frames(m_fps);
     if (posx > max && maxDuration() != GenTime()) posx = max;
     if (posx == endPos().frames(m_fps)) return;
     //kDebug() << "// NEW POS: " << posx << ", OLD END: " << endPos().frames(m_fps);
     const int previous = cropDuration().frames(m_fps);
-    AbstractClipItem::resizeEnd(posx, m_speed);
+    AbstractClipItem::resizeEnd(posx);
+
+    // set speed independant info
+    m_speedIndependantInfo = m_info;
+    m_speedIndependantInfo.cropStart = GenTime((int)(m_info.cropStart.frames(m_fps) * m_speed), m_fps);
+    m_speedIndependantInfo.cropDuration = GenTime((int)(m_info.cropDuration.frames(m_fps) * m_speed), m_fps);
+
     if ((int) cropDuration().frames(m_fps) != previous) {
         if (m_hasThumbs && KdenliveSettings::videothumbnails()) {
-            /*connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap)));*/
             m_endThumbTimer.start(150);
         }
     }
@@ -1159,7 +1165,9 @@ QVariant ClipItem::itemChange(GraphicsItemChange change, const QVariant &value)
         // Only one clip is moving
         QRectF sceneShape = rect();
         sceneShape.translate(newPos);
-        QList<QGraphicsItem*> items = scene()->items(sceneShape, Qt::IntersectsItemShape);
+        QList<QGraphicsItem*> items;
+        if (projectScene()->editMode() == NORMALEDIT)
+            items = scene()->items(sceneShape, Qt::IntersectsItemShape);
         items.removeAll(this);
         bool forwardMove = newPos.x() > pos().x();
         int offset = 0;
@@ -1247,7 +1255,7 @@ QDomElement ClipItem::getEffectAt(int ix) const
 
 void ClipItem::setEffectAt(int ix, QDomElement effect)
 {
-    if (ix < 0 || ix > (m_effectList.count() - 1)) {
+    if (ix < 0 || ix > (m_effectList.count() - 1) || effect.isNull()) {
         kDebug() << "Invalid effect index: " << ix;
         return;
     }
@@ -1265,7 +1273,7 @@ void ClipItem::setEffectAt(int ix, QDomElement effect)
     }
 }
 
-EffectsParameterList ClipItem::addEffect(const QDomElement effect, bool animate)
+EffectsParameterList ClipItem::addEffect(const QDomElement effect, bool /*animate*/)
 {
     bool needRepaint = false;
     int ix;
@@ -1484,6 +1492,8 @@ void ClipItem::setSpeed(const double speed, const int strobe)
     m_strobe = strobe;
     if (m_speed == 1.0) m_clipName = baseClip()->name();
     else m_clipName = baseClip()->name() + " - " + QString::number(speed * 100, 'f', 0) + '%';
+    m_info.cropStart = GenTime((int)(m_speedIndependantInfo.cropStart.frames(m_fps) / m_speed + 0.5), m_fps);
+    m_info.cropDuration = GenTime((int)(m_speedIndependantInfo.cropDuration.frames(m_fps) / m_speed + 0.5), m_fps);
     //update();
 }
 
@@ -1492,19 +1502,20 @@ GenTime ClipItem::maxDuration() const
     return GenTime((int)(m_maxDuration.frames(m_fps) / m_speed + 0.5), m_fps);
 }
 
-GenTime ClipItem::cropStart() const
+GenTime ClipItem::speedIndependantCropStart() const
 {
-    return GenTime((int)(m_info.originalcropStart.frames(m_fps) / m_speed + 0.5), m_fps);
+    return m_speedIndependantInfo.cropStart;
 }
 
-GenTime ClipItem::cropDuration() const
+GenTime ClipItem::speedIndependantCropDuration() const
 {
-    return GenTime((int)(m_info.cropDuration.frames(m_fps) / m_speed + 0.5), m_fps);
+    return m_speedIndependantInfo.cropDuration;
 }
 
-GenTime ClipItem::endPos() const
+
+const ItemInfo ClipItem::speedIndependantInfo() const
 {
-    return m_info.startPos + cropDuration();
+    return m_speedIndependantInfo;
 }
 
 //virtual
@@ -1551,7 +1562,14 @@ void ClipItem::setAudioOnly(bool force)
 {
     m_audioOnly = force;
     if (m_audioOnly) m_baseColor = QColor(141, 215, 166);
-    else m_baseColor = QColor(141, 166, 215);
+    else {
+        if (m_clipType == COLOR) {
+            QString colour = m_clip->getProperty("colour");
+            colour = colour.replace(0, 2, "#");
+            m_baseColor = QColor(colour.left(7));
+        } else if (m_clipType == AUDIO) m_baseColor = QColor(141, 215, 166);
+        else m_baseColor = QColor(141, 166, 215);
+    }
     m_audioThumbCachePic.clear();
 }