QDomDocument doc;
doc.setContent(effects, true);
QDomElement e = doc.documentElement();
+ e.setAttribute("kdenlive_ix", 0);
CustomTrackView *view = (CustomTrackView *) scene()->views()[0];
if (view) view->slotAddGroupEffect(e, this);
}
event->acceptProposedAction();
QDomDocument doc;
doc.setContent(effects, true);
- const QDomElement e = doc.documentElement();
+ QDomElement e = doc.documentElement();
+ e.setAttribute("kdenlive_ix", 0);
CustomTrackView *view = (CustomTrackView *) scene()->views()[0];
if (view) view->slotAddEffect(e, m_info.startPos, track());
}
if (clip) command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), oldeffect, effect, ix, true);
else command = new EditEffectCommand(this, m_document->tracksCount() - track, GenTime(-1), oldeffect, effect, ix, true);
m_commandStack->push(command);
+ kDebug()<<"// UPDATE EFFECT, "<<EffectsList::property(effect, "kdenlive_ix")<<" / "<<EffectsList::property(effect, "kdenlive_group");
}
void CustomTrackView::slotUpdateClipRegion(ClipItem *clip, int ix, QString region)
{
QDomNodeList params = effect.elementsByTagName("property");
// Update property if it already exists
+ bool found = false;
for (int i = 0; i < params.count(); i++) {
QDomElement e = params.item(i).toElement();
if (e.attribute("name") == name) {
e.firstChild().setNodeValue(value);
+ found = true;
break;
}
}
+ if (!found) {
+ // create property
+ QDomDocument doc = effect.ownerDocument();
+ QDomElement e = doc.createElement("property");
+ e.setAttribute("name", name);
+ QDomText val = doc.createTextNode(value);
+ e.appendChild(val);
+ effect.appendChild(e);
+ }
}
// static
}
-CollapsibleEffect::CollapsibleEffect(QDomElement effect, QDomElement original_effect, ItemInfo info, int ix, EffectMetaInfo *metaInfo, bool lastEffect, QWidget * parent) :
+CollapsibleEffect::CollapsibleEffect(QDomElement effect, QDomElement original_effect, ItemInfo info, int ix, EffectMetaInfo *metaInfo, bool lastEffect, bool isGroup, QWidget * parent) :
QWidget(parent),
m_paramWidget(NULL),
m_effect(effect),
m_original_effect(original_effect),
m_lastEffect(lastEffect),
+ m_isGroup(isGroup),
m_active(false)
{
//setMouseTracking(true);
//checkAll->setToolTip(i18n("Enable/Disable all effects"));
//buttonShowComments->setIcon(KIcon("help-about"));
//buttonShowComments->setToolTip(i18n("Show additional information for the parameters"));
- QDomElement namenode = m_effect.firstChildElement("name");
- if (namenode.isNull()) return;
- title->setText(i18n(namenode.text().toUtf8().data()));
- QString type = m_effect.attribute("type", QString());
- KIcon icon;
- if (type == "audio") icon = KIcon("kdenlive-show-audio");
- else if (m_effect.attribute("tag") == "region") icon = KIcon("kdenlive-mask-effect");
- else if (type == "custom") icon = KIcon("kdenlive-custom-effect");
- else icon = KIcon("kdenlive-show-video");
- title->setIcon(icon);
-
m_menu = new QMenu;
m_menu->addAction(KIcon("view-refresh"), i18n("Reset effect"), this, SLOT(slotResetEffect()));
m_menu->addAction(KIcon("document-save"), i18n("Save effect"), this, SLOT(slotSaveEffect()));
+
+ if (!m_isGroup) {
+ QDomElement namenode = m_effect.firstChildElement("name");
+ if (namenode.isNull()) return;
+ title->setText(i18n(namenode.text().toUtf8().data()));
+ QString type = m_effect.attribute("type", QString());
+ KIcon icon;
+ if (type == "audio") icon = KIcon("kdenlive-show-audio");
+ else if (m_effect.attribute("tag") == "region") icon = KIcon("kdenlive-mask-effect");
+ else if (type == "custom") icon = KIcon("kdenlive-custom-effect");
+ else icon = KIcon("kdenlive-show-video");
+ title->setIcon(icon);
+ m_menu->addAction(KIcon("folder-new"), i18n("Create Group"), this, SLOT(slotCreateGroup()));
+ setupWidget(info, ix, metaInfo);
+ }
+ else {
+ setAcceptDrops(true);
+ title->setText(i18n("Effect Group"));
+ title->setIcon(KIcon("folder"));
+ }
+
title->setMenu(m_menu);
if (m_effect.attribute("disable") == "1") {
connect(buttonDown, SIGNAL(clicked()), this, SLOT(slotEffectDown()));
connect(buttonDel, SIGNAL(clicked()), this, SLOT(slotDeleteEffect()));
- setupWidget(info, ix, metaInfo);
Q_FOREACH( QSpinBox * sp, findChildren<QSpinBox*>() ) {
sp->installEventFilter( this );
sp->setFocusPolicy( Qt::StrongFocus );
delete m_menu;
}
+void CollapsibleEffect::slotCreateGroup()
+{
+ emit createGroup(m_paramWidget->index());
+}
+
bool CollapsibleEffect::eventFilter( QObject * o, QEvent * e )
{
if (e->type() == QEvent::Wheel) {
void CollapsibleEffect::enterEvent ( QEvent * event )
{
- if (m_paramWidget->index() > 0) buttonUp->setVisible(true);
+ if (m_paramWidget == NULL || m_paramWidget->index() > 0) buttonUp->setVisible(true);
if (!m_lastEffect) buttonDown->setVisible(true);
buttonDel->setVisible(true);
if (!m_active) frame->setBackgroundRole(QPalette::Midlight);
}
}
+void CollapsibleEffect::addGroupEffect(CollapsibleEffect *effect)
+{
+ QVBoxLayout *vbox = static_cast<QVBoxLayout *>(widgetFrame->layout());
+ if (vbox == NULL) {
+ vbox = new QVBoxLayout();
+ vbox->setContentsMargins(10, 0, 0, 0);
+ vbox->setSpacing(2);
+ widgetFrame->setLayout(vbox);
+ }
+ vbox->addWidget(effect);
+}
+
+int CollapsibleEffect::index() const
+{
+ if (m_paramWidget) return m_paramWidget->index();
+ return 0;
+}
+
+int CollapsibleEffect::effectIndex() const
+{
+ if (m_effect.isNull()) return -1;
+ return m_effect.attribute("kdenlive_ix").toInt();
+}
+
void CollapsibleEffect::updateWidget(ItemInfo info, int index, QDomElement effect, EffectMetaInfo *metaInfo)
{
if (m_paramWidget) {
emit syncEffectsPos(pos);
}
+void CollapsibleEffect::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasFormat("kdenlive/effectslist"))
+ event->acceptProposedAction();
+}
+void CollapsibleEffect::dropEvent(QDropEvent *event)
+{
+ const QString effects = QString::fromUtf8(event->mimeData()->data("kdenlive/effectslist"));
+ //event->acceptProposedAction();
+ QDomDocument doc;
+ doc.setContent(effects, true);
+ const QDomElement e = doc.documentElement();
+ int ix = e.attribute("kdenlive_ix").toInt();
+ emit moveEffect(ix, this);
+ event->setDropAction(Qt::MoveAction);
+ event->accept();
+}
ParameterContainer::ParameterContainer(QDomElement effect, ItemInfo info, EffectMetaInfo *metaInfo, int index, QWidget * parent) :
m_index(index),
return QString(start + ";-1=" + end);
}
-int ParameterContainer::index()
+int ParameterContainer::index() const
{
return m_index;
}
}
}
}
+
~ParameterContainer();
void updateTimecodeFormat();
void updateProjectFormat(MltVideoProfile profile, Timecode t);
- int index();
+ int index() const;
private slots:
void slotCollectAllParameters();
Q_OBJECT
public:
- CollapsibleEffect(QDomElement effect, QDomElement original_effect, ItemInfo info, int ix, EffectMetaInfo *metaInfo, bool lastEffect, QWidget * parent = 0);
+ CollapsibleEffect(QDomElement effect, QDomElement original_effect, ItemInfo info, int ix, EffectMetaInfo *metaInfo, bool lastEffect, bool isGroup = false, QWidget * parent = 0);
~CollapsibleEffect();
static QMap<QString, QImage> iconCache;
void setupWidget(ItemInfo info, int index, EffectMetaInfo *metaInfo);
/** @brief Update effect GUI to reflect parameted changes. */
void updateWidget(ItemInfo info, int index, QDomElement effect, EffectMetaInfo *metaInfo);
QDomElement effect() const;
+ void addGroupEffect(CollapsibleEffect *effect);
+ int index() const;
+ int effectIndex() const;
public slots:
void slotSyncEffectsPos(int pos);
void slotEffectDown();
void slotSaveEffect();
void slotResetEffect();
+ void slotCreateGroup();
private:
ParameterContainer *m_paramWidget;
bool m_lastEffect;
int m_in;
int m_out;
+ bool m_isGroup;
bool m_active;
QMenu *m_menu;
QPoint m_clickPoint;
virtual void mousePressEvent ( QMouseEvent * event );
virtual void enterEvent( QEvent * event );
virtual void leaveEvent( QEvent * event );
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
signals:
void parameterChanged(const QDomElement, const QDomElement, int);
void startFilterJob(QString filterName, QString filterParams, QString finalFilterName, QString consumer, QString consumerParams, QString properties);
/** @brief An effect was saved, trigger effect list reload. */
void reloadEffects();
+ /** @brief An effect was reset, trigger param reload. */
void resetEffect(int ix);
+ /** @brief Ask for creation of a group. */
+ void createGroup(int ix);
+ void moveEffect(int ix, CollapsibleEffect*);
};
QWidget(parent),
m_clipref(NULL),
m_trackindex(-1),
- m_draggedEffect(NULL)
+ m_draggedEffect(NULL),
+ m_groupIndex(0)
{
m_effectMetaInfo.trackMode = false;
m_effectMetaInfo.monitor = monitor;
m_draggedEffect = NULL;
disconnect(m_effectMetaInfo.monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int)));
m_effects.clear();
+ m_groupIndex = 0;
QWidget *view = m_ui.container->takeWidget();
if (view) {
delete view;
kDebug() << " . . . . WARNING, NULL EFFECT IN STACK!!!!!!!!!";
continue;
}
+
+ CollapsibleEffect *group = NULL;
+ QString groupName = EffectsList::property(d, "kdenlive_group");
+ if (!groupName.isEmpty()) {
+ kDebug()<<"// CREATING EWFFECT GRP: "<<groupName;
+ group = new CollapsibleEffect(QDomElement(), QDomElement(), ItemInfo(), groupName.toInt(), &m_effectMetaInfo, false, true, m_ui.container->widget());
+ connect(group, SIGNAL(moveEffect(int, CollapsibleEffect*)), this , SLOT(slotMoveEffectToGroup(int, CollapsibleEffect*)));
+ vbox1->addWidget(group);
+ }
/*QDomDocument doc;
doc.appendChild(doc.importNode(d, true));
}
else info = m_clipref->info();
- CollapsibleEffect *currentEffect = new CollapsibleEffect(d, m_currentEffectList.at(i), info, i, &m_effectMetaInfo, i == m_currentEffectList.count() - 1, view);
+ CollapsibleEffect *currentEffect = new CollapsibleEffect(d, m_currentEffectList.at(i), info, i, &m_effectMetaInfo, i == m_currentEffectList.count() - 1, false, view);
m_effects.append(currentEffect);
- vbox1->addWidget(currentEffect);
+ if (group) {
+ group->addGroupEffect(currentEffect);
+ } else {
+ vbox1->addWidget(currentEffect);
+ }
// Check drag & drop
currentEffect->installEventFilter( this );
connect(currentEffect, SIGNAL(activateEffect(int)), this, SLOT(slotSetCurrentEffect(int)));
connect(currentEffect, SIGNAL(checkMonitorPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
connect(currentEffect, SIGNAL(seekTimeline(int)), this , SLOT(slotSeekTimeline(int)));
- //ui.title->setPixmap(icon.pixmap(QSize(12, 12)));
+ connect(currentEffect, SIGNAL(createGroup(int)), this , SLOT(slotCreateGroup(int)));
+ connect(currentEffect, SIGNAL(moveEffect(int, CollapsibleEffect*)), this , SLOT(slotMoveEffectToGroup(int, CollapsibleEffect*)));
+
+ //ui.title->setPixmap(icon.pixmap(QSize(12, 12)));
}
vbox1->addStretch(10);
connect(m_effectMetaInfo.monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int)));
QDomElement effect = m_draggedEffect->effect().cloneNode().toElement();
QPixmap pixmap = QPixmap::grabWidget(m_draggedEffect->title);
drag->setPixmap(pixmap);
- effect.setAttribute("kdenlive_ix", 0);
QDomDocument doc;
doc.appendChild(doc.importNode(effect, true));
QMimeData *mime = new QMimeData;
// 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);
+ drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
}
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_effectMetaInfo.trackMode)
}
if (!dom.isNull()) {
dom.setAttribute("kdenlive_ix", old.attribute("kdenlive_ix"));
- //TODO: Track mode
if (m_effectMetaInfo.trackMode) {
EffectsList::setParameter(dom, "in", QString::number(0));
EffectsList::setParameter(dom, "out", QString::number(m_trackInfo.duration));
} else {
m_clipref->initEffect(dom);
m_effects.at(ix)->updateWidget(m_clipref->info(), ix, dom, &m_effectMetaInfo);
- //m_effectedit->transferParamDesc(dom, m_clipref->info());
//m_ui.region_url->setUrl(KUrl(dom.attribute("region")));
emit updateEffect(m_clipref, -1, old, dom, ix);
}
m_ui.labelComment->setHidden(!m_ui.buttonShowComments->isChecked() || !m_ui.labelComment->text().count());*/
}
+
+void EffectStackView2::slotCreateGroup(int ix)
+{
+ QDomElement oldeffect = m_currentEffectList.at(ix);
+ QDomElement neweffect = oldeffect.cloneNode().toElement();
+ QString groupName = QString::number(m_groupIndex);
+ m_groupIndex++;
+ EffectsList::setProperty(neweffect, "kdenlive_group", groupName);
+
+ ItemInfo info;
+ if (m_effectMetaInfo.trackMode) {
+ 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);
+ } else {
+ emit updateEffect(m_clipref, -1, oldeffect, neweffect, ix);
+ }
+
+ QVBoxLayout *l = static_cast<QVBoxLayout *>(m_ui.container->widget()->layout());
+ int groupPos = l->indexOf(m_effects.at(ix));
+
+ CollapsibleEffect *group = new CollapsibleEffect(QDomElement(), QDomElement(), ItemInfo(), m_groupIndex, &m_effectMetaInfo, false, true, m_ui.container->widget());
+ connect(group, SIGNAL(moveEffect(int, CollapsibleEffect*)), this , SLOT(slotMoveEffectToGroup(int, CollapsibleEffect*)));
+ CollapsibleEffect *w = static_cast<CollapsibleEffect*>(l->takeAt(groupPos)->widget());
+ l->insertWidget(groupPos, group);
+ group->addGroupEffect(w);
+}
+
+void EffectStackView2::slotMoveEffectToGroup(int ix, CollapsibleEffect* group)
+{
+ QVBoxLayout *l = static_cast<QVBoxLayout *>(m_ui.container->widget()->layout());
+ CollapsibleEffect *effectToMove = getEffectByIndex(ix);
+ if (effectToMove == NULL) return;
+ l->removeWidget(effectToMove);
+ group->addGroupEffect(effectToMove);
+}
+
#include "effectstackview2.moc"
/** @brief Used to trigger drag effects. */
virtual bool eventFilter( QObject * o, QEvent * e );
+
+ CollapsibleEffect *getEffectByIndex(int ix);
protected:
virtual void mouseMoveEvent(QMouseEvent * event);
/** @brief The effect currently being dragged, NULL if no drag happening. */
CollapsibleEffect *m_draggedEffect;
+
+ /** @brief The current number of groups. */
+ int m_groupIndex;
/** @brief Sets the list of effects according to the clip's effect list.
* @param ix Number of the effect to preselect */
/** @brief Reset an effect to its default values. */
void slotResetEffect(int ix);
+
+ /** @brief Create a group containing effect with ix index. */
+ void slotCreateGroup(int ix);
+
+ /** @brief Move an effect into a group. */
+ void slotMoveEffectToGroup(int, CollapsibleEffect*);
signals: