diff --git a/src/effectstack/effectstackview2.cpp b/src/effectstack/effectstackview2.cpp index cf01f76a1..78b054978 100644 --- a/src/effectstack/effectstackview2.cpp +++ b/src/effectstack/effectstackview2.cpp @@ -1,1311 +1,1311 @@ /*************************************************************************** effecstackview.cpp2 - description ------------------- begin : Feb 15 2008 copyright : (C) 2008 by Marco Gittler (g.marco@freenet.de) copyright : (C) 2012 by Jean-Baptiste Mardelle (jb@kdenlive.org) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "effectstackview2.h" #include "collapsibleeffect.h" #include "collapsiblegroup.h" #include "kdenlivesettings.h" #include "mainwindow.h" #include "doc/kthumb.h" #include "bin/projectclip.h" #include "effectslist/effectslist.h" #include "timeline/clipitem.h" #include "project/effectsettings.h" #include "project/transitionsettings.h" #include "utils/KoIconUtils.h" #include "mltcontroller/clipcontroller.h" #include "timeline/transition.h" #include #include #include #include #include #include #include #include EffectStackView2::EffectStackView2(Monitor *projectMonitor, QWidget *parent) : QWidget(parent), m_clipref(NULL), m_masterclipref(NULL), m_status(EMPTY), m_stateStatus(NORMALSTATUS), m_trackindex(-1), m_draggedEffect(NULL), m_draggedGroup(NULL), m_groupIndex(0), m_monitorSceneWanted(MonitorSceneDefault), m_trackInfo(), m_transition(NULL) { m_effectMetaInfo.monitor = projectMonitor; m_effects = QList (); setAcceptDrops(true); setLayout(&m_layout); m_effect = new EffectSettings(this); m_transition = new TransitionSettings(projectMonitor, this); connect(m_transition, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap)), this, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap))); connect(m_effect->checkAll, SIGNAL(stateChanged(int)), this, SLOT(slotCheckAll(int))); connect(m_effect->effectCompare, &QToolButton::toggled, this, &EffectStackView2::slotSwitchCompare); m_layout.addWidget(m_effect); m_layout.addWidget(m_transition); m_transition->setHidden(true); //setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); setEnabled(false); setStyleSheet(getStyleSheet()); } EffectStackView2::~EffectStackView2() { delete m_effect; delete m_transition; } TransitionSettings *EffectStackView2::transitionConfig() { return m_transition; } void EffectStackView2::updatePalette() { setStyleSheet(getStyleSheet()); } void EffectStackView2::refreshIcons() { QList allMenus = this->findChildren(); for (int i = 0; i < allMenus.count(); i++) { QAction *m = allMenus.at(i); QIcon ic = m->icon(); if (ic.isNull() || ic.name().isEmpty()) continue; QIcon newIcon = KoIconUtils::themedIcon(ic.name()); m->setIcon(newIcon); } QList allButtons = this->findChildren(); for (int i = 0; i < allButtons.count(); i++) { QToolButton *m = allButtons.at(i); QIcon ic = m->icon(); if (ic.isNull() || ic.name().isEmpty()) continue; QIcon newIcon = KoIconUtils::themedIcon(ic.name()); m->setIcon(newIcon); } } void EffectStackView2::slotTransitionItemSelected(Transition* t, int nextTrack, const QPoint &p, bool update) { if (t) { m_effect->setHidden(true); m_transition->setHidden(false); setEnabled(true); m_status = TIMELINE_TRANSITION; } m_transition->slotTransitionItemSelected(t, nextTrack, p, update); } void EffectStackView2::slotRenderPos(int pos) { if (m_effects.isEmpty()) return; if (m_monitorSceneWanted != MonitorSceneDefault) slotCheckMonitorPosition(pos); if (m_status == TIMELINE_CLIP && m_clipref) pos = pos - m_clipref->startPos().frames(KdenliveSettings::project_fps()); for (int i = 0; i< m_effects.count(); ++i) m_effects.at(i)->slotSyncEffectsPos(pos); } void EffectStackView2::slotClipItemUpdate() { if (m_status != TIMELINE_CLIP || !m_clipref) { return; } int inPoint = m_clipref->cropStart().frames(KdenliveSettings::project_fps()); int outPoint = m_clipref->cropDuration().frames(KdenliveSettings::project_fps()) + inPoint; for (int i = 0; i < m_effects.count(); ++i) { m_effects.at(i)->setRange(inPoint, outPoint); } } void EffectStackView2::slotClipItemSelected(ClipItem* c, Monitor *m, bool reloadStack) { if (m_effect->effectCompare->isChecked()) { // disable split effect when changing clip m_effect->effectCompare->setChecked(false); } if (c) { m_effect->setHidden(false); m_transition->setHidden(true); m_effect->setEnabled(m_stateStatus != DISABLETIMELINE && m_stateStatus != DISABLEALL); } else if (m_status == TIMELINE_TRANSITION) return; m_masterclipref = NULL; m_trackindex = -1; if (c && !c->isEnabled()) return; if (c && c == m_clipref) { if (!reloadStack) { return; } } else { m_effectMetaInfo.monitor = m; if (m_clipref) disconnect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate())); m_clipref = c; if (c) { connect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate())); m_effect->setLabel(i18n("Effects for %1", m_clipref->clipName()), m_clipref->clipName()); int frameWidth = c->binClip()->getProducerIntProperty(QStringLiteral("meta.media.width")); int frameHeight = c->binClip()->getProducerIntProperty(QStringLiteral("meta.media.height")); double factor = c->binClip()->getDoubleProducerProperty(QStringLiteral("aspect_ratio")); m_effectMetaInfo.frameSize = QPoint(frameWidth, frameHeight);// (int)(frameWidth * factor + 0.5), frameHeight); m_effectMetaInfo.stretchFactor = factor; } } if (m_clipref == NULL) { //TODO: clear list, reset paramdesc and info // If monitor scene is displayed, hide it if (m_monitorSceneWanted != MonitorSceneDefault) { m_monitorSceneWanted = MonitorSceneDefault; m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted); } m_status = EMPTY; clear(); return; } setEnabled(true); m_status = TIMELINE_CLIP; m_currentEffectList = m_clipref->effectList(); setupListView(); } void EffectStackView2::slotRefreshMasterClipEffects(ClipController* c, Monitor *m) { if (c && m_status == MASTER_CLIP && m_masterclipref && m_masterclipref->clipId() == c->clipId()) { slotMasterClipItemSelected(c, m); } } void EffectStackView2::slotMasterClipItemSelected(ClipController* c, Monitor *m) { if (m_effect->effectCompare->isChecked()) { // disable split effect when changing clip m_effect->effectCompare->setChecked(false); } m_clipref = NULL; m_trackindex = -1; if (c) { m_effect->setHidden(false); m_transition->setHidden(true); if (!c->isValid()) { m_effect->setEnabled(false); c = NULL; } else m_effect->setEnabled(m_stateStatus != DISABLEBIN && m_stateStatus != DISABLEALL); } if (c && c == m_masterclipref) { } else { m_masterclipref = c; m_effectMetaInfo.monitor = m; if (m_masterclipref) { m_effect->setLabel(i18n("Bin effects for %1", m_masterclipref->clipName()), m_masterclipref->clipName()); int frameWidth = m_masterclipref->int_property(QStringLiteral("meta.media.width")); int frameHeight = m_masterclipref->int_property(QStringLiteral("meta.media.height")); double factor = m_masterclipref->double_property(QStringLiteral("aspect_ratio")); m_effectMetaInfo.frameSize = QPoint((int)(frameWidth * factor + 0.5), frameHeight); } } if (m_masterclipref == NULL) { //TODO: clear list, reset paramdesc and info // If monitor scene is displayed, hide it if (m_monitorSceneWanted != MonitorSceneDefault) { m_monitorSceneWanted = MonitorSceneDefault; m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted); } m_status = EMPTY; clear(); return; } setEnabled(true); m_status = MASTER_CLIP; m_currentEffectList = m_masterclipref->effectList(); setupListView(); } void EffectStackView2::slotTrackItemSelected(int ix, const TrackInfo &info, Monitor *m) { if (m_effect->effectCompare->isChecked()) { // disable split effect when changing clip m_effect->effectCompare->setChecked(false); } if (m_status != TIMELINE_TRACK || ix != m_trackindex) { m_clipref = NULL; m_status = TIMELINE_TRACK; m_effectMetaInfo.monitor = m; m_currentEffectList = info.effectsList; m_trackInfo = info; m_clipref = NULL; m_masterclipref = NULL; QString trackName = info.trackName.isEmpty() ? QString::number(ix) : info.trackName; m_effect->setLabel(i18n("Effects for track %1", trackName), trackName); } setEnabled(true); m_trackindex = ix; setupListView(); } void EffectStackView2::setupListView() { blockSignals(true); m_monitorSceneWanted = MonitorSceneDefault; m_draggedEffect = NULL; m_draggedGroup = NULL; disconnect(m_effectMetaInfo.monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int))); QWidget *view = m_effect->container->takeWidget(); if (view) { delete view; } m_effects.clear(); m_groupIndex = 0; blockSignals(false); view = new QWidget(m_effect->container); QPalette p = qApp->palette(); p.setBrush(QPalette::Window, QBrush(Qt::transparent)); view->setPalette(p); m_effect->container->setWidget(view); QVBoxLayout *vbox1 = new QVBoxLayout(view); vbox1->setContentsMargins(0, 0, 0, 0); vbox1->setSpacing(0); int effectsCount = m_currentEffectList.count(); m_effect->effectCompare->setEnabled(effectsCount > 0); if (effectsCount == 0) { // No effect, make sure to display normal monitor scene m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted); } // Make sure we always have one effect selected if (m_status == TIMELINE_CLIP) { int selectedEffect = m_clipref->selectedEffectIndex(); if (selectedEffect < 1 && effectsCount > 0) m_clipref->setSelectedEffect(1); else if (selectedEffect > effectsCount) m_clipref->setSelectedEffect(effectsCount); } CollapsibleEffect *selectedCollapsibleEffect = NULL; for (int i = 0; i < effectsCount; ++i) { QDomElement d = m_currentEffectList.at(i).cloneNode().toElement(); if (d.isNull()) { //qDebug() << " . . . . WARNING, NULL EFFECT IN STACK!!!!!!!!!"; continue; } CollapsibleGroup *group = NULL; EffectInfo effectInfo; effectInfo.fromString(d.attribute(QStringLiteral("kdenlive_info"))); if (effectInfo.groupIndex >= 0) { // effect is in a group for (int j = 0; j < vbox1->count(); ++j) { CollapsibleGroup *eff = static_cast(vbox1->itemAt(j)->widget()); if (eff->isGroup() && eff->groupIndex() == effectInfo.groupIndex) { group = eff; break; } } if (group == NULL) { group = new CollapsibleGroup(effectInfo.groupIndex, i == 0, i == effectsCount - 1, effectInfo, view); connectGroup(group); vbox1->addWidget(group); group->installEventFilter( this ); } if (effectInfo.groupIndex >= m_groupIndex) m_groupIndex = effectInfo.groupIndex + 1; } /*QDomDocument doc; doc.appendChild(doc.importNode(d, true)); //qDebug() << "IMPORTED STK: " << doc.toString();*/ ItemInfo info; bool isSelected = false; if (m_status == TIMELINE_TRACK) { // ?? cleanup following line info.track = m_trackInfo.type; info.cropDuration = GenTime(m_trackInfo.duration, KdenliveSettings::project_fps()); info.cropStart = GenTime(0); info.startPos = GenTime(-1); info.track = 0; } else if (m_status == TIMELINE_CLIP) { info = m_clipref->info(); } else if (m_status == MASTER_CLIP) { info.cropDuration = m_masterclipref->getPlaytime(); info.cropStart = GenTime(0); info.startPos = GenTime(0); } bool canMoveUp = true; if (i == 0 || m_currentEffectList.at(i - 1).attribute(QStringLiteral("id")) == QLatin1String("speed")) { canMoveUp = false; } CollapsibleEffect *currentEffect = new CollapsibleEffect(d, m_currentEffectList.at(i), info, &m_effectMetaInfo, canMoveUp, i == effectsCount - 1, view); isSelected = currentEffect->effectIndex() == activeEffectIndex(); if (isSelected) { m_monitorSceneWanted = currentEffect->needsMonitorEffectScene(); selectedCollapsibleEffect = currentEffect; // show monitor scene if necessary m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted); int position = (m_effectMetaInfo.monitor->position() - (m_status == TIMELINE_CLIP ? m_clipref->startPos() : GenTime())).frames(KdenliveSettings::project_fps()); currentEffect->slotSyncEffectsPos(position); } currentEffect->setActive(isSelected); m_effects.append(currentEffect); if (group) { group->addGroupEffect(currentEffect); } else { vbox1->addWidget(currentEffect); } connectEffect(currentEffect); } if (selectedCollapsibleEffect) { // pass frame size info to effect, so it can update the newly created qml scene selectedCollapsibleEffect->updateFrameInfo(); } if (m_currentEffectList.isEmpty()) { //m_ui.labelComment->setHidden(true); } else { // Adjust group effects (up / down buttons) QList allGroups = m_effect->container->widget()->findChildren(); for (int i = 0; i < allGroups.count(); ++i) { allGroups.at(i)->adjustEffects(); } connect(m_effectMetaInfo.monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int))); } vbox1->addStretch(10); slotUpdateCheckAllButton(); // Wait a little bit for the new layout to be ready, then check if we have a scrollbar QTimer::singleShot(200, this, SLOT(slotCheckWheelEventFilter())); } int EffectStackView2::activeEffectIndex() const { int index = 0; switch (m_status) { case TIMELINE_CLIP: index = m_clipref->selectedEffectIndex(); break; case MASTER_CLIP: index = m_masterclipref->selectedEffectIndex; break; case TIMELINE_TRACK: default: // TODO index = 1; } return index; } void EffectStackView2::connectEffect(CollapsibleEffect *currentEffect) { // Check drag & drop currentEffect->installEventFilter( this ); connect(currentEffect, SIGNAL(parameterChanged(QDomElement,QDomElement,int)), this , SLOT(slotUpdateEffectParams(QDomElement,QDomElement,int))); connect(currentEffect, SIGNAL(startFilterJob(QMap&, QMap&,QMap &)), this , SLOT(slotStartFilterJob(QMap&, QMap&,QMap &))); connect(currentEffect, SIGNAL(deleteEffect(QDomElement)), this , SLOT(slotDeleteEffect(QDomElement))); connect(currentEffect, SIGNAL(reloadEffects()), this , SIGNAL(reloadEffects())); connect(currentEffect, SIGNAL(resetEffect(int)), this , SLOT(slotResetEffect(int))); connect(currentEffect, SIGNAL(changeEffectPosition(QList,bool)), this , SLOT(slotMoveEffectUp(QList,bool))); connect(currentEffect, SIGNAL(effectStateChanged(bool,int,MonitorSceneType)), this, SLOT(slotUpdateEffectState(bool,int,MonitorSceneType))); connect(currentEffect, SIGNAL(activateEffect(int)), this, SLOT(slotSetCurrentEffect(int))); connect(currentEffect, SIGNAL(seekTimeline(int)), this , SLOT(slotSeekTimeline(int))); connect(currentEffect, SIGNAL(createGroup(int)), this , SLOT(slotCreateGroup(int))); connect(currentEffect, SIGNAL(moveEffect(QList,int,int,QString)), this , SLOT(slotMoveEffect(QList,int,int,QString))); connect(currentEffect, SIGNAL(addEffect(QDomElement)), this , SLOT(slotAddEffect(QDomElement))); connect(currentEffect, SIGNAL(createRegion(int,QUrl)), this, SLOT(slotCreateRegion(int,QUrl))); connect(currentEffect, SIGNAL(deleteGroup(QDomDocument)), this , SLOT(slotDeleteGroup(QDomDocument))); connect(currentEffect, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap)), this, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap))); } void EffectStackView2::slotCheckWheelEventFilter() { // If the effect stack widget has no scrollbar, we will not filter the // mouse wheel events, so that user can easily adjust effect params bool filterWheelEvent = false; if (m_effect->container->verticalScrollBar() && m_effect->container->verticalScrollBar()->isVisible()) { // widget has scroll bar, filterWheelEvent = true; } for (int i = 0; i < m_effects.count(); ++i) { m_effects.at(i)->filterWheelEvent = filterWheelEvent; } } void EffectStackView2::resizeEvent ( QResizeEvent * event ) { slotCheckWheelEventFilter(); QWidget::resizeEvent(event); } bool EffectStackView2::eventFilter( QObject * o, QEvent * e ) { // Check if user clicked in an effect's top bar to start dragging it if (e->type() == QEvent::MouseButtonPress) { m_draggedEffect = qobject_cast(o); if (m_draggedEffect) { QMouseEvent *me = static_cast(e); if (me->button() == Qt::LeftButton && (m_draggedEffect->frame->underMouse() || m_draggedEffect->title->underMouse())) { m_clickPoint = me->globalPos(); } else { m_clickPoint = QPoint(); m_draggedEffect = NULL; } e->accept(); return true; } m_draggedGroup = qobject_cast(o); if (m_draggedGroup) { QMouseEvent *me = static_cast(e); if (me->button() == Qt::LeftButton && (m_draggedGroup->frame->underMouse() || m_draggedGroup->title()->underMouse())) m_clickPoint = me->globalPos(); else { m_clickPoint = QPoint(); m_draggedGroup = NULL; } e->accept(); return true; } } /*if (e->type() == QEvent::MouseMove) { if (qobject_cast(o)) { QMouseEvent *me = static_cast(e); if (me->buttons() != Qt::LeftButton) { e->accept(); return false; } else { e->ignore(); return true; } } }*/ return QWidget::eventFilter(o, e); } void EffectStackView2::mouseMoveEvent(QMouseEvent * event) { if (m_draggedEffect || m_draggedGroup) { if ((event->buttons() & Qt::LeftButton) && (m_clickPoint != QPoint()) && ((event->globalPos() - m_clickPoint).manhattanLength() >= QApplication::startDragDistance())) { startDrag(); } } } void EffectStackView2::mouseReleaseEvent(QMouseEvent * event) { m_draggedEffect = NULL; m_draggedGroup = NULL; QWidget::mouseReleaseEvent(event); } void EffectStackView2::startDrag() { // The data to be transferred by the drag and drop operation is contained in a QMimeData object QDomDocument doc; QPixmap pixmap; if (m_draggedEffect) { QDomElement effect = m_draggedEffect->effect().cloneNode().toElement(); if (m_status == TIMELINE_TRACK || m_status == MASTER_CLIP) { // Keep clip crop start in case we want to paste effect effect.setAttribute(QStringLiteral("clipstart"), 0); } else { // Keep clip crop start in case we want to paste effect effect.setAttribute(QStringLiteral("clipstart"), m_clipref->cropStart().frames(KdenliveSettings::project_fps())); } doc.appendChild(doc.importNode(effect, true)); pixmap = m_draggedEffect->title->grab(); } else if (m_draggedGroup) { doc = m_draggedGroup->effectsData(); if (m_status == TIMELINE_TRACK || m_status == MASTER_CLIP) { doc.documentElement().setAttribute(QStringLiteral("clipstart"), 0); } else { doc.documentElement().setAttribute(QStringLiteral("clipstart"), m_clipref->cropStart().frames(KdenliveSettings::project_fps())); } pixmap = m_draggedGroup->title()->grab(); } else return; QDrag *drag = new QDrag(this); drag->setPixmap(pixmap); QMimeData *mime = new QMimeData; QByteArray data; data.append(doc.toString().toUtf8()); mime->setData(QStringLiteral("kdenlive/effectslist"), data); // Assign ownership of the QMimeData object to the QDrag object. drag->setMimeData(mime); // Start the drag and drop operation drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); } void EffectStackView2::slotUpdateEffectState(bool disable, int index, MonitorSceneType needsMonitorEffectScene) { if (m_monitorSceneWanted != MonitorSceneDefault && disable) { m_monitorSceneWanted = MonitorSceneDefault; m_effectMetaInfo.monitor->slotShowEffectScene(MonitorSceneDefault); } else if (!disable) { m_monitorSceneWanted = needsMonitorEffectScene; m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted == MonitorSceneDefault ? MonitorSceneNone : m_monitorSceneWanted); if (m_monitorSceneWanted != MonitorSceneDefault) { CollapsibleEffect *activeEffect = getEffectByIndex(index); if (activeEffect) { int position = (m_effectMetaInfo.monitor->position() - (m_status == TIMELINE_CLIP ? m_clipref->startPos() : GenTime())).frames(KdenliveSettings::project_fps()); activeEffect->slotSyncEffectsPos(position); } } } switch (m_status) { case TIMELINE_TRACK: emit changeEffectState(NULL, m_trackindex, QList () << index, disable); break; case MASTER_CLIP: m_masterclipref->changeEffectState(QList () << index, disable); m_effectMetaInfo.monitor->refreshMonitorIfActive(); break; default: // timeline clip effect emit changeEffectState(m_clipref, -1, QList () <raise(); } void EffectStackView2::slotSeekTimeline(int pos) { if (m_status == TIMELINE_TRACK) { emit seekTimeline(pos); } else if (m_status == TIMELINE_CLIP) { emit seekTimeline(m_clipref->startPos().frames(KdenliveSettings::project_fps()) + pos); } else if (m_status == MASTER_CLIP) { m_effectMetaInfo.monitor->slotSeek(pos); } } /*void EffectStackView2::slotRegionChanged() { if (!m_trackMode) emit updateClipRegion(m_clipref, m_ui.effectlist->currentRow(), m_ui.region_url->text()); }*/ void EffectStackView2::slotCheckMonitorPosition(int renderPos) { if (m_monitorSceneWanted != MonitorSceneDefault) { if (m_status == TIMELINE_TRACK || m_status == MASTER_CLIP || (m_clipref && renderPos >= m_clipref->startPos().frames(KdenliveSettings::project_fps()) && renderPos <= m_clipref->endPos().frames(KdenliveSettings::project_fps()))) { if (!m_effectMetaInfo.monitor->effectSceneDisplayed(m_monitorSceneWanted)) { m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted); // Find active effect and refresh frame info CollapsibleEffect *activeEffect = getEffectByIndex(activeEffectIndex()); if (activeEffect) activeEffect->updateFrameInfo(); } } else { m_effectMetaInfo.monitor->slotShowEffectScene(MonitorSceneDefault); } } else { m_effectMetaInfo.monitor->slotShowEffectScene(MonitorSceneDefault); } } EFFECTMODE EffectStackView2::effectStatus() const { return m_status; } int EffectStackView2::trackIndex() const { return m_trackindex; } void EffectStackView2::clear() { m_effects.clear(); m_monitorSceneWanted = MonitorSceneDefault; QWidget *view = m_effect->container->takeWidget(); if (view) { delete view; } m_effect->setLabel(QString()); //m_ui.labelComment->setText(QString()); if (m_status != TIMELINE_TRANSITION) setEnabled(false); } void EffectStackView2::slotCheckAll(int state) { if (state == Qt::PartiallyChecked) { state = Qt::Checked; m_effect->updateCheckState(state); } bool disabled = state == Qt::Unchecked; // Disable all effects QList indexes; for (int i = 0; i < m_effects.count(); ++i) { m_effects.at(i)->slotDisable(disabled, false); indexes << m_effects.at(i)->effectIndex(); } // Take care of groups QList allGroups = m_effect->container->widget()->findChildren(); for (int i = 0; i < allGroups.count(); ++i) { allGroups.at(i)->slotEnable(disabled, false); } if (m_status == TIMELINE_TRACK) emit changeEffectState(NULL, m_trackindex, indexes, disabled); else if (m_status == TIMELINE_CLIP) emit changeEffectState(m_clipref, -1, indexes, disabled); else if (m_status == MASTER_CLIP) m_masterclipref->changeEffectState(indexes, disabled); } void EffectStackView2::slotUpdateCheckAllButton() { bool hasEnabled = false; bool hasDisabled = false; for (int i = 0; i < m_effects.count(); ++i) { if (!m_effects.at(i)->isEnabled()) hasEnabled = true; else hasDisabled = true; } if (hasEnabled && hasDisabled) m_effect->updateCheckState(Qt::PartiallyChecked); else if (hasEnabled) m_effect->updateCheckState(Qt::Checked); else m_effect->updateCheckState(Qt::Unchecked); } void EffectStackView2::deleteCurrentEffect() { for (int i = 0; i < m_effects.count(); ++i) { if (m_effects.at(i)->isActive()) { slotDeleteEffect(m_effects.at(i)->effect()); break; } } } void EffectStackView2::updateTimecodeFormat() { for (int i = 0; i< m_effects.count(); ++i) m_effects.at(i)->updateTimecodeFormat(); } CollapsibleEffect *EffectStackView2::getEffectByIndex(int ix) { for (int i = 0; i< m_effects.count(); ++i) { if (m_effects.at(i)->effectIndex() == ix) { return m_effects.at(i); } } return NULL; } void EffectStackView2::slotUpdateEffectParams(const QDomElement &old, const QDomElement &e, int ix) { if (m_status == TIMELINE_TRACK) { emit updateEffect(NULL, m_trackindex, old, e, ix,false); } else if (m_status == TIMELINE_CLIP && m_clipref) { emit updateEffect(m_clipref, -1, old, e, ix, false); // Make sure the changed effect is currently displayed slotSetCurrentEffect(ix); } else if (m_status == MASTER_CLIP) { m_masterclipref->updateEffect(m_effectMetaInfo.monitor->profileInfo(), e, ix); m_effectMetaInfo.monitor->refreshMonitorIfActive(); } QTimer::singleShot(200, this, SLOT(slotCheckWheelEventFilter())); } void EffectStackView2::slotSetCurrentEffect(int ix) { if (m_status == TIMELINE_CLIP) { if (m_clipref && ix != m_clipref->selectedEffectIndex()) { m_clipref->setSelectedEffect(ix); for (int i = 0; i < m_effects.count(); ++i) { CollapsibleEffect *effect = m_effects.at(i); if (effect->effectIndex() == ix) { if (effect->isActive()) return; effect->setActive(true); m_monitorSceneWanted = effect->needsMonitorEffectScene(); m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted); int position = (m_effectMetaInfo.monitor->position() - (m_status == TIMELINE_CLIP ? m_clipref->startPos() : GenTime())).frames(KdenliveSettings::project_fps()); effect->slotSyncEffectsPos(position); } else effect->setActive(false); } } } } void EffectStackView2::setActiveKeyframe(int frame) { if (m_status == TIMELINE_CLIP) { CollapsibleEffect *activeEffect = getEffectByIndex(activeEffectIndex()); if (activeEffect) activeEffect->setActiveKeyframe(frame); } } void EffectStackView2::slotDeleteGroup(QDomDocument doc) { ClipItem * clip = NULL; int ix = -1; if (m_status == MASTER_CLIP) { //TODO return; } if (m_status == TIMELINE_TRACK) { ix = m_trackindex; } else if (m_status == TIMELINE_CLIP) { clip = m_clipref; ix = -1; } emit removeEffectGroup(clip, ix, doc); } void EffectStackView2::slotDeleteEffect(const QDomElement &effect) { if (m_status == TIMELINE_TRACK) emit removeEffect(NULL, m_trackindex, effect); else if (m_status == TIMELINE_CLIP) emit removeEffect(m_clipref, -1, effect); if (m_status == MASTER_CLIP) { emit removeMasterEffect(m_masterclipref->clipId(), effect); } } void EffectStackView2::slotAddEffect(const QDomElement &effect) { if (m_status == MASTER_CLIP) { emit addMasterEffect(m_masterclipref->clipId(), effect); } else { emit addEffect(m_clipref, effect, m_trackindex); } } void EffectStackView2::slotMoveEffectUp(const QList &indexes, bool up) { if (up && indexes.first() <= 1) return; if (!up && indexes.last() >= m_currentEffectList.count()) return; int endPos; if (up) { endPos = getPreviousIndex(indexes.first()); } else { endPos = getNextIndex(indexes.last()); } if (m_status == TIMELINE_TRACK) emit changeEffectPosition(NULL, m_trackindex, indexes, endPos); else if (m_status == TIMELINE_CLIP) emit changeEffectPosition(m_clipref, -1, indexes, endPos); else if (m_status == MASTER_CLIP) { //TODO } } int EffectStackView2::getPreviousIndex(int ix) { CollapsibleEffect *current = getEffectByIndex(ix); int previousIx = ix - 1; CollapsibleEffect *destination = getEffectByIndex(previousIx); while (previousIx > 1 && destination->groupIndex() != -1 && destination->groupIndex() != current->groupIndex()) { previousIx--; destination = getEffectByIndex(previousIx); } return previousIx; } int EffectStackView2::getNextIndex(int ix) { CollapsibleEffect *current = getEffectByIndex(ix); int previousIx = ix + 1; CollapsibleEffect *destination = getEffectByIndex(previousIx); while (destination && destination->groupIndex() != -1 && destination->groupIndex() != current->groupIndex()) { previousIx++; destination = getEffectByIndex(previousIx); } return previousIx; } void EffectStackView2::slotStartFilterJob(QMap &filterParams, QMap &consumerParams, QMap &extraParams) { if (m_status == TIMELINE_CLIP && m_clipref) { emit startFilterJob(m_clipref->info(), m_clipref->getBinId(), filterParams, consumerParams, extraParams); } else if (m_status == MASTER_CLIP && m_masterclipref) { ItemInfo info; emit startFilterJob(info, m_masterclipref->clipId(), filterParams, consumerParams, extraParams); } } void EffectStackView2::slotResetEffect(int ix) { QDomElement old = m_currentEffectList.itemFromIndex(ix); QDomElement dom; QString effectId = old.attribute(QStringLiteral("id")); QMap effectLists; effectLists[QStringLiteral("audio")] = &MainWindow::audioEffects; effectLists[QStringLiteral("video")] = &MainWindow::videoEffects; effectLists[QStringLiteral("custom")] = &MainWindow::customEffects; foreach(const EffectsList* list, effectLists) { dom = list->getEffectByTag(QString(), effectId).cloneNode().toElement(); if (!dom.isNull()) break; } if (!dom.isNull()) { dom.setAttribute(QStringLiteral("kdenlive_ix"), old.attribute(QStringLiteral("kdenlive_ix"))); if (m_status == TIMELINE_TRACK) { EffectsList::setParameter(dom, QStringLiteral("in"), QString::number(0)); EffectsList::setParameter(dom, QStringLiteral("out"), QString::number(m_trackInfo.duration)); ItemInfo info; info.track = m_trackInfo.type; info.cropDuration = GenTime(m_trackInfo.duration, KdenliveSettings::project_fps()); info.cropStart = GenTime(0); info.startPos = GenTime(-1); info.track = 0; for (int i = 0; i < m_effects.count(); ++i) { if (m_effects.at(i)->effectIndex() == ix) { m_effects.at(i)->updateWidget(info, dom, &m_effectMetaInfo); break; } } emit updateEffect(NULL, m_trackindex, old, dom, ix,false); } else if (m_status == TIMELINE_CLIP) { m_clipref->initEffect(m_effectMetaInfo.monitor->profileInfo(), dom); for (int i = 0; i < m_effects.count(); ++i) { if (m_effects.at(i)->effectIndex() == ix) { m_effects.at(i)->updateWidget(m_clipref->info(), dom, &m_effectMetaInfo); break; } } //m_ui.region_url->setUrl(QUrl(dom.attribute("region"))); emit updateEffect(m_clipref, -1, old, dom, ix,false); } else if (m_status == MASTER_CLIP) { //TODO } } //emit showComments(m_ui.buttonShowComments->isChecked()); //m_ui.labelComment->setHidden(!m_ui.buttonShowComments->isChecked() || m_ui.labelComment->text().isEmpty()); } void EffectStackView2::slotCreateRegion(int ix, QUrl url) { QDomElement oldeffect = m_currentEffectList.itemFromIndex(ix); QDomElement neweffect = oldeffect.cloneNode().toElement(); QDomElement region = MainWindow::videoEffects.getEffectByTag(QStringLiteral("region"), QStringLiteral("region")).cloneNode().toElement(); region.appendChild(region.ownerDocument().importNode(neweffect, true)); region.setAttribute(QStringLiteral("kdenlive_ix"), ix); EffectsList::setParameter(region, QStringLiteral("resource"), url.path()); if (m_status == TIMELINE_TRACK) { emit updateEffect(NULL, m_trackindex, oldeffect, region, ix,false); } else if (m_status == TIMELINE_CLIP && m_clipref) { emit updateEffect(m_clipref, -1, oldeffect, region, ix, false); // Make sure the changed effect is currently displayed //slotSetCurrentEffect(ix); } else if (m_status == MASTER_CLIP) { //TODO } // refresh effect stack ItemInfo info; bool isSelected = false; if (m_status == TIMELINE_TRACK) { info.track = m_trackInfo.type; info.cropDuration = GenTime(m_trackInfo.duration, KdenliveSettings::project_fps()); info.cropStart = GenTime(0); info.startPos = GenTime(-1); info.track = 0; } else if (m_status == TIMELINE_CLIP && m_clipref) { info = m_clipref->info(); } else if (m_status == MASTER_CLIP) { //TODO } CollapsibleEffect *current = getEffectByIndex(ix); m_effects.removeAll(current); current->setEnabled(false); m_currentEffectList.removeAt(ix); m_currentEffectList.insert(region); current->deleteLater(); CollapsibleEffect *currentEffect = new CollapsibleEffect(region, m_currentEffectList.itemFromIndex(ix), info, &m_effectMetaInfo, false, ix == m_currentEffectList.count() - 1, m_effect->container->widget()); connectEffect(currentEffect); if (m_status == TIMELINE_TRACK) { isSelected = currentEffect->effectIndex() == 1; } else if (m_status == TIMELINE_CLIP && m_clipref) { isSelected = currentEffect->effectIndex() == m_clipref->selectedEffectIndex(); } else if (m_status == MASTER_CLIP) { //TODO } if (isSelected) currentEffect->setActive(true); m_effects.append(currentEffect); // TODO: region in group? //if (group) { // group->addGroupEffect(currentEffect); //} else { QVBoxLayout *vbox = static_cast (m_effect->container->widget()->layout()); vbox->insertWidget(ix, currentEffect); //} // Check drag & drop currentEffect->installEventFilter( this ); QTimer::singleShot(200, this, SLOT(slotCheckWheelEventFilter())); } void EffectStackView2::slotCreateGroup(int ix) { QDomElement oldeffect = m_currentEffectList.itemFromIndex(ix); QDomElement neweffect = oldeffect.cloneNode().toElement(); EffectInfo effectinfo; effectinfo.fromString(oldeffect.attribute(QStringLiteral("kdenlive_info"))); effectinfo.groupIndex = m_groupIndex; neweffect.setAttribute(QStringLiteral("kdenlive_info"), effectinfo.toString()); ItemInfo info; if (m_status == TIMELINE_TRACK) { info.track = m_trackInfo.type; info.cropDuration = GenTime(m_trackInfo.duration, KdenliveSettings::project_fps()); info.cropStart = GenTime(0); info.startPos = GenTime(-1); info.track = 0; emit updateEffect(NULL, m_trackindex, oldeffect, neweffect, ix, false); } else if (m_status == TIMELINE_CLIP) { emit updateEffect(m_clipref, -1, oldeffect, neweffect, ix, false); } else if (m_status == MASTER_CLIP) { //TODO } QVBoxLayout *l = static_cast(m_effect->container->widget()->layout()); int groupPos = 0; CollapsibleEffect *effectToMove = NULL; for (int i = 0; i < m_effects.count(); ++i) { if (m_effects.at(i)->effectIndex() == ix) { effectToMove = m_effects.at(i); groupPos = l->indexOf(effectToMove); l->removeWidget(effectToMove); break; } } CollapsibleGroup *group = new CollapsibleGroup(m_groupIndex, false, ix == m_currentEffectList.count() - 2, effectinfo, m_effect->container->widget()); m_groupIndex++; connectGroup(group); l->insertWidget(groupPos, group); group->installEventFilter( this ); if (effectToMove) group->addGroupEffect(effectToMove); } void EffectStackView2::connectGroup(CollapsibleGroup *group) { connect(group, SIGNAL(moveEffect(QList,int,int,QString)), this , SLOT(slotMoveEffect(QList,int,int,QString))); connect(group, SIGNAL(addEffect(QDomElement)), this , SLOT(slotAddEffect(QDomElement))); connect(group, SIGNAL(unGroup(CollapsibleGroup*)), this , SLOT(slotUnGroup(CollapsibleGroup*))); connect(group, SIGNAL(groupRenamed(CollapsibleGroup*)), this , SLOT(slotRenameGroup(CollapsibleGroup*))); connect(group, SIGNAL(reloadEffects()), this , SIGNAL(reloadEffects())); connect(group, SIGNAL(deleteGroup(QDomDocument)), this , SLOT(slotDeleteGroup(QDomDocument))); connect(group, SIGNAL(changeEffectPosition(QList,bool)), this , SLOT(slotMoveEffectUp(QList,bool))); } void EffectStackView2::slotMoveEffect(QList currentIndexes, int newIndex, int groupIndex, QString groupName) { if (currentIndexes.count() == 1) { CollapsibleEffect *effectToMove = getEffectByIndex(currentIndexes.at(0)); CollapsibleEffect *destination = getEffectByIndex(newIndex); if (destination && !destination->isMovable()) { newIndex++; } if (effectToMove == NULL) return; QDomElement oldeffect = effectToMove->effect(); QDomElement neweffect = oldeffect.cloneNode().toElement(); EffectInfo effectinfo; effectinfo.fromString(oldeffect.attribute(QStringLiteral("kdenlive_info"))); effectinfo.groupIndex = groupIndex; effectinfo.groupName = groupName; neweffect.setAttribute(QStringLiteral("kdenlive_info"), effectinfo.toString()); if (oldeffect.attribute(QStringLiteral("kdenlive_info")) != effectinfo.toString()) { // effect's group info or collapsed state changed ItemInfo info; if (m_status == TIMELINE_TRACK) { info.track = m_trackInfo.type; info.cropDuration = GenTime(m_trackInfo.duration, KdenliveSettings::project_fps()); info.cropStart = GenTime(0); info.startPos = GenTime(-1); info.track = 0; emit updateEffect(NULL, m_trackindex, oldeffect, neweffect, effectToMove->effectIndex(),false); } else if (m_status == TIMELINE_CLIP) { emit updateEffect(m_clipref, -1, oldeffect, neweffect, effectToMove->effectIndex(),false); } else if (m_status == MASTER_CLIP) { //TODO } } } // Update effect index with new position if (m_status == TIMELINE_TRACK) { emit changeEffectPosition(NULL, m_trackindex, currentIndexes, newIndex); } else if (m_status == TIMELINE_CLIP) { emit changeEffectPosition(m_clipref, -1, currentIndexes, newIndex); } else if (m_status == MASTER_CLIP) { //TODO } } void EffectStackView2::slotUnGroup(CollapsibleGroup* group) { QVBoxLayout *l = static_cast(m_effect->container->widget()->layout()); int ix = l->indexOf(group); group->removeGroup(ix, l); group->deleteLater(); } void EffectStackView2::slotRenameGroup(CollapsibleGroup *group) { QList effects = group->effects(); for (int i = 0; i < effects.count(); ++i) { QDomElement origin = effects.at(i)->effect(); QDomElement changed = origin.cloneNode().toElement(); changed.setAttribute(QStringLiteral("kdenlive_info"), effects.at(i)->infoString()); if (m_status == TIMELINE_TRACK) { emit updateEffect(NULL, m_trackindex, origin, changed, effects.at(i)->effectIndex(),false); } else if (m_status == TIMELINE_CLIP) { emit updateEffect(m_clipref, -1, origin, changed, effects.at(i)->effectIndex(),false); } else if (m_status == MASTER_CLIP) { //TODO } } } void EffectStackView2::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/effectslist"))) { event->acceptProposedAction(); } } void EffectStackView2::processDroppedEffect(QDomElement e, QDropEvent *event) { int ix = e.attribute(QStringLiteral("kdenlive_ix")).toInt(); if (e.tagName() == QLatin1String("effectgroup")) { // We are dropping a group, all effects in group should be moved QDomNodeList effects = e.elementsByTagName(QStringLiteral("effect")); if (effects.count() == 0) { event->ignore(); return; } EffectInfo info; info.fromString(effects.at(0).toElement().attribute(QStringLiteral("kdenlive_info"))); if (info.groupIndex < 0) { //qDebug()<<"// ADDING EFFECT!!!"; // Adding a new group effect to the stack event->setDropAction(Qt::CopyAction); event->accept(); slotAddEffect(e); return; } // Moving group: delete all effects and re-add them QList indexes; for (int i = 0; i < effects.count(); ++i) { QDomElement effect = effects.at(i).cloneNode().toElement(); indexes << effect.attribute(QStringLiteral("kdenlive_ix")).toInt(); } //qDebug()<<"// Moving: "<setDropAction(Qt::CopyAction); event->accept(); slotAddEffect(e); return; } else { // User is moving an effect if (e.attribute(QStringLiteral("id")) == QLatin1String("speed")) { // Speed effect cannot be moved event->ignore(); return; } slotMoveEffect(QList () << ix, m_currentEffectList.count() + 1, -1); } event->setDropAction(Qt::MoveAction); event->accept(); } void EffectStackView2::dropEvent(QDropEvent *event) { const QString effects = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/effectslist"))); //event->acceptProposedAction(); QDomDocument doc; doc.setContent(effects, true); processDroppedEffect(doc.documentElement(), event); } void EffectStackView2::setKeyframes(const QString &tag, const QString &data) { for (int i = 0; i < m_effects.count(); ++i) { if (m_effects.at(i)->isActive()) { m_effects.at(i)->setKeyframes(tag, data); break; } } } //static const QString EffectStackView2::getStyleSheet() { KColorScheme scheme(QApplication::palette().currentColorGroup(), KColorScheme::View, KSharedConfig::openConfig(KdenliveSettings::colortheme())); QColor selected_bg = scheme.decoration(KColorScheme::FocusColor).color(); QColor hgh = KColorUtils::mix(QApplication::palette().window().color(), selected_bg, 0.2); QColor hover_bg = scheme.decoration(KColorScheme::HoverColor).color(); QColor light_bg = scheme.shade(KColorScheme::LightShade); QColor alt_bg = scheme.background(KColorScheme::NormalBackground).color(); QString stylesheet; // effect background stylesheet.append(QStringLiteral("QFrame#decoframe {border-top-left-radius:5px;border-top-right-radius:5px;border-bottom:2px solid palette(mid);border-top:1px solid palette(light);} QFrame#decoframe[active=\"true\"] {background: %1;}").arg(hgh.name())); // effect in group background stylesheet.append(QStringLiteral("QFrame#decoframesub {border-top:1px solid palette(light);} QFrame#decoframesub[active=\"true\"] {background: %1;}").arg(hgh.name())); // group background stylesheet.append(QStringLiteral("QFrame#decoframegroup {border-top-left-radius:5px;border-top-right-radius:5px;border:2px solid palette(dark);margin:0px;margin-top:2px;} ")); // effect title bar stylesheet.append(QStringLiteral("QFrame#frame {margin-bottom:2px;border-top-left-radius:5px;border-top-right-radius:5px;} QFrame#frame[target=\"true\"] {background: palette(highlight);}")); // group effect title bar stylesheet.append(QStringLiteral("QFrame#framegroup {border-top-left-radius:2px;border-top-right-radius:2px;background: palette(dark);} QFrame#framegroup[target=\"true\"] {background: palette(highlight);} ")); // draggable effect bar content stylesheet.append(QStringLiteral("QProgressBar::chunk:horizontal {background: palette(button);border-top-left-radius: 4px;border-bottom-left-radius: 4px;} QProgressBar::chunk:horizontal#dragOnly {background: %1;border-top-left-radius: 4px;border-bottom-left-radius: 4px;} QProgressBar::chunk:horizontal:hover {background: %2;}").arg(alt_bg.name(), selected_bg.name())); // draggable effect bar stylesheet.append(QStringLiteral("QProgressBar:horizontal {border: 1px solid palette(dark);border-top-left-radius: 4px;border-bottom-left-radius: 4px;border-right:0px;background:%3;padding: 0px;text-align:left center} QProgressBar:horizontal:disabled {border: 1px solid palette(button)} QProgressBar:horizontal#dragOnly {background: %3} QProgressBar:horizontal[inTimeline=\"true\"] { border: 1px solid %1;border-right: 0px;background: %2;padding: 0px;text-align:left center } QProgressBar::chunk:horizontal[inTimeline=\"true\"] {background: %1;}").arg(hover_bg.name(), light_bg.name(), alt_bg.name())); // spin box for draggable widget stylesheet.append(QStringLiteral("QAbstractSpinBox#dragBox {border: 1px solid palette(dark);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 palette(button);} QAbstractSpinBox::up-button#dragBox {width:0px;padding:0px;} QAbstractSpinBox[inTimeline=\"true\"]#dragBox { border: 1px solid %1;} QAbstractSpinBox:hover#dragBox {border: 1px solid %2;} ").arg(hover_bg.name(), selected_bg.name())); // group editable labels stylesheet.append(QStringLiteral("MyEditableLabel { background-color: transparent; color: palette(bright-text); border-radius: 2px;border: 1px solid transparent;} MyEditableLabel:hover {border: 1px solid palette(highlight);} ")); - + // transparent qcombobox stylesheet.append(QStringLiteral("QComboBox { background-color: transparent;} ")); return stylesheet; } void EffectStackView2::disableBinEffects(bool disable) { if (disable) { if (m_stateStatus == NORMALSTATUS) { m_stateStatus = DISABLEBIN; } else if (m_stateStatus == DISABLETIMELINE) { m_stateStatus = DISABLEALL; } } else { if (m_stateStatus == DISABLEBIN) { m_stateStatus = NORMALSTATUS; } else if (m_stateStatus == DISABLEALL) { m_stateStatus = DISABLETIMELINE; } } if (m_status == MASTER_CLIP) m_effect->setEnabled(!disable); } void EffectStackView2::disableTimelineEffects(bool disable) { if (disable) { if (m_stateStatus == NORMALSTATUS) { m_stateStatus = DISABLETIMELINE; } else if (m_stateStatus == DISABLEBIN) { m_stateStatus = DISABLEALL; } } else { if (m_stateStatus == DISABLETIMELINE) { m_stateStatus = NORMALSTATUS; } else if (m_stateStatus == DISABLEALL) { m_stateStatus = DISABLEBIN; } } if (m_status == TIMELINE_CLIP) m_effect->setEnabled(!disable); } void EffectStackView2::slotSwitchCompare(bool enable) { int pos = 0; if (enable) { if (m_status == TIMELINE_CLIP) { pos = (m_effectMetaInfo.monitor->position() - m_clipref->startPos()).frames(KdenliveSettings::project_fps()); } else { pos = m_effectMetaInfo.monitor->position().frames(KdenliveSettings::project_fps()); } m_effectMetaInfo.monitor->slotSwitchCompare(enable, pos); } else { if (m_status == TIMELINE_CLIP) { pos = (m_effectMetaInfo.monitor->position() + m_clipref->startPos()).frames(KdenliveSettings::project_fps()); } else { pos = m_effectMetaInfo.monitor->position().frames(KdenliveSettings::project_fps()); } m_effectMetaInfo.monitor->slotSwitchCompare(enable, pos); } } diff --git a/src/effectstack/parametercontainer.cpp b/src/effectstack/parametercontainer.cpp index 4e4f8cc8a..28b3946be 100644 --- a/src/effectstack/parametercontainer.cpp +++ b/src/effectstack/parametercontainer.cpp @@ -1,1363 +1,1370 @@ /*************************************************************************** * Copyright (C) 2012 by Jean-Baptiste Mardelle (jb@kdenlive.org) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include "parametercontainer.h" #include "complexparameter.h" #include "geometryval.h" #include "positionedit.h" #include "dragvalue.h" #include "widgets/kis_curve_widget.h" #include "widgets/kis_cubic_curve.h" #include "widgets/choosecolorwidget.h" #include "widgets/geometrywidget.h" #include "widgets/doubleparameterwidget.h" #include "widgets/cornerswidget.h" #include "widgets/bezier/beziersplinewidget.h" #include "effectstack/widgets/lumaliftgain.h" #include "effectstack/widgets/animationwidget.h" #include "kdenlivesettings.h" #include "mainwindow.h" #include "colortools.h" #include "dialogs/clipcreationdialog.h" #include "mltcontroller/effectscontroller.h" #include "utils/KoIconUtils.h" #include "onmonitoritems/rotoscoping/rotowidget.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 #include "klocalizedstring.h" #include #include #include #include #include #include #include DraggableLabel::DraggableLabel(const QString &text, QWidget *parent): QLabel(text, parent) + , m_dragStarted(false) { setContextMenuPolicy(Qt::NoContextMenu); setToolTip(i18n("Click to copy data to clipboard")); } void DraggableLabel::mousePressEvent(QMouseEvent *ev) { QLabel::mousePressEvent(ev); if (ev->button() == Qt::LeftButton) { m_clickStart = ev->pos(); + m_dragStarted = false; } } void DraggableLabel::mouseReleaseEvent(QMouseEvent *ev) { - QLabel::mouseReleaseEvent(ev); + // Don't call mouserelease in cas of drag because label might be deleted by a drop + if (!m_dragStarted) + QLabel::mouseReleaseEvent(ev); + else + ev->ignore(); m_clickStart = QPoint(); } void DraggableLabel::mouseMoveEvent(QMouseEvent *ev) { QLabel::mouseMoveEvent(ev); if (!m_clickStart.isNull() && (m_clickStart - ev->pos()).manhattanLength() >= QApplication::startDragDistance()) { emit startDrag(objectName()); + m_dragStarted = true; m_clickStart = QPoint(); } } MySpinBox::MySpinBox(QWidget * parent): QSpinBox(parent) { setFocusPolicy(Qt::StrongFocus); } void MySpinBox::focusInEvent(QFocusEvent *e) { setFocusPolicy(Qt::WheelFocus); e->accept(); } void MySpinBox::focusOutEvent(QFocusEvent *e) { setFocusPolicy(Qt::StrongFocus); e->accept(); } 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 { }; class Keywordval: public QWidget, public Ui::Keywordval_UI { }; class Fontval: public QWidget, public Ui::Fontval_UI { }; ParameterContainer::ParameterContainer(const QDomElement &effect, const ItemInfo &info, EffectMetaInfo *metaInfo, QWidget * parent) : m_info(info), m_keyframeEditor(NULL), m_geometryWidget(NULL), m_animationWidget(NULL), m_metaInfo(metaInfo), m_effect(effect), m_acceptDrops(false), m_monitorEffectScene(MonitorSceneDefault), m_conditionParameter(false) { QLocale locale; locale.setNumberOptions(QLocale::OmitGroupSeparator); setObjectName(QStringLiteral("ParameterContainer")); m_in = info.cropStart.frames(KdenliveSettings::project_fps()); m_out = (info.cropStart + info.cropDuration).frames(KdenliveSettings::project_fps()) - 1; QDomNodeList namenode = effect.childNodes(); QDomElement e = effect.toElement(); int minFrame = e.attribute(QStringLiteral("start")).toInt(); int maxFrame = e.attribute(QStringLiteral("end")).toInt(); // In transitions, maxFrame is in fact one frame after the end of transition if (maxFrame > 0) maxFrame --; bool disable = effect.attribute(QStringLiteral("disable")) == QLatin1String("1") && KdenliveSettings::disable_effect_parameters(); parent->setEnabled(!disable); bool stretch = true; m_vbox = new QVBoxLayout(parent); m_vbox->setContentsMargins(4, 0, 4, 0); m_vbox->setSpacing(2); /* QDomElement clone = effect.cloneNode(true).toElement(); QDomDocument doc; doc.appendChild(doc.importNode(clone, true)); qDebug()<<"-------------------------------------\n"<<"LOADED TRANS: "<addWidget(gainWidget); m_valueItems[effect.attribute(QStringLiteral("id"))] = gainWidget; connect(gainWidget, SIGNAL(valueChanged()), this, SLOT(slotCollectAllParameters())); } else for (int i = 0; i < namenode.count() ; ++i) { QDomElement pa = namenode.item(i).toElement(); if (pa.tagName() == QLatin1String("conditionalinfo")) { // Conditional info KMessageWidget *mw = new KMessageWidget; mw->setWordWrap(true); mw->setMessageType(KMessageWidget::Information); mw->setText(i18n(pa.text().toUtf8().data())); mw->setCloseButtonVisible(false); mw->setVisible(!m_conditionParameter); m_vbox->addWidget(mw); m_conditionalWidgets << mw; } if (pa.tagName() != QLatin1String("parameter")) continue; QDomElement na = pa.firstChildElement(QStringLiteral("name")); QDomElement commentElem = pa.firstChildElement(QStringLiteral("comment")); QString type = pa.attribute(QStringLiteral("type")); QString paramName = na.isNull() ? pa.attribute(QStringLiteral("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(QStringLiteral("value")).isNull() ? pa.attribute(QStringLiteral("default")) : pa.attribute(QStringLiteral("value")); /** See effects/README for info on the different types */ if (type == QLatin1String("double") || type == QLatin1String("constant")) { double min; double max; m_acceptDrops = true; if (pa.attribute(QStringLiteral("min")).contains('%')) min = EffectsController::getStringEval(m_metaInfo->monitor->profileInfo(), pa.attribute(QStringLiteral("min")), m_metaInfo->frameSize); else min = locale.toDouble(pa.attribute(QStringLiteral("min"))); if (pa.attribute(QStringLiteral("max")).contains('%')) max = EffectsController::getStringEval(m_metaInfo->monitor->profileInfo(), pa.attribute(QStringLiteral("max")), m_metaInfo->frameSize); else max = locale.toDouble(pa.attribute(QStringLiteral("max"))); DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, locale.toDouble(value), min, max, locale.toDouble(pa.attribute(QStringLiteral("default"))), comment, -1, pa.attribute(QStringLiteral("suffix")), pa.attribute(QStringLiteral("decimals")).toInt(), false, parent); doubleparam->setFocusPolicy(Qt::StrongFocus); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { doubleparam->setEnabled(false); m_conditionalWidgets << doubleparam; } 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 == QLatin1String("list")) { Listval *lsval = new Listval; lsval->setupUi(toFillin); lsval->list->setFocusPolicy(Qt::StrongFocus); QString items = pa.attribute(QStringLiteral("paramlist")); QStringList listitems; if (items == QLatin1String("%lumaPaths")) { // Special case: Luma files // Create thumbnails lsval->list->setIconSize(QSize(50, 30)); if (m_metaInfo->monitor->profileInfo().profileSize.width() > 1000) { // HD project listitems = MainWindow::m_lumaFiles.value(QStringLiteral("HD")); } else { listitems = MainWindow::m_lumaFiles.value(QStringLiteral("PAL")); } lsval->list->addItem(i18n("None (Dissolve)")); for (int i = 0; i < listitems.count(); ++i) { QString entry = listitems.at(i); lsval->list->addItem(listitems.at(i).section(QStringLiteral("/"), -1), entry); if (!entry.isEmpty() && (entry.endsWith(QLatin1String(".png")) || entry.endsWith(QLatin1String(".pgm")))) { if (!MainWindow::m_lumacache.contains(entry)) { QImage pix(entry); MainWindow::m_lumacache.insert(entry, pix.scaled(50, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } lsval->list->setItemIcon(i + 1, QPixmap::fromImage(MainWindow::m_lumacache.value(entry))); } } lsval->list->setCurrentText(pa.attribute(QStringLiteral("default"))); if (!value.isEmpty() && listitems.contains(value)) lsval->list->setCurrentIndex(listitems.indexOf(value) + 1); } else { listitems = items.split(';'); if (listitems.count() == 1) { // probably custom effect created before change to ';' as separator listitems = pa.attribute(QStringLiteral("paramlist")).split(','); } QDomElement list = pa.firstChildElement(QStringLiteral("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; for (int i = 0; i < listitems.count(); ++i) { lsval->list->addItem(listitemsdisplay.at(i), listitems.at(i)); } if (!value.isEmpty() && listitems.contains(value)) lsval->list->setCurrentIndex(listitems.indexOf(value)); } lsval->name->setText(paramName); lsval->setToolTip(comment); lsval->labelComment->setText(comment); lsval->widgetComment->setHidden(true); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { lsval->list->setEnabled(false); m_conditionalWidgets << lsval->list; } 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 == QLatin1String("bool")) { Boolval *bval = new Boolval; bval->setupUi(toFillin); bval->checkBox->setCheckState(value == QLatin1String("0") ? Qt::Unchecked : Qt::Checked); bval->name->setText(paramName); bval->name->setToolTip(comment); bval->labelComment->setText(comment); bval->widgetComment->setHidden(true); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { bval->setEnabled(false); m_conditionalWidgets << bval; } 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 == QLatin1String("switch")) { Boolval *bval = new Boolval; bval->setupUi(toFillin); bval->checkBox->setCheckState(value == pa.attribute("min") ? Qt::Unchecked : Qt::Checked); bval->name->setText(paramName); bval->name->setToolTip(comment); bval->labelComment->setText(comment); bval->widgetComment->setHidden(true); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { bval->setEnabled(false); m_conditionalWidgets << bval; } 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.startsWith(QLatin1String("animated"))) { m_acceptDrops = true; if (type == QLatin1String("animatedrect")) { m_monitorEffectScene = MonitorSceneGeometry; } if (m_animationWidget) { m_animationWidget->addParameter(pa); } else { m_animationWidget = new AnimationWidget(m_metaInfo, info.startPos.frames(KdenliveSettings::project_fps()), m_in, m_out, effect.attribute(QStringLiteral("in")).toInt(), effect.attribute(QStringLiteral("id")), pa, parent); connect(m_animationWidget, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int))); connect(this, SIGNAL(syncEffectsPos(int)), m_animationWidget, SLOT(slotSyncPosition(int))); connect(this, SIGNAL(initScene(int)), m_animationWidget, SLOT(slotPositionChanged(int))); connect(m_animationWidget, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); m_vbox->addWidget(m_animationWidget); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { m_animationWidget->setEnabled(false); m_conditionalWidgets << m_animationWidget; } } } else if (type == QLatin1String("complex")) { ComplexParameter *pl = new ComplexParameter; pl->setupParam(effect, pa.attribute(QStringLiteral("name")), 0, 100); m_vbox->addWidget(pl); m_valueItems[paramName+"complex"] = pl; connect(pl, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); } else if (type == QLatin1String("geometry")) { m_acceptDrops = true; if (true /*KdenliveSettings::on_monitor_effects()*/) { m_monitorEffectScene = MonitorSceneGeometry; bool useOffset = false; if (effect.tagName() == QLatin1String("effect") && effect.hasAttribute(QStringLiteral("kdenlive:sync_in_out")) && effect.attribute(QStringLiteral("kdenlive:sync_in_out")).toInt() == 0) { useOffset = true; } m_geometryWidget = new GeometryWidget(m_metaInfo, info.startPos.frames(KdenliveSettings::project_fps()), effect.hasAttribute(QStringLiteral("showrotation")), useOffset, parent); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { m_geometryWidget->setEnabled(false); m_conditionalWidgets << m_geometryWidget; } connect(m_geometryWidget, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); if (minFrame == maxFrame) { m_geometryWidget->setupParam(pa, m_in, m_out); connect(this, SIGNAL(updateRange(int,int)), m_geometryWidget, SLOT(slotUpdateRange(int,int))); } 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(m_geometryWidget, SIGNAL(importClipKeyframes()), this, SIGNAL(importClipKeyframes())); connect(this, SIGNAL(syncEffectsPos(int)), m_geometryWidget, SLOT(slotSyncPosition(int))); connect(this, SIGNAL(initScene(int)), m_geometryWidget, SLOT(slotInitScene(int))); } else { Geometryval *geo = new Geometryval(m_metaInfo->monitor->profile(), m_metaInfo->monitor->timecode(), m_metaInfo->frameSize, 0); if (minFrame == maxFrame) { geo->setupParam(pa, m_in, m_out); connect(this, SIGNAL(updateRange(int,int)), geo, SLOT(slotUpdateRange(int,int))); } else geo->setupParam(pa, minFrame, maxFrame); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { geo->setEnabled(false); m_conditionalWidgets << geo; } 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 == QLatin1String("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 == QLatin1String("keyframe") || type == QLatin1String("simplekeyframe")) { // keyframe editor widget if (m_keyframeEditor == NULL) { KeyframeEdit *geo; if (pa.attribute(QStringLiteral("widget")) == QLatin1String("corners")) { // we want a corners-keyframe-widget int relativePos = (m_metaInfo->monitor->position() - info.startPos).frames(KdenliveSettings::project_fps()); CornersWidget *corners = new CornersWidget(m_metaInfo->monitor, pa, m_in, m_out, relativePos, m_metaInfo->monitor->timecode(), e.attribute(QStringLiteral("active_keyframe"), QStringLiteral("-1")).toInt(), parent); connect(this, SIGNAL(updateRange(int,int)), corners, SLOT(slotUpdateRange(int,int))); m_monitorEffectScene = MonitorSceneCorners; connect(this, &ParameterContainer::updateFrameInfo, corners, &CornersWidget::setFrameSize); connect(this, SIGNAL(syncEffectsPos(int)), corners, SLOT(slotSyncPosition(int))); geo = static_cast(corners); } else { geo = new KeyframeEdit(pa, m_in, m_out, m_metaInfo->monitor->timecode(), e.attribute(QStringLiteral("active_keyframe"), QStringLiteral("-1")).toInt()); connect(this, SIGNAL(updateRange(int,int)), geo, SLOT(slotUpdateRange(int,int))); } if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { geo->setEnabled(false); m_conditionalWidgets << geo; } 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 == QLatin1String("color")) { if (pa.hasAttribute(QStringLiteral("paramprefix"))) value.remove(0, pa.attribute(QStringLiteral("paramprefix")).size()); if (value.startsWith('#')) value = value.replace('#', QLatin1String("0x")); ChooseColorWidget *choosecolor = new ChooseColorWidget(paramName, value, pa.hasAttribute(QStringLiteral("alpha")), parent); choosecolor->setToolTip(comment); m_vbox->addWidget(choosecolor); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { choosecolor->setEnabled(false); m_conditionalWidgets << choosecolor; } m_valueItems[paramName] = choosecolor; connect(choosecolor, SIGNAL(displayMessage(QString,int)), this, SIGNAL(displayMessage(QString,int))); connect(choosecolor, SIGNAL(modified()) , this, SLOT(slotCollectAllParameters())); connect(choosecolor, SIGNAL(disableCurrentFilter(bool)) , this, SIGNAL(disableCurrentFilter(bool))); } else if (type == QLatin1String("position")) { int pos = value.toInt(); if (effect.attribute(QStringLiteral("id")) == QLatin1String("fadein") || effect.attribute(QStringLiteral("id")) == QLatin1String("fade_from_black")) { pos = pos - m_in; } else if (effect.attribute(QStringLiteral("id")) == QLatin1String("fadeout") || effect.attribute(QStringLiteral("id")) == QLatin1String("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->monitor->timecode()); posedit->setToolTip(comment); connect(this, SIGNAL(updateRange(int,int)), posedit, SLOT(setRange(int,int))); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { posedit->setEnabled(false); m_conditionalWidgets << posedit; } m_vbox->addWidget(posedit); m_valueItems[paramName+"position"] = posedit; connect(posedit, SIGNAL(parameterChanged()), this, SLOT(slotCollectAllParameters())); } else if (type == QLatin1String("curve")) { KisCurveWidget *curve = new KisCurveWidget(parent); curve->setMaxPoints(pa.attribute(QStringLiteral("max")).toInt()); QList points; int number; double version = 0; QDomElement namenode = effect.firstChildElement(QStringLiteral("version")); if (!namenode.isNull()) { version = locale.toDouble(namenode.text()); } if (version > 0.2) { // Rounding gives really weird results. (int) (10 * 0.3) gives 2! So for now, add 0.5 to get correct result number = locale.toDouble(EffectsList::parameter(e, pa.attribute(QStringLiteral("number")))) * 10 + 0.5; } else { number = EffectsList::parameter(e, pa.attribute(QStringLiteral("number"))).toInt(); } QString inName = pa.attribute(QStringLiteral("inpoints")); QString outName = pa.attribute(QStringLiteral("outpoints")); int start = pa.attribute(QStringLiteral("min")).toInt(); for (int j = start; j <= number; ++j) { QString in = inName; in.replace(QLatin1String("%i"), QString::number(j)); QString out = outName; out.replace(QLatin1String("%i"), QString::number(j)); points << QPointF(locale.toDouble(EffectsList::parameter(e, in)), locale.toDouble(EffectsList::parameter(e, out))); } 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); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { curve->setEnabled(false); spinin->setEnabled(false); spinout->setEnabled(false); } m_vbox->addWidget(curve); m_vbox->addWidget(spinin); m_vbox->addWidget(spinout); connect(curve, SIGNAL(modified()), this, SLOT(slotCollectAllParameters())); m_valueItems[paramName] = curve; QString depends = pa.attribute(QStringLiteral("depends")); if (!depends.isEmpty()) meetDependency(paramName, type, EffectsList::parameter(e, depends)); } else if (type == QLatin1String("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(QStringLiteral("depends")); if (!depends.isEmpty()) meetDependency(paramName, type, EffectsList::parameter(e, depends)); } else if (type == QLatin1String("roto-spline")) { m_monitorEffectScene = MonitorSceneRoto; RotoWidget *roto = new RotoWidget(value.toLatin1(), m_metaInfo->monitor, info, m_metaInfo->monitor->timecode(), parent); connect(roto, SIGNAL(valueChanged()), this, SLOT(slotCollectAllParameters())); connect(roto, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int))); connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int))); m_vbox->addWidget(roto); m_valueItems[paramName] = roto; } else if (type == QLatin1String("wipe")) { Wipeval *wpval = new Wipeval; wpval->setupUi(toFillin); // Make sure button shows its pressed state even if widget loses focus QColor bg = QPalette().highlight().color(); toFillin->setStyleSheet(QStringLiteral("QPushButton:checked {background-color:rgb(%1,%2,%3);}").arg(bg.red()).arg(bg.green()).arg(bg.blue())); 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 == QLatin1String("url")) { Urlval *cval = new Urlval; cval->setupUi(toFillin); cval->label->setText(paramName); cval->setToolTip(comment); cval->urlwidget->setFilter(ClipCreationDialog::getExtensions().join(' ')); m_valueItems[paramName] = cval; cval->urlwidget->setUrl(QUrl(value)); connect(cval->urlwidget, SIGNAL(returnPressed()) , this, SLOT(slotCollectAllParameters())); connect(cval->urlwidget, SIGNAL(urlSelected(QUrl)) , this, SLOT(slotCollectAllParameters())); if (m_conditionParameter && pa.hasAttribute(QStringLiteral("conditional"))) { cval->setEnabled(false); m_conditionalWidgets << cval; } m_uiItems.append(cval); } else if (type == QLatin1String("keywords")) { Keywordval* kval = new Keywordval; kval->setupUi(toFillin); kval->label->setText(paramName); kval->lineeditwidget->setText(value); kval->setToolTip(comment); QDomElement klistelem = pa.firstChildElement(QStringLiteral("keywords")); QDomElement kdisplaylistelem = pa.firstChildElement(QStringLiteral("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)); } // Add disabled user prompt at index 0 kval->comboboxwidget->insertItem(0, i18n("