1 /***************************************************************************
2 effecstackedit.cpp - description
5 copyright : (C) 2008 by Marco Gittler
6 email : g.marco@freenet.de
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 ***************************************************************************/
18 #include "effectstackedit.h"
19 #include "ui_listval_ui.h"
20 #include "ui_boolval_ui.h"
21 #include "ui_wipeval_ui.h"
22 #include "ui_urlval_ui.h"
23 #include "complexparameter.h"
24 #include "geometryval.h"
25 #include "positionedit.h"
26 #include "projectlist.h"
27 #include "effectslist.h"
28 #include "kdenlivesettings.h"
29 #include "profilesdialog.h"
30 #include "kis_curve_widget.h"
31 #include "kis_cubic_curve.h"
32 #include "choosecolorwidget.h"
33 #include "geometrywidget.h"
34 #include "colortools.h"
35 #include "doubleparameterwidget.h"
36 #include "cornerswidget.h"
37 #include "beziercurve/beziersplinewidget.h"
39 #include "rotoscoping/rotowidget.h"
44 #include <KFileDialog>
45 #include <KColorScheme>
47 #include <QVBoxLayout>
49 #include <QPushButton>
51 #include <QScrollArea>
53 // For QDomNode debugging (output into files); leaving here as sample code.
57 class Boolval: public QWidget, public Ui::Boolval_UI
61 class Listval: public QWidget, public Ui::Listval_UI
65 class Wipeval: public QWidget, public Ui::Wipeval_UI
69 class Urlval: public QWidget, public Ui::Urlval_UI
73 QMap<QString, QImage> EffectStackEdit::iconCache;
75 EffectStackEdit::EffectStackEdit(Monitor *monitor, QWidget *parent) :
79 m_frameSize(QPoint()),
80 m_keyframeEditor(NULL),
83 m_baseWidget = new QWidget(this);
84 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
85 setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
86 setFrameStyle(QFrame::NoFrame);
87 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding));
89 QPalette p = palette();
90 KColorScheme scheme(p.currentColorGroup(), KColorScheme::View, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
91 QColor dark_bg = scheme.shade(KColorScheme::DarkShade);
92 QColor selected_bg = scheme.decoration(KColorScheme::FocusColor).color();
93 QColor hover_bg = scheme.decoration(KColorScheme::HoverColor).color();
94 QColor light_bg = scheme.shade(KColorScheme::LightShade);
95 QColor mid_bg = scheme.shade(KColorScheme::DarkShade);
97 QString stylesheet(QString("QProgressBar:horizontal {border: 1px solid %5;border-radius:0px;border-top-left-radius: 4px;border-bottom-left-radius: 4px;border-right: 0px;background:%4;padding: 0px;text-align:left center} QProgressBar:horizontal:hover {border: 1px solid %3;border-right: 0px;} QProgressBar::chunk:horizontal {background: %5;} QProgressBar::chunk:horizontal:hover {background: %3;} QProgressBar:horizontal[inTimeline=\"true\"] { border: 1px solid %2;border-right: 0px;background: %4;padding: 0px;text-align:left center } QProgressBar::chunk:horizontal[inTimeline=\"true\"] {background: %2;} QSpinBox {border: 1px solid %1;border-top-right-radius: 4px;border-bottom-right-radius: 4px;padding-right:0px;} QSpinBox::down-button {width:0px;padding:0px;} QSpinBox::up-button {width:0px;padding:0px;} QSpinBox[inTimeline=\"true\"]{ border: 1px solid %2;} QSpinBox:hover {border: 1px solid %3;} ").arg(dark_bg.name()).arg(selected_bg.name()).arg(hover_bg.name()).arg(light_bg.name()).arg(mid_bg.name()));
98 setStyleSheet(stylesheet);
100 setWidget(m_baseWidget);
101 setWidgetResizable(true);
102 m_vbox = new QVBoxLayout(m_baseWidget);
103 m_vbox->setContentsMargins(0, 0, 0, 0);
104 m_vbox->setSpacing(2);
107 EffectStackEdit::~EffectStackEdit()
113 void EffectStackEdit::setFrameSize(QPoint p)
116 QDomNodeList namenode = m_params.elementsByTagName("parameter");
117 for (int i = 0; i < namenode.count() ; i++) {
118 QDomNode pa = namenode.item(i);
119 QDomNode na = pa.firstChildElement("name");
120 QString type = pa.attributes().namedItem("type").nodeValue();
121 QString paramName = i18n(na.toElement().text().toUtf8().data());
123 if (type == "geometry" && !KdenliveSettings::on_monitor_effects()) {
124 Geometryval *geom = ((Geometryval*)m_valueItems[paramName+"geometry"]);
125 geom->setFrameSize(m_frameSize);
131 void EffectStackEdit::updateTimecodeFormat()
133 if (m_keyframeEditor)
134 m_keyframeEditor->updateTimecodeFormat();
136 QDomNodeList namenode = m_params.elementsByTagName("parameter");
137 for (int i = 0; i < namenode.count() ; i++) {
138 QDomNode pa = namenode.item(i);
139 QDomNode na = pa.firstChildElement("name");
140 QString type = pa.attributes().namedItem("type").nodeValue();
141 QString paramName = i18n(na.toElement().text().toUtf8().data());
143 if (type == "geometry") {
144 if (KdenliveSettings::on_monitor_effects()) {
145 GeometryWidget *geom = (GeometryWidget*)m_valueItems[paramName+"geometry"];
146 geom->updateTimecodeFormat();
148 Geometryval *geom = ((Geometryval*)m_valueItems[paramName+"geometry"]);
149 geom->updateTimecodeFormat();
153 if (type == "position") {
154 PositionEdit *posi = ((PositionEdit*)m_valueItems[paramName+"position"]);
155 posi->updateTimecodeFormat();
161 void EffectStackEdit::meetDependency(const QString& name, QString type, QString value)
163 if (type == "curve") {
164 KisCurveWidget *curve = (KisCurveWidget*)m_valueItems[name];
166 int color = value.toInt();
167 curve->setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(curve->size(), (ColorTools::ColorsRGB)(color == 3 ? 4 : color), 0.8)));
169 } else if (type == "bezier_spline") {
170 BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems[name];
172 widget->setMode((BezierSplineWidget::CurveModes)((int)(value.toDouble() * 10)));
177 void EffectStackEdit::updateProjectFormat(MltVideoProfile profile, Timecode t)
183 void EffectStackEdit::updateParameter(const QString &name, const QString &value)
185 m_params.setAttribute(name, value);
187 if (name == "disable") {
188 // if effect is disabled, disable parameters widget
189 bool enabled = value.toInt() == 0 || !KdenliveSettings::disable_effect_parameters();
191 emit effectStateChanged(enabled);
195 void EffectStackEdit::transferParamDesc(const QDomElement d, int pos, int in, int out, bool isEffect)
198 if (m_keyframeEditor) delete m_keyframeEditor;
199 m_keyframeEditor = NULL;
203 if (m_params.isNull()) {
204 kDebug() << "// EMPTY EFFECT STACK";
208 QDomNodeList namenode = m_params.elementsByTagName("parameter");
210 QFile debugFile("/tmp/namenodes.txt");
211 if (debugFile.open(QFile::WriteOnly | QFile::Truncate)) {
212 QTextStream out(&debugFile);
213 QTextStream out2(stdout);
214 for (int i = 0; i < namenode.size(); i++) {
216 namenode.at(i).save(out, 2);
218 namenode.at(i).save(out2, 2);
222 QDomElement e = m_params.toElement();
223 const int minFrame = e.attribute("start").toInt();
224 const int maxFrame = e.attribute("end").toInt();
226 bool disable = d.attribute("disable") == "1" && KdenliveSettings::disable_effect_parameters();
227 setEnabled(!disable);
232 for (int i = 0; i < namenode.count() ; i++) {
233 QDomElement pa = namenode.item(i).toElement();
234 QDomElement na = pa.firstChildElement("name");
235 QDomElement commentElem = pa.firstChildElement("comment");
236 QString type = pa.attribute("type");
237 QString paramName = i18n(na.text().toUtf8().data());
239 if (!commentElem.isNull())
240 comment = i18n(commentElem.text().toUtf8().data());
241 QWidget * toFillin = new QWidget(m_baseWidget);
242 QString value = pa.attribute("value").isNull() ?
243 pa.attribute("default") : pa.attribute("value");
245 /** Currently supported parameter types are:
246 * constant (=double): a slider with an integer value (use the "factor" attribute to divide the value so that you can get a double
247 * list: a combobox containing a list of values to choose
249 * complex: designed for keyframe parameters, but old and not finished, do not use
250 * geometry: a rectangle that can be moved & resized, with possible keyframes, used in composite transition
251 * keyframe: a list widget with a list of entries (position and value)
252 * color: a color chooser button
253 * position: a slider representing the position of a frame in the current clip
254 * curve: a single curve representing multiple points
255 * wipe: a widget designed for the wipe transition, allowing to choose a position (left, right, top,...)
258 if (type == "double" || type == "constant") {
261 if (pa.attribute("min").startsWith('%'))
262 min = (int) ProfilesDialog::getStringEval(m_profile, pa.attribute("min"));
264 min = pa.attribute("min").toInt();
265 if (pa.attribute("max").startsWith('%'))
266 max = (int) ProfilesDialog::getStringEval(m_profile, pa.attribute("max"));
268 max = pa.attribute("max").toInt();
270 DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, (int)(value.toDouble() + 0.5), min, max,
271 pa.attribute("default").toInt(), comment, -1, pa.attribute("suffix"), this);
272 m_vbox->addWidget(doubleparam);
273 m_valueItems[paramName] = doubleparam;
274 connect(doubleparam, SIGNAL(valueChanged(int)), this, SLOT(collectAllParameters()));
275 connect(this, SIGNAL(showComments(bool)), doubleparam, SLOT(slotShowComment(bool)));
276 } else if (type == "list") {
277 Listval *lsval = new Listval;
278 lsval->setupUi(toFillin);
279 QStringList listitems = pa.attribute("paramlist").split(',');
280 QDomElement list = pa.firstChildElement("paramlistdisplay");
281 QStringList listitemsdisplay;
282 if (!list.isNull()) listitemsdisplay = i18n(list.text().toUtf8().data()).split(',');
283 else listitemsdisplay = i18n(pa.attribute("paramlistdisplay").toUtf8().data()).split(',');
284 if (listitemsdisplay.count() != listitems.count())
285 listitemsdisplay = listitems;
286 lsval->list->setIconSize(QSize(30, 30));
287 for (int i = 0; i < listitems.count(); i++) {
288 lsval->list->addItem(listitemsdisplay.at(i), listitems.at(i));
289 QString entry = listitems.at(i);
290 if (!entry.isEmpty() && (entry.endsWith(".png") || entry.endsWith(".pgm"))) {
291 if (!EffectStackEdit::iconCache.contains(entry)) {
293 EffectStackEdit::iconCache[entry] = pix.scaled(30, 30);
295 lsval->list->setItemIcon(i, QPixmap::fromImage(iconCache[entry]));
298 if (!value.isEmpty()) lsval->list->setCurrentIndex(listitems.indexOf(value));
299 lsval->name->setText(paramName);
300 lsval->labelComment->setText(comment);
301 lsval->widgetComment->setHidden(true);
302 m_valueItems[paramName] = lsval;
303 connect(lsval->list, SIGNAL(currentIndexChanged(int)) , this, SLOT(collectAllParameters()));
304 if (!comment.isEmpty())
305 connect(this, SIGNAL(showComments(bool)), lsval->widgetComment, SLOT(setVisible(bool)));
306 m_uiItems.append(lsval);
307 } else if (type == "bool") {
308 Boolval *bval = new Boolval;
309 bval->setupUi(toFillin);
310 bval->checkBox->setCheckState(value == "0" ? Qt::Unchecked : Qt::Checked);
311 bval->name->setText(paramName);
312 bval->labelComment->setText(comment);
313 bval->widgetComment->setHidden(true);
314 m_valueItems[paramName] = bval;
315 connect(bval->checkBox, SIGNAL(stateChanged(int)) , this, SLOT(collectAllParameters()));
316 if (!comment.isEmpty())
317 connect(this, SIGNAL(showComments(bool)), bval->widgetComment, SLOT(setVisible(bool)));
318 m_uiItems.append(bval);
319 } else if (type == "complex") {
320 ComplexParameter *pl = new ComplexParameter;
321 pl->setupParam(d, pa.attribute("name"), 0, 100);
322 m_vbox->addWidget(pl);
323 m_valueItems[paramName+"complex"] = pl;
324 connect(pl, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
325 } else if (type == "geometry") {
326 if (KdenliveSettings::on_monitor_effects()) {
327 GeometryWidget *geometry = new GeometryWidget(m_monitor, m_timecode, pos, isEffect, this);
328 geometry->slotShowScene(!disable);
329 // connect this before setupParam to make sure the monitor scene shows up at startup
330 connect(geometry, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
331 connect(geometry, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
332 if (minFrame == maxFrame)
333 geometry->setupParam(pa, m_in, m_out);
335 geometry->setupParam(pa, minFrame, maxFrame);
336 m_vbox->addWidget(geometry);
337 m_valueItems[paramName+"geometry"] = geometry;
338 connect(geometry, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
339 connect(this, SIGNAL(syncEffectsPos(int)), geometry, SLOT(slotSyncPosition(int)));
340 connect(this, SIGNAL(effectStateChanged(bool)), geometry, SLOT(slotShowScene(bool)));
342 Geometryval *geo = new Geometryval(m_profile, m_timecode, m_frameSize, pos);
343 if (minFrame == maxFrame)
344 geo->setupParam(pa, m_in, m_out);
346 geo->setupParam(pa, minFrame, maxFrame);
347 m_vbox->addWidget(geo);
348 m_valueItems[paramName+"geometry"] = geo;
349 connect(geo, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
350 connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
351 connect(this, SIGNAL(syncEffectsPos(int)), geo, SLOT(slotSyncPosition(int)));
353 } else if (type == "keyframe" || type == "simplekeyframe") {
354 // keyframe editor widget
355 if (m_keyframeEditor == NULL) {
357 if (pa.attribute("widget") == "corners") {
358 // we want a corners-keyframe-widget
359 CornersWidget *corners = new CornersWidget(m_monitor, pa, m_in, m_in + m_out, m_timecode, e.attribute("active_keyframe", "-1").toInt(), this);
360 corners->slotShowScene(!disable);
361 connect(corners, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
362 connect(this, SIGNAL(effectStateChanged(bool)), corners, SLOT(slotShowScene(bool)));
363 connect(this, SIGNAL(syncEffectsPos(int)), corners, SLOT(slotSyncPosition(int)));
364 geo = static_cast<KeyframeEdit *>(corners);
366 geo = new KeyframeEdit(pa, m_in, m_in + m_out, m_timecode, e.attribute("active_keyframe", "-1").toInt());
368 m_vbox->addWidget(geo);
369 m_valueItems[paramName+"keyframe"] = geo;
370 m_keyframeEditor = geo;
371 connect(geo, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
372 connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
373 connect(this, SIGNAL(showComments(bool)), geo, SIGNAL(showComments(bool)));
375 // we already have a keyframe editor, so just add another column for the new param
376 m_keyframeEditor->addParameter(pa);
378 } else if (type == "color") {
379 if (value.startsWith('#'))
380 value = value.replace('#', "0x");
382 ChooseColorWidget *choosecolor = new ChooseColorWidget(paramName, QColor(value.toUInt(&ok, 16)), this);
383 m_vbox->addWidget(choosecolor);
384 m_valueItems[paramName] = choosecolor;
385 connect(choosecolor, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int)));
386 connect(choosecolor, SIGNAL(modified()) , this, SLOT(collectAllParameters()));
387 } else if (type == "position") {
388 int pos = value.toInt();
389 if (d.attribute("id") == "fadein" || d.attribute("id") == "fade_from_black") {
391 } else if (d.attribute("id") == "fadeout" || d.attribute("id") == "fade_to_black") {
392 // fadeout position starts from clip end
395 PositionEdit *posedit = new PositionEdit(paramName, pos, 0, m_out - m_in, m_timecode);
396 m_vbox->addWidget(posedit);
397 m_valueItems[paramName+"position"] = posedit;
398 connect(posedit, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
399 } else if (type == "curve") {
400 KisCurveWidget *curve = new KisCurveWidget(this);
401 curve->setMaxPoints(pa.attribute("max").toInt());
402 QList<QPointF> points;
403 int number = EffectsList::parameter(e, pa.attribute("number")).toInt();
404 QString inName = pa.attribute("inpoints");
405 QString outName = pa.attribute("outpoints");
406 int start = pa.attribute("min").toInt();
407 for (int j = start; j <= number; j++) {
409 in.replace("%i", QString::number(j));
410 QString out = outName;
411 out.replace("%i", QString::number(j));
412 points << QPointF(EffectsList::parameter(e, in).toDouble(), EffectsList::parameter(e, out).toDouble());
414 if (!points.isEmpty())
415 curve->setCurve(KisCubicCurve(points));
416 QSpinBox *spinin = new QSpinBox();
417 spinin->setRange(0, 1000);
418 QSpinBox *spinout = new QSpinBox();
419 spinout->setRange(0, 1000);
420 curve->setupInOutControls(spinin, spinout, 0, 1000);
421 m_vbox->addWidget(curve);
422 m_vbox->addWidget(spinin);
423 m_vbox->addWidget(spinout);
425 connect(curve, SIGNAL(modified()), this, SLOT(collectAllParameters()));
426 m_valueItems[paramName] = curve;
428 QString depends = pa.attribute("depends");
429 if (!depends.isEmpty())
430 meetDependency(paramName, type, EffectsList::parameter(e, depends));
431 } else if (type == "bezier_spline") {
432 BezierSplineWidget *widget = new BezierSplineWidget(value, this);
434 m_vbox->addWidget(widget);
435 m_valueItems[paramName] = widget;
436 connect(widget, SIGNAL(modified()), this, SLOT(collectAllParameters()));
437 QString depends = pa.attribute("depends");
438 if (!depends.isEmpty())
439 meetDependency(paramName, type, EffectsList::parameter(e, depends));
441 } else if (type == "roto-spline") {
442 RotoWidget *roto = new RotoWidget(value, m_monitor, m_in, m_out, this);
443 roto->slotShowScene(!disable);
444 connect(roto, SIGNAL(valueChanged()), this, SLOT(collectAllParameters()));
445 connect(roto, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
446 connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int)));
447 connect(this, SIGNAL(effectStateChanged(bool)), roto, SLOT(slotShowScene(bool)));
448 m_vbox->addWidget(roto);
449 m_valueItems[paramName] = roto;
451 } else if (type == "wipe") {
452 Wipeval *wpval = new Wipeval;
453 wpval->setupUi(toFillin);
454 wipeInfo w = getWipeInfo(value);
457 wpval->start_up->setChecked(true);
460 wpval->start_down->setChecked(true);
463 wpval->start_right->setChecked(true);
466 wpval->start_left->setChecked(true);
469 wpval->start_center->setChecked(true);
474 wpval->end_up->setChecked(true);
477 wpval->end_down->setChecked(true);
480 wpval->end_right->setChecked(true);
483 wpval->end_left->setChecked(true);
486 wpval->end_center->setChecked(true);
489 wpval->start_transp->setValue(w.startTransparency);
490 wpval->end_transp->setValue(w.endTransparency);
491 m_valueItems[paramName] = wpval;
492 connect(wpval->end_up, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
493 connect(wpval->end_down, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
494 connect(wpval->end_left, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
495 connect(wpval->end_right, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
496 connect(wpval->end_center, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
497 connect(wpval->start_up, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
498 connect(wpval->start_down, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
499 connect(wpval->start_left, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
500 connect(wpval->start_right, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
501 connect(wpval->start_center, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
502 connect(wpval->start_transp, SIGNAL(valueChanged(int)), this, SLOT(collectAllParameters()));
503 connect(wpval->end_transp, SIGNAL(valueChanged(int)), this, SLOT(collectAllParameters()));
504 //wpval->title->setTitle(na.toElement().text());
505 m_uiItems.append(wpval);
506 } else if (type == "url") {
507 Urlval *cval = new Urlval;
508 cval->setupUi(toFillin);
509 cval->label->setText(paramName);
510 cval->urlwidget->fileDialog()->setFilter(ProjectList::getExtensions());
511 m_valueItems[paramName] = cval;
512 cval->urlwidget->setUrl(KUrl(value));
513 connect(cval->urlwidget, SIGNAL(returnPressed()) , this, SLOT(collectAllParameters()));
514 connect(cval->urlwidget, SIGNAL(urlSelected(const KUrl&)) , this, SLOT(collectAllParameters()));
515 m_uiItems.append(cval);
522 m_vbox->addWidget(toFillin);
526 m_vbox->addStretch();
528 if (m_keyframeEditor)
529 m_keyframeEditor->checkVisibleParam();
531 // Make sure all doubleparam spinboxes have the same width, looks much better
532 QList<DoubleParameterWidget *> allWidgets = findChildren<DoubleParameterWidget *>();
534 for (int i = 0; i < allWidgets.count(); i++) {
535 if (minSize < allWidgets.at(i)->spinSize()) minSize = allWidgets.at(i)->spinSize();
537 for (int i = 0; i < allWidgets.count(); i++) {
538 allWidgets.at(i)->setSpinSize(minSize);
542 wipeInfo EffectStackEdit::getWipeInfo(QString value)
545 QString start = value.section(';', 0, 0);
546 QString end = value.section(';', 1, 1).section('=', 1, 1);
548 if (start.startsWith("-100%,0"))
550 else if (start.startsWith("100%,0"))
552 else if (start.startsWith("0%,100%"))
554 else if (start.startsWith("0%,-100%"))
559 if (start.count(':') == 2)
560 info.startTransparency = start.section(':', -1).toInt();
562 info.startTransparency = 100;
564 if (end.startsWith("-100%,0"))
566 else if (end.startsWith("100%,0"))
568 else if (end.startsWith("0%,100%"))
570 else if (end.startsWith("0%,-100%"))
575 if (end.count(':') == 2)
576 info.endTransparency = end.section(':', -1).toInt();
578 info.endTransparency = 100;
583 QString EffectStackEdit::getWipeString(wipeInfo info)
588 switch (info.start) {
590 start = "-100%,0%:100%x100%";
593 start = "100%,0%:100%x100%";
596 start = "0%,100%:100%x100%";
599 start = "0%,-100%:100%x100%";
602 start = "0%,0%:100%x100%";
605 start.append(':' + QString::number(info.startTransparency));
609 end = "-100%,0%:100%x100%";
612 end = "100%,0%:100%x100%";
615 end = "0%,100%:100%x100%";
618 end = "0%,-100%:100%x100%";
621 end = "0%,0%:100%x100%";
624 end.append(':' + QString::number(info.endTransparency));
625 return QString(start + ";-1=" + end);
628 void EffectStackEdit::collectAllParameters()
630 if (m_valueItems.isEmpty() || m_params.isNull()) return;
631 const QDomElement oldparam = m_params.cloneNode().toElement();
632 QDomElement newparam = oldparam.cloneNode().toElement();
633 QDomNodeList namenode = newparam.elementsByTagName("parameter");
635 for (int i = 0; i < namenode.count() ; i++) {
636 QDomNode pa = namenode.item(i);
637 QDomNode na = pa.firstChildElement("name");
638 QString type = pa.attributes().namedItem("type").nodeValue();
639 QString paramName = i18n(na.toElement().text().toUtf8().data());
640 if (type == "complex")
641 paramName.append("complex");
642 else if (type == "position")
643 paramName.append("position");
644 else if (type == "geometry")
645 paramName.append("geometry");
646 else if (type == "keyframe")
647 paramName.append("keyframe");
648 if (type != "simplekeyframe" && !m_valueItems.contains(paramName)) {
649 kDebug() << "// Param: " << paramName << " NOT FOUND";
654 if (type == "double" || type == "constant") {
655 DoubleParameterWidget *doubleparam = (DoubleParameterWidget*)m_valueItems.value(paramName);
656 setValue = QString::number(doubleparam->getValue());
657 } else if (type == "list") {
658 KComboBox *box = ((Listval*)m_valueItems.value(paramName))->list;
659 setValue = box->itemData(box->currentIndex()).toString();
660 } else if (type == "bool") {
661 QCheckBox *box = ((Boolval*)m_valueItems.value(paramName))->checkBox;
662 setValue = box->checkState() == Qt::Checked ? "1" : "0" ;
663 } else if (type == "color") {
664 ChooseColorWidget *choosecolor = ((ChooseColorWidget*)m_valueItems.value(paramName));
665 setValue = choosecolor->getColor().name();
666 } else if (type == "complex") {
667 ComplexParameter *complex = ((ComplexParameter*)m_valueItems.value(paramName));
668 namenode.item(i) = complex->getParamDesc();
669 } else if (type == "geometry") {
670 if (KdenliveSettings::on_monitor_effects()) {
671 GeometryWidget *geometry = ((GeometryWidget*)m_valueItems.value(paramName));
672 namenode.item(i).toElement().setAttribute("value", geometry->getValue());
674 Geometryval *geom = ((Geometryval*)m_valueItems.value(paramName));
675 namenode.item(i).toElement().setAttribute("value", geom->getValue());
677 } else if (type == "position") {
678 PositionEdit *pedit = ((PositionEdit*)m_valueItems.value(paramName));
679 int pos = pedit->getPosition();
680 setValue = QString::number(pos);
681 if (newparam.attribute("id") == "fadein" || newparam.attribute("id") == "fade_from_black") {
682 // Make sure duration is not longer than clip
685 pedit->setPosition(pos);
687 EffectsList::setParameter(newparam, "in", QString::number(m_in));
688 EffectsList::setParameter(newparam, "out", QString::number(m_in + pos));
690 } else if (newparam.attribute("id") == "fadeout" || newparam.attribute("id") == "fade_to_black") {
691 // Make sure duration is not longer than clip
694 pedit->setPosition(pos);
696 EffectsList::setParameter(newparam, "in", QString::number(m_out - pos));
697 EffectsList::setParameter(newparam, "out", QString::number(m_out));
700 } else if (type == "curve") {
701 KisCurveWidget *curve = ((KisCurveWidget*)m_valueItems.value(paramName));
702 QList<QPointF> points = curve->curve().points();
703 QString number = pa.attributes().namedItem("number").nodeValue();
704 QString inName = pa.attributes().namedItem("inpoints").nodeValue();
705 QString outName = pa.attributes().namedItem("outpoints").nodeValue();
706 int off = pa.attributes().namedItem("min").nodeValue().toInt();
707 int end = pa.attributes().namedItem("max").nodeValue().toInt();
708 EffectsList::setParameter(newparam, number, QString::number(points.count()));
709 for (int j = 0; (j < points.count() && j + off <= end); j++) {
711 in.replace("%i", QString::number(j + off));
712 QString out = outName;
713 out.replace("%i", QString::number(j + off));
714 EffectsList::setParameter(newparam, in, QString::number(points.at(j).x()));
715 EffectsList::setParameter(newparam, out, QString::number(points.at(j).y()));
717 QString depends = pa.attributes().namedItem("depends").nodeValue();
718 if (!depends.isEmpty())
719 meetDependency(paramName, type, EffectsList::parameter(newparam, depends));
720 } else if (type == "bezier_spline") {
721 BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems.value(paramName);
722 setValue = widget->spline();
723 QString depends = pa.attributes().namedItem("depends").nodeValue();
724 if (!depends.isEmpty())
725 meetDependency(paramName, type, EffectsList::parameter(newparam, depends));
727 } else if (type == "roto-spline") {
728 RotoWidget *widget = static_cast<RotoWidget *>(m_valueItems.value(paramName));
729 setValue = widget->getSpline();
731 } else if (type == "wipe") {
732 Wipeval *wp = (Wipeval*)m_valueItems.value(paramName);
734 if (wp->start_left->isChecked())
736 else if (wp->start_right->isChecked())
738 else if (wp->start_up->isChecked())
740 else if (wp->start_down->isChecked())
742 else if (wp->start_center->isChecked())
746 info.startTransparency = wp->start_transp->value();
748 if (wp->end_left->isChecked())
750 else if (wp->end_right->isChecked())
752 else if (wp->end_up->isChecked())
754 else if (wp->end_down->isChecked())
756 else if (wp->end_center->isChecked())
760 info.endTransparency = wp->end_transp->value();
762 setValue = getWipeString(info);
763 } else if ((type == "simplekeyframe" || type == "keyframe") && m_keyframeEditor) {
764 QDomElement elem = pa.toElement();
765 QString realName = i18n(na.toElement().text().toUtf8().data());
766 QString val = m_keyframeEditor->getValue(realName);
767 elem.setAttribute("keyframes", val);
769 if (m_keyframeEditor->isVisibleParam(realName))
770 elem.setAttribute("intimeline", "1");
771 else if (elem.hasAttribute("intimeline"))
772 elem.removeAttribute("intimeline");
773 } else if (type == "url") {
774 KUrlRequester *req = ((Urlval*)m_valueItems.value(paramName))->urlwidget;
775 setValue = req->url().path();
778 if (!setValue.isNull())
779 pa.attributes().namedItem("value").setNodeValue(setValue);
782 emit parameterChanged(oldparam, newparam);
785 void EffectStackEdit::clearAllItems()
788 m_valueItems.clear();
790 /*while (!m_items.isEmpty()) {
791 QWidget *die = m_items.takeFirst();
795 //qDeleteAll(m_uiItems);
797 while ((child = m_vbox->takeAt(0)) != 0) {
798 QWidget *wid = child->widget();
802 m_keyframeEditor = NULL;
806 void EffectStackEdit::slotSyncEffectsPos(int pos)
808 emit syncEffectsPos(pos);