[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdenlive] src/timeline: Prepare smooth/hard timeline keyframes
From:       Vincent Pinon <vpinon () kde ! org>
Date:       2016-02-01 0:35:05
Message-ID: E1aQ2SP-0000iK-Fk () scm ! kde ! org
[Download RAW message or body]

Git commit 17aa8a85f97b1d41050c004ba927d5b89250e081 by Vincent Pinon.
Committed on 01/02/2016 at 00:34.
Pushed by vpinon into branch 'master'.

Prepare smooth/hard timeline keyframes

M  +90   -105  src/timeline/abstractclipitem.cpp
M  +13   -10   src/timeline/abstractclipitem.h
M  +64   -37   src/timeline/clipitem.cpp
M  +1    -0    src/timeline/clipitem.h
M  +25   -23   src/timeline/customtrackview.cpp
M  +2    -2    src/timeline/customtrackview.h

http://commits.kde.org/kdenlive/17aa8a85f97b1d41050c004ba927d5b89250e081

diff --git a/src/timeline/abstractclipitem.cpp b/src/timeline/abstractclipitem.cpp
index 2d09b9b..d02e4d6 100644
--- a/src/timeline/abstractclipitem.cpp
+++ b/src/timeline/abstractclipitem.cpp
@@ -41,9 +41,10 @@ AbstractClipItem::AbstractClipItem(const ItemInfo &info, const \
QRectF& rect, dou  , m_editedKeyframe(-1)
         , m_selectedKeyframe(0)
         , m_keyframeType(KEYFRAMETYPE::NoKeyframe)
-        , m_keyframeFactor(1)
-        , m_keyframeOffset(0)
         , m_keyframeDefault(0)
+        , m_keyframeMin(0)
+        , m_keyframeMax(1)
+        , m_keyframeFactor(1)
         , m_visibleParam(0)
         , m_fps(fps)
         , m_isMainSelectedClip(false)
@@ -161,7 +162,6 @@ void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, \
bool /*emitChang  moveBy(durationDiff.frames(m_fps), 0);
 
     if (m_info.startPos != GenTime(posx, m_fps)) {
-        ////qDebug() << "//////  WARNING, DIFF IN XPOS: " << pos().x() << " == " << \
m_info.startPos.frames(m_fps);  GenTime diff = m_info.startPos - GenTime(posx, \
m_fps);  
         if (type() == AVWidget)
@@ -169,32 +169,11 @@ void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, \
bool /*emitChang  
         m_info.cropDuration -= diff;
         setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height());
-        ////qDebug()<<"// NEW START: "<<m_startPos.frames(25)<<", NW DUR: \
"<<m_cropDuration.frames(25);  }
 
     // set crop from start to 0 (isn't relevant as this only happens for color \
clips, images)  if (negCropStart)
         m_info.cropStart = GenTime();
-
-    ////qDebug() << "-- NEW CLIP=" << startPos().frames(25) << '-' << \
                endPos().frames(25);
-    //setRect((double) m_startPos.frames(m_fps) * scale, rect().y(), (double) \
                m_cropDuration.frames(m_fps) * scale, rect().height());
-
-    /*    if (durationDiff < GenTime()) {
-            QList <QGraphicsItem *> collisionList = \
                collidingItems(Qt::IntersectsItemBoundingRect);
-            for (int i = 0; i < collisionList.size(); ++i) {
-                QGraphicsItem *item = collisionList.at(i);
-                if (item->type() == type() && item->pos().x() < pos().x()) {
-                    //qDebug() << "/////////  COLLISION DETECTED!!!!!!!!!";
-                    GenTime diff = ((AbstractClipItem *)item)->endPos() + GenTime(1, \
                m_fps) - m_startPos;
-                    setRect(0, 0, (m_cropDuration - diff).frames(m_fps) - 0.02, \
                rect().height());
-                    setPos((m_startPos + diff).frames(m_fps), pos().y());
-                    m_startPos += diff;
-                    if (type() == AVWidget) m_cropStart += diff;
-                    m_cropDuration = m_cropDuration - diff;
-                    break;
-                }
-            }
-        }*/
 }
 
 void AbstractClipItem::resizeEnd(int posx, bool /*emitChange*/)
@@ -216,9 +195,6 @@ void AbstractClipItem::resizeEnd(int posx, bool /*emitChange*/)
             if (!collisionList.at(i)->isEnabled()) continue;
             QGraphicsItem *item = collisionList.at(i);
             if (item->type() == type() && item->pos().x() > pos().x()) {
-                ////qDebug() << "/////////  COLLISION DETECTED!!!!!!!!!";
-                ////qDebug() << "/////////  CURRENT: " << startPos().frames(25) << \
                'x' << endPos().frames(25) << ", RECT: " << rect() << '-' << pos();
-                ////qDebug() << "/////////  COLLISION: " << ((AbstractClipItem \
*)item)->startPos().frames(25) << 'x' << ((AbstractClipItem \
*)item)->endPos().frames(25) << ", RECT: " << ((AbstractClipItem *)item)->rect() << \
                '-' << item->pos();
                 GenTime diff = static_cast<AbstractClipItem*>(item)->startPos() - \
startPos();  if (fixItem == false || diff < m_info.cropDuration) {
                     fixItem = true;
@@ -252,29 +228,40 @@ GenTime AbstractClipItem::maxDuration() const
     return m_maxDuration;
 }
 
