bool ClipItem::checkKeyFrames()
{
bool clipEffectsModified = false;
+ QLocale locale;
// go through all effects this clip has
for (int ix = 0; ix < m_effectList.count(); ++ix) {
QStringList keyframeParams = keyframes(ix);
// go through all keyframes for one param
foreach(const QString &str, keyframes) {
int pos = str.section(':', 0, 0).toInt();
- double val = str.section(':', 1, 1).toDouble();
+ double val = locale.toDouble(str.section(':', 1, 1));
if (pos - start < 0) {
// a keyframe is defined before the start of the clip
cutKeyFrame = true;
int diff = pos - lastPos;
double ratio = (double)(start - lastPos) / diff;
double newValue = lastValue + (val - lastValue) * ratio;
- newKeyFrames.append(QString::number(start) + ':' + QString::number(newValue));
+ newKeyFrames.append(QString::number(start) + ':' + locale.toString(newValue));
modified = true;
}
cutKeyFrame = false;
if (diff != 0) {
double ratio = (double)(end - lastPos) / diff;
double newValue = lastValue + (val - lastValue) * ratio;
- newKeyFrames.append(QString::number(end) + ':' + QString::number(newValue));
+ newKeyFrames.append(QString::number(end) + ':' + locale.toString(newValue));
modified = true;
}
break;
} else {
- newKeyFrames.append(QString::number(pos) + ':' + QString::number(val));
+ newKeyFrames.append(QString::number(pos) + ':' + locale.toString(val));
}
}
lastPos = pos;
{
QDomElement effect = getEffectAt(ix);
if (effect.attribute("disable") == "1") return;
+ QLocale locale;
QDomNodeList params = effect.elementsByTagName("parameter");
int keyframeParams = 0;
for (int i = 0; i < params.count(); i++) {
if (ix == m_selectedEffect && keyframeParams == 0) {
m_keyframes.clear();
m_visibleParam = i;
- double max = e.attribute("max").toDouble();
- double min = e.attribute("min").toDouble();
+ double max = locale.toDouble(e.attribute("max"));
+ double min = locale.toDouble(e.attribute("min"));
m_keyframeFactor = 100.0 / (max - min);
m_keyframeOffset = min;
- m_keyframeDefault = e.attribute("default").toDouble();
+ m_keyframeDefault = locale.toDouble(e.attribute("default"));
m_selectedKeyframe = 0;
// parse keyframes
const QStringList keyframes = e.attribute("keyframes").split(';', QString::SkipEmptyParts);
foreach(const QString &str, keyframes) {
int pos = str.section(':', 0, 0).toInt();
- double val = str.section(':', 1, 1).toDouble();
+ double val = locale.toDouble(str.section(':', 1, 1));
m_keyframes[pos] = val;
}
if (m_keyframes.find(m_editedKeyframe) == m_keyframes.end()) m_editedKeyframe = -1;
void ClipItem::setSelectedEffect(const int ix)
{
m_selectedEffect = ix;
+ QLocale locale;
QDomElement effect = effectAt(m_selectedEffect);
if (!effect.isNull() && effect.attribute("disable") != "1") {
QDomNodeList params = effect.elementsByTagName("parameter");
m_keyframes.clear();
m_limitedKeyFrames = e.attribute("type") == "keyframe";
m_visibleParam = i;
- double max = e.attribute("max").toDouble();
- double min = e.attribute("min").toDouble();
+ double max = locale.toDouble(e.attribute("max"));
+ double min = locale.toDouble(e.attribute("min"));
m_keyframeFactor = 100.0 / (max - min);
m_keyframeOffset = min;
- m_keyframeDefault = e.attribute("default").toDouble();
+ m_keyframeDefault = locale.toDouble(e.attribute("default"));
m_selectedKeyframe = 0;
// parse keyframes
const QStringList keyframes = e.attribute("keyframes").split(';', QString::SkipEmptyParts);
foreach(const QString &str, keyframes) {
int pos = str.section(':', 0, 0).toInt();
- double val = str.section(':', 1, 1).toDouble();
+ double val = locale.toDouble(str.section(':', 1, 1));
m_keyframes[pos] = val;
}
if (m_keyframes.find(m_editedKeyframe) == m_keyframes.end())
}
else {
#if KDE_IS_VERSION(4,5,0)
- m_clip->thumbProducer()->queryIntraThumbs(left, right);
- connect(m_clip->thumbProducer(), SIGNAL(thumbsCached()), this, SLOT(slotGotThumbsCache()));
- QString path = m_clip->fileURL().path() + "%";
- for (int i = left; i <= right; i++) {
- painter->drawImage(startPos + QPointF(twidth *(i - startOffset), 0), m_clip->thumbProducer()->findCachedThumb(path + QString::number(i)));
+ if (m_clip && m_clip->thumbProducer()) {
+ m_clip->thumbProducer()->queryIntraThumbs(left, right);
+ connect(m_clip->thumbProducer(), SIGNAL(thumbsCached()), this, SLOT(slotGotThumbsCache()));
+ QString path = m_clip->fileURL().path() + "_";
+ for (int i = left; i <= right; i++) {
+ painter->drawImage(startPos + QPointF(twidth *(i - startOffset), 0), m_clip->thumbProducer()->findCachedThumb(path + QString::number(i)));
+ }
}
#endif
}
EffectsParameterList ClipItem::addEffect(const QDomElement effect, bool /*animate*/)
{
bool needRepaint = false;
+ QLocale locale;
int ix;
if (!effect.hasAttribute("kdenlive_ix")) {
ix = effectsCounter();
parameters.addParam("id", effectId);
// special case: the affine effect needs in / out points
- if (effectId == "pan_zoom") {
- parameters.addParam("in", QString::number(cropStart().frames(m_fps)));
- parameters.addParam("out", QString::number((cropStart() + cropDuration()).frames(m_fps)));
- }
QDomNodeList params = effect.elementsByTagName("parameter");
int fade = 0;
+ bool needInOutSync = false;
for (int i = 0; i < params.count(); i++) {
QDomElement e = params.item(i).toElement();
if (!e.isNull()) {
+ if (e.attribute("type") == "geometry" && !e.hasAttribute("fixed")) {
+ // Effects with a geometry parameter need to sync in / out with parent clip
+ needInOutSync = true;
+ }
if (e.attribute("type") == "simplekeyframe") {
QStringList values = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
- double factor = e.attribute("factor", "1").toDouble();
- if (factor != 1) {
+ double factor = locale.toDouble(e.attribute("factor", "1"));
+ double offset = e.attribute("offset", "0").toDouble();
+ if (factor != 1 || offset != 0) {
for (int j = 0; j < values.count(); j++) {
QString pos = values.at(j).section(':', 0, 0);
- double val = values.at(j).section(':', 1, 1).toDouble() / factor;
- values[j] = pos + "=" + QString::number(val);
+ double val = (locale.toDouble(values.at(j).section(':', 1, 1)) - offset) / factor;
+ values[j] = pos + "=" + locale.toString(val);
}
}
parameters.addParam(e.attribute("name"), values.join(";"));
parameters.addParam("max", e.attribute("max"));
parameters.addParam("min", e.attribute("min"));
parameters.addParam("factor", e.attribute("factor", "1"));
+ parameters.addParam("offset", e.attribute("offset", "0"));
parameters.addParam("starttag", e.attribute("starttag", "start"));
parameters.addParam("endtag", e.attribute("endtag", "end"));
- } else if (e.attribute("factor", "1") == "1") {
+ } else if (e.attribute("factor", "1") == "1" && e.attribute("offset", "0") == "0") {
parameters.addParam(e.attribute("name"), e.attribute("value"));
// check if it is a fade effect
double fact;
if (e.attribute("factor").contains('%')) {
fact = ProfilesDialog::getStringEval(projectScene()->profile(), e.attribute("factor"));
- } else fact = e.attribute("factor", "1").toDouble();
- parameters.addParam(e.attribute("name"), QString::number(e.attribute("value").toDouble() / fact));
+ } else {
+ fact = locale.toDouble(e.attribute("factor", "1"));
+ }
+ double offset = e.attribute("offset", "0").toDouble();
+ parameters.addParam(e.attribute("name"), locale.toString((locale.toDouble(e.attribute("value")) - offset) / fact));
}
}
}
+ if (needInOutSync) {
+ parameters.addParam("in", QString::number(cropStart().frames(m_fps)));
+ parameters.addParam("out", QString::number((cropStart() + cropDuration()).frames(m_fps) - 1));
+ parameters.addParam("_sync_in_out", "1");
+ }
m_effectNames = m_effectList.effectNames().join(" / ");
if (fade > 0) m_startFade = fade;
else if (fade < 0) m_endFade = -fade;
void ClipItem::insertKeyframe(QDomElement effect, int pos, int val)
{
if (effect.attribute("disable") == "1") return;
+ QLocale locale;
effect.setAttribute("active_keyframe", pos);
m_editedKeyframe = pos;
QDomNodeList params = effect.elementsByTagName("parameter");
bool added = false;
foreach(const QString &str, keyframes) {
int kpos = str.section(':', 0, 0).toInt();
- double newval = str.section(':', 1, 1).toDouble();
+ double newval = locale.toDouble(str.section(':', 1, 1));
if (kpos < pos) {
newkfr.append(str);
} else if (!added) {
if (i == m_visibleParam)
newkfr.append(QString::number(pos) + ":" + QString::number(val));
else
- newkfr.append(QString::number(pos) + ":" + QString::number(newval));
+ newkfr.append(QString::number(pos) + ":" + locale.toString(newval));
if (kpos > pos) newkfr.append(str);
added = true;
} else newkfr.append(str);
void ClipItem::movedKeyframe(QDomElement effect, int oldpos, int newpos, double value)
{
if (effect.attribute("disable") == "1") return;
+ QLocale locale;
effect.setAttribute("active_keyframe", newpos);
QDomNodeList params = effect.elementsByTagName("parameter");
int start = cropStart().frames(m_fps);
newpos = qMax(newpos, start);
newpos = qMin(newpos, end);
if (i == m_visibleParam)
- newkfr.append(QString::number(newpos) + ":" + QString::number(value));
+ newkfr.append(QString::number(newpos) + ":" + locale.toString(value));
else
newkfr.append(QString::number(newpos) + ":" + str.section(':', 1, 1));
}
void ClipItem::updateKeyframes(QDomElement effect)
{
m_keyframes.clear();
+ QLocale locale;
// parse keyframes
QDomNodeList params = effect.elementsByTagName("parameter");
QDomElement e = params.item(m_visibleParam).toElement();
const QStringList keyframes = e.attribute("keyframes").split(';', QString::SkipEmptyParts);
foreach(const QString &str, keyframes) {
int pos = str.section(':', 0, 0).toInt();
- double val = str.section(':', 1, 1).toDouble();
+ double val = locale.toDouble(str.section(':', 1, 1));
m_keyframes[pos] = val;
}
if (!m_keyframes.contains(m_selectedKeyframe)) m_selectedKeyframe = -1;
}
-/*void ClipItem::slotGetIntraThumbs(CustomTrackView *view, int start, int end)
-{
- const int theight = KdenliveSettings::trackheight();
- const int twidth = FRAME_SIZE;
- QString path = m_clip->fileURL().path() + "%";
- QPixmap p;
- for (int i = start; i <= end; i++) {
-#if KDE_IS_VERSION(4,5,0)
- if (!view->m_pixmapCache->contains(path + QString::number(i))) {
- p = m_clip->extractImage(i, twidth, theight);
- view->m_pixmapCache->insertPixmap(path + QString::number(i), p);
- }
-#else
- if (!view->m_pixmapCache->find(path + QString::number(i), p)) {
- p = m_clip->extractImage(i, twidth, theight);
- view->m_pixmapCache->insert(path + QString::number(i), p);
- }
-#endif
- }
- update();
-}*/
-
Mlt::Producer *ClipItem::getProducer(int track, bool trackSpecific)
{
if (isAudioOnly())
QString id = effect.attribute("id");
int in = EffectsList::parameter(effect, "in").toInt();
int out = EffectsList::parameter(effect, "out").toInt();
- int clipEnd = (cropStart() + cropDuration()).frames(m_fps);
+ int clipEnd = (cropStart() + cropDuration()).frames(m_fps) - 1;
if (id == "fade_from_black" || id == "fadein") {
if (in != cropStart().frames(m_fps)) {
effects[i] = effect.cloneNode().toElement();
if (out != clipEnd) {
effects[i] = effect.cloneNode().toElement();
int diff = out - clipEnd;
- in -= diff;
+ in = qMax(in - diff, (int) cropStart().frames(m_fps));
out -= diff;
EffectsList::setParameter(effect, "in", QString::number(in));
EffectsList::setParameter(effect, "out", QString::number(out));
{
int in = cropStart().frames(m_fps);
int out = (cropStart() + cropDuration()).frames(m_fps) - 1;
+ QLocale locale;
const QStringList data = parameter.attribute("keyframes").split(';', QString::SkipEmptyParts);
QMap <int, double> keyframes;
foreach (QString keyframe, data)
- keyframes[keyframe.section(':', 0, 0).toInt()] = keyframe.section(':', 1, 1).toDouble();
+ keyframes[keyframe.section(':', 0, 0).toInt()] = locale.toDouble(keyframe.section(':', 1, 1));
QMap<int, double>::iterator i = keyframes.end();
}
#include "clipitem.moc"
+