[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