+double AbstractClipItem::keyframeUnmap(double y) {
+    QRectF br = rect();
+    return ((br.bottom() - y) / br.height() * (m_keyframeMax - m_keyframeMin) + \
m_keyframeMin) / m_keyframeFactor; +}
+
+QPointF AbstractClipItem::keyframeMap(int frame, double value) {
+    QRectF br = rect();
+    return QPointF(br.x() + br.width() * (frame - cropStart().frames(m_fps)) / \
cropDuration().frames(m_fps), +                   br.bottom() - br.height() * (value \
* m_keyframeFactor - m_keyframeMin) / (m_keyframeMax - m_keyframeMin)); +}
+
+QPointF AbstractClipItem::keyframePoint(int index) {
+    int frame = m_keyAnim.key_get_frame(index);
+    return keyframeMap(frame, m_keyProperties.anim_get_double("keyframes", frame));
+}
+
 void AbstractClipItem::drawKeyFrames(QPainter *painter, const QTransform \
&transformation)  {
-    Mlt::Animation* anim = m_animation.get_anim("keyframes");
-    if (anim->key_count() < 1)
+    if (m_keyAnim.key_count() < 1)
         return;
-    QRectF br = rect();
-    double maxw = br.width() / cropDuration().frames(m_fps);
-    double maxh = br.height() / 100.0 * m_keyframeFactor;
-    double start = cropStart().frames(m_fps);
-    double x1, y1, x2, y2;
     bool antialiasing = painter->renderHints() & QPainter::Antialiasing;
     bool active = isSelected() || (parentItem() && parentItem()->isSelected());
+    QRectF br = rect();
 
     // draw keyframes
     // Special case: Geometry keyframes are just vertical lines
     if (m_keyframeType == GeometryKeyframe) {
-        for(int i = 0; i < anim->key_count(); ++i) {
-            int key = anim->key_get_frame(i);
+        for(int i = 0; i < m_keyAnim.key_count(); ++i) {
+            int key = m_keyAnim.key_get_frame(i);
             QColor color = (key == m_editedKeyframe) ? QColor(Qt::red) : \
QColor(Qt::blue);  if (active)
                 painter->setPen(color);
-            x1 = br.x() + maxw * (key - start);
-            QLineF line = transformation.map(QLineF(x1, br.top(), x1, br.height()));
+            double x = keyframePoint(i).x();
+            QLineF line = transformation.map(QLineF(x, br.top(), x, br.height()));
             painter->drawLine(line);
             if (active) {
                 const QRectF frame(line.x1() - 3, line.y1() + (line.y2() - \
line.y1()) / 2 - 3, 6, 6); @@ -287,10 +274,8 @@ void \
AbstractClipItem::drawKeyFrames(QPainter *painter, const QTransform &transf  
     // draw line showing default value
     if (active) {
-        x1 = br.x();
-        x2 = br.right();
-        y1 = br.bottom() - (m_keyframeDefault - m_keyframeOffset) * maxh;
-        QLineF line = transformation.map(QLineF(x1, y1, x2, y1));
+        double y = keyframeUnmap(m_keyframeDefault);
+        QLineF line = transformation.map(QLineF(br.x(), y, br.right(), y));
         painter->setPen(QColor(168, 168, 168, 180));
         painter->drawLine(line);
         painter->setPen(QColor(108, 108, 108, 180));
@@ -299,53 +284,57 @@ void AbstractClipItem::drawKeyFrames(QPainter *painter, const \
QTransform &transf  painter->setRenderHint(QPainter::Antialiasing);
     }
 
-    int key = anim->key_get_frame(0);
-    x1 = br.x() + maxw * (key - start);
-    y1 = br.bottom() - (m_animation.anim_get_double("keyframes", key) - \
                m_keyframeOffset) * maxh;
-    // make sure line starts at clip start
-    if (x1 != br.x())
-        painter->drawLine(transformation.map(QLineF(br.x(), y1, x1, y1)));
-    
-    for(int i = 1; i < anim->key_count(); ++i) {
-        key = anim->key_get_frame(i);
-        x2 = br.x() + maxw * (key - start);
-        y2 = br.bottom() - (m_animation.anim_get_double("keyframes", key) - \
                m_keyframeOffset) * maxh;
-        QLineF line = transformation.map(QLineF(x1, y1, x2, y2));
-        painter->drawLine(line);
+    QPointF start = keyframePoint(0);
+    QPainterPath path;
+    path.moveTo(br.x(), start.y());
+    path.lineTo(start);
+    for(int i = 0; i < m_keyAnim.key_count(); ++i) {
         if (active)
-            painter->fillRect(QRectF(line.x2() - 3, line.y2() - 3, 6, 6),
-                              (key == m_editedKeyframe) ? QColor(Qt::red) : \
                QColor(Qt::blue));
-        x1 = x2;
-        y1 = y2;
+            painter->fillRect(QRectF(transformation.map(start) - QPointF(3, 3), \
QSizeF(6, 6)), +                              (m_keyAnim.key_get_frame(i) == \
m_editedKeyframe) ? QColor(Qt::red) : QColor(Qt::blue)); +        if (i + 1 < \
m_keyAnim.key_count()) { +            QPointF end = keyframePoint(i + 1);
+            switch (m_keyAnim.key_get_type(i)) {
+                case mlt_keyframe_discrete:
+                    path.lineTo(end.x(), start.y());
+                    path.lineTo(end);
+                    break;
+                case mlt_keyframe_linear:
+                    path.lineTo(end);
+                    break;
+                case mlt_keyframe_smooth:
+                    QPointF pre = keyframePoint(qMax(i - 1, 0));
+                    QPointF post = keyframePoint(qMin(i + 2, \
m_keyAnim.key_count())); +                    QPointF c1 = (end - pre) / 6.0; // + \
start +                    QPointF c2 = (start - post) / 6.0; // + end
+                    double mid = (end.x() - start.x()) / 2;
+                    if (c1.x() >  mid) c1 = c1 * mid / c1.x(); // scale down tangent \
vector to not go beyond middle +                    if (c2.x() < -mid) c2 = c2 * -mid \
/ c2.x(); +                    path.cubicTo(start + c1, end + c2, end);
+                    break;
+            }
+            start = end;
+        } else {
+            path.lineTo(br.right(), start.y());
+        }
     }
-
-    // make sure line ends at clip end
-    if (x1 != br.right())
-        painter->drawLine(transformation.map(QLineF(x1, y1, br.right(), y1)));
-
+    painter->drawPath(transformation.map(path));
     painter->setRenderHint(QPainter::Antialiasing, antialiasing);
 }
 
 int AbstractClipItem::mouseOverKeyFrames(QPointF pos, double maxOffset)
 {
-    const QRectF br = sceneBoundingRect();
-    double maxw = br.width() / cropDuration().frames(m_fps);
-    double maxh = br.height() / 100.0 * m_keyframeFactor;
-    Mlt::Animation *anim = m_animation.get_anim("keyframes");
-    for(int i = 0; i < anim->key_count(); ++i) {
-        int key = anim->key_get_frame(i);
-        int value = m_animation.anim_get_double("keyframes", key);
-        double x1 = br.x() + maxw * (key - cropStart().frames(m_fps));
-        double y1;
+    for(int i = 0; i < m_keyAnim.key_count(); ++i) {
+        int key = m_keyAnim.key_get_frame(i);
+        int value = m_keyProperties.anim_get_double("keyframes", key);
+        QPointF p = keyframeMap(key, value);
         if (m_keyframeType == GeometryKeyframe)
-            y1 = br.bottom() - (br.height() /2);
-        else
-            y1 = br.bottom() - (value - m_keyframeOffset) * maxh;
-        if (qAbs(pos.x() - x1) < maxOffset && qAbs(pos.y() - y1) < maxOffset) {
+            p.setY(rect().bottom() - rect().height() / 2);
+        if ((pos - p).manhattanLength() < maxOffset) {
             setToolTip('[' + QString::number((GenTime(key, m_fps) - \
                cropStart()).seconds(), 'f', 2)
                        + i18n("seconds") + ", " + QString::number(value, 'f', 1) + \
']');  return key;
-        } else if (x1 > pos.x()) {
+        } else if (p.x() > pos.x() + maxOffset) {
             break;
         }
     }
@@ -357,12 +346,12 @@ void AbstractClipItem::updateSelectedKeyFrame()
 {
     if (m_editedKeyframe == -1)
         return;
-    QRectF br = sceneBoundingRect();
-    double maxw = br.width() / cropDuration().frames(m_fps);
-    double maxh = br.height() / 100.0 * m_keyframeFactor;
-    update(br.x() + maxw *(m_selectedKeyframe - cropStart().frames(m_fps)) - 3, \
br.bottom() - (m_animation.anim_get_double("keyframes", m_selectedKeyframe) - \
m_keyframeOffset) * maxh - 3, 12, 12); +    QPointF h(12, 12);
+    QPointF p = keyframeMap(m_selectedKeyframe, \
m_keyProperties.anim_get_double("keyframes", m_selectedKeyframe)); +    \
update(QRectF(p - h/2, p + h/2));  m_selectedKeyframe = m_editedKeyframe;
-    update(br.x() + maxw *(m_selectedKeyframe - cropStart().frames(m_fps)) - 3, \
br.bottom() - (m_animation.anim_get_double("keyframes", m_selectedKeyframe) - \
m_keyframeOffset) * maxh - 3, 12, 12); +    p = keyframeMap(m_selectedKeyframe, \
m_keyProperties.anim_get_double("keyframes", m_selectedKeyframe)); +    \
update(QRectF(p - h/2, p + h/2));  }
 
 int AbstractClipItem::editedKeyFramePos() const
@@ -372,7 +361,7 @@ int AbstractClipItem::editedKeyFramePos() const
 
 double AbstractClipItem::editedKeyFrameValue()
 {
-    return m_animation.anim_get_double("keyframes", m_editedKeyframe);
+    return m_keyProperties.anim_get_double("keyframes", m_editedKeyframe);
 }
 
 int AbstractClipItem::selectedKeyFramePos() const
@@ -380,56 +369,52 @@ int AbstractClipItem::selectedKeyFramePos() const
     return m_selectedKeyframe;
 }
 
-void AbstractClipItem::updateKeyFramePos(const GenTime &pos, const double value)
+void AbstractClipItem::updateKeyFramePos(int frame, const double y)
 {
-    Mlt::Animation *anim = m_animation.get_anim("keyframes");
-    if (!anim->is_key(m_editedKeyframe))
+    if (!m_keyProperties.get_anim("keyframes")->is_key(m_editedKeyframe))
         return;
-    int newpos = qBound(anim->previous_key(m_editedKeyframe - 1) + 1,
-                    (int)pos.frames(m_fps),
-                    anim->next_key(m_editedKeyframe + 1) - 1);
-    double newval = qBound(0.0, value, 100.0) / m_keyframeFactor + m_keyframeOffset;
+    int prev = m_keyAnim.previous_key(m_editedKeyframe - 1) + 1;
+    int next = m_keyAnim.next_key(m_editedKeyframe + 1) - 1;
+    if (next <= 0) next = m_editedKeyframe;
+    int newpos = qBound(prev, frame, next);
+    double newval = keyframeUnmap(y);
+    m_keyProperties.anim_set("keyframes", newval, newpos, 0, \
m_keyAnim.keyframe_type(m_editedKeyframe));  if (m_editedKeyframe != newpos)
-        m_animation.get_anim("keyframes")->remove(m_editedKeyframe);
-    m_animation.anim_set("keyframes", newval, newpos);
+        m_keyAnim.remove(m_editedKeyframe);
     m_editedKeyframe = newpos;
     update();
 }
 
 int AbstractClipItem::keyFrameNumber()
 {
-    return m_animation.get_anim("keyframes")->key_count();
+    return m_keyAnim.key_count();
 }
 
 int AbstractClipItem::checkForSingleKeyframe()
 {
     // Check if we have only one keyframe
-    Mlt::Animation *anim = m_animation.get_anim("keyframes");
     int start = cropStart().frames(m_fps);
-    if (anim->key_count() == 1 && anim->is_key(start)) {
-        double value = m_animation.anim_get_double("keyframes", start);
+    if (m_keyAnim.key_count() == 1 && m_keyAnim.is_key(start)) {
+        double value = m_keyProperties.anim_get_double("keyframes", start);
         // Add keyframe at end of clip to allow inserting a new keframe in between
-        m_animation.anim_set("keyframes", value, (cropStart() + \
cropDuration()).frames(m_fps) - 1); +        m_keyProperties.anim_set("keyframes", \
value, cropDuration().frames(m_fps));  return value;
     }
     return -1;
 }
 
-int AbstractClipItem::addKeyFrame(const GenTime &pos, const double value)
+int AbstractClipItem::addKeyFrame(const GenTime &pos, const double y)
 {
-    QRectF br = sceneBoundingRect();
-    double maxh = 100.0 / br.height() / m_keyframeFactor;
-    //TODO: apply transformation when drawing, not in stored data
-    double newval = (br.bottom() - value) * maxh + m_keyframeOffset;
+    double newval = keyframeUnmap(y);
     m_selectedKeyframe = pos.frames(m_fps);
-    m_animation.anim_set("keyframes", newval, m_selectedKeyframe);
+    m_keyProperties.anim_set("keyframes", newval, m_selectedKeyframe, 0, \
m_keyAnim.keyframe_type(m_selectedKeyframe));  update();
     return newval;
 }
 
 bool AbstractClipItem::hasKeyFrames()
 {
-    return m_animation.get_anim("keyframes")->key_count() > 0;
+    return m_keyAnim.key_count() > 0;
 }
 
 CustomTrackScene* AbstractClipItem::projectScene()
diff --git a/src/timeline/abstractclipitem.h b/src/timeline/abstractclipitem.h
index 8d86ced..76a9d04 100644
--- a/src/timeline/abstractclipitem.h
+++ b/src/timeline/abstractclipitem.h
@@ -25,6 +25,7 @@
 #include "gentime.h"
 
 #include "mlt++/MltProperties.h"
+#include "mlt++/MltAnimation.h"
 
 #include <QGraphicsRectItem>
 #include <QGraphicsWidget>
@@ -45,7 +46,8 @@ public:
         NoKeyframe = 0,
         SimpleKeyframe,
         NormalKeyframe,
-        GeometryKeyframe
+        GeometryKeyframe,
+        AnimatedKeyframe
     };
 
     AbstractClipItem(const ItemInfo &info, const QRectF& rect, double fps);
@@ -55,9 +57,9 @@ public:
     /** @brief Move the selected keyframe (does not influence the effect, only the \
                display in timeline).
     * @param pos new Position
     * @param value new Value */
-    void updateKeyFramePos(const GenTime &pos, const double value);
+    void updateKeyFramePos(int frame, const double y);
     int checkForSingleKeyframe();
-    int addKeyFrame(const GenTime &pos, const double value);
+    int addKeyFrame(const GenTime &pos, const double y);
     bool hasKeyFrames();
     int editedKeyFramePos() const;
     int selectedKeyFramePos() const;
@@ -113,14 +115,12 @@ protected:
         GenTime m_startPos;*/
     GenTime m_maxDuration;
     KEYFRAMETYPE m_keyframeType;
-    Mlt::Properties m_animation;
-    /** @brief Stretch factor so that keyframes display on the full clip height. */
-    double m_keyframeFactor;
-    /** @brief Offset factor so that keyframes minimum value are displaed at the \
                bottom of the clip. */
-    double m_keyframeOffset;
-    /** @brief Default reset value for keyframe. */
+    Mlt::Properties m_keyProperties;
+    Mlt::Animation m_keyAnim;
     double m_keyframeDefault;
-    /** The (keyframe) parameter that is visible and editable in timeline (on the \
clip) */ +    double m_keyframeMin;
+    double m_keyframeMax;
+    double m_keyframeFactor;
     int m_visibleParam;
     double m_fps;
     /** @brief True if this is the last clip the user selected */
@@ -128,6 +128,9 @@ protected:
     /** @brief Draw the keyframes of a clip
       * @param painter The painter device for the clip
       */
+    double keyframeUnmap(double y);
+    QPointF keyframeMap(int frame, double value);
+    QPointF keyframePoint(int index);
     void drawKeyFrames(QPainter *painter, const QTransform &transformation);
     int mouseOverKeyFrames(QPointF pos, double maxOffset);
     void mousePressEvent(QGraphicsSceneMouseEvent * event);
diff --git a/src/timeline/clipitem.cpp b/src/timeline/clipitem.cpp
index be0f7c0..2f7ccad 100644
--- a/src/timeline/clipitem.cpp
+++ b/src/timeline/clipitem.cpp
@@ -62,7 +62,6 @@ ClipItem::ClipItem(ProjectClip *clip, const ItemInfo& info, double \
fps, double s  setZValue(2);
     m_effectList = EffectsList(true);
     FRAME_SIZE = frame_width;
-    //qDebug()<<" + + +LOADING CLP on TK: "<<info.track<<" / THEIGHT; \
                "<<KdenliveSettings::trackheight();
     setRect(0, 0, (info.endPos - info.startPos).frames(m_fps) - 0.02, (double) \
itemHeight());  // set speed independent info
     if (m_speed <= 0 && m_speed > -1)
@@ -138,7 +137,6 @@ ClipItem *ClipItem::clone(const ItemInfo &info) const
             duplicate->slotSetEndThumb(m_endPix);
         }
     }
-    ////qDebug() << "// CLoning clip: " << (info.cropStart + (info.endPos - \
info.startPos)).frames(m_fps) << ", CURRENT end: " << (cropStart() + \
duration()).frames(m_fps);  duplicate->setEffectList(m_effectList);
     duplicate->setState(m_clipState);
     duplicate->setFades(fadeIn(), fadeOut());
@@ -288,24 +286,15 @@ void ClipItem::setKeyframes(const int ix, const QStringList \
&keyframes)  int keyframeParams = 0;
     for (int i = 0; i < params.count(); ++i) {
         QDomElement e = params.item(i).toElement();
-        if (!e.isNull() && (e.attribute(QStringLiteral("type")) == \
QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe")) && (!e.hasAttribute(QStringLiteral("intimeline")) || \
e.attribute(QStringLiteral("intimeline")) == QLatin1String("1"))) { +        if \
(e.isNull()) continue; +        if (!(QStringList() << "keyframe" << "simplekeyframe" \
<< "geometry" << "animated").contains(e.attribute("type"))) +            continue;
+        if (!e.hasAttribute(QStringLiteral("intimeline"))
+            || e.attribute(QStringLiteral("intimeline")) == QLatin1String("1")) {
             e.setAttribute(QStringLiteral("keyframes"), \
keyframes.at(keyframeParams));  if (ix + 1 == m_selectedEffect && keyframeParams == \
0) {  m_visibleParam = i;
-                double max = locale.toDouble(e.attribute(QStringLiteral("max")));
-                double min = locale.toDouble(e.attribute(QStringLiteral("min")));
-                m_keyframeFactor = 100.0 / (max - min);
-                m_keyframeOffset = min;
-                m_keyframeDefault = \
                locale.toDouble(e.attribute(QStringLiteral("default")));
-                m_selectedKeyframe = 0;
-                if (m_keyframeType == GeometryKeyframe) {
-                    m_animation.set("keyframes", \
                e.attribute("value").toUtf8().constData());
-                    m_animation.anim_get_rect("keyframes", 0);
-                } else {
-                    m_animation.set("keyframes", \
                e.attribute("keyframes").toUtf8().constData());
-                    m_animation.anim_get_double("keyframes", 0);
-                }
-                if (m_animation.get_anim("keyframes")->next_key(m_editedKeyframe) <= \
m_editedKeyframe) m_editedKeyframe = -1; +                parseKeyframes(locale, e);
                 update();
             }
             ++keyframeParams;
@@ -313,7 +302,6 @@ void ClipItem::setKeyframes(const int ix, const QStringList \
&keyframes)  }
 }
 
-
 void ClipItem::setSelectedEffect(const int ix)
 {
     m_selectedEffect = ix;
@@ -408,8 +396,12 @@ QStringList ClipItem::keyframes(const int index)
 
     for (int i = 0; i < params.count(); ++i) {
         QDomElement e = params.item(i).toElement();
-        if (!e.isNull() && (e.attribute(QStringLiteral("type")) == \
QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe"))) +        if (e.isNull()) continue;
+        if (   e.attribute(QStringLiteral("type")) == QLatin1String("keyframe")
+            || e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe"))  \
result.append(e.attribute(QStringLiteral("keyframes"))); +        else if \
(e.attribute(QStringLiteral("type")) == QLatin1String("animated")) +            \
result.append(e.attribute(QStringLiteral("value")));  }
     return result;
 }
@@ -1187,7 +1179,6 @@ void ClipItem::resizeEnd(int posx, bool emitChange)
     if (posx == endPos().frames(m_fps)) {
         return;
     }
-    ////qDebug() << "// NEW POS: " << posx << ", OLD END: " << \
endPos().frames(m_fps);  const int previous = cropDuration().frames(m_fps);
     AbstractClipItem::resizeEnd(posx);
 
@@ -1294,7 +1285,6 @@ QVariant ClipItem::itemChange(GraphicsItemChange change, const \
QVariant &value)  }
         m_info.track = newTrack;
         m_info.startPos = GenTime((int) newPos.x(), m_fps);
-        ////qDebug()<<"// ITEM NEW POS: "<<newPos.x()<<", mapped: \
"<<mapToScene(newPos.x(), 0).x();  return newPos;
     }
     if (change == ItemParentChange) {
@@ -1349,7 +1339,6 @@ QDomElement ClipItem::getEffectAtIndex(int ix) const
 
 void ClipItem::updateEffect(QDomElement effect)
 {
-    ////qDebug() << "CHange EFFECT AT: " << ix << ", CURR: " << \
m_effectList.at(ix).attribute("tag") << ", NEW: " << effect.attribute("tag");  \
                m_effectList.updateEffect(effect);
     m_effectNames = m_effectList.effectNames().join(QStringLiteral(" / "));
     QString id = effect.attribute(QStringLiteral("id"));
@@ -1370,7 +1359,6 @@ void ClipItem::enableEffects(QList <int> indexes, bool disable)
 bool ClipItem::moveEffect(QDomElement effect, int ix)
 {
     if (ix <= 0 || ix > (m_effectList.count()) || effect.isNull()) {
-        //qDebug() << "Invalid effect index: " << ix;
         return false;
     }
     m_effectList.removeAt(effect.attribute(QStringLiteral("kdenlive_ix")).toInt());
@@ -1735,7 +1723,9 @@ void ClipItem::insertKeyframe(QDomElement effect, int pos, int \
                val)
     QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter"));
     for (int i = 0; i < params.count(); ++i) {
         QDomElement e = params.item(i).toElement();
-        if (!e.isNull() && (e.attribute(QStringLiteral("type")) == \
QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe"))) { +        if (e.isNull()) continue;
+        if (   e.attribute(QStringLiteral("type")) == QLatin1String("keyframe")
+            || e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe")) {  QString kfr = \
                e.attribute(QStringLiteral("keyframes"));
             const QStringList keyframes = kfr.split(';', QString::SkipEmptyParts);
             QStringList newkfr;
@@ -1761,6 +1751,9 @@ void ClipItem::insertKeyframe(QDomElement effect, int pos, int \
                val)
                     newkfr.append(QString::number(pos) + '=' + \
e.attribute(QStringLiteral("default")));  }
             e.setAttribute(QStringLiteral("keyframes"), \
newkfr.join(QStringLiteral(";"))); +        } else if \
(e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { +            \
m_keyProperties.anim_set("keyframes", val, pos, 0, m_keyAnim.keyframe_type(pos)); +   \
e.setAttribute(QStringLiteral("value"), m_keyAnim.serialize_cut());  }
     }
 }
@@ -1809,6 +1802,10 @@ void ClipItem::movedKeyframe(QDomElement effect, int oldpos, \
int newpos, double  }
             }
             e.setAttribute(QStringLiteral("value"), \
newkfr.join(QStringLiteral(";"))); +        } else if \
(e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { +            if \
(oldpos != newpos) m_keyAnim.remove(oldpos); +            \
m_keyProperties.anim_set("keyframes", value, newpos, 0, \
m_keyAnim.keyframe_type(oldpos)); +            \
e.setAttribute(QStringLiteral("value"), m_keyAnim.serialize_cut());  }
     }
 
@@ -1837,26 +1834,36 @@ bool ClipItem::parseKeyframes(const QLocale locale, \
                QDomElement e)
     if (type == QLatin1String("keyframe")) m_keyframeType = NormalKeyframe;
     else if (type == QLatin1String("simplekeyframe")) m_keyframeType = \
                SimpleKeyframe;
     else if (type == QLatin1String("geometry")) m_keyframeType = GeometryKeyframe;
-    if (m_keyframeType != NoKeyframe && \
(!e.hasAttribute(QStringLiteral("intimeline")) || \
                e.attribute(QStringLiteral("intimeline")) == QLatin1String("1"))) {
-        double max = locale.toDouble(e.attribute(QStringLiteral("max")));
-        double min = locale.toDouble(e.attribute(QStringLiteral("min")));
-        m_keyframeFactor = 100.0 / (max - min);
-        m_keyframeOffset = min;
+    else if (type == QLatin1String("animated")) m_keyframeType = AnimatedKeyframe;
+    else return false;
+    if (m_keyframeType != NoKeyframe && \
(!e.hasAttribute(QStringLiteral("intimeline")) +        || \
e.attribute(QStringLiteral("intimeline")) == QLatin1String("1"))) { +        \
m_keyframeMin = locale.toDouble(e.attribute(QStringLiteral("min"))); +        \
                m_keyframeMax = locale.toDouble(e.attribute(QStringLiteral("max")));
         m_keyframeDefault = locale.toDouble(e.attribute(QStringLiteral("default")));
+        m_keyframeFactor = 1;
         m_selectedKeyframe = 0;
 
         // parse keyframes
-        if (m_keyframeType == GeometryKeyframe) {
-            m_animation.set("keyframes", e.attribute("value").toUtf8().constData());
-            m_animation.anim_get_rect("keyframes", 0);
-        } else {
-            m_animation.set("keyframes", \
                e.attribute("keyframes").toUtf8().constData());
-            m_animation.anim_get_double("keyframes", 0);
+        switch (m_keyframeType) {
+            case GeometryKeyframe:
+                m_keyProperties.set("keyframes", \
e.attribute("value").toUtf8().constData()); +                \
m_keyProperties.anim_get_rect("keyframes", 0); +                break;
+            case AnimatedKeyframe:
+                m_keyProperties.set("keyframes", \
e.attribute("value").toUtf8().constData()); +                \
m_keyProperties.anim_get_double("keyframes", 0); +                m_keyframeFactor = \
locale.toDouble(e.attribute(QStringLiteral("factor"))); +                break;
+            default:
+                m_keyProperties.set("keyframes", \
e.attribute("keyframes").toUtf8().constData()); +                \
m_keyProperties.anim_get_double("keyframes", 0);  }
-        if (m_animation.get_anim("keyframes")->next_key(m_editedKeyframe) <= \
m_editedKeyframe) m_editedKeyframe = -1; +        m_keyAnim = \
m_keyProperties.get_animation("keyframes"); +        if \
(m_keyAnim.next_key(m_editedKeyframe) <= m_editedKeyframe) m_editedKeyframe = -1;  \
return true;  }
-    m_animation.set("keyframes", 0, 0);
+    m_keyProperties.set("keyframes", 0, 0);
     return false;
 }
 
@@ -1930,6 +1937,10 @@ QMap<int, QDomElement> ClipItem::adjustEffectsToDuration(int \
width, int height,  if (!effects.contains(i))
                     effects[i] = effect.cloneNode().toElement();
                 updateNormalKeyframes(param, oldInfo);
+            } else if (type == QLatin1String("animated")) {
+                if (!effects.contains(i))
+                    effects[i] = effect.cloneNode().toElement();
+                updateAnimatedKeyframes(param, j, oldInfo);
             } else if (type == QLatin1String("roto-spline")) {
                 if (!effects.contains(i))
                     effects[i] = effect.cloneNode().toElement();
@@ -2053,6 +2064,22 @@ void ClipItem::updateGeometryKeyframes(QDomElement effect, int \
paramIndex, int w  param.setAttribute(QStringLiteral("value"), result);
 }
 
+void ClipItem::updateAnimatedKeyframes(QDomElement effect, int paramIndex, ItemInfo \
oldInfo) +{
+    QDomElement param = \
effect.elementsByTagName("parameter").item(paramIndex).toElement(); +    int offset = \
oldInfo.cropStart.frames(m_fps); +    if (offset > 0) {
+        for(int i = 0; i < m_keyAnim.key_count(); ++i){
+            int oldPos = m_keyAnim.key_get_frame(i);
+            int newPos = oldPos + offset;
+            m_keyAnim.remove(oldPos);
+            m_keyProperties.anim_set("keyframes", \
m_keyProperties.anim_get_double("keyframes", oldPos), newPos, 0, \
m_keyAnim.keyframe_type(i)); +        }
+    }
+    QString result = m_keyAnim.serialize_cut();
+    param.setAttribute("value", result);
+}
+
 void ClipItem::slotRefreshClip()
 {
     update();
diff --git a/src/timeline/clipitem.h b/src/timeline/clipitem.h
index e28f1b1..d3bbbc9 100644
--- a/src/timeline/clipitem.h
+++ b/src/timeline/clipitem.h
@@ -173,6 +173,7 @@ public:
     void updateKeyframes(QDomElement effect);
     void updateGeometryKeyframes(QDomElement effect, int paramIndex, int width, int \
height, ItemInfo oldInfo);  bool updateNormalKeyframes(QDomElement parameter, \
ItemInfo oldInfo); +    void updateAnimatedKeyframes(QDomElement parameter, int \
paramIndex, ItemInfo oldInfo);  
     /** @brief Adjusts effects after a clip duration change. */
     QMap<int, QDomElement> adjustEffectsToDuration(int width, int height, const \
                ItemInfo &oldInfo);
diff --git a/src/timeline/customtrackview.cpp b/src/timeline/customtrackview.cpp
index 9f047ab..7dfc4e4 100644
--- a/src/timeline/customtrackview.cpp
+++ b/src/timeline/customtrackview.cpp
@@ -88,7 +88,7 @@ CustomTrackView::CustomTrackView(KdenliveDoc *doc, Timeline \
*timeline, CustomTra  , m_dragItem(NULL)
   , m_dragGuide(NULL)
   , m_visualTip(NULL)
-  , m_animation(NULL)
+  , m_keyProperties(NULL)
   , m_autoScroll(KdenliveSettings::autoscroll())
   , m_timelineContextMenu(NULL)
   , m_timelineContextClipMenu(NULL)
@@ -131,10 +131,10 @@ CustomTrackView::CustomTrackView(KdenliveDoc *doc, Timeline \
                *timeline, CustomTra
     m_selectedTrackColor = scheme.background(KColorScheme::ActiveBackground \
).color();  m_selectedTrackColor.setAlpha(150);
 
-    m_animationTimer = new QTimeLine(800);
-    m_animationTimer->setFrameRange(0, 5);
-    m_animationTimer->setUpdateInterval(100);
-    m_animationTimer->setLoopCount(0);
+    m_keyPropertiesTimer = new QTimeLine(800);
+    m_keyPropertiesTimer->setFrameRange(0, 5);
+    m_keyPropertiesTimer->setUpdateInterval(100);
+    m_keyPropertiesTimer->setLoopCount(0);
 
     m_tipColor = QColor(0, 192, 0, 200);
     m_tipPen.setColor(QColor(255, 255, 255, 100));
@@ -180,7 +180,7 @@ CustomTrackView::~CustomTrackView()
     qDeleteAll(m_guides);
     m_guides.clear();
     m_waitingThumbs.clear();
-    delete m_animationTimer;
+    delete m_keyPropertiesTimer;
 }
 
 //virtual
@@ -632,10 +632,7 @@ void CustomTrackView::mouseMoveEvent(QMouseEvent * event)
             } else if (m_moveOpMode == KeyFrame) {
                 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();
-                double maxh = 100.0 / br.height();
-                pos = (br.bottom() - pos) * maxh;
-                m_dragItem->updateKeyFramePos(keyFramePos, pos);
+                m_dragItem->updateKeyFramePos(keyFramePos.frames(fps()), pos);
                 QString position = \
m_document->timecode().getDisplayTimecodeFromFrames(m_dragItem->editedKeyFramePos(), \
                KdenliveSettings::frametimecode());
                 emit displayMessage(position + " : " + \
QString::number(m_dragItem->editedKeyFrameValue()), InformationMessage);  }
@@ -6394,10 +6391,15 @@ void CustomTrackView::adjustKeyfames(GenTime oldstart, \
                GenTime newstart, GenTime
     QDomNodeList params = xml.elementsByTagName(QStringLiteral("parameter"));
     for (int i = 0; i < params.count(); ++i) {
         QDomElement e = params.item(i).toElement();
-        if (!e.isNull() && (e.attribute(QStringLiteral("type")) == \
QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe"))) { +        if (e.isNull()) continue;
+        if (e.attribute(QStringLiteral("type")) == QLatin1String("keyframe")
+            || e.attribute(QStringLiteral("type")) == \
                QLatin1String("simplekeyframe")) {
             // Effect has a keyframe type parameter, we need to adjust the values
             QString adjusted = \
EffectsController::adjustKeyframes(e.attribute(QStringLiteral("keyframes")), \
oldstart.frames(m_document->fps()), newstart.frames(m_document->fps()), (newstart + \
duration).frames(m_document->fps()) - 1, m_document->getProfileInfo());  \
e.setAttribute(QStringLiteral("keyframes"), adjusted); +        } else if \
(e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { +            \
QString adjusted = EffectsController::adjustKeyframes(e.attribute(QStringLiteral("value")), \
oldstart.frames(m_document->fps()), newstart.frames(m_document->fps()), (newstart + \
duration).frames(m_document->fps()) - 1, m_document->getProfileInfo()); +            \
e.setAttribute(QStringLiteral("value"), adjusted);  }
     }
 }
@@ -7541,9 +7543,9 @@ void CustomTrackView::removeTipAnimation()
 {
     if (m_visualTip) {
         scene()->removeItem(m_visualTip);
-        m_animationTimer->stop();
-        delete m_animation;
-        m_animation = NULL;
+        m_keyPropertiesTimer->stop();
+        delete m_keyProperties;
+        m_keyProperties = NULL;
         delete m_visualTip;
         m_visualTip = NULL;
     }
@@ -7553,9 +7555,9 @@ void CustomTrackView::setTipAnimation(AbstractClipItem *clip, \
OperationType mode  {
     if (m_visualTip == NULL) {
         QRectF rect = clip->sceneBoundingRect();
-        m_animation = new QGraphicsItemAnimation;
-        m_animation->setTimeLine(m_animationTimer);
-        m_animation->setScaleAt(1, 1, 1);
+        m_keyProperties = new QGraphicsItemAnimation;
+        m_keyProperties->setTimeLine(m_keyPropertiesTimer);
+        m_keyProperties->setScaleAt(1, 1, 1);
         QPolygon polygon;
         switch (mode) {
         case FadeIn:
@@ -7568,7 +7570,7 @@ void CustomTrackView::setTipAnimation(AbstractClipItem *clip, \
OperationType mode  else
                 m_visualTip->setPos(rect.right() - \
static_cast<ClipItem*>(clip)->fadeOut(), rect.y());  
-            m_animation->setScaleAt(.5, 2, 2);
+            m_keyProperties->setScaleAt(.5, 2, 2);
             break;
         case ResizeStart:
         case ResizeEnd:
@@ -7588,7 +7590,7 @@ void CustomTrackView::setTipAnimation(AbstractClipItem *clip, \
OperationType mode  else
                 m_visualTip->setPos(rect.right(), rect.y() + rect.height() / 2);
 
-            m_animation->setScaleAt(.5, 2, 1);
+            m_keyProperties->setScaleAt(.5, 2, 1);
             break;
         case TransitionStart:
         case TransitionEnd:
@@ -7608,18 +7610,18 @@ void CustomTrackView::setTipAnimation(AbstractClipItem *clip, \
OperationType mode  else
                 m_visualTip->setPos(rect.right(), rect.bottom());
 
-            m_animation->setScaleAt(.5, 2, 2);
+            m_keyProperties->setScaleAt(.5, 2, 2);
             break;
         default:
-            delete m_animation;
+            delete m_keyProperties;
             return;
         }
 
         m_visualTip->setFlags(QGraphicsItem::ItemIgnoresTransformations);
         m_visualTip->setZValue(100);
         scene()->addItem(m_visualTip);
-        m_animation->setItem(m_visualTip);
-        m_animationTimer->start();
+        m_keyProperties->setItem(m_visualTip);
+        m_keyPropertiesTimer->start();
     }
 }
 
diff --git a/src/timeline/customtrackview.h b/src/timeline/customtrackview.h
index 1e0a886..6a95dfc 100644
--- a/src/timeline/customtrackview.h
+++ b/src/timeline/customtrackview.h
@@ -360,8 +360,8 @@ private:
     Guide *m_dragGuide;
     QUndoStack *m_commandStack;
     QGraphicsItem *m_visualTip;
-    QGraphicsItemAnimation *m_animation;
-    QTimeLine *m_animationTimer;
+    QGraphicsItemAnimation *m_keyProperties;
+    QTimeLine *m_keyPropertiesTimer;
     QColor m_tipColor;
     QPen m_tipPen;
     QPoint m_clickEvent;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic