X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Feffectstack%2Fcollapsibleeffect.cpp;h=c2a59f7a41e2d30ef667f956649f4aeaaf80d2e5;hb=c3302003093710ee247ad84c0fe2ef3c579d417f;hp=71ed8e44e346814a82a2685231ff0fab36dd85a9;hpb=65291fac2609fe71e4be801a4d5349ddda5b9243;p=kdenlive diff --git a/src/effectstack/collapsibleeffect.cpp b/src/effectstack/collapsibleeffect.cpp index 71ed8e44..c2a59f7a 100644 --- a/src/effectstack/collapsibleeffect.cpp +++ b/src/effectstack/collapsibleeffect.cpp @@ -19,117 +19,43 @@ #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 -{ -}; +#include -class Urlval: public QWidget, public Ui::Urlval_UI -{ -}; - -class Keywordval: public QWidget, public Ui::Keywordval_UI -{ -}; -class Fontval: public QWidget, public Ui::Fontval_UI +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) { -}; - -QMap CollapsibleEffect::iconCache; - -void clearLayout(QLayout *layout) -{ - 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, EffectMetaInfo *metaInfo, bool lastEffect, QWidget * parent) : - AbstractCollapsibleWidget(parent), - m_paramWidget(NULL), - m_effect(effect), - m_original_effect(original_effect), - m_lastEffect(lastEffect) -{ - setupUi(this); filterWheelEvent = true; m_info.fromString(effect.attribute("kdenlive_info")); setFont(KGlobalSettings::smallestReadableFont()); - buttonUp->setIcon(KIcon("kdenlive-up")); buttonUp->setToolTip(i18n("Move effect up")); if (!lastEffect) { @@ -152,33 +78,53 @@ CollapsibleEffect::CollapsibleEffect(QDomElement effect, QDomElement original_ef m_menu->addAction(KIcon("view-refresh"), i18n("Reset Effect"), this, SLOT(slotResetEffect())); m_menu->addAction(KIcon("document-save"), i18n("Save Effect"), this, SLOT(slotSaveEffect())); + 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()) return; - title->setText(i18n(namenode.text().toUtf8().data())); + if (namenode.isNull()) { + // Warning, broken effect? + kDebug()<<"// Could not create effect"; + return; + } + 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)); - m_menu->addAction(KIcon("folder-new"), i18n("Create Group"), this, SLOT(slotCreateGroup())); + 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())); + } setupWidget(info, metaInfo); - setAcceptDrops(true); menuButton->setIcon(KIcon("kdenlive-menu")); menuButton->setMenu(m_menu); if (m_effect.attribute("disable") == "1") { title->setEnabled(false); - enabledBox->setChecked(false); + enabledButton->setChecked(true); + enabledButton->setIcon(KIcon("novisible")); } else { - enabledBox->setChecked(true); + 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())); @@ -188,70 +134,38 @@ 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; } -//static -const QString CollapsibleEffect::getStyleSheet(QPalette p) +void CollapsibleEffect::slotCreateGroup() { - KColorScheme scheme(p.currentColorGroup(), KColorScheme::View, KSharedConfig::openConfig(KdenliveSettings::colortheme())); - QColor dark_bg = scheme.shade(KColorScheme::DarkShade); - QColor selected_bg = scheme.decoration(KColorScheme::FocusColor).color(); - QColor hover_bg = scheme.decoration(KColorScheme::HoverColor).color(); - QColor light_bg = scheme.shade(KColorScheme::LightShade); - //QColor midlight_bg = scheme.shade(KColorScheme::MidlightShade); - QColor normal_bg = scheme.background(KColorScheme::AlternateBackground).color(); - QColor alt_bg = scheme.background(KColorScheme::NormalBackground).color(); - - KColorScheme scheme2(p.currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme())); - QColor normal_bg2 = scheme2.background(KColorScheme::NormalBackground).color(); - QColor normal_bg3 = scheme2.background(KColorScheme::AlternateBackground).color(); - - QString stylesheet; - - // group editable labels - stylesheet.append(QString("MyEditableLabel { background-color: transparent;} ")); - - // effect background - stylesheet.append(QString("QFrame#decoframe {border-radius:5px;border:0px solid %1;background:%3;} QFrame:hover#decoframe {background:%4;} QFrame#decoframe[active=\"true\"] {background:%2;} ").arg(dark_bg.name()).arg(alt_bg.name()).arg(normal_bg2.name()).arg(normal_bg.name())); - - // effect group background - stylesheet.append(QString("QFrame#decoframegroup {border-radius:5px;border:1px solid %1;background:%2;} QFrame#decoframegroup[active=\"true\"] {background:%3;} ").arg(dark_bg.name()).arg(normal_bg2.name()).arg(alt_bg.name())); - - // effect title bar - stylesheet.append(QString("QFrame#frame {border-radius: 5px;} QFrame#frame[active=\"true\"] {background:%1;}").arg(selected_bg.name())); - - // group effect title bar - stylesheet.append(QString("QFrame#framegroup {border-radius: 5px; background: %2;} QFrame#framegroup[active=\"true\"] {background:%1;} ").arg(selected_bg.name()).arg(normal_bg3.name())); - - // draggable effect content bar - stylesheet.append(QString("QProgressBar::chunk:horizontal {background: %1;border-top-left-radius: 4px;border-bottom-left-radius: 4px;} QProgressBar::chunk:horizontal#dragOnly {background: %2;border-top-left-radius: 4px;border-bottom-left-radius: 4px;} QProgressBar::chunk:horizontal:hover {background: %3;}").arg(normal_bg2.name()).arg(alt_bg.name()).arg(selected_bg.name())); - - // draggable effect content bar - stylesheet.append(QString("QProgressBar:horizontal {border: 1px solid %1;border-top-left-radius: 4px;border-bottom-left-radius: 4px;border-right:0px;background:%4;padding: 0px;text-align:left center} QProgressBar:horizontal:disabled {border: 1px solid %5} QProgressBar:horizontal#dragOnly {background: %4} QProgressBar:horizontal[inTimeline=\"true\"] { border: 1px solid %2;border-right: 0px;background: %3;padding: 0px;text-align:left center } QProgressBar::chunk:horizontal[inTimeline=\"true\"] {background: %2;}").arg(dark_bg.name()).arg(hover_bg.name()).arg(light_bg.name()).arg(alt_bg.name()).arg(normal_bg2.name())); - - - // spin box for draggable widget - stylesheet.append(QString("QAbstractSpinBox#dragBox {border: 1px solid %1;border-top-right-radius: 4px;border-bottom-right-radius: 4px;padding-right:0px;} QAbstractSpinBox::down-button#dragBox {width:0px;padding:0px;} QAbstractSpinBox:disabled#dragBox {border: 1px solid %4;} QAbstractSpinBox::up-button#dragBox {width:0px;padding:0px;} QAbstractSpinBox[inTimeline=\"true\"]#dragBox { border: 1px solid %2;} QAbstractSpinBox:hover#dragBox {border: 1px solid %3;} ").arg(dark_bg.name()).arg(hover_bg.name()).arg(selected_bg.name()).arg(normal_bg2.name())); - - return stylesheet; + emit createGroup(effectIndex()); } -void CollapsibleEffect::slotCreateGroup() +void CollapsibleEffect::slotCreateRegion() { - emit createGroup(effectIndex()); + 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() @@ -261,48 +175,53 @@ void CollapsibleEffect::slotUnGroup() 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 (!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; - } - } + 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); } @@ -325,29 +244,31 @@ void CollapsibleEffect::setActive(bool activate) void CollapsibleEffect::mouseDoubleClickEvent ( QMouseEvent * event ) { - if (frame->underMouse() && collapseButton->isEnabled()) slotSwitch(); - QWidget::mouseDoubleClickEvent(event); + if (frame->underMouse() && collapseButton->isEnabled()) { + event->accept(); + slotSwitch(); + } + else event->ignore(); } -void CollapsibleEffect::mousePressEvent ( QMouseEvent *event ) +void CollapsibleEffect::mouseReleaseEvent( QMouseEvent *event ) { - - if (!decoframe->property("active").toBool() && !isGroup()) emit activateEffect(effectIndex()); - QWidget::mousePressEvent(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); - enabledBox->blockSignals(true); - enabledBox->setChecked(enable); - enabledBox->blockSignals(false); - 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, effectIndex()); + if (emitInfo) emit effectStateChanged(disable, effectIndex(), isActive() && needsMonitorEffectScene()); } void CollapsibleEffect::slotDeleteEffect() @@ -357,12 +278,12 @@ void CollapsibleEffect::slotDeleteEffect() void CollapsibleEffect::slotEffectUp() { - emit changeEffectPosition(effectIndex(), true); + emit changeEffectPosition(QList () <() <setVisible(show); if (show) { collapseButton->setArrowType(Qt::DownArrow); - m_info.isCollapsed = false; - } - else { + m_info.isCollapsed = false; + } else { collapseButton->setArrowType(Qt::RightArrow); - m_info.isCollapsed = true; + 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()); } - m_effect.setAttribute("kdenlive_info", m_info.toString()); - 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()); } QString CollapsibleEffect::infoString() const @@ -442,6 +384,9 @@ QString CollapsibleEffect::infoString() const void CollapsibleEffect::removeFromGroup() { + if (m_info.groupIndex != -1) { + m_menu->addAction(m_groupAction); + } m_info.groupIndex = -1; m_info.groupName.clear(); m_effect.setAttribute("kdenlive_info", m_info.toString()); @@ -459,36 +404,35 @@ int CollapsibleEffect::effectIndex() const return m_effect.attribute("kdenlive_ix").toInt(); } -void CollapsibleEffect::updateWidget(ItemInfo info, 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, metaInfo); } -void CollapsibleEffect::setupWidget(ItemInfo info, 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(2, 0, 2, 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, container); - for (int i = 0; i < effects.count(); i++) { + // 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); @@ -497,30 +441,42 @@ void CollapsibleEffect::setupWidget(ItemInfo info, EffectMetaInfo *metaInfo) } else { 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); - collapseButton->setVisible(false); - widgetFrame->setVisible(false); + collapseButton->setVisible(false); + widgetFrame->setVisible(false); } } if (collapseButton->isEnabled() && m_info.isCollapsed) { - widgetFrame->setVisible(false); - collapseButton->setArrowType(Qt::RightArrow); - + widgetFrame->setVisible(false); + collapseButton->setArrowType(Qt::RightArrow); + } - connect (m_paramWidget, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)), this, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int))); + 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; @@ -531,11 +487,17 @@ 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); @@ -544,21 +506,21 @@ void CollapsibleEffect::slotSyncEffectsPos(int pos) void CollapsibleEffect::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("kdenlive/effectslist")) { - frame->setProperty("active", true); - frame->setStyleSheet(frame->styleSheet()); - event->acceptProposedAction(); + frame->setProperty("target", true); + frame->setStyleSheet(frame->styleSheet()); + event->acceptProposedAction(); } } void CollapsibleEffect::dragLeaveEvent(QDragLeaveEvent */*event*/) { - frame->setProperty("active", false); + frame->setProperty("target", false); frame->setStyleSheet(frame->styleSheet()); } void CollapsibleEffect::dropEvent(QDropEvent *event) { - frame->setProperty("active", false); + frame->setProperty("target", false); frame->setStyleSheet(frame->styleSheet()); const QString effects = QString::fromUtf8(event->mimeData()->data("kdenlive/effectslist")); //event->acceptProposedAction(); @@ -566,728 +528,81 @@ void CollapsibleEffect::dropEvent(QDropEvent *event) doc.setContent(effects, true); QDomElement e = doc.documentElement(); int ix = e.attribute("kdenlive_ix").toInt(); - if (ix == effectIndex()) { - // effect dropped on itself, reject - event->ignore(); - return; - } - if (ix == 0) { - // effect dropped from effects list, add it - e.setAttribute("kdenlive_ix", ix); - event->setDropAction(Qt::CopyAction); - event->accept(); - emit addEffect(e); - return; + int currentEffectIx = effectIndex(); + if (ix == currentEffectIx) { + // effect dropped on itself, reject + event->ignore(); + return; } - emit moveEffect(ix, effectIndex(), m_info.groupIndex, m_info.groupName); - event->setDropAction(Qt::MoveAction); - event->accept(); -} - -ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, EffectMetaInfo *metaInfo, QWidget * parent) : - 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(2, 0, 2, 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(","); + if (ix == 0 || e.tagName() == "effectgroup") { + if (e.tagName() == "effectgroup") { + // moving a group + QDomNodeList subeffects = e.elementsByTagName("effect"); + if (subeffects.isEmpty()) { + event->ignore(); + return; } - 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))); - } - } 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); - } - } 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()); + emit moveEffect(effectsIds, currentEffectIx, info.groupIndex, info.groupName); } - 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); + else { + // group effect dropped from effect list + if (m_info.groupIndex > -1) { + // TODO: Should we merge groups?? - connect(curve, SIGNAL(modified()), this, SLOT(slotCollectAllParameters())); - m_valueItems[paramName] = curve; - - 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("