Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit d6b00054 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle

Merge branch '16.12'

parents effa6bf4 b348355e
......@@ -863,6 +863,29 @@ void Bin::slotReloadClip()
ProjectClip *currentItem = qobject_cast<ProjectClip*>(item);
if (currentItem) {
emit openClip(Q_NULLPTR);
if (currentItem->clipType() == Playlist) {
//Check if a clip inside playlist is missing
QString path = currentItem->url().path();
QFile f(path);
QDomDocument doc;
doc.setContent(&f, false);
f.close();
DocumentChecker d(QUrl::fromLocalFile(path), doc);
if (!d.hasErrorInClips() && doc.documentElement().attribute(QStringLiteral("modified")) == QLatin1String("1")) {
QString backupFile = path + QStringLiteral(".backup");
KIO::FileCopyJob *copyjob = KIO::file_copy(QUrl::fromLocalFile(path), QUrl::fromLocalFile(backupFile));
if (copyjob->exec()) {
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
KMessageBox::sorry(this, i18n("Unable to write to file %1", path));
} else {
QTextStream out(&f);
out << doc.toString();
f.close();
KMessageBox::information(this, i18n("Your project file was modified by Kdenlive.\nTo make sure you don't lose data, a backup copy called %1 was created.", backupFile));
}
}
}
}
QDomDocument doc;
QDomElement xml = currentItem->toXml(doc);
qDebug()<<"*****************\n"<<doc.toString()<<"\n******************";
......
......@@ -1496,7 +1496,7 @@ bool DocumentValidator::upgrade(double version, const double currentVersion)
}
}
EffectsList::setProperty(eff, conversionParams.at(2), parsedValues.join(QStringLiteral(";")));
EffectsList::setProperty(eff, QStringLiteral("kdenlive:sync_in_out"), QStringLiteral("1"));
//EffectsList::setProperty(eff, QStringLiteral("kdenlive:sync_in_out"), QStringLiteral("1"));
eff.setAttribute(QStringLiteral("out"), out);
}
}
......
......@@ -232,9 +232,9 @@ void AnimationWidget::finishSetup()
}
//static
QString AnimationWidget::getDefaultKeyframes(const QString &defaultValue, bool linearOnly)
QString AnimationWidget::getDefaultKeyframes(int start, const QString &defaultValue, bool linearOnly)
{
QString keyframes = QStringLiteral("0");
QString keyframes = QString::number(start);
if (linearOnly) {
keyframes.append(QStringLiteral("="));
} else {
......@@ -676,7 +676,7 @@ void AnimationWidget::addParameter(const QDomElement &e)
keyframes = e.attribute(QStringLiteral("value"));
}
if (keyframes.isEmpty()) {
keyframes = getDefaultKeyframes(e.attribute(QStringLiteral("default")));
keyframes = getDefaultKeyframes(m_inPoint, e.attribute(QStringLiteral("default")));
if (keyframes.contains('%')) {
keyframes = EffectsController::getStringRectEval(m_monitor->profileInfo(), keyframes);
}
......@@ -1017,7 +1017,7 @@ void AnimationWidget::loadPresets(QString currentText)
QMap <QString, QVariant> defaultEntry;
QStringList paramNames = m_doubleWidgets.keys();
for (int i = 0; i < paramNames.count(); i++) {
defaultEntry.insert(paramNames.at(i), getDefaultKeyframes(m_params.at(i).attribute(QStringLiteral("default"))));
defaultEntry.insert(paramNames.at(i), getDefaultKeyframes(m_inPoint, m_params.at(i).attribute(QStringLiteral("default"))));
}
m_presetCombo->addItem(i18n("Default"), defaultEntry);
loadPreset(dir.absoluteFilePath(m_xml.attribute(QStringLiteral("type"))));
......@@ -1309,7 +1309,7 @@ void AnimationWidget::reload(const QString &tag, const QString &data)
if (!m_rectParameter.isEmpty() && tag != m_rectParameter) {
// reset geometry keyframes
// simple anim parameter, get default value
QString def = getDefaultKeyframes(defaultValue(m_rectParameter));
QString def = getDefaultKeyframes(m_inPoint, defaultValue(m_rectParameter));
// Clear current keyframes
m_animProperties.set(m_rectParameter.toUtf8().constData(), def.toUtf8().constData());
// Add default keyframes
......
......@@ -50,7 +50,7 @@ public:
void updateTimecodeFormat();
void addParameter(const QDomElement &e);
const QMap <QString, QString> getAnimation();
static QString getDefaultKeyframes(const QString &defaultValue, bool linearOnly = false);
static QString getDefaultKeyframes(int start, const QString &defaultValue, bool linearOnly = false);
void setActiveKeyframe(int frame);
void finishSetup();
/** @brief Returns true if currently active param is name */
......
......@@ -103,8 +103,9 @@ EffectsParameterList EffectsController::getEffectArgs(const ProfileInfo &info, c
parameters.addParam(QStringLiteral("tag"), effect.attribute(QStringLiteral("tag")));
//if (effect.hasAttribute("region")) parameters.addParam("region", effect.attribute("region"));
parameters.addParam(QStringLiteral("kdenlive_ix"), effect.attribute(QStringLiteral("kdenlive_ix")));
if (effect.hasAttribute(QStringLiteral("sync_in_out")))
if (effect.hasAttribute(QStringLiteral("sync_in_out"))) {
parameters.addParam(QStringLiteral("kdenlive:sync_in_out"), effect.attribute(QStringLiteral("sync_in_out")));
}
parameters.addParam(QStringLiteral("kdenlive_info"), effect.attribute(QStringLiteral("kdenlive_info")));
parameters.addParam(QStringLiteral("id"), effect.attribute(QStringLiteral("id")));
if (effect.hasAttribute(QStringLiteral("src"))) parameters.addParam(QStringLiteral("src"), effect.attribute(QStringLiteral("src")));
......@@ -137,10 +138,11 @@ void EffectsController::adjustEffectParameters(EffectsParameterList &parameters,
for (int i = 0; i < params.count(); ++i) {
QDomElement e = params.item(i).toElement();
QString paramname = prefix + e.attribute(QStringLiteral("name"));
if (e.attribute(QStringLiteral("type")) == QLatin1String("animated") || (e.attribute(QStringLiteral("type")) == QLatin1String("geometry") && !e.hasAttribute(QStringLiteral("fixed")))) {
/*if (e.attribute(QStringLiteral("type")) == QLatin1String("animated") || (e.attribute(QStringLiteral("type")) == QLatin1String("geometry") && !e.hasAttribute(QStringLiteral("fixed")))) {
// effects with geometry param need in / out synced with the clip, request it...
//parameters.addParam(QStringLiteral("kdenlive:sync_in_out"), QStringLiteral("1"));
}
parameters.addParam(QStringLiteral("kdenlive:sync_in_out"), QStringLiteral("1"));
qDebug()<<" ** * ADDIN EFFECT ANIM SYN TRUE";
}*/
if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) {
parameters.addParam(paramname, e.attribute(QStringLiteral("value")));
} else if (e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) {
......@@ -229,7 +231,7 @@ void EffectsController::initTrackEffect(ProfileInfo pInfo, const QDomElement &ef
bool hasValue = e.hasAttribute(QStringLiteral("value"));
// Check if this effect has a variable parameter, init effects default value
if ((type == QLatin1String("animatedrect") || type == QLatin1String("geometry")) && !hasValue) {
QString kfr = AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default")), type == QLatin1String("geometry"));
QString kfr = AnimationWidget::getDefaultKeyframes(0, e.attribute(QStringLiteral("default")), type == QLatin1String("geometry"));
if (kfr.contains(QLatin1String("%"))) {
kfr = EffectsController::getStringRectEval(pInfo, kfr);
}
......@@ -244,7 +246,7 @@ void EffectsController::initTrackEffect(ProfileInfo pInfo, const QDomElement &ef
} else e.setAttribute(QStringLiteral("value"), evaluatedValue);
} else {
if (type == QLatin1String("animated") && !hasValue) {
e.setAttribute(QStringLiteral("value"), AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default"))));
e.setAttribute(QStringLiteral("value"), AnimationWidget::getDefaultKeyframes(0, e.attribute(QStringLiteral("default"))));
}
else if (!hasValue) {
e.setAttribute(QStringLiteral("value"), e.attribute(QStringLiteral("default")));
......@@ -273,7 +275,7 @@ void EffectsController::initEffect(const ItemInfo &info, ProfileInfo pInfo, cons
bool hasValue = e.hasAttribute(QStringLiteral("value"));
// Check if this effect has a variable parameter, init effects default value
if ((type == QLatin1String("animatedrect") || type == QLatin1String("geometry")) && !hasValue) {
QString kfr = AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default")), type == QLatin1String("geometry"));
QString kfr = AnimationWidget::getDefaultKeyframes(info.cropStart.frames(fps), e.attribute(QStringLiteral("default")), type == QLatin1String("geometry"));
if (kfr.contains(QLatin1String("%"))) {
kfr = EffectsController::getStringRectEval(pInfo, kfr);
}
......@@ -288,7 +290,7 @@ void EffectsController::initEffect(const ItemInfo &info, ProfileInfo pInfo, cons
} else e.setAttribute(QStringLiteral("value"), evaluatedValue);
} else {
if (type == QLatin1String("animated") && !hasValue) {
e.setAttribute(QStringLiteral("value"), AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default"))));
e.setAttribute(QStringLiteral("value"), AnimationWidget::getDefaultKeyframes(info.cropStart.frames(fps), e.attribute(QStringLiteral("default"))));
}
else if (!hasValue) {
e.setAttribute(QStringLiteral("value"), e.attribute(QStringLiteral("default")));
......@@ -312,7 +314,7 @@ void EffectsController::initEffect(const ItemInfo &info, ProfileInfo pInfo, cons
}
}
if (type.startsWith(QStringLiteral("animated")) || (type == QLatin1String("geometry") && !e.hasAttribute(QStringLiteral("fixed")))) {
if (EffectsList::parameter(effect, QStringLiteral("kdenlive:sync_in_out")) == QLatin1String("1") || (type == QLatin1String("geometry") && !e.hasAttribute(QStringLiteral("fixed")))) {
// Effects with a geometry parameter need to sync in / out with parent clip
effect.setAttribute(QStringLiteral("in"), QString::number((int) info.cropStart.frames(fps)));
effect.setAttribute(QStringLiteral("out"), QString::number((int) (info.cropStart + info.cropDuration).frames(fps) - 1));
......
......@@ -200,7 +200,6 @@ void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, bool /*emitChang
}
m_info.startPos += durationDiff;
m_keyframeView.setOffset(durationDiff.frames(m_fps));
// set to true if crop from start is negative (possible for color clips, images as they have no size limit)
bool negCropStart = false;
if (type() == AVWidget) {
......@@ -615,7 +614,7 @@ QString AbstractClipItem::resizeAnimations(QDomElement effect, int previousDurat
effect.setAttribute(QStringLiteral("out"), QString::number(start + duration));
}
else {
keyframes = KeyframeView::cutAnimation(animation, cropstart, duration, previousDuration, false);
keyframes = KeyframeView::addBorderKeyframes(animation, cropstart, duration);
}
// TODO: in case of multiple animated params, use _intimeline to detect active one
e.setAttribute(QStringLiteral("value"), keyframes);
......@@ -627,10 +626,12 @@ QString AbstractClipItem::resizeAnimations(QDomElement effect, int previousDurat
bool AbstractClipItem::switchKeyframes(QDomElement param, int in, int oldin, int out, int oldout)
{
QString animation = param.attribute(QStringLiteral("value"));
if (in != oldin)
if (in != oldin) {
animation = KeyframeView::switchAnimation(animation, in, oldin, out, oldout, param.attribute(QStringLiteral("type")) == QLatin1String("animatedrect"));
if (out != oldout)
animation = KeyframeView::switchAnimation(animation, out - 1, oldout - 1, out, oldout, param.attribute(QStringLiteral("type")) == QLatin1String("animatedrect"));
}
if (out != oldout) {
animation = KeyframeView::switchAnimation(animation, out, oldout, out, oldout, param.attribute(QStringLiteral("type")) == QLatin1String("animatedrect"));
}
if (animation != param.attribute(QStringLiteral("value"))) {
param.setAttribute(QStringLiteral("value"), animation);
return true;
......
......@@ -1453,7 +1453,7 @@ EffectsParameterList ClipItem::addEffect(ProfileInfo info, QDomElement effect, b
else if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) {
parameters.addParam(e.attribute(QStringLiteral("name")), e.attribute(QStringLiteral("value")));
// Effects with a animated parameter need to sync in / out with parent clip
if (!e.hasAttribute(QStringLiteral("sync_in_out")) || e.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) {
if (e.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) {
needInOutSync = true;
}
} else if (e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) {
......@@ -1808,10 +1808,9 @@ QMap<int, QDomElement> ClipItem::adjustEffectsToDuration(const ItemInfo &oldInfo
if (effect.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) {
effect.setAttribute(QStringLiteral("in"), cropStart().frames(m_fps));
effect.setAttribute(QStringLiteral("out"), (cropStart() + cropDuration()).frames(m_fps) - 1);
} else {
// Check if we have keyframes at in/out points
updateAnimatedKeyframes(i, param, oldInfo);
}
// Check if we have keyframes at in/out points
updateAnimatedKeyframes(i, param, oldInfo);
effects[i] = effect.cloneNode().toElement();
} else if (type == QLatin1String("roto-spline")) {
if (!effects.contains(i))
......@@ -1856,7 +1855,6 @@ bool ClipItem::updateNormalKeyframes(QDomElement parameter, const ItemInfo &oldI
keyframes[keyframepos] = locale.toDouble(keyframe.section('=', 1, 1));
}
QMap<int, double>::iterator i = keyframes.end();
int lastPos = -1;
double lastValue = 0;
......
......@@ -1380,7 +1380,7 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
ClipItem * item = static_cast <ClipItem *>(m_dragItem);
QDomElement oldEffect = item->selectedEffect().cloneNode().toElement();
if (single == 1) {
item->insertKeyframe(m_document->getProfileInfo(), item->getEffectAtIndex(item->selectedEffectIndex()), (item->cropDuration()).frames(m_document->fps()) - 1, -1, true);
item->insertKeyframe(m_document->getProfileInfo(), item->getEffectAtIndex(item->selectedEffectIndex()), (item->cropStart() + item->cropDuration()).frames(m_document->fps()) - 1, -1, true);
}
//QString previous = item->keyframes(item->selectedEffectIndex());
item->insertKeyframe(m_document->getProfileInfo(), item->getEffectAtIndex(item->selectedEffectIndex()), keyFramePos.frames(m_document->fps()), val);
......@@ -1906,7 +1906,6 @@ bool CustomTrackView::itemCollision(AbstractClipItem *item, const ItemInfo &newP
void CustomTrackView::slotRefreshEffects(ClipItem *clip)
{
// Does not seem used anywhere...
int track = clip->track();
GenTime pos = clip->startPos();
if (!m_timeline->track(track)->removeEffect(pos.seconds(), -1, false)) {
......
......@@ -316,8 +316,7 @@ bool EffectManager::editEffect(EffectsParameterList params, int duration, bool r
if (params.paramValue(QStringLiteral("kdenlive:sync_in_out")) == QLatin1String("1")) {
// This effect must sync in / out with parent clip
//params.removeParam(QStringLiteral("sync_in_out"));
Mlt::Producer prod(m_producer);
filter->set_in_and_out(prod.get_in(), prod.get_out());
filter->set_in_and_out(m_producer.get_int("in"), m_producer.get_int("out"));
} else {
// Reset in/out properties
filter->set("in", (char*)Q_NULLPTR);
......
......@@ -23,7 +23,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QPainter>
#include <QAction>
#include <QApplication>
#include "klocalizedstring.h"
#include "keyframeview.h"
......@@ -142,14 +141,28 @@ void KeyframeView::drawKeyFrames(const QRectF &br, int length, bool active, QPai
Mlt::Animation drawAnim = m_keyProperties.get_animation(paramName.toUtf8().constData());
if (!drawAnim.is_valid()) continue;
QPainterPath path;
int frame = drawAnim.key_get_frame(0);
// Find first key before our clip start, get frame for rect left first
int firstKF = qMax(0, drawAnim.previous_key(-m_offset));
int lastKF = drawAnim.next_key(duration - m_offset);
if (lastKF < duration - m_offset) {
lastKF = duration - m_offset;
}
int frame = firstKF;
double value = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - m_offset);
QPointF start = keyframePoint(br, frame + m_offset, value, info.factor, info.min, info.max);
path.moveTo(br.x(), br.bottom());
path.lineTo(br.x(), start.y());
path.lineTo(start);
int currentFrame;
painter->setPen(paramName == m_inTimeline ? QColor(Qt::white) : Qt::NoPen);
for(int i = 0; i < drawAnim.key_count(); ++i) {
currentFrame = drawAnim.key_get_frame(i);
if (currentFrame < firstKF) {
continue;
}
if (currentFrame > lastKF) {
break;
}
if (active && paramName == m_inTimeline) {
painter->setBrush((drawAnim.key_get_frame(i) == activeKeyframe) ? QColor(Qt::red) : QColor(Qt::blue));
painter->drawEllipse(QRectF(transformation.map(start) - h/2, transformation.map(start) + h / 2));
......@@ -170,10 +183,10 @@ void KeyframeView::drawKeyFrames(const QRectF &br, int length, bool active, QPai
case mlt_keyframe_smooth:
frame = drawAnim.key_get_frame(qMax(i - 1, 0));
value = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - m_offset);
QPointF pre = keyframePoint(br, frame, value, info.factor, info.min, info.max);
QPointF pre = keyframePoint(br, frame + m_offset, value, info.factor, info.min, info.max);
frame = drawAnim.key_get_frame(qMin(i + 2, drawAnim.key_count() - 1));
value = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - m_offset);
QPointF post = keyframePoint(br, frame, value, info.factor, info.min, info.max);
QPointF post = keyframePoint(br, frame + m_offset, value, info.factor, info.min, info.max);
QPointF c1 = (end - pre) / 6.0; // + start
QPointF c2 = (start - post) / 6.0; // + end
double mid = (end.x() - start.x()) / 2;
......@@ -891,9 +904,23 @@ bool KeyframeView::loadKeyframes(const QLocale &locale, const QDomElement &effec
void KeyframeView::setOffset(int frames)
{
if (m_useOffset) {
if (!m_keyAnim.is_valid())
return;
if (m_keyAnim.is_key(-m_offset)) {
mlt_keyframe_type type = m_keyAnim.keyframe_type(-m_offset);
double value = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), -m_offset, duration - m_offset);
m_keyAnim.remove(-m_offset);
if (activeKeyframe == -m_offset) {
activeKeyframe -= frames;
}
m_offset -= frames;
m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), value, - m_offset, duration - m_offset, type);
//addKeyframe(-m_offset, value, type);
} else {
m_offset -= frames;
}
//double value = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), 0, duration - m_offset);
//}
}
// static
......@@ -961,6 +988,34 @@ QString KeyframeView::cutAnimation(const QString &animation, int start, int dura
return anim.serialize_cut(start, start + duration);
}
//static
const QString KeyframeView::addBorderKeyframes(const QString &animation, int start, int duration)
{
bool modified = false;
Mlt::Properties props;
props.set("keyframes", animation.toUtf8().constData());
props.anim_get_double("keyframes", 0, start+duration);
Mlt::Animation anim = props.get_animation("keyframes");
if (!anim.is_key(start)) {
double value = props.anim_get_double("keyframes", start, start+duration);
int previous = anim.previous_key(start);
mlt_keyframe_type type = anim.keyframe_type(previous);
props.anim_set("keyframes", value, start, start+duration, type);
modified = true;
}
if (!anim.is_key(start+duration)) {
double value = props.anim_get_double("keyframes", start+duration, start+duration);
int previous = anim.previous_key(start+duration);
mlt_keyframe_type type = anim.keyframe_type(previous);
props.anim_set("keyframes", value, start+duration, start+duration, type);
modified = true;
}
if (modified) {
return anim.serialize_cut();
}
return animation;
}
//static
QString KeyframeView::switchAnimation(QString animation, int newPos, int oldPos, int newDuration, int oldDuration, bool isRect)
{
......@@ -971,7 +1026,7 @@ QString KeyframeView::switchAnimation(QString animation, int newPos, int oldPos,
if (anim.is_key(oldPos)) {
// insert new keyframe at start
if (isRect) {
mlt_rect rect = props.anim_get_rect("keyframes", oldPos);
mlt_rect rect = props.anim_get_rect("keyframes", oldPos, oldDuration);
props.anim_set("keyframes", rect, newPos, newDuration, anim.keyframe_type(oldPos));
anim.remove(oldPos);
} else {
......
......@@ -97,6 +97,8 @@ public:
static QString switchAnimation(QString animation, int newPos, int oldPos, int newDuration, int oldDuration, bool isRect);
/** @brief when loading an animation from a serialized string, check where is the first negative keyframe) */
static int checkNegatives(const QString &data, int maxDuration);
/** @brief Add keyframes at start / end points if not existing */
static const QString addBorderKeyframes(const QString &animation, int start, int duration);
/** @brief returns true if currently edited parameter name is name */
bool activeParam(const QString &name) const;
/** @brief Sets a temporary offset for drawing keyframes when resizing clip start */
......
......@@ -905,9 +905,9 @@ bool Track::editEffect(double start, EffectsParameterList params, bool replace)
if (!clip) {
return false;
}
Mlt::Service clipService(clip->get_service());
EffectManager effect(clipService);
return effect.editEffect(params, duration, replace);
EffectManager effect(*clip.data());
bool result = effect.editEffect(params, duration, replace);
return result;
}
bool Track::editTrackEffect(EffectsParameterList params, bool replace)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment