]> git.sesse.net Git - kdenlive/blobdiff - src/clipitem.cpp
Fix several problems with clip crop start, fix undo transition deletion, set monitor...
[kdenlive] / src / clipitem.cpp
index 1792e636f0d60ffcc06f076d3b123a03e261e50c..ef46cbaebe92f8c1b9f071abecd134bdf9645d44 100644 (file)
@@ -39,7 +39,7 @@
 #include "kdenlivesettings.h"
 #include "kthumb.h"
 
-ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, GenTime cropStart, double scale, double fps)
+ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, double scale, double fps)
         : AbstractClipItem(info, QRectF(), fps), m_clip(clip), m_resizeMode(NONE), m_grabPoint(0), m_maxTrack(0), m_hasThumbs(false), startThumbTimer(NULL), endThumbTimer(NULL), m_effectsCounter(1), audioThumbWasDrawn(false), m_opacity(1.0), m_timeLine(0), m_thumbsRequested(0), m_startFade(0), m_endFade(0), m_hover(false), m_selectedEffect(-1) {
     QRectF rect((double) info.startPos.frames(fps) * scale, (double)(info.track * KdenliveSettings::trackheight() + 1), (double)(info.endPos - info.startPos).frames(fps) * scale, (double)(KdenliveSettings::trackheight() - 1));
     setRect(rect);
@@ -47,14 +47,11 @@ ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, GenTime cropStart, double s
     m_clipName = clip->name();
     m_producer = clip->getId();
     m_clipType = clip->clipType();
-    m_cropStart = cropStart;
+    m_cropStart = info.cropStart;
     m_maxDuration = clip->maxDuration();
     setAcceptDrops(true);
     audioThumbReady = clip->audioThumbCreated();
-    /*m_keyframes[0] = 50;
-    m_keyframes[30] = 20;
-    m_keyframes[70] = 90;
-    m_keyframes[100] = 10;*/
+
     /*
       m_cropStart = xml.attribute("in", 0).toInt();
       m_maxDuration = xml.attribute("duration", 0).toInt();
@@ -66,7 +63,7 @@ ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, GenTime cropStart, double s
 
     setFlags(QGraphicsItem::ItemClipsToShape | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
     setAcceptsHoverEvents(true);
-    connect(this , SIGNAL(prepareAudioThumb(double, QPainterPath, int, int)) , this, SLOT(slotPrepareAudioThumb(double, QPainterPath, int, int)));
+    connect(this , SIGNAL(prepareAudioThumb(double, QPainterPath, int, int, int)) , this, SLOT(slotPrepareAudioThumb(double, QPainterPath, int, int, int)));
 
     setBrush(QColor(141, 166, 215));
     if (m_clipType == VIDEO || m_clipType == AV || m_clipType == SLIDESHOW) {
@@ -100,31 +97,55 @@ ClipItem::~ClipItem() {
     if (endThumbTimer) delete endThumbTimer;
 }
 
+ClipItem *ClipItem::clone(double scale) const {
+    ClipItem *duplicate = new ClipItem(m_clip, info(), scale, m_fps);
+    duplicate->setEffectList(m_effectList);
+    return duplicate;
+}
+
+void ClipItem::setEffectList(const EffectsList effectList) {
+    //m_effectList = effectList.clone();
+}
+
 int ClipItem::selectedEffectIndex() const {
     return m_selectedEffect;
 }
 
-
-void ClipItem::setSelectedEffect(int ix) {
-    //if (ix == m_selectedEffect) return;
-    m_selectedEffect = ix;
-    QDomElement effect = effectAt(m_selectedEffect);
+void ClipItem::initEffect(QDomElement effect) {
+    // 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
     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") == "keyframe") {
-            m_keyframes.clear();
-            int max = e.attribute("max").toInt();
-            int min = e.attribute("min").toInt();
-            int def = e.attribute("default").toInt();
-            double factor = e.attribute("factor", "1").toDouble();
-
+            QString def = e.attribute("default");
             // Effect has a keyframe type parameter, we need to set the values
             if (e.attribute("keyframes").isEmpty()) {
-                // no keyframes defined, set up 2 keyframes (start and end) with default value.
-                m_keyframes[m_cropStart.frames(m_fps)] = 100 * def / (max - min);
-                m_keyframes[(m_cropStart + m_cropDuration).frames(m_fps)] = 100 * def / (max - min);
-            } else {
+                e.setAttribute("keyframes", QString::number(m_cropStart.frames(m_fps)) + ":" + def + ";" + QString::number((m_cropStart + m_cropDuration).frames(m_fps)) + ":" + def);
+                //kDebug() << "///// EFFECT KEYFRAMES INITED: " << e.attribute("keyframes");
+                break;
+            }
+        }
+    }
+}
+
+void ClipItem::setKeyframes(const int ix, const QString keyframes) {
+    QDomElement effect = effectAt(ix);
+    if (effect.attribute("disabled") == "1") return;
+    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") == "keyframe") {
+            e.setAttribute("keyframes", keyframes);
+            if (ix == m_selectedEffect) {
+                m_keyframes.clear();
+                double max = e.attribute("max").toDouble();
+                double min = e.attribute("min").toDouble();
+                m_keyframeFactor = 100.0 / (max - min);
+                m_keyframeDefault = e.attribute("default").toDouble();
                 // parse keyframes
                 QStringList keyframes = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
                 foreach(QString str, keyframes) {
@@ -132,30 +153,70 @@ void ClipItem::setSelectedEffect(int ix) {
                     double val = str.section(":", 1, 1).toDouble();
                     m_keyframes[pos] = val;
                 }
+                update();
+                return;
             }
-            update();
-            return;
+            break;
         }
     }
+}
+
+
+void ClipItem::setSelectedEffect(const int ix) {
+    m_selectedEffect = ix;
+    QDomElement effect = effectAt(m_selectedEffect);
+    QDomNodeList params = effect.elementsByTagName("parameter");
+    if (effect.attribute("disabled") != "1")
+        for (int i = 0; i < params.count(); i++) {
+            QDomElement e = params.item(i).toElement();
+            if (!e.isNull() && e.attribute("type") == "keyframe") {
+                m_keyframes.clear();
+                double max = e.attribute("max").toDouble();
+                double min = e.attribute("min").toDouble();
+                m_keyframeFactor = 100.0 / (max - min);
+                m_keyframeDefault = e.attribute("default").toDouble();
+                // parse keyframes
+                QStringList keyframes = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
+                foreach(QString str, keyframes) {
+                    int pos = str.section(":", 0, 0).toInt();
+                    double val = str.section(":", 1, 1).toDouble();
+                    m_keyframes[pos] = val;
+                }
+                update();
+                return;
+            }
+        }
     if (!m_keyframes.isEmpty()) {
         m_keyframes.clear();
         update();
     }
 }
 
+QString ClipItem::keyframes(const int index) {
+    QString result;
+    QDomElement effect = effectAt(index);
+    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") == "keyframe") {
+            result = e.attribute("keyframes");
+            break;
+        }
+    }
+    return result;
+}
+
 void ClipItem::updateKeyframeEffect() {
+    // regenerate xml parameter from the clip keyframes
     QDomElement effect = effectAt(m_selectedEffect);
+    if (effect.attribute("disabled") == "1") return;
     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") == "keyframe") {
-            int max = e.attribute("max").toInt();
-            int min = e.attribute("min").toInt();
-            int def = e.attribute("default").toInt();
-            double factor = e.attribute("factor", "1").toDouble();
             QString keyframes;
-
             if (m_keyframes.count() > 1) {
                 QMap<int, double>::const_iterator i = m_keyframes.constBegin();
                 double x1;
@@ -166,7 +227,7 @@ void ClipItem::updateKeyframeEffect() {
                 }
             }
             // Effect has a keyframe type parameter, we need to set the values
-            kDebug() << ":::::::::::::::   SETTING EFFECT KEYFRAMES: " << keyframes;
+            //kDebug() << ":::::::::::::::   SETTING EFFECT KEYFRAMES: " << keyframes;
             e.setAttribute("keyframes", keyframes);
             break;
         }
@@ -292,7 +353,7 @@ void ClipItem::paint(QPainter *painter,
 
     if (startpixel < 0)
         startpixel = 0;
-    int endpixel = (int)option->exposedRect.right() - rect().x();
+    int endpixel = (int)option->exposedRect.right();
     if (endpixel < 0)
         endpixel = 0;
 
@@ -324,15 +385,15 @@ void ClipItem::paint(QPainter *painter,
     }
 
     // draw audio thumbnails
-    if (KdenliveSettings::audiothumbnails() && ((m_clipType == AV && option->exposedRect.bottom() > br.height() / 2) || m_clipType == AUDIO) && audioThumbReady) {
+    if (KdenliveSettings::audiothumbnails() && ((m_clipType == AV && option->exposedRect.bottom() > (br.y() + br.height() / 2)) || m_clipType == AUDIO) && audioThumbReady) {
 
         QPainterPath path = m_clipType == AV ? roundRectPathLower : resultClipPath;
         if (m_clipType == AV) painter->fillPath(path, QBrush(QColor(200, 200, 200, 140)));
 
-        int channels = 2;
+        int channels = baseClip()->getProperty("channels").toInt();
         if (scale != framePixelWidth)
             audioThumbCachePic.clear();
-        emit prepareAudioThumb(scale, path, startpixel, endpixel + 200);//200 more for less missing parts before repaint after scrolling
+        emit prepareAudioThumb(scale, path, startpixel, endpixel + 200, channels);//200 more for less missing parts before repaint after scrolling
         int cropLeft = (int)((m_cropStart).frames(m_fps) * scale);
         for (int startCache = startpixel - startpixel % 100; startCache < endpixel + 300;startCache += 100) {
             if (audioThumbCachePic.contains(startCache) && !audioThumbCachePic[startCache].isNull())
@@ -542,11 +603,26 @@ QList <GenTime> ClipItem::snapMarkers() const {
     return snaps;
 }
 
-void ClipItem::slotPrepareAudioThumb(double pixelForOneFrame, QPainterPath path, int startpixel, int endpixel) {
-    int channels = 2;
+QList <CommentedTime> ClipItem::commentedSnapMarkers() const {
+    QList < CommentedTime > snaps;
+    QList < CommentedTime > markers = baseClip()->commentedSnapMarkers();
+    GenTime pos;
+    double framepos;
 
-    QRectF re = path.boundingRect();
+    for (int i = 0; i < markers.size(); i++) {
+        pos = markers.at(i).time() - cropStart();
+        if (pos > GenTime()) {
+            if (pos > duration()) break;
+            else snaps.append(CommentedTime(pos + startPos(), markers.at(i).comment()));
+        }
+    }
+    return snaps;
+}
+
+void ClipItem::slotPrepareAudioThumb(double pixelForOneFrame, QPainterPath path, int startpixel, int endpixel, int channels) {
 
+    QRectF re = path.boundingRect();
+    //kDebug() << "// PREP AUDIO THMB FRMO : " << startpixel << ", to: " << endpixel;
     //if ( (!audioThumbWasDrawn || framePixelWidth!=pixelForOneFrame ) && !baseClip()->audioFrameChache.isEmpty()){
 
     for (int startCache = startpixel - startpixel % 100;startCache + 100 < endpixel ;startCache += 100) {
@@ -727,7 +803,7 @@ void ClipItem::checkEffectsKeyframesPos(const int previous, const int current, b
             }
         }
     }
-    setSelectedEffect(m_selectedEffect);
+    if (m_selectedEffect >= 0) setSelectedEffect(m_selectedEffect);
 }
 
 
@@ -784,7 +860,17 @@ QMap <QString, QString> ClipItem::addEffect(QDomElement effect, bool animate) {
     for (int i = 0; i < params.count(); i++) {
         QDomElement e = params.item(i).toElement();
         if (!e.isNull()) {
-                       double f = e.attribute("factor", "1").toDouble();
+            if (e.attribute("type") == "keyframe") {
+                effectParams["keyframes"] = e.attribute("keyframes");
+                effectParams["min"] = e.attribute("min");
+                effectParams["max"] = e.attribute("max");
+                effectParams["factor"] = e.attribute("factor", "1");
+                effectParams["starttag"] = e.attribute("starttag", "start");
+                effectParams["endtag"] = e.attribute("endtag", "end");
+            }
+
+            double f = e.attribute("factor", "1").toDouble();
+
             if (f == 1) {
                 effectParams[e.attribute("name")] = e.attribute("value");
                 // check if it is a fade effect
@@ -813,6 +899,10 @@ QMap <QString, QString> ClipItem::addEffect(QDomElement effect, bool animate) {
         r.setHeight(20);
         update(r);
     }
+    if (m_selectedEffect == -1) {
+        m_selectedEffect = 0;
+        setSelectedEffect(m_selectedEffect);
+    }
     return effectParams;
 }