X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Feffectstack%2Fcollapsibleeffect.cpp;h=1bf090612d4c4896d08fcf79f8698c61977df6e7;hb=5d4746e4c3e8665de83e6d281dcd08a46cd22c31;hp=c23a9e36b1c01037497097dddd3fc684a4687cb4;hpb=e13c3ee236eede63a25c7db67ecf6045e2dff9b9;p=kdenlive diff --git a/src/effectstack/collapsibleeffect.cpp b/src/effectstack/collapsibleeffect.cpp index c23a9e36..1bf09061 100644 --- a/src/effectstack/collapsibleeffect.cpp +++ b/src/effectstack/collapsibleeffect.cpp @@ -19,130 +19,55 @@ #include "collapsibleeffect.h" - -#include "ui_listval_ui.h" -#include "ui_boolval_ui.h" -#include "ui_wipeval_ui.h" -#include "ui_urlval_ui.h" -#include "ui_keywordval_ui.h" -#include "ui_fontval_ui.h" -#include "complexparameter.h" -#include "geometryval.h" -#include "positionedit.h" -#include "projectlist.h" #include "effectslist.h" #include "kdenlivesettings.h" -#include "profilesdialog.h" -#include "kis_curve_widget.h" -#include "kis_cubic_curve.h" -#include "choosecolorwidget.h" -#include "geometrywidget.h" -#include "colortools.h" -#include "doubleparameterwidget.h" -#include "cornerswidget.h" -#include "dragvalue.h" -#include "beziercurve/beziersplinewidget.h" -#ifdef USE_QJSON -#include "rotoscoping/rotowidget.h" -#endif +#include "projectlist.h" #include #include #include #include +#include +#include +#include + #include +#include #include -#include +#include #include #include #include -#include - -class Boolval: public QWidget, public Ui::Boolval_UI -{ -}; - -class Listval: public QWidget, public Ui::Listval_UI -{ -}; - -class Wipeval: public QWidget, public Ui::Wipeval_UI -{ -}; - -class Urlval: public QWidget, public Ui::Urlval_UI -{ -}; +#include -class Keywordval: public QWidget, public Ui::Keywordval_UI -{ -}; - -class Fontval: public QWidget, public Ui::Fontval_UI -{ -}; -QMap CollapsibleEffect::iconCache; - -void clearLayout(QLayout *layout) +CollapsibleEffect::CollapsibleEffect(const QDomElement &effect, const QDomElement &original_effect, const ItemInfo &info, EffectMetaInfo *metaInfo, bool lastEffect, QWidget * parent) : + AbstractCollapsibleWidget(parent), + m_paramWidget(NULL), + m_effect(effect), + m_original_effect(original_effect), + m_lastEffect(lastEffect), + m_regionEffect(false) { - QLayoutItem *item; - while((item = layout->takeAt(0))) { - if (item->layout()) { - clearLayout(item->layout()); - delete item->layout(); - } - if (item->widget()) { - delete item->widget(); - } - delete item; + if (m_effect.attribute("tag") == "region") { + m_regionEffect = true; + decoframe->setObjectName("decoframegroup"); } -} - -MySpinBox::MySpinBox(QWidget * parent): - QSpinBox(parent) -{ - setFocusPolicy(Qt::StrongFocus); -} - -void MySpinBox::focusInEvent(QFocusEvent*) -{ - setFocusPolicy(Qt::WheelFocus); -} - -void MySpinBox::focusOutEvent(QFocusEvent*) -{ - setFocusPolicy(Qt::StrongFocus); -} - - -CollapsibleEffect::CollapsibleEffect(QDomElement effect, QDomElement original_effect, ItemInfo info, int ix, EffectMetaInfo *metaInfo, bool lastEffect, bool isGroup, QWidget * parent) : - QWidget(parent), - m_paramWidget(NULL), - m_effect(effect), - m_original_effect(original_effect), - m_lastEffect(lastEffect), - m_isGroup(isGroup), - m_active(false) -{ - //setMouseTracking(true); - setupUi(this); - frame->setBackgroundRole(QPalette::Midlight); - frame->setAutoFillBackground(true); + filterWheelEvent = true; + m_info.fromString(effect.attribute("kdenlive_info")); setFont(KGlobalSettings::smallestReadableFont()); - - buttonUp->setIcon(KIcon("go-up")); + buttonUp->setIcon(KIcon("kdenlive-up")); buttonUp->setToolTip(i18n("Move effect up")); if (!lastEffect) { - buttonDown->setIcon(KIcon("go-down")); + buttonDown->setIcon(KIcon("kdenlive-down")); buttonDown->setToolTip(i18n("Move effect down")); } - buttonDel->setIcon(KIcon("edit-delete")); + buttonDel->setIcon(KIcon("kdenlive-deleffect")); buttonDel->setToolTip(i18n("Delete effect")); - - buttonUp->setVisible(false); - buttonDown->setVisible(false); - buttonDel->setVisible(false); + if (effectIndex() == 1) buttonUp->setVisible(false); + if (m_lastEffect) buttonDown->setVisible(false); + //buttonUp->setVisible(false); + //buttonDown->setVisible(false); /*buttonReset->setIcon(KIcon("view-refresh")); buttonReset->setToolTip(i18n("Reset effect"));*/ @@ -150,41 +75,56 @@ CollapsibleEffect::CollapsibleEffect(QDomElement effect, QDomElement original_ef //buttonShowComments->setIcon(KIcon("help-about")); //buttonShowComments->setToolTip(i18n("Show additional information for the parameters")); m_menu = new QMenu; - m_menu->addAction(KIcon("view-refresh"), i18n("Reset effect"), this, SLOT(slotResetEffect())); - m_menu->addAction(KIcon("document-save"), i18n("Save effect"), this, SLOT(slotSaveEffect())); + m_menu->addAction(KIcon("view-refresh"), i18n("Reset Effect"), this, SLOT(slotResetEffect())); + m_menu->addAction(KIcon("document-save"), i18n("Save Effect"), this, SLOT(slotSaveEffect())); - if (!m_isGroup) { - QDomElement namenode = m_effect.firstChildElement("name"); - if (namenode.isNull()) return; - title->setText(i18n(namenode.text().toUtf8().data())); - QString type = m_effect.attribute("type", QString()); - KIcon icon; - if (type == "audio") icon = KIcon("kdenlive-show-audio"); - else if (m_effect.attribute("tag") == "region") icon = KIcon("kdenlive-mask-effect"); - else if (type == "custom") icon = KIcon("kdenlive-custom-effect"); - else icon = KIcon("kdenlive-show-video"); - title->setIcon(icon); - m_menu->addAction(KIcon("folder-new"), i18n("Create Group"), this, SLOT(slotCreateGroup())); - setupWidget(info, ix, metaInfo); + QHBoxLayout *l = static_cast (frame->layout()); + title = new QLabel(this); + l->insertWidget(2, title); + + m_groupAction = new QAction(KIcon("folder-new"), i18n("Create Group"), this); + connect(m_groupAction, SIGNAL(triggered(bool)), this, SLOT(slotCreateGroup())); + + QDomElement namenode = m_effect.firstChildElement("name"); + if (namenode.isNull()) { + // Warning, broken effect? + kDebug()<<"// Could not create effect"; + return; } - else { - setAcceptDrops(true); - title->setText(i18n("Effect Group")); - title->setIcon(KIcon("folder")); + QString effectname = i18n(namenode.text().toUtf8().data()); + if (m_regionEffect) effectname.append(':' + KUrl(EffectsList::parameter(m_effect, "resource")).fileName()); + title->setText(effectname); + /* + * Do not show icon, makes too much visual noise + QString type = m_effect.attribute("type", QString()); + KIcon icon; + if (type == "audio") icon = KIcon("kdenlive-show-audio"); + else if (m_effect.attribute("tag") == "region") icon = KIcon("kdenlive-mask-effect"); + else if (type == "custom") icon = KIcon("kdenlive-custom-effect"); + else icon = KIcon("kdenlive-show-video"); + effecticon->setPixmap(icon.pixmap(16,16));*/ + + if (!m_regionEffect) { + if (m_info.groupIndex == -1) m_menu->addAction(m_groupAction); + m_menu->addAction(KIcon("folder-new"), i18n("Create Region"), this, SLOT(slotCreateRegion())); } - - title->setMenu(m_menu); + setupWidget(info, metaInfo); + setAcceptDrops(true); + menuButton->setIcon(KIcon("kdenlive-menu")); + menuButton->setMenu(m_menu); if (m_effect.attribute("disable") == "1") { - enabledBox->setCheckState(Qt::Unchecked); title->setEnabled(false); + enabledButton->setChecked(true); + enabledButton->setIcon(KIcon("novisible")); } else { - enabledBox->setCheckState(Qt::Checked); + enabledButton->setChecked(false); + enabledButton->setIcon(KIcon("visible")); } connect(collapseButton, SIGNAL(clicked()), this, SLOT(slotSwitch())); - connect(enabledBox, SIGNAL(toggled(bool)), this, SLOT(slotEnable(bool))); + connect(enabledButton, SIGNAL(toggled(bool)), this, SLOT(slotDisable(bool))); connect(buttonUp, SIGNAL(clicked()), this, SLOT(slotEffectUp())); connect(buttonDown, SIGNAL(clicked()), this, SLOT(slotEffectDown())); connect(buttonDel, SIGNAL(clicked()), this, SLOT(slotDeleteEffect())); @@ -194,70 +134,94 @@ CollapsibleEffect::CollapsibleEffect(QDomElement effect, QDomElement original_ef sp->setFocusPolicy( Qt::StrongFocus ); } Q_FOREACH( KComboBox * cb, findChildren() ) { - cb->installEventFilter( this ); + cb->installEventFilter( this ); cb->setFocusPolicy( Qt::StrongFocus ); } Q_FOREACH( QProgressBar * cb, findChildren() ) { - cb->installEventFilter( this ); + cb->installEventFilter( this ); cb->setFocusPolicy( Qt::StrongFocus ); } } CollapsibleEffect::~CollapsibleEffect() { - if (m_paramWidget) delete m_paramWidget; + delete m_paramWidget; delete m_menu; } void CollapsibleEffect::slotCreateGroup() { - emit createGroup(m_paramWidget->index()); + emit createGroup(effectIndex()); +} + +void CollapsibleEffect::slotCreateRegion() +{ + QString allExtensions = ProjectList::getExtensions(); + const QString dialogFilter = allExtensions + ' ' + QLatin1Char('|') + i18n("All Supported Files") + "\n* " + QLatin1Char('|') + i18n("All Files"); + QPointer d = new KFileDialog(KUrl("kfiledialog:///clipfolder"), dialogFilter, kapp->activeWindow()); + d->setOperationMode(KFileDialog::Opening); + d->setMode(KFile::File); + if (d->exec() == QDialog::Accepted) { + KUrl url = d->selectedUrl(); + if (!url.isEmpty()) emit createRegion(effectIndex(), url); + } + delete d; +} + +void CollapsibleEffect::slotUnGroup() +{ + emit unGroup(this); } bool CollapsibleEffect::eventFilter( QObject * o, QEvent * e ) { + if (e->type() == QEvent::Enter) { + frame->setProperty("mouseover", true); + frame->setStyleSheet(frame->styleSheet()); + return QWidget::eventFilter(o, e); + } if (e->type() == QEvent::Wheel) { - QWheelEvent *we = static_cast(e); - if (we->modifiers() != Qt::NoModifier) { - e->accept(); - return false; - } - if (qobject_cast(o)) { - if(qobject_cast(o)->focusPolicy() == Qt::WheelFocus) - { - e->accept(); - return false; - } - else - { - e->ignore(); - return true; - } - } - if (qobject_cast(o)) { - if(qobject_cast(o)->focusPolicy() == Qt::WheelFocus) - { - e->accept(); - return false; - } - else - { - e->ignore(); - return true; - } - } - if (qobject_cast(o)) { - if(qobject_cast(o)->focusPolicy() == Qt::WheelFocus) - { - e->accept(); - return false; - } - else - { - e->ignore(); - return true; - } - } + QWheelEvent *we = static_cast(e); + if (!filterWheelEvent || we->modifiers() != Qt::NoModifier) { + e->accept(); + return false; + } + if (qobject_cast(o)) { + if(qobject_cast(o)->focusPolicy() == Qt::WheelFocus) + { + e->accept(); + return false; + } + else + { + e->ignore(); + return true; + } + } + if (qobject_cast(o)) { + if(qobject_cast(o)->focusPolicy() == Qt::WheelFocus) + { + e->accept(); + return false; + } + else + { + e->ignore(); + return true; + } + } + if (qobject_cast(o)) { + if(qobject_cast(o)->focusPolicy() == Qt::WheelFocus) + { + e->accept(); + return false; + } + else + { + e->ignore(); + return true; + } + } } return QWidget::eventFilter(o, e); } @@ -267,67 +231,59 @@ QDomElement CollapsibleEffect::effect() const return m_effect; } -void CollapsibleEffect::setActive(bool activate) -{ - m_active = activate; - frame->setBackgroundRole(m_active ? QPalette::Mid : QPalette::Midlight); - frame->setAutoFillBackground(activate); -} - -void CollapsibleEffect::mouseDoubleClickEvent ( QMouseEvent * event ) +bool CollapsibleEffect::isActive() const { - if (frame->underMouse() && collapseButton->isEnabled()) slotSwitch(); - QWidget::mouseDoubleClickEvent(event); + return decoframe->property("active").toBool(); } -void CollapsibleEffect::mousePressEvent ( QMouseEvent *event ) +void CollapsibleEffect::setActive(bool activate) { - if (!m_active) emit activateEffect(m_paramWidget->index()); - QWidget::mousePressEvent(event); + decoframe->setProperty("active", activate); + decoframe->setStyleSheet(decoframe->styleSheet()); } -void CollapsibleEffect::enterEvent ( QEvent * event ) +void CollapsibleEffect::mouseDoubleClickEvent ( QMouseEvent * event ) { - if (m_paramWidget == NULL || m_paramWidget->index() > 0) buttonUp->setVisible(true); - if (!m_lastEffect) buttonDown->setVisible(true); - buttonDel->setVisible(true); - if (!m_active) frame->setBackgroundRole(QPalette::Midlight); - frame->setAutoFillBackground(true); - QWidget::enterEvent(event); + if (frame->underMouse() && collapseButton->isEnabled()) { + event->accept(); + slotSwitch(); + } + else event->ignore(); } -void CollapsibleEffect::leaveEvent ( QEvent * event ) +void CollapsibleEffect::mouseReleaseEvent( QMouseEvent *event ) { - buttonUp->setVisible(false); - buttonDown->setVisible(false); - buttonDel->setVisible(false); - if (!m_active) frame->setAutoFillBackground(false); - QWidget::leaveEvent(event); + if (!decoframe->property("active").toBool()) emit activateEffect(effectIndex()); + QWidget::mouseReleaseEvent(event); } -void CollapsibleEffect::slotEnable(bool enable) +void CollapsibleEffect::slotDisable(bool disable, bool emitInfo) { - title->setEnabled(enable); - m_effect.setAttribute("disable", enable ? 0 : 1); - if (enable || KdenliveSettings::disable_effect_parameters()) { - widgetFrame->setEnabled(enable); + title->setEnabled(!disable); + enabledButton->blockSignals(true); + enabledButton->setChecked(disable); + enabledButton->blockSignals(false); + enabledButton->setIcon(disable ? KIcon("novisible") : KIcon("visible")); + m_effect.setAttribute("disable", disable ? 1 : 0); + if (!disable || KdenliveSettings::disable_effect_parameters()) { + widgetFrame->setEnabled(!disable); } - emit effectStateChanged(!enable, m_paramWidget->index()); + if (emitInfo) emit effectStateChanged(disable, effectIndex(), isActive() && needsMonitorEffectScene()); } void CollapsibleEffect::slotDeleteEffect() { - emit deleteEffect(m_effect, m_paramWidget->index()); + emit deleteEffect(m_effect); } void CollapsibleEffect::slotEffectUp() { - emit changeEffectPosition(m_paramWidget->index(), true); + emit changeEffectPosition(QList () <index(), false); + emit changeEffectPosition(QList () <index()); + emit resetEffect(effectIndex()); } void CollapsibleEffect::slotSwitch() @@ -380,30 +336,66 @@ void CollapsibleEffect::slotShow(bool show) widgetFrame->setVisible(show); if (show) { collapseButton->setArrowType(Qt::DownArrow); - m_original_effect.removeAttribute("k_collapsed"); - } - else { + m_info.isCollapsed = false; + } else { collapseButton->setArrowType(Qt::RightArrow); - m_original_effect.setAttribute("k_collapsed", 1); + m_info.isCollapsed = true; + } + updateCollapsedState(); +} + +void CollapsibleEffect::groupStateChanged(bool collapsed) +{ + m_info.groupIsCollapsed = collapsed; + updateCollapsedState(); +} + +void CollapsibleEffect::updateCollapsedState() +{ + QString info = m_info.toString(); + if (info != m_effect.attribute("kdenlive_info")) { + m_effect.setAttribute("kdenlive_info", info); + emit parameterChanged(m_original_effect, m_effect, effectIndex()); + } +} + +void CollapsibleEffect::setGroupIndex(int ix) +{ + if (m_info.groupIndex == -1 && ix != -1) { + m_menu->removeAction(m_groupAction); + } + else if (m_info.groupIndex != -1 && ix == -1) { + m_menu->addAction(m_groupAction); } + m_info.groupIndex = ix; + m_effect.setAttribute("kdenlive_info", m_info.toString()); +} + +void CollapsibleEffect::setGroupName(const QString &groupName) +{ + m_info.groupName = groupName; + m_effect.setAttribute("kdenlive_info", m_info.toString()); } -void CollapsibleEffect::addGroupEffect(CollapsibleEffect *effect) +QString CollapsibleEffect::infoString() const { - QVBoxLayout *vbox = static_cast(widgetFrame->layout()); - if (vbox == NULL) { - vbox = new QVBoxLayout(); - vbox->setContentsMargins(10, 0, 0, 0); - vbox->setSpacing(2); - widgetFrame->setLayout(vbox); + return m_info.toString(); +} + +void CollapsibleEffect::removeFromGroup() +{ + if (m_info.groupIndex != -1) { + m_menu->addAction(m_groupAction); } - vbox->addWidget(effect); + m_info.groupIndex = -1; + m_info.groupName.clear(); + m_effect.setAttribute("kdenlive_info", m_info.toString()); + emit parameterChanged(m_original_effect, m_effect, effectIndex()); } -int CollapsibleEffect::index() const +int CollapsibleEffect::groupIndex() const { - if (m_paramWidget) return m_paramWidget->index(); - return 0; + return m_info.groupIndex; } int CollapsibleEffect::effectIndex() const @@ -412,36 +404,35 @@ int CollapsibleEffect::effectIndex() const return m_effect.attribute("kdenlive_ix").toInt(); } -void CollapsibleEffect::updateWidget(ItemInfo info, int index, QDomElement effect, EffectMetaInfo *metaInfo) +void CollapsibleEffect::updateWidget(const ItemInfo &info, const QDomElement &effect, EffectMetaInfo *metaInfo) { - if (m_paramWidget) { - // cleanup - delete m_paramWidget; - m_paramWidget = NULL; - } + // cleanup + delete m_paramWidget; + m_paramWidget = NULL; m_effect = effect; - setupWidget(info, index, metaInfo); + setupWidget(info, metaInfo); } -void CollapsibleEffect::setupWidget(ItemInfo info, int index, EffectMetaInfo *metaInfo) +void CollapsibleEffect::setupWidget(const ItemInfo &info, EffectMetaInfo *metaInfo) { if (m_effect.isNull()) { -// kDebug() << "// EMPTY EFFECT STACK"; + // kDebug() << "// EMPTY EFFECT STACK"; return; } if (m_effect.attribute("tag") == "region") { - QVBoxLayout *vbox = new QVBoxLayout(widgetFrame); - vbox->setContentsMargins(0, 0, 0, 0); - vbox->setSpacing(2); + m_regionEffect = true; QDomNodeList effects = m_effect.elementsByTagName("effect"); - QDomNodeList origin_effects = m_original_effect.elementsByTagName("effect"); + QDomNodeList origin_effects = m_original_effect.elementsByTagName("effect"); + m_paramWidget = new ParameterContainer(m_effect, info, metaInfo, widgetFrame); QWidget *container = new QWidget(widgetFrame); + QVBoxLayout *vbox = static_cast (widgetFrame->layout()); vbox->addWidget(container); - m_paramWidget = new ParameterContainer(m_effect.toElement(), info, metaInfo, index, container); - for (int i = 0; i < effects.count(); i++) { - CollapsibleEffect *coll = new CollapsibleEffect(effects.at(i).toElement(), origin_effects.at(i).toElement(), info, i, metaInfo, container); + // m_paramWidget = new ParameterContainer(m_effect.toElement(), info, metaInfo, container); + for (int i = 0; i < effects.count(); ++i) { + CollapsibleEffect *coll = new CollapsibleEffect(effects.at(i).toElement(), origin_effects.at(i).toElement(), info, metaInfo, container); m_subParamWidgets.append(coll); + connect(coll, SIGNAL(parameterChanged(QDomElement,QDomElement,int)), this , SLOT(slotUpdateRegionEffectParams(QDomElement,QDomElement,int))); //container = new QWidget(widgetFrame); vbox->addWidget(coll); //p = new ParameterContainer(effects.at(i).toElement(), info, isEffect, container); @@ -449,36 +440,64 @@ void CollapsibleEffect::setupWidget(ItemInfo info, int index, EffectMetaInfo *me } else { - m_paramWidget = new ParameterContainer(m_effect, info, metaInfo, index, widgetFrame); + m_paramWidget = new ParameterContainer(m_effect, info, metaInfo, widgetFrame); + connect(m_paramWidget, SIGNAL(disableCurrentFilter(bool)), this, SLOT(slotDisableEffect(bool))); if (m_effect.firstChildElement("parameter").isNull()) { // Effect has no parameter, don't allow expand collapseButton->setEnabled(false); - widgetFrame->setVisible(false); + collapseButton->setVisible(false); + widgetFrame->setVisible(false); } } - if (collapseButton->isEnabled()) slotShow(!m_effect.hasAttribute("k_collapsed")); - connect (m_paramWidget, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)), this, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int))); + if (collapseButton->isEnabled() && m_info.isCollapsed) { + widgetFrame->setVisible(false); + collapseButton->setArrowType(Qt::RightArrow); + + } + connect (m_paramWidget, SIGNAL(parameterChanged(QDomElement,QDomElement,int)), this, SIGNAL(parameterChanged(QDomElement,QDomElement,int))); - connect(m_paramWidget, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)), this, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString))); + connect(m_paramWidget, SIGNAL(startFilterJob(QString,QString,QString,QString,QMap)), this, SIGNAL(startFilterJob(QString,QString,QString,QString,QMap))); connect (this, SIGNAL(syncEffectsPos(int)), m_paramWidget, SIGNAL(syncEffectsPos(int))); - connect (this, SIGNAL(effectStateChanged(bool)), m_paramWidget, SIGNAL(effectStateChanged(bool))); connect (m_paramWidget, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int))); connect (m_paramWidget, SIGNAL(seekTimeline(int)), this, SIGNAL(seekTimeline(int))); + connect(m_paramWidget, SIGNAL(importClipKeyframes()), this, SIGNAL(importClipKeyframes())); } +void CollapsibleEffect::slotDisableEffect(bool disable) +{ + title->setEnabled(!disable); + enabledButton->blockSignals(true); + enabledButton->setChecked(disable); + enabledButton->blockSignals(false); + enabledButton->setIcon(disable ? KIcon("novisible") : KIcon("visible")); + m_effect.setAttribute("disable", disable ? 1 : 0); + emit effectStateChanged(disable, effectIndex(), isActive() && needsMonitorEffectScene()); +} + +bool CollapsibleEffect::isGroup() const +{ + return false; +} + void CollapsibleEffect::updateTimecodeFormat() { m_paramWidget->updateTimecodeFormat(); if (!m_subParamWidgets.isEmpty()) { // we have a group - for (int i = 0; i < m_subParamWidgets.count(); i++) + for (int i = 0; i < m_subParamWidgets.count(); ++i) m_subParamWidgets.at(i)->updateTimecodeFormat(); } } +void CollapsibleEffect::slotUpdateRegionEffectParams(const QDomElement /*old*/, const QDomElement /*e*/, int /*ix*/) +{ + kDebug()<<"// EMIT CHANGE SUBEFFECT.....:"; + emit parameterChanged(m_original_effect, m_effect, effectIndex()); +} + void CollapsibleEffect::slotSyncEffectsPos(int pos) { emit syncEffectsPos(pos); @@ -486,734 +505,104 @@ void CollapsibleEffect::slotSyncEffectsPos(int pos) void CollapsibleEffect::dragEnterEvent(QDragEnterEvent *event) { - if (event->mimeData()->hasFormat("kdenlive/effectslist")) - event->acceptProposedAction(); + if (event->mimeData()->hasFormat("kdenlive/effectslist")) { + frame->setProperty("target", true); + frame->setStyleSheet(frame->styleSheet()); + event->acceptProposedAction(); + } +} + +void CollapsibleEffect::dragLeaveEvent(QDragLeaveEvent */*event*/) +{ + frame->setProperty("target", false); + frame->setStyleSheet(frame->styleSheet()); } void CollapsibleEffect::dropEvent(QDropEvent *event) { + frame->setProperty("target", false); + frame->setStyleSheet(frame->styleSheet()); const QString effects = QString::fromUtf8(event->mimeData()->data("kdenlive/effectslist")); //event->acceptProposedAction(); QDomDocument doc; doc.setContent(effects, true); - const QDomElement e = doc.documentElement(); + QDomElement e = doc.documentElement(); int ix = e.attribute("kdenlive_ix").toInt(); - emit moveEffect(ix, this); - event->setDropAction(Qt::MoveAction); - event->accept(); -} - -ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, EffectMetaInfo *metaInfo, int index, QWidget * parent) : - m_index(index), - m_keyframeEditor(NULL), - m_geometryWidget(NULL), - m_metaInfo(metaInfo), - m_effect(effect) -{ - m_in = info.cropStart.frames(KdenliveSettings::project_fps()); - m_out = (info.cropStart + info.cropDuration).frames(KdenliveSettings::project_fps()) - 1; - - QDomNodeList namenode = effect.childNodes(); //elementsByTagName("parameter"); - - QDomElement e = effect.toElement(); - int minFrame = e.attribute("start").toInt(); - int maxFrame = e.attribute("end").toInt(); - // In transitions, maxFrame is in fact one frame after the end of transition - if (maxFrame > 0) maxFrame --; - - bool disable = effect.attribute("disable") == "1" && KdenliveSettings::disable_effect_parameters(); - parent->setEnabled(!disable); - - bool stretch = true; - m_vbox = new QVBoxLayout(parent); - m_vbox->setContentsMargins(0, 0, 0, 0); - m_vbox->setSpacing(2); - - for (int i = 0; i < namenode.count() ; i++) { - QDomElement pa = namenode.item(i).toElement(); - if (pa.tagName() != "parameter") continue; - QDomElement na = pa.firstChildElement("name"); - QDomElement commentElem = pa.firstChildElement("comment"); - QString type = pa.attribute("type"); - QString paramName = na.isNull() ? pa.attribute("name") : i18n(na.text().toUtf8().data()); - QString comment; - if (!commentElem.isNull()) - comment = i18n(commentElem.text().toUtf8().data()); - QWidget * toFillin = new QWidget(parent); - QString value = pa.attribute("value").isNull() ? - pa.attribute("default") : pa.attribute("value"); - - - /** See effects/README for info on the different types */ - - if (type == "double" || type == "constant") { - double min; - double max; - if (pa.attribute("min").contains('%')) - min = ProfilesDialog::getStringEval(m_metaInfo->profile, pa.attribute("min"), m_metaInfo->frameSize); - else - min = pa.attribute("min").toDouble(); - if (pa.attribute("max").contains('%')) - max = ProfilesDialog::getStringEval(m_metaInfo->profile, pa.attribute("max"), m_metaInfo->frameSize); - else - max = pa.attribute("max").toDouble(); - - DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, value.toDouble(), min, max, - pa.attribute("default").toDouble(), comment, -1, pa.attribute("suffix"), pa.attribute("decimals").toInt(), parent); - doubleparam->setFocusPolicy(Qt::StrongFocus); - m_vbox->addWidget(doubleparam); - m_valueItems[paramName] = doubleparam; - connect(doubleparam, SIGNAL(valueChanged(double)), this, SLOT(slotCollectAllParameters())); - connect(this, SIGNAL(showComments(bool)), doubleparam, SLOT(slotShowComment(bool))); - } else if (type == "list") { - Listval *lsval = new Listval; - lsval->setupUi(toFillin); - lsval->list->setFocusPolicy(Qt::StrongFocus); - QStringList listitems = pa.attribute("paramlist").split(';'); - if (listitems.count() == 1) { - // probably custom effect created before change to ';' as separator - listitems = pa.attribute("paramlist").split(","); - } - QDomElement list = pa.firstChildElement("paramlistdisplay"); - QStringList listitemsdisplay; - if (!list.isNull()) { - listitemsdisplay = i18n(list.text().toUtf8().data()).split(','); - } else { - listitemsdisplay = i18n(pa.attribute("paramlistdisplay").toUtf8().data()).split(','); - } - if (listitemsdisplay.count() != listitems.count()) - listitemsdisplay = listitems; - lsval->list->setIconSize(QSize(30, 30)); - for (int i = 0; i < listitems.count(); i++) { - lsval->list->addItem(listitemsdisplay.at(i), listitems.at(i)); - QString entry = listitems.at(i); - if (!entry.isEmpty() && (entry.endsWith(".png") || entry.endsWith(".pgm"))) { - if (!CollapsibleEffect::iconCache.contains(entry)) { - QImage pix(entry); - CollapsibleEffect::iconCache[entry] = pix.scaled(30, 30); - } - lsval->list->setItemIcon(i, QPixmap::fromImage(CollapsibleEffect::iconCache[entry])); - } - } - if (!value.isEmpty()) lsval->list->setCurrentIndex(listitems.indexOf(value)); - lsval->name->setText(paramName); - lsval->labelComment->setText(comment); - lsval->widgetComment->setHidden(true); - m_valueItems[paramName] = lsval; - connect(lsval->list, SIGNAL(currentIndexChanged(int)) , this, SLOT(slotCollectAllParameters())); - if (!comment.isEmpty()) - connect(this, SIGNAL(showComments(bool)), lsval->widgetComment, SLOT(setVisible(bool))); - m_uiItems.append(lsval); - } else if (type == "bool") { - Boolval *bval = new Boolval; - bval->setupUi(toFillin); - bval->checkBox->setCheckState(value == "0" ? Qt::Unchecked : Qt::Checked); - bval->name->setText(paramName); - bval->labelComment->setText(comment); - bval->widgetComment->setHidden(true); - m_valueItems[paramName] = bval; - connect(bval->checkBox, SIGNAL(stateChanged(int)) , this, SLOT(slotCollectAllParameters())); - if (!comment.isEmpty()) - connect(this, SIGNAL(showComments(bool)), bval->widgetComment, SLOT(setVisible(bool))); - m_uiItems.append(bval); - } else if (type == "complex") { - ComplexParameter *pl = new ComplexParameter; - pl->setupParam(effect, pa.attribute("name"), 0, 100); - m_vbox->addWidget(pl); - m_valueItems[paramName+"complex"] = pl; - connect(pl, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); - } else if (type == "geometry") { - if (KdenliveSettings::on_monitor_effects()) { - m_geometryWidget = new GeometryWidget(m_metaInfo->monitor, m_metaInfo->timecode, 0, true, effect.hasAttribute("showrotation"), parent); - m_geometryWidget->setFrameSize(m_metaInfo->frameSize); - m_geometryWidget->slotShowScene(!disable); - // connect this before setupParam to make sure the monitor scene shows up at startup - connect(m_geometryWidget, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int))); - connect(m_geometryWidget, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); - if (minFrame == maxFrame) - m_geometryWidget->setupParam(pa, m_in, m_out); - else - m_geometryWidget->setupParam(pa, minFrame, maxFrame); - m_vbox->addWidget(m_geometryWidget); - m_valueItems[paramName+"geometry"] = m_geometryWidget; - connect(m_geometryWidget, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int))); - connect(this, SIGNAL(syncEffectsPos(int)), m_geometryWidget, SLOT(slotSyncPosition(int))); - connect(this, SIGNAL(effectStateChanged(bool)), m_geometryWidget, SLOT(slotShowScene(bool))); - } else { - Geometryval *geo = new Geometryval(m_metaInfo->profile, m_metaInfo->timecode, m_metaInfo->frameSize, 0); - if (minFrame == maxFrame) - geo->setupParam(pa, m_in, m_out); - else - geo->setupParam(pa, minFrame, maxFrame); - m_vbox->addWidget(geo); - m_valueItems[paramName+"geometry"] = geo; - connect(geo, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); - connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int))); - connect(this, SIGNAL(syncEffectsPos(int)), geo, SLOT(slotSyncPosition(int))); + int currentEffectIx = effectIndex(); + if (ix == currentEffectIx) { + // effect dropped on itself, reject + event->ignore(); + return; + } + if (ix == 0 || e.tagName() == "effectgroup") { + if (e.tagName() == "effectgroup") { + // moving a group + QDomNodeList subeffects = e.elementsByTagName("effect"); + if (subeffects.isEmpty()) { + event->ignore(); + return; } - } else if (type == "addedgeometry") { - // this is a parameter that should be linked to the geometry widget, for example rotation, shear, ... - if (m_geometryWidget) m_geometryWidget->addParameter(pa); - } else if (type == "keyframe" || type == "simplekeyframe") { - // keyframe editor widget - if (m_keyframeEditor == NULL) { - KeyframeEdit *geo; - if (pa.attribute("widget") == "corners") { - // we want a corners-keyframe-widget - CornersWidget *corners = new CornersWidget(m_metaInfo->monitor, pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt(), parent); - corners->slotShowScene(!disable); - connect(corners, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int))); - connect(this, SIGNAL(effectStateChanged(bool)), corners, SLOT(slotShowScene(bool))); - connect(this, SIGNAL(syncEffectsPos(int)), corners, SLOT(slotSyncPosition(int))); - geo = static_cast(corners); - } else { - geo = new KeyframeEdit(pa, m_in, m_out, m_metaInfo->timecode, e.attribute("active_keyframe", "-1").toInt()); + EffectInfo info; + info.fromString(subeffects.at(0).toElement().attribute("kdenlive_info")); + event->setDropAction(Qt::MoveAction); + event->accept(); + if (info.groupIndex >= 0) { + // Moving group + QList effectsIds; + // Collect moved effects ids + for (int i = 0; i < subeffects.count(); ++i) { + QDomElement effect = subeffects.at(i).toElement(); + effectsIds << effect.attribute("kdenlive_ix").toInt(); } - m_vbox->addWidget(geo); - m_valueItems[paramName+"keyframe"] = geo; - m_keyframeEditor = geo; - connect(geo, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); - connect(geo, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int))); - connect(this, SIGNAL(showComments(bool)), geo, SIGNAL(showComments(bool))); - } else { - // we already have a keyframe editor, so just add another column for the new param - m_keyframeEditor->addParameter(pa); + emit moveEffect(effectsIds, currentEffectIx, info.groupIndex, info.groupName); } - } else if (type == "color") { - if (value.startsWith('#')) - value = value.replace('#', "0x"); - ChooseColorWidget *choosecolor = new ChooseColorWidget(paramName, value, parent); - m_vbox->addWidget(choosecolor); - m_valueItems[paramName] = choosecolor; - connect(choosecolor, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int))); - connect(choosecolor, SIGNAL(modified()) , this, SLOT(slotCollectAllParameters())); - } else if (type == "position") { - int pos = value.toInt(); - if (effect.attribute("id") == "fadein" || effect.attribute("id") == "fade_from_black") { - pos = pos - m_in; - } else if (effect.attribute("id") == "fadeout" || effect.attribute("id") == "fade_to_black") { - // fadeout position starts from clip end - pos = m_out - pos; - } - PositionEdit *posedit = new PositionEdit(paramName, pos, 0, m_out - m_in, m_metaInfo->timecode); - m_vbox->addWidget(posedit); - m_valueItems[paramName+"position"] = posedit; - connect(posedit, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); - } else if (type == "curve") { - KisCurveWidget *curve = new KisCurveWidget(parent); - curve->setMaxPoints(pa.attribute("max").toInt()); - QList points; - int number = EffectsList::parameter(e, pa.attribute("number")).toInt(); - QString inName = pa.attribute("inpoints"); - QString outName = pa.attribute("outpoints"); - int start = pa.attribute("min").toInt(); - for (int j = start; j <= number; j++) { - QString in = inName; - in.replace("%i", QString::number(j)); - QString out = outName; - out.replace("%i", QString::number(j)); - points << QPointF(EffectsList::parameter(e, in).toDouble(), EffectsList::parameter(e, out).toDouble()); - } - if (!points.isEmpty()) - curve->setCurve(KisCubicCurve(points)); - MySpinBox *spinin = new MySpinBox(); - spinin->setRange(0, 1000); - MySpinBox *spinout = new MySpinBox(); - spinout->setRange(0, 1000); - curve->setupInOutControls(spinin, spinout, 0, 1000); - m_vbox->addWidget(curve); - m_vbox->addWidget(spinin); - m_vbox->addWidget(spinout); - - connect(curve, SIGNAL(modified()), this, SLOT(slotCollectAllParameters())); - m_valueItems[paramName] = curve; + else { + // group effect dropped from effect list + if (m_info.groupIndex > -1) { + // TODO: Should we merge groups?? - QString depends = pa.attribute("depends"); - if (!depends.isEmpty()) - meetDependency(paramName, type, EffectsList::parameter(e, depends)); - } else if (type == "bezier_spline") { - BezierSplineWidget *widget = new BezierSplineWidget(value, parent); - stretch = false; - m_vbox->addWidget(widget); - m_valueItems[paramName] = widget; - connect(widget, SIGNAL(modified()), this, SLOT(slotCollectAllParameters())); - QString depends = pa.attribute("depends"); - if (!depends.isEmpty()) - meetDependency(paramName, type, EffectsList::parameter(e, depends)); -#ifdef USE_QJSON - } else if (type == "roto-spline") { - RotoWidget *roto = new RotoWidget(value, m_metaInfo->monitor, info, m_metaInfo->timecode, parent); - roto->slotShowScene(!disable); - connect(roto, SIGNAL(valueChanged()), this, SLOT(slotCollectAllParameters())); - connect(roto, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int))); - connect(roto, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int))); - connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int))); - connect(this, SIGNAL(effectStateChanged(bool)), roto, SLOT(slotShowScene(bool))); - m_vbox->addWidget(roto); - m_valueItems[paramName] = roto; -#endif - } else if (type == "wipe") { - Wipeval *wpval = new Wipeval; - wpval->setupUi(toFillin); - wipeInfo w = getWipeInfo(value); - switch (w.start) { - case UP: - wpval->start_up->setChecked(true); - break; - case DOWN: - wpval->start_down->setChecked(true); - break; - case RIGHT: - wpval->start_right->setChecked(true); - break; - case LEFT: - wpval->start_left->setChecked(true); - break; - default: - wpval->start_center->setChecked(true); - break; - } - switch (w.end) { - case UP: - wpval->end_up->setChecked(true); - break; - case DOWN: - wpval->end_down->setChecked(true); - break; - case RIGHT: - wpval->end_right->setChecked(true); - break; - case LEFT: - wpval->end_left->setChecked(true); - break; - default: - wpval->end_center->setChecked(true); - break; - } - wpval->start_transp->setValue(w.startTransparency); - wpval->end_transp->setValue(w.endTransparency); - m_valueItems[paramName] = wpval; - connect(wpval->end_up, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->end_down, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->end_left, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->end_right, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->end_center, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->start_up, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->start_down, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->start_left, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->start_right, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->start_center, SIGNAL(clicked()), this, SLOT(slotCollectAllParameters())); - connect(wpval->start_transp, SIGNAL(valueChanged(int)), this, SLOT(slotCollectAllParameters())); - connect(wpval->end_transp, SIGNAL(valueChanged(int)), this, SLOT(slotCollectAllParameters())); - //wpval->title->setTitle(na.toElement().text()); - m_uiItems.append(wpval); - } else if (type == "url") { - Urlval *cval = new Urlval; - cval->setupUi(toFillin); - cval->label->setText(paramName); - cval->urlwidget->fileDialog()->setFilter(ProjectList::getExtensions()); - m_valueItems[paramName] = cval; - cval->urlwidget->setUrl(KUrl(value)); - connect(cval->urlwidget, SIGNAL(returnPressed()) , this, SLOT(slotCollectAllParameters())); - connect(cval->urlwidget, SIGNAL(urlSelected(const KUrl&)) , this, SLOT(slotCollectAllParameters())); - m_uiItems.append(cval); - } else if (type == "keywords") { - Keywordval* kval = new Keywordval; - kval->setupUi(toFillin); - kval->label->setText(paramName); - kval->lineeditwidget->setText(value); - QDomElement klistelem = pa.firstChildElement("keywords"); - QDomElement kdisplaylistelem = pa.firstChildElement("keywordsdisplay"); - QStringList keywordlist; - QStringList keyworddisplaylist; - if (!klistelem.isNull()) { - keywordlist = klistelem.text().split(';'); - keyworddisplaylist = i18n(kdisplaylistelem.text().toUtf8().data()).split(';'); - } - if (keyworddisplaylist.count() != keywordlist.count()) { - keyworddisplaylist = keywordlist; - } - for (int i = 0; i < keywordlist.count(); i++) { - kval->comboboxwidget->addItem(keyworddisplaylist.at(i), keywordlist.at(i)); + } + emit addEffect(e); } - // Add disabled user prompt at index 0 - kval->comboboxwidget->insertItem(0, i18n("