#include <KLocale>
-MoveEffectCommand::MoveEffectCommand(CustomTrackView *view, const int track, GenTime pos, int oldPos, int newPos, QUndoCommand * parent) :
+MoveEffectCommand::MoveEffectCommand(CustomTrackView *view, const int track, GenTime pos, QList <int> oldPos, int newPos, QUndoCommand * parent) :
QUndoCommand(parent),
m_view(view),
m_track(track),
m_oldindex(oldPos),
- m_newindex(newPos),
m_pos(pos)
{
+ for (int i = 0; i < m_oldindex.count(); i++) {
+ m_newindex << newPos + i;
+ }
/* QString effectName;
QDomElement namenode = effect.firstChildElement("name");
if (!namenode.isNull()) effectName = i18n(namenode.text().toUtf8().data());
class MoveEffectCommand : public QUndoCommand
{
public:
- MoveEffectCommand(CustomTrackView *view, const int track, GenTime pos, int oldPos, int newPos, QUndoCommand * parent = 0);
+ MoveEffectCommand(CustomTrackView *view, const int track, GenTime pos, QList <int> oldPos, int newPos, QUndoCommand * parent = 0);
virtual int id() const;
virtual bool mergeWith(const QUndoCommand * command);
private:
CustomTrackView *m_view;
int m_track;
- int m_oldindex;
- int m_newindex;
+ QList <int> m_oldindex;
+ QList <int> m_newindex;
GenTime m_pos;
};
setDocumentModified();
}
-void CustomTrackView::moveEffect(int track, GenTime pos, int oldPos, int newPos)
+void CustomTrackView::moveEffect(int track, GenTime pos, QList <int> oldPos, QList <int> newPos)
{
if (pos < GenTime()) {
// Moving track effect
- if (newPos > m_document->getTrackEffects(m_document->tracksCount() - track - 1).count()) {
- newPos = m_document->getTrackEffects(m_document->tracksCount() - track - 1).count();
+ int documentTrack = m_document->tracksCount() - track - 1;
+ int max = m_document->getTrackEffects(documentTrack).count();
+ int new_position = newPos.at(0);
+ if (new_position > max) {
+ new_position = max;
}
- QDomElement act = m_document->getTrackEffect(m_document->tracksCount() - track - 1, newPos);
- QDomElement before = m_document->getTrackEffect(m_document->tracksCount() - track - 1, oldPos);
- if (!act.isNull() && !before.isNull()) {
- //m_document->setTrackEffect(m_document->tracksCount() - track - 1, oldPos, act);
- m_document->setTrackEffect(m_document->tracksCount() - track - 1, newPos, before);
- m_document->renderer()->mltMoveEffect(m_document->tracksCount() - track, pos, oldPos, newPos);
- emit showTrackEffects(m_document->tracksCount() - track, m_document->trackInfoAt(m_document->tracksCount() - track - 1));
- } else emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
+ int old_position = oldPos.at(0);
+ for (int i = 0; i < newPos.count(); i++) {
+ QDomElement act = m_document->getTrackEffect(documentTrack, new_position);
+ if (old_position > new_position) {
+ // Moving up, we need to adjust index
+ old_position = oldPos.at(i);
+ new_position = newPos.at(i);
+ }
+ QDomElement before = m_document->getTrackEffect(documentTrack, old_position);
+ if (!act.isNull() && !before.isNull()) {
+ m_document->setTrackEffect(documentTrack, new_position, before);
+ m_document->renderer()->mltMoveEffect(m_document->tracksCount() - track, pos, old_position, new_position);
+ } else emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
+ }
+ emit showTrackEffects(m_document->tracksCount() - track, m_document->trackInfoAt(documentTrack));
return;
}
ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()), m_document->tracksCount() - track);
- if (newPos > clip->effectsCount()) {
- newPos = clip->effectsCount();
- }
if (clip) {
- QDomElement act = clip->effectAt(newPos);
- QDomElement before = clip->effectAt(oldPos);
- if (act.isNull() || before.isNull()) {
- emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
- return;
+ int new_position = newPos.at(0);
+ if (new_position > clip->effectsCount()) {
+ new_position = clip->effectsCount();
}
- //clip->moveEffect(act, oldPos);
- clip->moveEffect(before, newPos);
- // special case: speed effect, which is a pseudo-effect, not appearing in MLT's effects
- if (act.attribute("id") == "speed") {
- m_document->renderer()->mltUpdateEffectPosition(track, pos, oldPos, newPos);
- } else if (before.attribute("id") == "speed") {
- m_document->renderer()->mltUpdateEffectPosition(track, pos, newPos, oldPos);
- } else m_document->renderer()->mltMoveEffect(track, pos, oldPos, newPos);
- clip->setSelectedEffect(newPos);
- emit clipItemSelected(clip);
+ int old_position = oldPos.at(0);
+ for (int i = 0; i < newPos.count(); i++) {
+ QDomElement act = clip->effectAt(new_position);
+ if (old_position > new_position) {
+ // Moving up, we need to adjust index
+ old_position = oldPos.at(i);
+ new_position = newPos.at(i);
+ }
+ QDomElement before = clip->effectAt(old_position);
+ if (act.isNull() || before.isNull()) {
+ emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
+ return;
+ }
+ clip->moveEffect(before, new_position);
+ // special case: speed effect, which is a pseudo-effect, not appearing in MLT's effects
+ if (act.attribute("id") == "speed") {
+ m_document->renderer()->mltUpdateEffectPosition(track, pos, old_position, new_position);
+ } else if (before.attribute("id") == "speed") {
+ m_document->renderer()->mltUpdateEffectPosition(track, pos, new_position, old_position);
+ } else m_document->renderer()->mltMoveEffect(track, pos, old_position, new_position);
+ }
+ clip->setSelectedEffect(newPos.at(0));
+ emit clipItemSelected(clip);
setDocumentModified();
} else emit displayMessage(i18n("Cannot move effect"), ErrorMessage);
}
setDocumentModified();;
}
-void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int track, int currentPos, int newPos)
+void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int track, QList <int> currentPos, int newPos)
{
MoveEffectCommand *command;
if (clip == NULL) {
void addEffect(int track, GenTime pos, QDomElement effect);
void deleteEffect(int track, GenTime pos, QDomElement effect);
void updateEffect(int track, GenTime pos, QDomElement insertedEffect, int ix, bool refreshEffectStack = false);
- void moveEffect(int track, GenTime pos, int oldPos, int newPos);
+ void moveEffect(int track, GenTime pos, QList <int> oldPos, QList <int> newPos);
void addTransition(ItemInfo transitionInfo, int endTrack, QDomElement params, bool refresh);
void deleteTransition(ItemInfo transitionInfo, int endTrack, QDomElement params, bool refresh);
void updateTransition(int track, GenTime pos, QDomElement oldTransition, QDomElement transition, bool updateTransitionWidget);
void updateCursorPos();
void slotDeleteEffect(ClipItem *clip, int track, QDomElement effect, bool affectGroup = true);
void slotChangeEffectState(ClipItem *clip, int track, int effectPos, bool disable);
- void slotChangeEffectPosition(ClipItem *clip, int track, int currentPos, int newPos);
+ void slotChangeEffectPosition(ClipItem *clip, int track, QList <int> currentPos, int newPos);
void slotUpdateClipEffect(ClipItem *clip, int track, QDomElement oldeffect, QDomElement effect, int ix, bool refreshEffectStack = true);
void slotUpdateClipRegion(ClipItem *clip, int ix, QString region);
void slotRefreshEffects(ClipItem *clip);
class EffectInfo
{
public:
- EffectInfo() {isCollapsed = false; groupIndex = -1;}
+ EffectInfo() {isCollapsed = false; groupIndex = -1; groupIsCollapsed = false;}
bool isCollapsed;
+ bool groupIsCollapsed;
int groupIndex;
QString groupName;
QString toString() const {
QStringList data;
- data << QString::number(isCollapsed) << QString::number(groupIndex) << groupName;
+ // effect collapsed state: 0 = effect not collapsed, 1 = effect collapsed,
+ // 2 = group collapsed - effect not, 3 = group and effect collapsed
+ int collapsedState = (int) isCollapsed;
+ if (groupIsCollapsed) collapsedState += 2;
+ data << QString::number(collapsedState) << QString::number(groupIndex) << groupName;
return data.join("/");
}
void fromString(QString value) {
if (value.isEmpty()) return;
QStringList data = value.split("/");
- isCollapsed = data.at(0).toInt();
+ isCollapsed = data.at(0).toInt() == 1 || data.at(0).toInt() == 3;
+ groupIsCollapsed = data.at(0).toInt() == 3;
if (data.count() > 1) groupIndex = data.at(1).toInt();
if (data.count() > 2) groupName = data.at(2);
}
collapseButton->setArrowType(Qt::RightArrow);
m_info.isCollapsed = true;
}
- m_effect.setAttribute("kdenlive_info", m_info.toString());
- emit parameterChanged(m_original_effect, m_effect, effectIndex());
+ updateCollapsedState();
+}
+
+void CollapsibleEffect::groupStateChanged(bool collapsed)
+{
+ m_info.groupIsCollapsed = collapsed;
+ updateCollapsedState();
+}
+
+void CollapsibleEffect::updateCollapsedState()
+{
+ QString info = m_info.toString();
+ if (info != m_effect.attribute("kdenlive_info")) {
+ m_effect.setAttribute("kdenlive_info", info);
+ emit parameterChanged(m_original_effect, m_effect, effectIndex());
+ }
}
void CollapsibleEffect::setGroupIndex(int ix)
{
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
doc.setContent(effects, true);
QDomElement e = doc.documentElement();
int ix = e.attribute("kdenlive_ix").toInt();
- if (ix == effectIndex()) {
+ int currentEffectIx = effectIndex();
+ if (ix == currentEffectIx) {
// effect dropped on itself, reject
event->ignore();
return;
}
- if (ix == 0) {
+ if (ix == 0 || e.tagName() == "effectgroup") {
+ if (e.tagName() == "effectgroup") {
+ // moving a group
+ QDomNodeList subeffects = e.elementsByTagName("effect");
+ if (subeffects.isEmpty()) {
+ event->ignore();
+ return;
+ }
+ EffectInfo info;
+ info.fromString(subeffects.at(0).toElement().attribute("kdenlive_info"));
+ event->setDropAction(Qt::MoveAction);
+ event->accept();
+ if (info.groupIndex >= 0) {
+ // Moving group
+ QList <int> 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();
+ }
+ emit moveEffect(effectsIds, currentEffectIx, info.groupIndex, info.groupName);
+ }
+ else {
+ // group effect dropped from effect list
+ if (m_info.groupIndex > -1) {
+ // TODO: Should we merge groups??
+
+ }
+ emit addEffect(e);
+ }
+ return;
+ }
// effect dropped from effects list, add it
e.setAttribute("kdenlive_ix", ix);
+ if (m_info.groupIndex > -1) {
+ // Dropped on a group
+ e.setAttribute("kdenlive_info", m_info.toString());
+ }
event->setDropAction(Qt::CopyAction);
event->accept();
emit addEffect(e);
return;
}
- emit moveEffect(ix, effectIndex(), m_info.groupIndex, m_info.groupName);
+ emit moveEffect(QList <int> () <<ix, currentEffectIx, m_info.groupIndex, m_info.groupName);
event->setDropAction(Qt::MoveAction);
event->accept();
}
return QString(start + ";-1=" + end);
}
+void ParameterContainer::updateParameter(const QString &key, const QString &value)
+{
+ m_effect.setAttribute(key, value);
+}
+
void ParameterContainer::slotStartFilterJobAction()
{
QDomNodeList namenode = m_effect.elementsByTagName("parameter");
~ParameterContainer();
void updateTimecodeFormat();
void updateProjectFormat(MltVideoProfile profile, Timecode t);
+ void updateParameter(const QString &key, const QString &value);
private slots:
void slotCollectAllParameters();
bool isActive() const;
/** @brief Should the wheel event be sent to parent widget for scrolling. */
bool filterWheelEvent;
-
/** @brief Return the stylesheet required for effect parameters. */
static const QString getStyleSheet();
+ /** @brief Parent group was collapsed, update. */
+ void groupStateChanged(bool collapsed);
public slots:
void slotSyncEffectsPos(int pos);
EffectInfo m_info;
/** @brief True if this is a region effect, which behaves in a special way, like a group. */
bool m_regionEffect;
+ /** @brief Check if collapsed state changed and inform MLT. */
+ void updateCollapsedState();
protected:
virtual void mouseDoubleClickEvent ( QMouseEvent * event );
void resetEffect(int ix);
/** @brief Ask for creation of a group. */
void createGroup(int ix);
- void moveEffect(int current_pos, int new_pos, int groupIndex, QString groupName);
+ void moveEffect(QList <int> current_pos, int new_pos, int groupIndex, QString groupName);
void unGroup(CollapsibleEffect *);
void addEffect(QDomElement e);
void createRegion(int, KUrl);
+ void deleteGroup(QDomDocument);
};
}
-CollapsibleGroup::CollapsibleGroup(int ix, bool firstGroup, bool lastGroup, QString groupName, QWidget * parent) :
- AbstractCollapsibleWidget(parent),
- m_index(ix)
+CollapsibleGroup::CollapsibleGroup(int ix, bool firstGroup, bool lastGroup, EffectInfo info, QWidget * parent) :
+ AbstractCollapsibleWidget(parent)
{
setupUi(this);
+ m_info.groupIndex = ix;
m_subWidgets = QList <CollapsibleEffect *> ();
setFont(KGlobalSettings::smallestReadableFont());
QHBoxLayout *l = static_cast <QHBoxLayout *>(framegroup->layout());
m_title = new MyEditableLabel(this);
l->insertWidget(3, m_title);
- m_title->setText(groupName.isEmpty() ? i18n("Effect Group") : groupName);
+ m_title->setText(info.groupName.isEmpty() ? i18n("Effect Group") : info.groupName);
+ m_info.groupName = m_title->text();
connect(m_title, SIGNAL(editingFinished()), this, SLOT(slotRenameGroup()));
buttonUp->setIcon(KIcon("kdenlive-up"));
buttonUp->setToolTip(i18n("Move effect up"));
enabledButton->setChecked(false);
enabledButton->setIcon(KIcon("visible"));
+
+ if (info.groupIsCollapsed) {
+ slotShow(false);
+ }
connect(collapseButton, SIGNAL(clicked()), this, SLOT(slotSwitch()));
connect(enabledButton, SIGNAL(toggled(bool)), this, SLOT(slotEnable(bool)));
widgetFrame->setVisible(show);
if (show) {
collapseButton->setArrowType(Qt::DownArrow);
- m_info.isCollapsed = false;
+ m_info.groupIsCollapsed = false;
}
else {
collapseButton->setArrowType(Qt::RightArrow);
- m_info.isCollapsed = true;
+ m_info.groupIsCollapsed = true;
}
- //emit parameterChanged(m_original_effect, m_effect, effectIndex());
+ if (!m_subWidgets.isEmpty()) m_subWidgets.at(0)->groupStateChanged(m_info.groupIsCollapsed);
}
QWidget *CollapsibleGroup::title() const
int CollapsibleGroup::groupIndex() const
{
- return m_index;
+ return m_info.groupIndex;
}
bool CollapsibleGroup::isGroup() const
doc.setContent(effects, true);
QDomElement e = doc.documentElement();
int ix = e.attribute("kdenlive_ix").toInt();
- if (ix == 0) {
+ if (ix == 0 || e.tagName() == "effectgroup") {
+ if (e.tagName() == "effectgroup") {
+ // dropped a group on another group
+ QDomNodeList pastedEffects = e.elementsByTagName("effect");
+ if (pastedEffects.isEmpty() || m_subWidgets.isEmpty()) {
+ // Buggy groups, should not happen
+ event->ignore();
+ return;
+ }
+ QList <int> pastedEffectIndexes;
+ QList <int> currentEffectIndexes;
+ EffectInfo pasteInfo;
+ pasteInfo.fromString(pastedEffects.at(0).toElement().attribute("kdenlive_info"));
+ if (pasteInfo.groupIndex == -1) {
+ // Group dropped from effects list, add effect
+ e.setAttribute("kdenlive_ix", m_subWidgets.last()->effectIndex());
+ emit addEffect(e);
+ event->setDropAction(Qt::CopyAction);
+ event->accept();
+ return;
+ }
+ // Moving group
+ for (int i = 0; i < pastedEffects.count(); i++) {
+ pastedEffectIndexes << pastedEffects.at(i).toElement().attribute("kdenlive_ix").toInt();
+ }
+ for (int i = 0; i < m_subWidgets.count(); i++) {
+ currentEffectIndexes << m_subWidgets.at(i)->effectIndex();
+ }
+ kDebug()<<"PASTING: "<<pastedEffectIndexes<<" TO "<<currentEffectIndexes;
+ if (pastedEffectIndexes.at(0) < currentEffectIndexes.at(0)) {
+ // Pasting group after current one:
+ emit moveEffect(pastedEffectIndexes, currentEffectIndexes.last(), pasteInfo.groupIndex, pasteInfo.groupName);
+ }
+ else {
+ // Group moved before current one
+ emit moveEffect(pastedEffectIndexes, currentEffectIndexes.first(), pasteInfo.groupIndex, pasteInfo.groupName);
+ }
+ event->setDropAction(Qt::MoveAction);
+ event->accept();
+ return;
+ }
// effect dropped from effects list, add it
- e.setAttribute("kdenlive_ix", ix);
+ e.setAttribute("kdenlive_info", m_info.toString());
+ if (!m_subWidgets.isEmpty()) {
+ e.setAttribute("kdenlive_ix", m_subWidgets.at(0)->effectIndex());
+ }
+ emit addEffect(e);
event->setDropAction(Qt::CopyAction);
event->accept();
- emit addEffect(e);
return;
}
if (m_subWidgets.isEmpty()) return;
int new_index = m_subWidgets.last()->effectIndex();
- emit moveEffect(ix, new_index, m_index, m_title->text());
+ emit moveEffect(QList <int> () <<ix, new_index, m_info.groupIndex, m_title->text());
event->setDropAction(Qt::MoveAction);
event->accept();
}
for (int j = 0; j < m_subWidgets.count(); j++) {
m_subWidgets.at(j)->setGroupName(m_title->text());
}
+ m_info.groupName = m_title->text();
emit groupRenamed(this);
}
Q_OBJECT
public:
- CollapsibleGroup(int ix, bool firstGroup, bool lastGroup, QString groupName = QString(), QWidget * parent = 0);
+ CollapsibleGroup(int ix, bool firstGroup, bool lastGroup, EffectInfo info, QWidget * parent = 0);
~CollapsibleGroup();
void updateTimecodeFormat();
void setActive(bool activate);
QList <CollapsibleEffect *> m_subWidgets;
QMenu *m_menu;
EffectInfo m_info;
- int m_index;
MyEditableLabel *m_title;
QMutex m_mutex;
void deleteGroup(QDomDocument);
void changeGroupPosition(int, bool);
void activateEffect(int);
- void moveEffect(int current_pos, int new_pos, int groupIndex, QString groupName);
+ void moveEffect(QList <int> current_pos, int new_pos, int groupIndex, QString groupName);
void addEffect(QDomElement e);
void unGroup(CollapsibleGroup *);
void groupRenamed(CollapsibleGroup *);
m_effectMetaInfo.trackMode = false;
m_effectMetaInfo.monitor = monitor;
m_effects = QList <CollapsibleEffect*>();
+ setAcceptDrops(true);
m_ui.setupUi(this);
setFont(KGlobalSettings::smallestReadableFont());
}
if (group == NULL) {
- group = new CollapsibleGroup(effectInfo.groupIndex, i == 0, i == m_currentEffectList.count() - 1, effectInfo.groupName, m_ui.container->widget());
- connect(group, SIGNAL(moveEffect(int,int,int,QString)), this, SLOT(slotMoveEffect(int,int,int,QString)));
- 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)));
+ group = new CollapsibleGroup(effectInfo.groupIndex, i == 0, i == m_currentEffectList.count() - 1, effectInfo, m_ui.container->widget());
+ connectGroup(group);
vbox1->addWidget(group);
group->installEventFilter( this );
}
connect(currentEffect, SIGNAL(checkMonitorPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
connect(currentEffect, SIGNAL(seekTimeline(int)), this , SLOT(slotSeekTimeline(int)));
connect(currentEffect, SIGNAL(createGroup(int)), this , SLOT(slotCreateGroup(int)));
- connect(currentEffect, SIGNAL(moveEffect(int,int,int,QString)), this , SLOT(slotMoveEffect(int,int,int,QString)));
+ connect(currentEffect, SIGNAL(moveEffect(QList<int>,int,int,QString)), this , SLOT(slotMoveEffect(QList<int>,int,int,QString)));
connect(currentEffect, SIGNAL(addEffect(QDomElement)), this , SLOT(slotAddEffect(QDomElement)));
connect(currentEffect, SIGNAL(createRegion(int,KUrl)), this, SLOT(slotCreateRegion(int,KUrl)));
+ connect(currentEffect, SIGNAL(deleteGroup(QDomDocument)), this , SLOT(slotDeleteGroup(QDomDocument)));
}
void EffectStackView2::slotCheckWheelEventFilter()
else {
endPos = index + 1;
}
- if (m_effectMetaInfo.trackMode) emit changeEffectPosition(NULL, m_trackindex, index, endPos);
- else emit changeEffectPosition(m_clipref, -1, index, endPos);
+ if (m_effectMetaInfo.trackMode) emit changeEffectPosition(NULL, m_trackindex, QList <int>() <<index, endPos);
+ else emit changeEffectPosition(m_clipref, -1, QList <int>() <<index, endPos);
}
void EffectStackView2::slotStartFilterJob(const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties)
}
}
- CollapsibleGroup *group = new CollapsibleGroup(m_groupIndex, ix == 1, ix == m_currentEffectList.count() - 2, QString(), m_ui.container->widget());
+ CollapsibleGroup *group = new CollapsibleGroup(m_groupIndex, ix == 1, ix == m_currentEffectList.count() - 2, effectinfo, m_ui.container->widget());
m_groupIndex++;
- connect(group, SIGNAL(moveEffect(int,int,int,QString)), this , SLOT(slotMoveEffect(int,int,int,QString)));
+ connectGroup(group);
+ l->insertWidget(groupPos, group);
+ group->installEventFilter( this );
+ group->addGroupEffect(effectToMove);
+}
+
+void EffectStackView2::connectGroup(CollapsibleGroup *group)
+{
+ connect(group, SIGNAL(moveEffect(QList<int>,int,int,QString)), this , SLOT(slotMoveEffect(QList<int>,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)));
- l->insertWidget(groupPos, group);
- group->installEventFilter( this );
- group->addGroupEffect(effectToMove);
}
-void EffectStackView2::slotMoveEffect(int currentIndex, int newIndex, int groupIndex, QString groupName)
+void EffectStackView2::slotMoveEffect(QList <int> currentIndexes, int newIndex, int groupIndex, QString groupName)
{
- CollapsibleEffect *effectToMove = getEffectByIndex(currentIndex);
- if (effectToMove == NULL) return;
+ if (currentIndexes.count() == 1) {
+ CollapsibleEffect *effectToMove = getEffectByIndex(currentIndexes.at(0));
+ if (effectToMove == NULL) return;
- QDomElement oldeffect = effectToMove->effect();
- QDomElement neweffect = oldeffect.cloneNode().toElement();
+ QDomElement oldeffect = effectToMove->effect();
+ QDomElement neweffect = oldeffect.cloneNode().toElement();
- EffectInfo effectinfo;
- effectinfo.fromString(oldeffect.attribute("kdenlive_info"));
- effectinfo.groupIndex = groupIndex;
- effectinfo.groupName = groupName;
- neweffect.setAttribute("kdenlive_info", effectinfo.toString());
-
- 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, effectToMove->effectIndex(),false);
- } else {
- emit updateEffect(m_clipref, -1, oldeffect, neweffect, effectToMove->effectIndex(),false);
+ EffectInfo effectinfo;
+ effectinfo.fromString(oldeffect.attribute("kdenlive_info"));
+ effectinfo.groupIndex = groupIndex;
+ effectinfo.groupName = groupName;
+ neweffect.setAttribute("kdenlive_info", effectinfo.toString());
+
+ if (oldeffect.attribute("kdenlive_info") != effectinfo.toString()) {
+ // effect's group info or collapsed state changed
+ 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, effectToMove->effectIndex(),false);
+ } else {
+ emit updateEffect(m_clipref, -1, oldeffect, neweffect, effectToMove->effectIndex(),false);
+ }
+ }
}
- //if (currentIndex == newIndex) return;
+
// Update effect index with new position
if (m_effectMetaInfo.trackMode) {
- emit changeEffectPosition(NULL, m_trackindex, currentIndex, newIndex);
+ emit changeEffectPosition(NULL, m_trackindex, currentIndexes, newIndex);
}
else {
- emit changeEffectPosition(m_clipref, -1, currentIndex, newIndex);
+ emit changeEffectPosition(m_clipref, -1, currentIndexes, newIndex);
}
}
}
}
+void EffectStackView2::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasFormat("kdenlive/effectslist")) {
+ event->acceptProposedAction();
+ }
+}
+
+void EffectStackView2::processDroppedEffect(QDomElement e, QDropEvent *event)
+{
+ int ix = e.attribute("kdenlive_ix").toInt();
+ if (e.tagName() == "effectgroup") {
+ // We are dropping a group, all effects in group should be moved
+ QDomNodeList effects = e.elementsByTagName("effect");
+ if (effects.count() == 0) {
+ event->ignore();
+ return;
+ }
+ EffectInfo info;
+ info.fromString(effects.at(0).toElement().attribute("kdenlive_info"));
+ if (info.groupIndex < 0) {
+ kDebug()<<"// 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 <int> indexes;
+ for (int i = 0; i < effects.count(); i++) {
+ QDomElement effect = effects.at(i).cloneNode().toElement();
+ indexes << effect.attribute("kdenlive_ix").toInt();
+ }
+ kDebug()<<"// Moving: "<<indexes<<" TO "<<m_currentEffectList.count();
+ slotMoveEffect(indexes, m_currentEffectList.count(), info.groupIndex, info.groupName);
+ }
+ else if (ix == 0) {
+ // effect dropped from effects list, add it
+ e.setAttribute("kdenlive_ix", m_currentEffectList.count() + 1);
+ event->setDropAction(Qt::CopyAction);
+ event->accept();
+ slotAddEffect(e);
+ return;
+ }
+ else {
+ // User is moving an effect
+ slotMoveEffect(QList<int> () << 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("kdenlive/effectslist"));
+ //event->acceptProposedAction();
+ QDomDocument doc;
+ doc.setContent(effects, true);
+ processDroppedEffect(doc.documentElement(), event);
+}
+
#include "effectstackview2.moc"
/** @brief Palette was changed, update style. */
void updatePalette();
+
+ /** @brief Process dropped xml effect. */
+ void processDroppedEffect(QDomElement e, QDropEvent *event);
protected:
virtual void mouseMoveEvent(QMouseEvent * event);
virtual void mouseReleaseEvent(QMouseEvent * event);
virtual void resizeEvent ( QResizeEvent * event );
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
private:
Ui::EffectStack2_UI m_ui;
/** @brief Connect an effect to its signals. */
void connectEffect(CollapsibleEffect *currentEffect);
+ /** @brief Connect a group to its signals. */
+ void connectGroup(CollapsibleGroup *group);
public slots:
/** @brief Sets the clip whose effect list should be managed.
/** @brief Create a region effect with ix index. */
void slotCreateRegion(int ix, KUrl url);
- /** @brief Move an effect into a group.
- ** @param ix the index of effect to move in stack layout
- ** @param group the effect on which the effect was dropped
- ** @param lastEffectIndex the last effect index in the group, effect will be inserted after that index
+ /** @brief Move an effect.
+ ** @param currentIndexes the list of effect indexes to move in stack layout
+ ** @param newIndex the position where the effects will be moved
+ ** @param groupIndex the index of the group if any (-1 if none)
+ ** @param groupName the name of the group to paste the effect
*/
- void slotMoveEffect(int currentIndex, int newIndex, int groupIndex, QString groupName = QString());
+ void slotMoveEffect(QList <int> currentIndexes, int newIndex, int groupIndex, QString groupName = QString());
/** @brief Remove effects from a group */
void slotUnGroup(CollapsibleGroup* group);
/** Enable or disable an effect */
void changeEffectState(ClipItem*, int, int, bool);
/** An effect in stack was moved */
- void changeEffectPosition(ClipItem*, int, int, int);
+ void changeEffectPosition(ClipItem*, int, QList <int>, int);
/** an effect was saved, reload list */
void reloadEffects();
/** An effect with position parameter was changed, seek */
void EffectStackEdit::updateParameter(const QString &name, const QString &value)
{
- m_params.setAttribute(name, value);
+ m_paramWidget->updateParameter(name, value);
if (name == "disable") {
// if effect is disabled, disable parameters widget
emit syncEffectsPos(pos);
}
-void EffectStackEdit::slotStartFilterJobAction()
-{
- QDomNodeList namenode = m_params.elementsByTagName("parameter");
- for (int i = 0; i < namenode.count() ; i++) {
- QDomElement pa = namenode.item(i).toElement();
- QString type = pa.attribute("type");
- if (type == "filterjob") {
- emit startFilterJob(pa.attribute("filtertag"), pa.attribute("filterparams"), pa.attribute("finalfilter"), pa.attribute("consumer"), pa.attribute("consumerparams"), pa.attribute("wantedproperties"));
- kDebug()<<" - - -PROPS:\n"<<pa.attribute("filtertag")<<"-"<< pa.attribute("filterparams")<<"-"<< pa.attribute("consumer")<<"-"<< pa.attribute("consumerparams")<<"-"<< pa.attribute("wantedproperties");
- break;
- }
- }
-}
QVBoxLayout *m_vbox;
QList<QWidget*> m_uiItems;
- QDomElement m_params;
QMap<QString, QWidget*> m_valueItems;
int m_in;
int m_out;
/** @brief Pass position changes of the timeline cursor to the effects to keep their local timelines in sync. */
void slotSyncEffectsPos(int pos);
-
-private slots:
- void slotStartFilterJobAction();
signals:
void parameterChanged(const QDomElement, const QDomElement, int);
disconnect(m_effectStack, SIGNAL(removeEffect(ClipItem*, int, QDomElement)), m_activeTimeline->projectView(), SLOT(slotDeleteEffect(ClipItem*, int, QDomElement)));
disconnect(m_effectStack, SIGNAL(addEffect(ClipItem*, QDomElement)), trackView->projectView(), SLOT(slotAddEffect(ClipItem*, QDomElement)));
disconnect(m_effectStack, SIGNAL(changeEffectState(ClipItem*, int, int, bool)), m_activeTimeline->projectView(), SLOT(slotChangeEffectState(ClipItem*, int, int, bool)));
- disconnect(m_effectStack, SIGNAL(changeEffectPosition(ClipItem*, int, int, int)), m_activeTimeline->projectView(), SLOT(slotChangeEffectPosition(ClipItem*, int, int, int)));
+ disconnect(m_effectStack, SIGNAL(changeEffectPosition(ClipItem*, int, QList<int>, int)), m_activeTimeline->projectView(), SLOT(slotChangeEffectPosition(ClipItem*, int, QList <int>, int)));
disconnect(m_effectStack, SIGNAL(refreshEffectStack(ClipItem*)), m_activeTimeline->projectView(), SLOT(slotRefreshEffects(ClipItem*)));
disconnect(m_effectStack, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects()));
disconnect(m_effectStack, SIGNAL(displayMessage(const QString&, int)), this, SLOT(slotGotProgressInfo(const QString&, int)));
connect(m_projectList, SIGNAL(gotFilterJobResults(const QString &, int, int, const QString &, stringMap)), trackView->projectView(), SLOT(slotGotFilterJobResults(const QString &, int, int, const QString &, stringMap)));
+ // Effect stack signals
connect(m_effectStack, SIGNAL(updateEffect(ClipItem*, int, QDomElement, QDomElement, int,bool)), trackView->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, int, QDomElement, QDomElement, int,bool)));
connect(m_effectStack, SIGNAL(updateClipRegion(ClipItem*, int, QString)), trackView->projectView(), SLOT(slotUpdateClipRegion(ClipItem*, int, QString)));
connect(m_effectStack, SIGNAL(removeEffect(ClipItem*, int, QDomElement)), trackView->projectView(), SLOT(slotDeleteEffect(ClipItem*, int, QDomElement)));
connect(m_effectStack, SIGNAL(addEffect(ClipItem*, QDomElement)), trackView->projectView(), SLOT(slotAddEffect(ClipItem*, QDomElement)));
connect(m_effectStack, SIGNAL(changeEffectState(ClipItem*, int, int, bool)), trackView->projectView(), SLOT(slotChangeEffectState(ClipItem*, int, int, bool)));
- connect(m_effectStack, SIGNAL(changeEffectPosition(ClipItem*, int, int, int)), trackView->projectView(), SLOT(slotChangeEffectPosition(ClipItem*, int, int, int)));
+ connect(m_effectStack, SIGNAL(changeEffectPosition(ClipItem*, int, QList <int>, int)), trackView->projectView(), SLOT(slotChangeEffectPosition(ClipItem*, int, QList <int>, int)));
connect(m_effectStack, SIGNAL(refreshEffectStack(ClipItem*)), trackView->projectView(), SLOT(slotRefreshEffects(ClipItem*)));
- connect(m_transitionConfig, SIGNAL(transitionUpdated(Transition *, QDomElement)), trackView->projectView() , SLOT(slotTransitionUpdated(Transition *, QDomElement)));
- connect(m_transitionConfig, SIGNAL(seekTimeline(int)), trackView->projectView() , SLOT(setCursorPos(int)));
connect(m_effectStack, SIGNAL(seekTimeline(int)), trackView->projectView() , SLOT(setCursorPos(int)));
connect(m_effectStack, SIGNAL(reloadEffects()), this, SLOT(slotReloadEffects()));
connect(m_effectStack, SIGNAL(displayMessage(const QString&, int)), this, SLOT(slotGotProgressInfo(const QString&, int)));
+
+ // Transition config signals
+ connect(m_transitionConfig, SIGNAL(transitionUpdated(Transition *, QDomElement)), trackView->projectView() , SLOT(slotTransitionUpdated(Transition *, QDomElement)));
+ connect(m_transitionConfig, SIGNAL(seekTimeline(int)), trackView->projectView() , SLOT(setCursorPos(int)));
connect(trackView->projectView(), SIGNAL(activateDocumentMonitor()), m_projectMonitor, SLOT(slotActivateMonitor()));
connect(trackView, SIGNAL(zoneMoved(int, int)), this, SLOT(slotZoneMoved(int, int)));