+ if (m_timeLine) m_timeLine;
+}
+
+ClipItem *ClipItem::clone(double scale, ItemInfo info) const {
+ ClipItem *duplicate = new ClipItem(m_clip, info, scale, m_fps);
+ if (info.cropStart == cropStart()) duplicate->slotThumbReady(info.cropStart.frames(m_fps), m_startPix);
+ if (info.cropStart + (info.endPos - info.startPos) == m_cropStart + m_cropDuration) duplicate->slotThumbReady((m_cropStart + m_cropDuration).frames(m_fps) - 1, m_endPix);
+ kDebug() << "// CLoning clip: " << (info.cropStart + (info.endPos - info.startPos)).frames(m_fps) << ", CURRENT end: " << (cropStart() + duration()).frames(m_fps);
+ duplicate->setEffectList(m_effectList);
+ duplicate->setSpeed(m_speed);
+ return duplicate;
+}
+
+void ClipItem::setEffectList(const EffectsList effectList) {
+ m_effectList = effectList;
+ m_effectNames = m_effectList.effectNames().join(" / ");
+}
+
+const EffectsList ClipItem::effectList() {
+ return m_effectList;
+}
+
+int ClipItem::selectedEffectIndex() const {
+ return m_selectedEffect;
+}
+
+void ClipItem::initEffect(QDomElement effect) {
+ // the kdenlive_ix int is used to identify an effect in mlt's playlist, should
+ // not be changed
+ if (effect.attribute("kdenlive_ix").toInt() == 0)
+ effect.setAttribute("kdenlive_ix", QString::number(effectsCounter()));
+ // init keyframes if required
+ QDomNodeList params = effect.elementsByTagName("parameter");
+ for (int i = 0; i < params.count(); i++) {
+ QDomElement e = params.item(i).toElement();
+ if (!e.isNull() && e.attribute("type") == "keyframe") {
+ QString def = e.attribute("default");
+ // Effect has a keyframe type parameter, we need to set the values
+ if (e.attribute("keyframes").isEmpty()) {
+ e.setAttribute("keyframes", QString::number(m_cropStart.frames(m_fps)) + ":" + def + ";" + QString::number((m_cropStart + m_cropDuration).frames(m_fps)) + ":" + def);
+ //kDebug() << "///// EFFECT KEYFRAMES INITED: " << e.attribute("keyframes");
+ break;
+ }
+ }
+ }
+}
+
+void ClipItem::setKeyframes(const int ix, const QString keyframes) {
+ QDomElement effect = effectAt(ix);
+ if (effect.attribute("disabled") == "1") return;
+ QDomNodeList params = effect.elementsByTagName("parameter");
+ for (int i = 0; i < params.count(); i++) {
+ QDomElement e = params.item(i).toElement();
+ if (!e.isNull() && e.attribute("type") == "keyframe") {
+ e.setAttribute("keyframes", keyframes);
+ if (ix == m_selectedEffect) {
+ m_keyframes.clear();
+ double max = e.attribute("max").toDouble();
+ double min = e.attribute("min").toDouble();
+ m_keyframeFactor = 100.0 / (max - min);
+ m_keyframeDefault = e.attribute("default").toDouble();
+ // parse keyframes
+ 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();
+ m_keyframes[pos] = val;
+ }
+ update();
+ return;
+ }
+ break;
+ }
+ }
+}
+
+
+void ClipItem::setSelectedEffect(const int ix) {
+ m_selectedEffect = ix;
+ QDomElement effect = effectAt(m_selectedEffect);
+ QDomNodeList params = effect.elementsByTagName("parameter");
+ if (effect.attribute("disabled") != "1")
+ for (int i = 0; i < params.count(); i++) {
+ QDomElement e = params.item(i).toElement();
+ if (!e.isNull() && e.attribute("type") == "keyframe") {
+ m_keyframes.clear();
+ double max = e.attribute("max").toDouble();
+ double min = e.attribute("min").toDouble();
+ m_keyframeFactor = 100.0 / (max - min);
+ m_keyframeDefault = e.attribute("default").toDouble();
+ // parse keyframes
+ 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();
+ m_keyframes[pos] = val;
+ }
+ update();
+ return;
+ }
+ }
+ if (!m_keyframes.isEmpty()) {
+ m_keyframes.clear();
+ update();
+ }
+}
+
+QString ClipItem::keyframes(const int index) {
+ QString result;
+ QDomElement effect = effectAt(index);
+ QDomNodeList params = effect.elementsByTagName("parameter");
+
+ for (int i = 0; i < params.count(); i++) {
+ QDomElement e = params.item(i).toElement();
+ if (!e.isNull() && e.attribute("type") == "keyframe") {
+ result = e.attribute("keyframes");
+ break;
+ }
+ }
+ return result;
+}
+
+void ClipItem::updateKeyframeEffect() {
+ // regenerate xml parameter from the clip keyframes
+ QDomElement effect = effectAt(m_selectedEffect);
+ if (effect.attribute("disabled") == "1") return;
+ QDomNodeList params = effect.elementsByTagName("parameter");
+
+ for (int i = 0; i < params.count(); i++) {
+ QDomElement e = params.item(i).toElement();
+ if (!e.isNull() && e.attribute("type") == "keyframe") {
+ QString keyframes;
+ if (m_keyframes.count() > 1) {
+ QMap<int, double>::const_iterator i = m_keyframes.constBegin();
+ double x1;
+ double y1;
+ while (i != m_keyframes.constEnd()) {
+ keyframes.append(QString::number(i.key()) + ":" + QString::number(i.value()) + ";");
+ ++i;
+ }
+ }
+ // Effect has a keyframe type parameter, we need to set the values
+ //kDebug() << "::::::::::::::: SETTING EFFECT KEYFRAMES: " << keyframes;
+ e.setAttribute("keyframes", keyframes);
+ break;
+ }
+ }
+}
+
+QDomElement ClipItem::selectedEffect() {
+ if (m_selectedEffect == -1 || m_effectList.isEmpty()) return QDomElement();
+ return effectAt(m_selectedEffect);