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 "ui_keywordval_ui.h"
24 #include "ui_fontval_ui.h"
25 #include "complexparameter.h"
26 #include "geometryval.h"
27 #include "positionedit.h"
28 #include "projectlist.h"
29 #include "effectslist.h"
30 #include "kdenlivesettings.h"
31 #include "profilesdialog.h"
32 #include "kis_curve_widget.h"
33 #include "kis_cubic_curve.h"
34 #include "choosecolorwidget.h"
35 #include "geometrywidget.h"
36 #include "colortools.h"
37 #include "doubleparameterwidget.h"
38 #include "cornerswidget.h"
39 #include "beziercurve/beziersplinewidget.h"
41 #include "rotoscoping/rotowidget.h"
46 #include <KFileDialog>
48 #include <QVBoxLayout>
50 #include <QPushButton>
52 #include <QScrollArea>
54 #include <QProgressBar>
56 // For QDomNode debugging (output into files); leaving here as sample code.
60 class Boolval: public QWidget, public Ui::Boolval_UI
64 class Listval: public QWidget, public Ui::Listval_UI
68 class Wipeval: public QWidget, public Ui::Wipeval_UI
72 class Urlval: public QWidget, public Ui::Urlval_UI
76 class Keywordval: public QWidget, public Ui::Keywordval_UI
80 class Fontval: public QWidget, public Ui::Fontval_UI
84 QMap<QString, QImage> EffectStackEdit::iconCache;
86 EffectStackEdit::EffectStackEdit(Monitor *monitor, QWidget *parent) :
90 m_keyframeEditor(NULL),
92 m_geometryWidget(NULL),
95 m_baseWidget = new QWidget(this);
96 m_metaInfo.monitor = monitor;
97 m_metaInfo.trackMode = false;
98 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
99 setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
100 setFrameStyle(QFrame::NoFrame);
101 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding));
103 setStyleSheet(CollapsibleEffect::getStyleSheet());
104 setWidget(m_baseWidget);
105 /*m_vbox = new QVBoxLayout(m_baseWidget);
106 m_vbox->setContentsMargins(0, 0, 0, 0);
107 m_vbox->setSpacing(2); */
108 setWidgetResizable(true);
111 EffectStackEdit::~EffectStackEdit()
117 Monitor *EffectStackEdit::monitor()
119 return m_metaInfo.monitor;
122 void EffectStackEdit::updateProjectFormat(MltVideoProfile profile, Timecode t)
124 m_metaInfo.profile = profile;
125 m_metaInfo.timecode = t;
128 void EffectStackEdit::setFrameSize(QPoint p)
130 m_metaInfo.frameSize = p;
133 QDomNodeList namenode = m_params.elementsByTagName("parameter");
134 for (int i = 0; i < namenode.count() ; i++) {
135 QDomNode pa = namenode.item(i);
136 QDomElement na = pa.firstChildElement("name");
137 QString type = pa.attributes().namedItem("type").nodeValue();
138 QString paramName = na.isNull() ? pa.attributes().namedItem("name").nodeValue() : i18n(na.text().toUtf8().data());
140 if (type == "geometry") {
141 if (!KdenliveSettings::on_monitor_effects()) {
142 Geometryval *geom = ((Geometryval*)m_valueItems[paramName+"geometry"]);
143 geom->setFrameSize(m_frameSize);
147 if (m_geometryWidget) m_geometryWidget->setFrameSize(m_frameSize);
154 void EffectStackEdit::updateTimecodeFormat()
156 if (m_paramWidget) m_paramWidget->updateTimecodeFormat();
159 void EffectStackEdit::meetDependency(const QString& name, QString type, QString value)
161 if (type == "curve") {
162 KisCurveWidget *curve = (KisCurveWidget*)m_valueItems[name];
164 int color = value.toInt();
165 curve->setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(curve->size(), (ColorTools::ColorsRGB)(color == 3 ? 4 : color), 0.8)));
167 } else if (type == "bezier_spline") {
168 BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems[name];
170 widget->setMode((BezierSplineWidget::CurveModes)((int)(value.toDouble() * 10)));
175 void EffectStackEdit::updateParameter(const QString &name, const QString &value)
177 m_params.setAttribute(name, value);
179 if (name == "disable") {
180 // if effect is disabled, disable parameters widget
181 bool enabled = value.toInt() == 0 || !KdenliveSettings::disable_effect_parameters();
183 emit effectStateChanged(enabled);
187 bool EffectStackEdit::eventFilter( QObject * o, QEvent * e )
189 if (e->type() == QEvent::Wheel) {
190 QWheelEvent *we = static_cast<QWheelEvent *>(e);
191 bool filterWheel = verticalScrollBar() && verticalScrollBar()->isVisible();
192 if (!filterWheel || we->modifiers() != Qt::NoModifier) {
196 if (qobject_cast<QAbstractSpinBox*>(o)) {
197 if(qobject_cast<QAbstractSpinBox*>(o)->focusPolicy() == Qt::WheelFocus)
208 if (qobject_cast<KComboBox*>(o)) {
209 if(qobject_cast<KComboBox*>(o)->focusPolicy() == Qt::WheelFocus)
220 if (qobject_cast<QProgressBar*>(o)) {
221 if(qobject_cast<QProgressBar*>(o)->focusPolicy() == Qt::WheelFocus)
233 return QWidget::eventFilter(o, e);
236 void EffectStackEdit::transferParamDesc(const QDomElement &d, ItemInfo info, bool /*isEffect*/)
238 if (m_paramWidget) delete m_paramWidget;
239 m_paramWidget = new ParameterContainer(d, info, &m_metaInfo, m_baseWidget);
240 connect (m_paramWidget, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)), this, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)));
242 connect(m_paramWidget, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)), this, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)));
244 connect (this, SIGNAL(syncEffectsPos(int)), m_paramWidget, SIGNAL(syncEffectsPos(int)));
245 connect (m_paramWidget, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
246 connect (m_paramWidget, SIGNAL(seekTimeline(int)), this, SIGNAL(seekTimeline(int)));
249 Q_FOREACH( QSpinBox * sp, m_baseWidget->findChildren<QSpinBox*>() ) {
250 sp->installEventFilter( this );
251 sp->setFocusPolicy( Qt::StrongFocus );
253 Q_FOREACH( KComboBox * cb, m_baseWidget->findChildren<KComboBox*>() ) {
254 cb->installEventFilter( this );
255 cb->setFocusPolicy( Qt::StrongFocus );
257 Q_FOREACH( QProgressBar * cb, m_baseWidget->findChildren<QProgressBar*>() ) {
258 cb->installEventFilter( this );
259 cb->setFocusPolicy( Qt::StrongFocus );
265 if (m_keyframeEditor) delete m_keyframeEditor;
266 m_keyframeEditor = NULL;
268 m_in = isEffect ? info.cropStart.frames(KdenliveSettings::project_fps()) : info.startPos.frames(KdenliveSettings::project_fps());
269 m_out = isEffect ? (info.cropStart + info.cropDuration).frames(KdenliveSettings::project_fps()) - 1 : info.endPos.frames(KdenliveSettings::project_fps());
270 if (m_params.isNull()) {
271 // kDebug() << "// EMPTY EFFECT STACK";
275 QDomNodeList namenode = m_params.elementsByTagName("parameter");
277 QFile debugFile("/tmp/namenodes.txt");
278 if (debugFile.open(QFile::WriteOnly | QFile::Truncate)) {
279 QTextStream out(&debugFile);
280 QTextStream out2(stdout);
281 for (int i = 0; i < namenode.size(); i++) {
283 namenode.at(i).save(out, 2);
285 namenode.at(i).save(out2, 2);
289 int minFrame = d.attribute("start").toInt();
290 int maxFrame = d.attribute("end").toInt();
291 // In transitions, maxFrame is in fact one frame after the end of transition
292 if (maxFrame > 0) maxFrame --;
294 bool disable = d.attribute("disable") == "1" && KdenliveSettings::disable_effect_parameters();
295 setEnabled(!disable);
300 for (int i = 0; i < namenode.count() ; i++) {
301 QDomElement pa = namenode.item(i).toElement();
302 QDomElement na = pa.firstChildElement("name");
303 QDomElement commentElem = pa.firstChildElement("comment");
304 QString type = pa.attribute("type");
305 QString paramName = na.isNull() ? pa.attribute("name") : i18n(na.text().toUtf8().data());
307 if (!commentElem.isNull())
308 comment = i18n(commentElem.text().toUtf8().data());
309 QString value = pa.attribute("value").isNull() ?
310 pa.attribute("default") : pa.attribute("value");
315 if (type == "double" || type == "constant") {
318 if (pa.attribute("min").contains('%'))
319 min = ProfilesDialog::getStringEval(m_profile, pa.attribute("min"), m_frameSize);
321 min = pa.attribute("min").toDouble();
322 if (pa.attribute("max").contains('%'))
323 max = ProfilesDialog::getStringEval(m_profile, pa.attribute("max"), m_frameSize);
325 max = pa.attribute("max").toDouble();
327 DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, value.toDouble(), min, max,
328 pa.attribute("default").toDouble(), comment, -1, pa.attribute("suffix"), pa.attribute("decimals").toInt(), this);
329 m_vbox->addWidget(doubleparam);
330 m_valueItems[paramName] = doubleparam;
331 connect(doubleparam, SIGNAL(valueChanged(double)), this, SLOT(collectAllParameters()));
332 connect(this, SIGNAL(showComments(bool)), doubleparam, SLOT(slotShowComment(bool)));
333 } else if (type == "list") {
334 Listval *lsval = new Listval;
335 QWidget * toFillin = new QWidget(m_baseWidget);
336 lsval->setupUi(toFillin);
337 m_vbox->addWidget(toFillin);
338 QStringList listitems = pa.attribute("paramlist").split(';');
339 if (listitems.count() == 1) {
340 // probably custom effect created before change to ';' as separator
341 listitems = pa.attribute("paramlist").split(',');
343 QDomElement list = pa.firstChildElement("paramlistdisplay");
344 QStringList listitemsdisplay;
345 if (!list.isNull()) {
346 listitemsdisplay = i18n(list.text().toUtf8().data()).split(',');
348 listitemsdisplay = i18n(pa.attribute("paramlistdisplay").toUtf8().data()).split(',');
350 if (listitemsdisplay.count() != listitems.count())
351 listitemsdisplay = listitems;
352 lsval->list->setIconSize(QSize(30, 30));
353 for (int i = 0; i < listitems.count(); i++) {
354 lsval->list->addItem(listitemsdisplay.at(i), listitems.at(i));
355 QString entry = listitems.at(i);
356 if (!entry.isEmpty() && (entry.endsWith(".png") || entry.endsWith(".pgm"))) {
357 if (!EffectStackEdit::iconCache.contains(entry)) {
359 EffectStackEdit::iconCache[entry] = pix.scaled(30, 30);
361 lsval->list->setItemIcon(i, QPixmap::fromImage(iconCache[entry]));
364 if (!value.isEmpty()) lsval->list->setCurrentIndex(listitems.indexOf(value));
365 lsval->name->setText(paramName);
366 lsval->labelComment->setText(comment);
367 lsval->widgetComment->setHidden(true);
368 m_valueItems[paramName] = lsval;
369 connect(lsval->list, SIGNAL(currentIndexChanged(int)) , this, SLOT(collectAllParameters()));
370 if (!comment.isEmpty())
371 connect(this, SIGNAL(showComments(bool)), lsval->widgetComment, SLOT(setVisible(bool)));
372 m_uiItems.append(lsval);
373 } else if (type == "bool") {
374 Boolval *bval = new Boolval;
375 QWidget * toFillin = new QWidget(m_baseWidget);
376 bval->setupUi(toFillin);
377 m_vbox->addWidget(toFillin);
378 bval->checkBox->setCheckState(value == "0" ? Qt::Unchecked : Qt::Checked);
379 bval->name->setText(paramName);
380 bval->labelComment->setText(comment);
381 bval->widgetComment->setHidden(true);
382 m_valueItems[paramName] = bval;
383 connect(bval->checkBox, SIGNAL(stateChanged(int)) , this, SLOT(collectAllParameters()));
384 if (!comment.isEmpty())
385 connect(this, SIGNAL(showComments(bool)), bval->widgetComment, SLOT(setVisible(bool)));
386 m_uiItems.append(bval);
387 } else if (type == "complex") {
388 ComplexParameter *pl = new ComplexParameter;
389 pl->setupParam(d, pa.attribute("name"), 0, 100);
390 m_vbox->addWidget(pl);
391 m_valueItems[paramName+"complex"] = pl;
392 connect(pl, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
393 } else if (type == "geometry") {
394 if (KdenliveSettings::on_monitor_effects()) {
395 m_geometryWidget = new GeometryWidget(m_monitor, m_timecode, isEffect ? 0 : qMax(0, (int)info.startPos.frames(KdenliveSettings::project_fps())), isEffect, m_params.hasAttribute("showrotation"), this);
396 m_geometryWidget->setFrameSize(m_frameSize);
397 m_geometryWidget->slotShowScene(!disable);
398 // connect this before setupParam to make sure the monitor scene shows up at startup
399 connect(m_geometryWidget, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
400 connect(m_geometryWidget, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
401 if (minFrame == maxFrame)
402 m_geometryWidget->setupParam(pa, m_in, m_out);
404 m_geometryWidget->setupParam(pa, minFrame, maxFrame);
405 m_vbox->addWidget(m_geometryWidget);
406 m_valueItems[paramName+"geometry"] = m_geometryWidget;
407 connect(m_geometryWidget, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
408 connect(this, SIGNAL(syncEffectsPos(int)), m_geometryWidget, SLOT(slotSyncPosition(int)));
409 connect(this, SIGNAL(effectStateChanged(bool)), m_geometryWidget, SLOT(slotShowScene(bool)));
411 Geometryval *geo = new Geometryval(m_profile, m_timecode, m_frameSize, isEffect ? 0 : qMax(0, (int)info.startPos.frames(KdenliveSettings::project_fps())));
412 if (minFrame == maxFrame)
413 geo->setupParam(pa, m_in, m_out);
415 geo->setupParam(pa, minFrame, maxFrame);
416 m_vbox->addWidget(geo);
417 m_valueItems[paramName+"geometry"] = geo;
418 connect(geo, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
419 connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
420 connect(this, SIGNAL(syncEffectsPos(int)), geo, SLOT(slotSyncPosition(int)));
422 } else if (type == "addedgeometry") {
423 // this is a parameter that should be linked to the geometry widget, for example rotation, shear, ...
424 if (m_geometryWidget) m_geometryWidget->addParameter(pa);
425 } else if (type == "keyframe" || type == "simplekeyframe") {
426 // keyframe editor widget
427 if (m_keyframeEditor == NULL) {
429 if (pa.attribute("widget") == "corners") {
430 // we want a corners-keyframe-widget
431 CornersWidget *corners = new CornersWidget(m_monitor, pa, m_in, m_out, m_timecode, d.attribute("active_keyframe", "-1").toInt(), this);
432 corners->slotShowScene(!disable);
433 connect(corners, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
434 connect(this, SIGNAL(effectStateChanged(bool)), corners, SLOT(slotShowScene(bool)));
435 connect(this, SIGNAL(syncEffectsPos(int)), corners, SLOT(slotSyncPosition(int)));
436 geo = static_cast<KeyframeEdit *>(corners);
438 geo = new KeyframeEdit(pa, m_in, m_out, m_timecode, d.attribute("active_keyframe", "-1").toInt());
440 m_vbox->addWidget(geo);
441 m_valueItems[paramName+"keyframe"] = geo;
442 m_keyframeEditor = geo;
443 connect(geo, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
444 connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
445 connect(this, SIGNAL(showComments(bool)), geo, SIGNAL(showComments(bool)));
447 // we already have a keyframe editor, so just add another column for the new param
448 m_keyframeEditor->addParameter(pa);
450 } else if (type == "color") {
451 ChooseColorWidget *choosecolor = new ChooseColorWidget(paramName, value, this);
452 choosecolor->setAlphaChannelEnabled(pa.attribute("alpha") == "1");
453 m_vbox->addWidget(choosecolor);
454 m_valueItems[paramName] = choosecolor;
455 connect(choosecolor, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int)));
456 connect(choosecolor, SIGNAL(modified()) , this, SLOT(collectAllParameters()));
457 } else if (type == "position") {
458 int pos = value.toInt();
459 if (d.attribute("id") == "fadein" || d.attribute("id") == "fade_from_black") {
461 } else if (d.attribute("id") == "fadeout" || d.attribute("id") == "fade_to_black") {
462 // fadeout position starts from clip end
465 PositionEdit *posedit = new PositionEdit(paramName, pos, 0, m_out - m_in, m_timecode);
466 m_vbox->addWidget(posedit);
467 m_valueItems[paramName+"position"] = posedit;
468 connect(posedit, SIGNAL(parameterChanged()), this, SLOT(collectAllParameters()));
469 } else if (type == "curve") {
470 KisCurveWidget *curve = new KisCurveWidget(this);
471 curve->setMaxPoints(pa.attribute("max").toInt());
472 QList<QPointF> points;
474 if (d.attribute("version").toDouble() > 0.2) {
475 number = EffectsList::parameter(d, pa.attribute("number")).toDouble() * 10;
477 number = EffectsList::parameter(d, pa.attribute("number")).toInt();
479 QString inName = pa.attribute("inpoints");
480 QString outName = pa.attribute("outpoints");
481 int start = pa.attribute("min").toInt();
482 for (int j = start; j <= number; j++) {
484 in.replace("%i", QString::number(j));
485 QString out = outName;
486 out.replace("%i", QString::number(j));
487 points << QPointF(EffectsList::parameter(d, in).toDouble(), EffectsList::parameter(d, out).toDouble());
489 if (!points.isEmpty())
490 curve->setCurve(KisCubicCurve(points));
491 QSpinBox *spinin = new QSpinBox();
492 spinin->setRange(0, 1000);
493 QSpinBox *spinout = new QSpinBox();
494 spinout->setRange(0, 1000);
495 curve->setupInOutControls(spinin, spinout, 0, 1000);
496 m_vbox->addWidget(curve);
497 m_vbox->addWidget(spinin);
498 m_vbox->addWidget(spinout);
500 connect(curve, SIGNAL(modified()), this, SLOT(collectAllParameters()));
501 m_valueItems[paramName] = curve;
503 QString depends = pa.attribute("depends");
504 if (!depends.isEmpty())
505 meetDependency(paramName, type, EffectsList::parameter(d, depends));
506 } else if (type == "bezier_spline") {
507 BezierSplineWidget *widget = new BezierSplineWidget(value, this);
509 m_vbox->addWidget(widget);
510 m_valueItems[paramName] = widget;
511 connect(widget, SIGNAL(modified()), this, SLOT(collectAllParameters()));
512 QString depends = pa.attribute("depends");
513 if (!depends.isEmpty())
514 meetDependency(paramName, type, EffectsList::parameter(d, depends));
516 } else if (type == "roto-spline") {
517 RotoWidget *roto = new RotoWidget(value, m_monitor, info, m_timecode, this);
518 roto->slotShowScene(!disable);
519 connect(roto, SIGNAL(valueChanged()), this, SLOT(collectAllParameters()));
520 connect(roto, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
521 connect(roto, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
522 connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int)));
523 connect(this, SIGNAL(effectStateChanged(bool)), roto, SLOT(slotShowScene(bool)));
524 m_vbox->addWidget(roto);
525 m_valueItems[paramName] = roto;
527 } else if (type == "wipe") {
528 Wipeval *wpval = new Wipeval;
529 QWidget * toFillin = new QWidget(m_baseWidget);
530 wpval->setupUi(toFillin);
531 m_vbox->addWidget(toFillin);
532 wipeInfo w = getWipeInfo(value);
535 wpval->start_up->setChecked(true);
538 wpval->start_down->setChecked(true);
541 wpval->start_right->setChecked(true);
544 wpval->start_left->setChecked(true);
547 wpval->start_center->setChecked(true);
552 wpval->end_up->setChecked(true);
555 wpval->end_down->setChecked(true);
558 wpval->end_right->setChecked(true);
561 wpval->end_left->setChecked(true);
564 wpval->end_center->setChecked(true);
567 wpval->start_transp->setValue(w.startTransparency);
568 wpval->end_transp->setValue(w.endTransparency);
569 m_valueItems[paramName] = wpval;
570 connect(wpval->end_up, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
571 connect(wpval->end_down, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
572 connect(wpval->end_left, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
573 connect(wpval->end_right, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
574 connect(wpval->end_center, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
575 connect(wpval->start_up, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
576 connect(wpval->start_down, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
577 connect(wpval->start_left, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
578 connect(wpval->start_right, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
579 connect(wpval->start_center, SIGNAL(clicked()), this, SLOT(collectAllParameters()));
580 connect(wpval->start_transp, SIGNAL(valueChanged(int)), this, SLOT(collectAllParameters()));
581 connect(wpval->end_transp, SIGNAL(valueChanged(int)), this, SLOT(collectAllParameters()));
582 //wpval->title->setTitle(na.toElement().text());
583 m_uiItems.append(wpval);
584 } else if (type == "url") {
585 Urlval *cval = new Urlval;
586 QWidget * toFillin = new QWidget(m_baseWidget);
587 cval->setupUi(toFillin);
588 m_vbox->addWidget(toFillin);
589 cval->label->setText(paramName);
590 cval->urlwidget->fileDialog()->setFilter(ProjectList::getExtensions());
591 m_valueItems[paramName] = cval;
592 cval->urlwidget->setUrl(KUrl(value));
593 connect(cval->urlwidget, SIGNAL(returnPressed()) , this, SLOT(collectAllParameters()));
594 connect(cval->urlwidget, SIGNAL(urlSelected(const KUrl&)) , this, SLOT(collectAllParameters()));
595 m_uiItems.append(cval);
596 } else if (type == "keywords") {
597 Keywordval* kval = new Keywordval;
598 QWidget * toFillin = new QWidget(m_baseWidget);
599 kval->setupUi(toFillin);
600 m_vbox->addWidget(toFillin);
601 kval->label->setText(paramName);
602 kval->lineeditwidget->setText(value);
603 QDomElement klistelem = pa.firstChildElement("keywords");
604 QDomElement kdisplaylistelem = pa.firstChildElement("keywordsdisplay");
605 QStringList keywordlist;
606 QStringList keyworddisplaylist;
607 if (!klistelem.isNull()) {
608 keywordlist = klistelem.text().split(';');
609 keyworddisplaylist = i18n(kdisplaylistelem.text().toUtf8().data()).split(';');
611 if (keyworddisplaylist.count() != keywordlist.count()) {
612 keyworddisplaylist = keywordlist;
614 for (int i = 0; i < keywordlist.count(); i++) {
615 kval->comboboxwidget->addItem(keyworddisplaylist.at(i), keywordlist.at(i));
617 // Add disabled user prompt at index 0
618 kval->comboboxwidget->insertItem(0, i18n("<select a keyword>"), "");
619 kval->comboboxwidget->model()->setData( kval->comboboxwidget->model()->index(0,0), QVariant(Qt::NoItemFlags), Qt::UserRole -1);
620 kval->comboboxwidget->setCurrentIndex(0);
621 m_valueItems[paramName] = kval;
622 connect(kval->lineeditwidget, SIGNAL(editingFinished()) , this, SLOT(collectAllParameters()));
623 connect(kval->comboboxwidget, SIGNAL(activated (const QString&)), this, SLOT(collectAllParameters()));
624 m_uiItems.append(kval);
625 } else if (type == "fontfamily") {
626 Fontval* fval = new Fontval;
627 QWidget * toFillin = new QWidget(m_baseWidget);
628 fval->setupUi(toFillin);
629 m_vbox->addWidget(toFillin);
630 fval->name->setText(paramName);
631 fval->fontfamilywidget->setCurrentFont(QFont(value));
632 m_valueItems[paramName] = fval;
633 connect(fval->fontfamilywidget, SIGNAL(currentFontChanged(const QFont &)), this, SLOT(collectAllParameters())) ;
634 m_uiItems.append(fval);
635 } else if (type == "filterjob") {
636 QPushButton *button = new QPushButton(paramName, m_baseWidget);
637 m_vbox->addWidget(button);
638 m_valueItems[paramName] = button;
639 connect(button, SIGNAL(pressed()), this, SLOT(slotStartFilterJobAction()));
644 m_vbox->addStretch();
646 if (m_keyframeEditor)
647 m_keyframeEditor->checkVisibleParam();
649 // Make sure all doubleparam spinboxes have the same width, looks much better
650 QList<DoubleParameterWidget *> allWidgets = findChildren<DoubleParameterWidget *>();
652 for (int i = 0; i < allWidgets.count(); i++) {
653 if (minSize < allWidgets.at(i)->spinSize()) minSize = allWidgets.at(i)->spinSize();
655 for (int i = 0; i < allWidgets.count(); i++) {
656 allWidgets.at(i)->setSpinSize(minSize);
660 void EffectStackEdit::collectAllParameters()
663 if (m_valueItems.isEmpty() || m_params.isNull()) return;
664 const QDomElement oldparam = m_params.cloneNode().toElement();
665 QDomElement newparam = oldparam.cloneNode().toElement();
666 QDomNodeList namenode = newparam.elementsByTagName("parameter");
669 for (int i = 0; i < namenode.count() ; i++) {
670 QDomNode pa = namenode.item(i);
671 QDomElement na = pa.firstChildElement("name");
672 QString type = pa.attributes().namedItem("type").nodeValue();
673 QString paramName = na.isNull() ? pa.attributes().namedItem("name").nodeValue() : i18n(na.text().toUtf8().data());
674 if (type == "complex")
675 paramName.append("complex");
676 else if (type == "position")
677 paramName.append("position");
678 else if (type == "geometry")
679 paramName.append("geometry");
680 else if (type == "keyframe")
681 paramName.append("keyframe");
682 if (type != "simplekeyframe" && type != "fixed" && type != "addedgeometry" && !m_valueItems.contains(paramName)) {
683 kDebug() << "// Param: " << paramName << " NOT FOUND";
688 if (type == "double" || type == "constant") {
689 DoubleParameterWidget *doubleparam = (DoubleParameterWidget*)m_valueItems.value(paramName);
690 setValue = locale.toString(doubleparam->getValue());
691 } else if (type == "list") {
692 KComboBox *box = ((Listval*)m_valueItems.value(paramName))->list;
693 setValue = box->itemData(box->currentIndex()).toString();
694 } else if (type == "bool") {
695 QCheckBox *box = ((Boolval*)m_valueItems.value(paramName))->checkBox;
696 setValue = box->checkState() == Qt::Checked ? "1" : "0" ;
697 } else if (type == "color") {
698 ChooseColorWidget *choosecolor = ((ChooseColorWidget*)m_valueItems.value(paramName));
699 setValue = choosecolor->getColor();
700 } else if (type == "complex") {
701 ComplexParameter *complex = ((ComplexParameter*)m_valueItems.value(paramName));
702 namenode.item(i) = complex->getParamDesc();
703 } else if (type == "geometry") {
704 if (KdenliveSettings::on_monitor_effects()) {
705 if (m_geometryWidget) namenode.item(i).toElement().setAttribute("value", m_geometryWidget->getValue());
707 Geometryval *geom = ((Geometryval*)m_valueItems.value(paramName));
708 namenode.item(i).toElement().setAttribute("value", geom->getValue());
710 } else if (type == "addedgeometry") {
711 namenode.item(i).toElement().setAttribute("value", m_geometryWidget->getExtraValue(namenode.item(i).toElement().attribute("name")));
712 } else if (type == "position") {
713 PositionEdit *pedit = ((PositionEdit*)m_valueItems.value(paramName));
714 int pos = pedit->getPosition();
715 setValue = QString::number(pos);
716 if (newparam.attribute("id") == "fadein" || newparam.attribute("id") == "fade_from_black") {
717 // Make sure duration is not longer than clip
719 EffectsList::setParameter(newparam, "in", QString::number(m_in));
720 EffectsList::setParameter(newparam, "out", QString::number(m_in + pos));
722 } else if (newparam.attribute("id") == "fadeout" || newparam.attribute("id") == "fade_to_black") {
723 // Make sure duration is not longer than clip
725 EffectsList::setParameter(newparam, "in", QString::number(m_out - pos));
726 EffectsList::setParameter(newparam, "out", QString::number(m_out));
729 } else if (type == "curve") {
730 KisCurveWidget *curve = ((KisCurveWidget*)m_valueItems.value(paramName));
731 QList<QPointF> points = curve->curve().points();
732 QString number = pa.attributes().namedItem("number").nodeValue();
733 QString inName = pa.attributes().namedItem("inpoints").nodeValue();
734 QString outName = pa.attributes().namedItem("outpoints").nodeValue();
735 int off = pa.attributes().namedItem("min").nodeValue().toInt();
736 int end = pa.attributes().namedItem("max").nodeValue().toInt();
737 if (oldparam.attribute("version").toDouble() > 0.2) {
738 EffectsList::setParameter(newparam, number, locale.toString(points.count() / 10.));
740 EffectsList::setParameter(newparam, number, QString::number(points.count()));
742 for (int j = 0; (j < points.count() && j + off <= end); j++) {
744 in.replace("%i", QString::number(j + off));
745 QString out = outName;
746 out.replace("%i", QString::number(j + off));
747 EffectsList::setParameter(newparam, in, locale.toString(points.at(j).x()));
748 EffectsList::setParameter(newparam, out, locale.toString(points.at(j).y()));
750 QString depends = pa.attributes().namedItem("depends").nodeValue();
751 if (!depends.isEmpty())
752 meetDependency(paramName, type, EffectsList::parameter(newparam, depends));
753 } else if (type == "bezier_spline") {
754 BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems.value(paramName);
755 setValue = widget->spline();
756 QString depends = pa.attributes().namedItem("depends").nodeValue();
757 if (!depends.isEmpty())
758 meetDependency(paramName, type, EffectsList::parameter(newparam, depends));
760 } else if (type == "roto-spline") {
761 RotoWidget *widget = static_cast<RotoWidget *>(m_valueItems.value(paramName));
762 setValue = widget->getSpline();
764 } else if (type == "wipe") {
765 Wipeval *wp = (Wipeval*)m_valueItems.value(paramName);
767 if (wp->start_left->isChecked())
769 else if (wp->start_right->isChecked())
771 else if (wp->start_up->isChecked())
773 else if (wp->start_down->isChecked())
775 else if (wp->start_center->isChecked())
779 info.startTransparency = wp->start_transp->value();
781 if (wp->end_left->isChecked())
783 else if (wp->end_right->isChecked())
785 else if (wp->end_up->isChecked())
787 else if (wp->end_down->isChecked())
789 else if (wp->end_center->isChecked())
793 info.endTransparency = wp->end_transp->value();
795 setValue = getWipeString(info);
796 } else if ((type == "simplekeyframe" || type == "keyframe") && m_keyframeEditor) {
797 QDomElement elem = pa.toElement();
798 QString realName = i18n(na.toElement().text().toUtf8().data());
799 QString val = m_keyframeEditor->getValue(realName);
800 elem.setAttribute("keyframes", val);
802 if (m_keyframeEditor->isVisibleParam(realName))
803 elem.setAttribute("intimeline", "1");
804 else if (elem.hasAttribute("intimeline"))
805 elem.removeAttribute("intimeline");
806 } else if (type == "url") {
807 KUrlRequester *req = ((Urlval*)m_valueItems.value(paramName))->urlwidget;
808 setValue = req->url().path();
809 } else if (type == "keywords"){
810 QLineEdit *line = ((Keywordval*)m_valueItems.value(paramName))->lineeditwidget;
811 QComboBox *combo = ((Keywordval*)m_valueItems.value(paramName))->comboboxwidget;
812 if(combo->currentIndex())
814 QString comboval = combo->itemData(combo->currentIndex()).toString();
815 line->insert(comboval);
816 combo->setCurrentIndex(0);
818 setValue = line->text();
819 } else if (type == "fontfamily") {
820 QFontComboBox* fontfamily = ((Fontval*)m_valueItems.value(paramName))->fontfamilywidget;
821 setValue = fontfamily->currentFont().family();
824 if (!setValue.isNull())
825 pa.attributes().namedItem("value").setNodeValue(setValue);
828 emit parameterChanged(oldparam, newparam);*/
831 void EffectStackEdit::clearAllItems()
834 m_valueItems.clear();
836 /*while (!m_items.isEmpty()) {
837 QWidget *die = m_items.takeFirst();
841 //qDeleteAll(m_uiItems);
843 while ((child = m_vbox->takeAt(0)) != 0) {
844 QWidget *wid = child->widget();
848 m_keyframeEditor = NULL;
849 m_geometryWidget = NULL;
853 void EffectStackEdit::slotSyncEffectsPos(int pos)
855 emit syncEffectsPos(pos);
858 void EffectStackEdit::slotStartFilterJobAction()
860 QDomNodeList namenode = m_params.elementsByTagName("parameter");
861 for (int i = 0; i < namenode.count() ; i++) {
862 QDomElement pa = namenode.item(i).toElement();
863 QString type = pa.attribute("type");
864 if (type == "filterjob") {
865 emit startFilterJob(pa.attribute("filtertag"), pa.attribute("filterparams"), pa.attribute("finalfilter"), pa.attribute("consumer"), pa.attribute("consumerparams"), pa.attribute("wantedproperties"));
866 kDebug()<<" - - -PROPS:\n"<<pa.attribute("filtertag")<<"-"<< pa.attribute("filterparams")<<"-"<< pa.attribute("consumer")<<"-"<< pa.attribute("consumerparams")<<"-"<< pa.attribute("wantedproperties");