effectstackview2.cpp 51.3 KB
Newer Older
1 2 3 4
/***************************************************************************
                          effecstackview.cpp2  -  description
                             -------------------
    begin                : Feb 15 2008
5 6
    copyright            : (C) 2008 by Marco Gittler (g.marco@freenet.de)
    copyright            : (C) 2012 by Jean-Baptiste Mardelle (jb@kdenlive.org)
7 8 9 10 11 12 13 14 15 16 17
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

18 19
#include "effectstackview2.h"

Vincent Pinon's avatar
Vincent Pinon committed
20 21 22 23
#include "collapsibleeffect.h"
#include "collapsiblegroup.h"

#include "kdenlivesettings.h"
24
#include "mainwindow.h"
Vincent Pinon's avatar
Vincent Pinon committed
25
#include "doc/kthumb.h"
26
#include "bin/projectclip.h"
Vincent Pinon's avatar
Vincent Pinon committed
27 28
#include "effectslist/effectslist.h"
#include "timeline/clipitem.h"
29
#include "project/effectsettings.h"
30
#include "project/transitionsettings.h"
31
#include "utils/KoIconUtils.h"
32
#include "mltcontroller/clipcontroller.h"
33
#include "timeline/transition.h"
34

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
35
#include <QDebug>
36
#include <klocalizedstring.h>
37
#include <KColorScheme>
38
#include <QFontDatabase>
39
#include <KColorUtils>
40

41
#include <QScrollBar>
42
#include <QDrag>
43
#include <QMimeData>
44

45
EffectStackView2::EffectStackView2(Monitor *projectMonitor, QWidget *parent) :
46 47
        QWidget(parent),
        m_clipref(NULL),
48
        m_masterclipref(NULL),
Vincent Pinon's avatar
Vincent Pinon committed
49
        m_status(EMPTY),
50
        m_stateStatus(NORMALSTATUS),
51
        m_trackindex(-1),
52
        m_draggedEffect(NULL),
53
        m_draggedGroup(NULL),
54
        m_groupIndex(0),
55
        m_monitorSceneWanted(MonitorSceneDefault),
56 57
        m_trackInfo(),
        m_transition(NULL)
58
{
59
    m_effectMetaInfo.monitor = projectMonitor;
60
    m_effects = QList <CollapsibleEffect*>();
61
    setAcceptDrops(true);
62 63
    setLayout(&m_layout);

64
    m_effect = new EffectSettings(this);
65
    m_transition = new TransitionSettings(projectMonitor, this);
66
    connect(m_transition, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap<QString,QString>)), this, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap<QString,QString>)));
67
    connect(m_effect->checkAll, SIGNAL(stateChanged(int)), this, SLOT(slotCheckAll(int)));
68
    connect(m_effect->effectCompare, &QToolButton::toggled, this, &EffectStackView2::slotSwitchCompare);
69

70 71 72
    m_layout.addWidget(m_effect);
    m_layout.addWidget(m_transition);
    m_transition->setHidden(true);
73
    //setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
74
    setEnabled(false);
75
    setStyleSheet(getStyleSheet());
76 77 78 79
}

EffectStackView2::~EffectStackView2()
{
80 81 82 83 84 85 86
    delete m_effect;
    delete m_transition;
}

TransitionSettings *EffectStackView2::transitionConfig()
{
    return m_transition;
87 88
}

89 90
void EffectStackView2::updatePalette()
{
91
    setStyleSheet(getStyleSheet());
92
}
93

94 95 96 97 98 99
void EffectStackView2::refreshIcons()
{
    QList<QAction *> allMenus = this->findChildren<QAction *>();
    for (int i = 0; i < allMenus.count(); i++) {
        QAction *m = allMenus.at(i);
        QIcon ic = m->icon();
100
        if (ic.isNull() || ic.name().isEmpty()) continue;
101 102 103 104 105 106 107
        QIcon newIcon = KoIconUtils::themedIcon(ic.name());
        m->setIcon(newIcon);
    }
    QList<QToolButton *> allButtons = this->findChildren<QToolButton *>();
    for (int i = 0; i < allButtons.count(); i++) {
        QToolButton *m = allButtons.at(i);
        QIcon ic = m->icon();
108
        if (ic.isNull() || ic.name().isEmpty()) continue;
109 110 111 112 113
        QIcon newIcon = KoIconUtils::themedIcon(ic.name());
        m->setIcon(newIcon);
    }
}

114 115 116 117 118 119 120 121 122 123 124
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);
}

125 126 127
void EffectStackView2::slotRenderPos(int pos)
{
    if (m_effects.isEmpty()) return;
128
    if (m_monitorSceneWanted != MonitorSceneDefault) slotCheckMonitorPosition(pos);
129
    if (m_status == TIMELINE_CLIP && m_clipref) pos = pos - m_clipref->startPos().frames(KdenliveSettings::project_fps());
130

131
    for (int i = 0; i< m_effects.count(); ++i)
132 133 134
        m_effects.at(i)->slotSyncEffectsPos(pos);
}

135 136
void EffectStackView2::slotClipItemUpdate()
{
137 138 139
    if (m_status != TIMELINE_CLIP || !m_clipref) {
        return;
    }
140
    int inPoint = m_clipref->cropStart().frames(KdenliveSettings::project_fps());
141
    int outPoint = m_clipref->cropDuration().frames(KdenliveSettings::project_fps()) + inPoint;
142
    for (int i = 0; i < m_effects.count(); ++i) {
143 144 145 146
        m_effects.at(i)->setRange(inPoint, outPoint);
    }
}

147
void EffectStackView2::slotClipItemSelected(ClipItem* c, Monitor *m, bool reloadStack)
148
{
149
    QMutexLocker lock (&m_mutex);
150 151 152 153
    if (m_effect->effectCompare->isChecked()) {
        // disable split effect when changing clip
        m_effect->effectCompare->setChecked(false);
    }
154 155 156
    if (c) {
        m_effect->setHidden(false);
        m_transition->setHidden(true);
157
        m_effect->setEnabled(m_stateStatus != DISABLETIMELINE && m_stateStatus != DISABLEALL);
158 159
    }
    else if (m_status == TIMELINE_TRANSITION) return;
160 161
    m_masterclipref = NULL;
    m_trackindex = -1;
162 163
    if (c && !c->isEnabled()) return;
    if (c && c == m_clipref) {
164 165 166
        if (!reloadStack) {
            return;
        }
167
    } else {
168 169
        m_effectMetaInfo.monitor = m;
        if (m_clipref) disconnect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate()));
170 171
        m_clipref = c;
        if (c) {
172
            connect(m_clipref, SIGNAL(updateRange()), this, SLOT(slotClipItemUpdate()));
173
            m_effect->setLabel(i18n("Effects for %1", m_clipref->clipName()), m_clipref->clipName());
174 175
            int frameWidth = c->binClip()->getProducerIntProperty(QStringLiteral("meta.media.width"));
            int frameHeight = c->binClip()->getProducerIntProperty(QStringLiteral("meta.media.height"));
176
            double factor = c->binClip()->getDoubleProducerProperty(QStringLiteral("aspect_ratio"));
177 178
            m_effectMetaInfo.frameSize = QPoint(frameWidth, frameHeight);// (int)(frameWidth * factor + 0.5), frameHeight);
            m_effectMetaInfo.stretchFactor = factor;
179 180 181 182
        }
    }
    if (m_clipref == NULL) {
        //TODO: clear list, reset paramdesc and info
183
        // If monitor scene is displayed, hide it
184 185
        if (m_monitorSceneWanted != MonitorSceneDefault) {
            m_monitorSceneWanted = MonitorSceneDefault;
186
            m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted);
187
        }
188
        m_status = EMPTY;
189
        clear();
190 191 192
        return;
    }
    setEnabled(true);
193
    m_status = TIMELINE_CLIP;
194
    m_currentEffectList = m_clipref->effectList();
195
    setupListView();
196 197
}

198 199 200 201 202 203 204
void EffectStackView2::slotRefreshMasterClipEffects(ClipController* c, Monitor *m)
{
    if (c && m_status == MASTER_CLIP && m_masterclipref && m_masterclipref->clipId() == c->clipId()) {
        slotMasterClipItemSelected(c, m);
    }
}

205 206
void EffectStackView2::slotMasterClipItemSelected(ClipController* c, Monitor *m)
{
207 208 209 210
    if (m_effect->effectCompare->isChecked()) {
        // disable split effect when changing clip
        m_effect->effectCompare->setChecked(false);
    }
211 212
    m_clipref = NULL;
    m_trackindex = -1;
213 214 215
    if (c) {
        m_effect->setHidden(false);
        m_transition->setHidden(true);
216 217 218 219 220
        if (!c->isValid()) {
            m_effect->setEnabled(false);
            c = NULL;
        }
        else m_effect->setEnabled(m_stateStatus != DISABLEBIN && m_stateStatus != DISABLEALL);
221
    }
222 223 224 225 226
    if (c && c == m_masterclipref) {
    } else {
        m_masterclipref = c;
        m_effectMetaInfo.monitor = m;
        if (m_masterclipref) {
227
            m_effect->setLabel(i18n("Bin effects for %1", m_masterclipref->clipName()), m_masterclipref->clipName());
228 229 230
            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"));
231 232 233 234 235 236
            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
237 238
        if (m_monitorSceneWanted != MonitorSceneDefault) {
            m_monitorSceneWanted = MonitorSceneDefault;
239
            m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted);
240 241 242 243 244 245 246 247 248 249 250 251
        }
        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)
252
{
253 254 255 256
    if (m_effect->effectCompare->isChecked()) {
        // disable split effect when changing clip
        m_effect->effectCompare->setChecked(false);
    }
257 258 259 260 261 262 263 264
    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;
265 266
        QString trackName = info.trackName.isEmpty() ? QString::number(ix) : info.trackName;
        m_effect->setLabel(i18n("Effects for track %1", trackName), trackName);
267
    }
268 269
    setEnabled(true);
    m_trackindex = ix;
270
    setupListView();
271 272
}

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
273

274
void EffectStackView2::setupListView()
275 276
{
    blockSignals(true);
277
    m_monitorSceneWanted = MonitorSceneDefault;
278
    m_draggedEffect = NULL;
279
    m_draggedGroup = NULL;
280
    disconnect(m_effectMetaInfo.monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int)));
281
    QWidget *view = m_effect->container->takeWidget();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
282
    if (view) {
283
        delete view;
284
    }
285 286
    m_effects.clear();
    m_groupIndex = 0;
287
    blockSignals(false);
288
    view = new QWidget(m_effect->container);
289 290 291
    QPalette p = qApp->palette();
    p.setBrush(QPalette::Window, QBrush(Qt::transparent));
    view->setPalette(p);
292
    m_effect->container->setWidget(view);
293

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
294
    QVBoxLayout *vbox1 = new QVBoxLayout(view);
295 296 297
    vbox1->setContentsMargins(0, 0, 0, 0);
    vbox1->setSpacing(0);

298
    int effectsCount = m_currentEffectList.count();
299
    m_effect->effectCompare->setEnabled(effectsCount > 0);
300 301 302 303
    if (effectsCount == 0) {
        // No effect, make sure to display normal monitor scene
        m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted);
    }
304

305
    // Make sure we always have one effect selected
306
    if (m_status == TIMELINE_CLIP) {
307 308 309 310
        int selectedEffect = m_clipref->selectedEffectIndex();
        if (selectedEffect < 1 && effectsCount > 0) m_clipref->setSelectedEffect(1);
        else if (selectedEffect > effectsCount) m_clipref->setSelectedEffect(effectsCount);
    }
311

312
    CollapsibleEffect *selectedCollapsibleEffect = NULL;
313
    for (int i = 0; i < effectsCount; ++i) {
314 315
        QDomElement d = m_currentEffectList.at(i).cloneNode().toElement();
        if (d.isNull()) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
316
            //qDebug() << " . . . . WARNING, NULL EFFECT IN STACK!!!!!!!!!";
317 318
            continue;
        }
319

320
        CollapsibleGroup *group = NULL;
321
        EffectInfo effectInfo;
322
        effectInfo.fromString(d.attribute(QStringLiteral("kdenlive_info")));
323 324
        if (effectInfo.groupIndex >= 0) {
            // effect is in a group
325
            for (int j = 0; j < vbox1->count(); ++j) {
326 327 328 329 330 331 332 333
                CollapsibleGroup *eff = static_cast<CollapsibleGroup *>(vbox1->itemAt(j)->widget());
                if (eff->isGroup() &&  eff->groupIndex() == effectInfo.groupIndex) {
                    group = eff;
                    break;
                }
            }

            if (group == NULL) {
334
                group = new CollapsibleGroup(effectInfo.groupIndex, i == 0, i == effectsCount - 1, effectInfo, view);
335 336 337 338 339 340
                connectGroup(group);
                vbox1->addWidget(group);
                group->installEventFilter( this );
            }
            if (effectInfo.groupIndex >= m_groupIndex) m_groupIndex = effectInfo.groupIndex + 1;
        }
341 342 343

        /*QDomDocument doc;
        doc.appendChild(doc.importNode(d, true));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
344
        //qDebug() << "IMPORTED STK: " << doc.toString();*/
345 346 347

        ItemInfo info;
        bool isSelected = false;
348 349
        if (m_status == TIMELINE_TRACK) {
            // ?? cleanup following line
350 351 352 353 354
            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;
355
        } else if (m_status == TIMELINE_CLIP) {
356
            info = m_clipref->info();
357 358 359 360
        } else if (m_status == MASTER_CLIP) {
            info.cropDuration = m_masterclipref->getPlaytime();
            info.cropStart = GenTime(0);
            info.startPos = GenTime(0);
361
        }
362 363 364 365 366
        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);
367
        isSelected = currentEffect->effectIndex() == activeEffectIndex();
368
        if (isSelected) {
369
            m_monitorSceneWanted = currentEffect->needsMonitorEffectScene();
370
            selectedCollapsibleEffect = currentEffect;
371 372
            // show monitor scene if necessary
            m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted);
373 374
            int position = (m_effectMetaInfo.monitor->position() - (m_status == TIMELINE_CLIP ? m_clipref->startPos() : GenTime())).frames(KdenliveSettings::project_fps());
            currentEffect->slotSyncEffectsPos(position);
375
        }
376
        currentEffect->setActive(isSelected);
377
        m_effects.append(currentEffect);
378
        if (group) {
379 380 381 382 383
            group->addGroupEffect(currentEffect);
        } else {
            vbox1->addWidget(currentEffect);
        }
        connectEffect(currentEffect);
384
    }
385

386 387 388 389
    if (selectedCollapsibleEffect) {
        // pass frame size info to effect, so it can update the newly created qml scene
        selectedCollapsibleEffect->updateFrameInfo();
    }
390
    if (m_currentEffectList.isEmpty()) {
391
        //m_ui.labelComment->setHidden(true);
392 393
    }
    else {
394
        // Adjust group effects (up / down buttons)
395
        QList<CollapsibleGroup *> allGroups = m_effect->container->widget()->findChildren<CollapsibleGroup *>();
396
        for (int i = 0; i < allGroups.count(); ++i) {
397 398 399 400 401
            allGroups.at(i)->adjustEffects();
        }
        connect(m_effectMetaInfo.monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int)));
    }

402
    vbox1->addStretch(10);
403
    slotUpdateCheckAllButton();
404

405 406 407 408
    // Wait a little bit for the new layout to be ready, then check if we have a scrollbar
    QTimer::singleShot(200, this, SLOT(slotCheckWheelEventFilter()));
}

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
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;
}

427 428 429 430
void EffectStackView2::connectEffect(CollapsibleEffect *currentEffect)
{
    // Check drag & drop
    currentEffect->installEventFilter( this );
Laurent Montel's avatar
Laurent Montel committed
431
    connect(currentEffect, SIGNAL(parameterChanged(QDomElement,QDomElement,int)), this , SLOT(slotUpdateEffectParams(QDomElement,QDomElement,int)));
432
    connect(currentEffect, SIGNAL(startFilterJob(QMap<QString,QString>&, QMap<QString,QString>&,QMap <QString, QString>&)), this , SLOT(slotStartFilterJob(QMap<QString,QString>&, QMap<QString,QString>&,QMap <QString, QString>&)));
Laurent Montel's avatar
Laurent Montel committed
433
    connect(currentEffect, SIGNAL(deleteEffect(QDomElement)), this , SLOT(slotDeleteEffect(QDomElement)));
434 435
    connect(currentEffect, SIGNAL(reloadEffects()), this , SIGNAL(reloadEffects()));
    connect(currentEffect, SIGNAL(resetEffect(int)), this , SLOT(slotResetEffect(int)));
Laurent Montel's avatar
Laurent Montel committed
436
    connect(currentEffect, SIGNAL(changeEffectPosition(QList<int>,bool)), this , SLOT(slotMoveEffectUp(QList<int>,bool)));
437
    connect(currentEffect, SIGNAL(effectStateChanged(bool,int,MonitorSceneType)), this, SLOT(slotUpdateEffectState(bool,int,MonitorSceneType)));
438 439 440
    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)));
441
    connect(currentEffect, SIGNAL(moveEffect(QList<int>,int,int,QString)), this , SLOT(slotMoveEffect(QList<int>,int,int,QString)));
442
    connect(currentEffect, SIGNAL(addEffect(QDomElement)), this , SLOT(slotAddEffect(QDomElement)));
443
    connect(currentEffect, SIGNAL(createRegion(int,QUrl)), this, SLOT(slotCreateRegion(int,QUrl)));
444
    connect(currentEffect, SIGNAL(deleteGroup(QDomDocument)), this , SLOT(slotDeleteGroup(QDomDocument)));
445
    connect(currentEffect, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap<QString,QString>)), this, SIGNAL(importClipKeyframes(GraphicsRectItem, ItemInfo, QDomElement, QMap<QString,QString>)));
446
}
447 448 449 450 451 452

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;
453
    if (m_effect->container->verticalScrollBar() && m_effect->container->verticalScrollBar()->isVisible()) {
454 455
        // widget has scroll bar,
        filterWheelEvent = true;
456
    }
457
    for (int i = 0; i < m_effects.count(); ++i) {
458 459
        m_effects.at(i)->filterWheelEvent = filterWheelEvent;
    }
460 461 462 463 464 465
}

void EffectStackView2::resizeEvent ( QResizeEvent * event )
{
    slotCheckWheelEventFilter();
    QWidget::resizeEvent(event);
466 467
}

468
bool EffectStackView2::eventFilter( QObject * o, QEvent * e )
469 470 471
{
    // Check if user clicked in an effect's top bar to start dragging it
    if (e->type() == QEvent::MouseButtonPress)  {
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
        m_draggedEffect = qobject_cast<CollapsibleEffect*>(o);
        if (m_draggedEffect) {
            QMouseEvent *me = static_cast<QMouseEvent *>(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<CollapsibleGroup*>(o);
        if (m_draggedGroup) {
            QMouseEvent *me = static_cast<QMouseEvent *>(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;
        }
    }
498
    /*if (e->type() == QEvent::MouseMove)  {
499 500 501 502 503 504 505 506 507 508 509
    if (qobject_cast<CollapsibleEffect*>(o)) {
        QMouseEvent *me = static_cast<QMouseEvent *>(e);
        if (me->buttons() != Qt::LeftButton) {
    	e->accept();
    	return false;
        }
        else {
    	e->ignore();
    	return true;
        }
    }
510
    }*/
511 512 513 514 515
    return QWidget::eventFilter(o, e);
}

void EffectStackView2::mouseMoveEvent(QMouseEvent * event)
{
516
    if (m_draggedEffect || m_draggedGroup) {
517 518 519
        if ((event->buttons() & Qt::LeftButton) && (m_clickPoint != QPoint()) && ((event->globalPos() - m_clickPoint).manhattanLength() >= QApplication::startDragDistance())) {
            startDrag();
        }
520
    }
521 522 523 524 525
}

void EffectStackView2::mouseReleaseEvent(QMouseEvent * event)
{
    m_draggedEffect = NULL;
526
    m_draggedGroup = NULL;
527 528 529 530 531 532 533
    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;
534 535
    QPixmap pixmap;
    if (m_draggedEffect) {
536
        QDomElement effect = m_draggedEffect->effect().cloneNode().toElement();
537
	if (m_status == TIMELINE_TRACK || m_status == MASTER_CLIP) {
538
	    // Keep clip crop start in case we want to paste effect 
539
	    effect.setAttribute(QStringLiteral("clipstart"), 0);
540 541 542
	}
	else {
	    // Keep clip crop start in case we want to paste effect
543
	    effect.setAttribute(QStringLiteral("clipstart"), m_clipref->cropStart().frames(KdenliveSettings::project_fps()));
544
	}
545
        doc.appendChild(doc.importNode(effect, true));
546
        pixmap = m_draggedEffect->title->grab();
547 548
    }
    else if (m_draggedGroup) {
549
        doc = m_draggedGroup->effectsData();
550
	if (m_status == TIMELINE_TRACK || m_status == MASTER_CLIP) {
551
	    doc.documentElement().setAttribute(QStringLiteral("clipstart"), 0);
552 553
	}
	else {
554
	    doc.documentElement().setAttribute(QStringLiteral("clipstart"), m_clipref->cropStart().frames(KdenliveSettings::project_fps()));
555
	}
556
        pixmap = m_draggedGroup->title()->grab();
557 558 559 560
    }
    else return;
    QDrag *drag = new QDrag(this);
    drag->setPixmap(pixmap);
561 562 563
    QMimeData *mime = new QMimeData;
    QByteArray data;
    data.append(doc.toString().toUtf8());
564
    mime->setData(QStringLiteral("kdenlive/effectslist"), data);
565 566 567 568

    // Assign ownership of the QMimeData object to the QDrag object.
    drag->setMimeData(mime);
    // Start the drag and drop operation
569
    drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
570 571
}

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
572

573
void EffectStackView2::slotUpdateEffectState(bool disable, int index, MonitorSceneType needsMonitorEffectScene)
574
{
575 576 577
    if (m_monitorSceneWanted != MonitorSceneDefault && disable) {
        m_monitorSceneWanted = MonitorSceneDefault;
        m_effectMetaInfo.monitor->slotShowEffectScene(MonitorSceneDefault);
578
    }
579
    else if (!disable) {
580
        m_monitorSceneWanted = needsMonitorEffectScene;
581
        m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted == MonitorSceneDefault ? MonitorSceneNone : m_monitorSceneWanted);
582 583 584 585 586 587 588
        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);
            }
        }
589
    }
590 591 592 593 594 595
    switch (m_status) {
        case TIMELINE_TRACK:
            emit changeEffectState(NULL, m_trackindex, QList <int>() << index, disable);
            break;
        case MASTER_CLIP:
            m_masterclipref->changeEffectState(QList <int>() << index, disable);
596
            m_effectMetaInfo.monitor->refreshMonitorIfActive();
597 598 599 600 601
            break;
        default:
            // timeline clip effect
            emit changeEffectState(m_clipref, -1, QList <int>() <<index, disable);
    }
602
    slotUpdateCheckAllButton();
603 604 605 606 607
}


void EffectStackView2::raiseWindow(QWidget* dock)
{
608
    if (m_status != EMPTY && dock)
609 610 611 612 613 614
        dock->raise();
}


void EffectStackView2::slotSeekTimeline(int pos)
{
615
    if (m_status == TIMELINE_TRACK) {
616
        emit seekTimeline(pos);
617
    } else if (m_status == TIMELINE_CLIP) {
618
        emit seekTimeline(m_clipref->startPos().frames(KdenliveSettings::project_fps()) + pos);
619
    } else if (m_status == MASTER_CLIP) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
620
        m_effectMetaInfo.monitor->slotSeek(pos);
621 622 623 624 625 626 627 628 629 630 631
    }
}


/*void EffectStackView2::slotRegionChanged()
{
    if (!m_trackMode) emit updateClipRegion(m_clipref, m_ui.effectlist->currentRow(), m_ui.region_url->text());
}*/

void EffectStackView2::slotCheckMonitorPosition(int renderPos)
{
632
    if (m_monitorSceneWanted != MonitorSceneDefault) {
633
        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()))) {
634 635
            if (!m_effectMetaInfo.monitor->effectSceneDisplayed(m_monitorSceneWanted)) {
                m_effectMetaInfo.monitor->slotShowEffectScene(m_monitorSceneWanted);
636 637 638
                // Find active effect and refresh frame info
                CollapsibleEffect *activeEffect = getEffectByIndex(activeEffectIndex());
                if (activeEffect) activeEffect->updateFrameInfo();
639 640
            }
        } else {
641
            m_effectMetaInfo.monitor->slotShowEffectScene(MonitorSceneDefault);
642
        }
643 644
    }
    else {
645
        m_effectMetaInfo.monitor->slotShowEffectScene(MonitorSceneDefault);
646 647 648
    }
}

649 650 651 652 653 654
EFFECTMODE EffectStackView2::effectStatus() const
{
    return m_status;
}

int EffectStackView2::trackIndex() const
655 656 657 658 659 660
{
    return m_trackindex;
}

void EffectStackView2::clear()
{
661
    m_effects.clear();
662
    m_monitorSceneWanted = MonitorSceneDefault;
663
    QWidget *view = m_effect->container->takeWidget();
664
    if (view) {
665
        delete view;
666
    }
667 668
    m_effect->setLabel(QString());
    //m_ui.labelComment->setText(QString());
669
    if (m_status != TIMELINE_TRANSITION) setEnabled(false);
670 671
}

672
void EffectStackView2::slotCheckAll(int state)
673
{
674 675
    if (state == Qt::PartiallyChecked) {
        state = Qt::Checked;
676
        m_effect->updateCheckState(state);
677 678
    }

679
    bool disabled = state == Qt::Unchecked;
680 681
    // Disable all effects
    QList <int> indexes;
682
    for (int i = 0; i < m_effects.count(); ++i) {
683
        m_effects.at(i)->slotDisable(disabled, false);
684
        indexes << m_effects.at(i)->effectIndex();
685 686
    }
    // Take care of groups
687
    QList<CollapsibleGroup *> allGroups = m_effect->container->widget()->findChildren<CollapsibleGroup *>();
688
    for (int i = 0; i < allGroups.count(); ++i) {
689
        allGroups.at(i)->slotEnable(disabled, false);
690
    }
691

692
    if (m_status == TIMELINE_TRACK)
693
        emit changeEffectState(NULL, m_trackindex, indexes, disabled);
694
    else if (m_status == TIMELINE_CLIP)
695
        emit changeEffectState(m_clipref, -1, indexes, disabled);
696 697
    else if (m_status == MASTER_CLIP)
        m_masterclipref->changeEffectState(indexes, disabled);
698 699
}

700
void EffectStackView2::slotUpdateCheckAllButton()
701
{
702 703
    bool hasEnabled = false;
    bool hasDisabled = false;
704

705
    for (int i = 0; i < m_effects.count(); ++i) {
706
        if (!m_effects.at(i)->isEnabled()) hasEnabled = true;
707
        else hasDisabled = true;
708
    }
709

710
    if (hasEnabled && hasDisabled)
711
        m_effect->updateCheckState(Qt::PartiallyChecked);
712
    else if (hasEnabled)
713
        m_effect->updateCheckState(Qt::Checked);
714
    else
715
        m_effect->updateCheckState(Qt::Unchecked);
716 717 718 719
}

void EffectStackView2::deleteCurrentEffect()
{
720
    for (int i = 0; i < m_effects.count(); ++i) {
721
        if (m_effects.at(i)->isActive()) {
722 723 724
            slotDeleteEffect(m_effects.at(i)->effect());
            break;
        }
725 726 727
    }
}

728 729
void EffectStackView2::updateTimecodeFormat()
{
730
    for (int i = 0; i< m_effects.count(); ++i)
731 732 733
        m_effects.at(i)->updateTimecodeFormat();
}

734 735
CollapsibleEffect *EffectStackView2::getEffectByIndex(int ix)
{
736
    for (int i = 0; i< m_effects.count(); ++i) {
737
        if (m_effects.at(i)->effectIndex() == ix) {
738 739
            return m_effects.at(i);
        }
740 741 742 743
    }
    return NULL;
}

744
void EffectStackView2::slotUpdateEffectParams(const QDomElement &old, const QDomElement &e, int ix)
745
{
746
    if (m_status == TIMELINE_TRACK) {
747
        emit updateEffect(NULL, m_trackindex, old, e, ix,false);
748
    }
749
    else if (m_status == TIMELINE_CLIP && m_clipref) {
750
        emit updateEffect(m_clipref, -1, old, e, ix, false);
751 752 753
        // Make sure the changed effect is currently displayed
        slotSetCurrentEffect(ix);
    }
754
    else if (m_status == MASTER_CLIP) {
755
        m_masterclipref->updateEffect(m_effectMetaInfo.monitor->profileInfo(), e, ix);
756
        m_effectMetaInfo.monitor->refreshMonitorIfActive();
757
    }
758
    QTimer::singleShot(200, this, SLOT(slotCheckWheelEventFilter()));
759 760 761 762
}

void EffectStackView2::slotSetCurrentEffect(int ix)
{
763 764 765 766
    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) {
767 768 769 770 771 772 773 774
                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);
775
                }
776
                else effect->setActive(false);
777 778
            }
        }
779 780 781
    }
}

782 783 784 785 786 787 788 789
void EffectStackView2::setActiveKeyframe(int frame)
{
    if (m_status == TIMELINE_CLIP) {
        CollapsibleEffect *activeEffect = getEffectByIndex(activeEffectIndex());
        if (activeEffect) activeEffect->setActiveKeyframe(frame);
    }
}

790
void EffectStackView2::slotDeleteGroup(QDomDocument doc)
791 792
{
    ClipItem * clip = NULL;
Vincent Pinon's avatar
Vincent Pinon committed
793
    int ix = -1;
794 795 796 797 798
    if (m_status == MASTER_CLIP) {
        //TODO
        return;
    }
    if (m_status == TIMELINE_TRACK) {
799
        ix = m_trackindex;
800
    }
801
    else if (m_status == TIMELINE_CLIP) {
802 803
        clip = m_clipref;
        ix = -1;
804
    }
805
    emit removeEffectGroup(clip, ix, doc);
806 807
}

808
void EffectStackView2::slotDeleteEffect(const QDomElement effect)
809
{
810
    if (m_status == TIMELINE_TRACK)
811
        emit removeEffect(NULL, m_trackindex, effect);
812
    else if (m_status == TIMELINE_CLIP)
813
        emit removeEffect(m_clipref, -1, effect);
814
    if (m_status == MASTER_CLIP) {
815
        emit removeMasterEffect(m_masterclipref->clipId(), effect);
816
    }
817 818
}

819
void EffectStackView2::slotAddEffect(const QDomElement &effect)
820
{
821 822 823 824 825
    if (m_status == MASTER_CLIP) {
	emit addMasterEffect(m_masterclipref->clipId(), effect);
    } else {
      emit addEffect(m_clipref, effect, m_trackindex);
    }
826 827
}

828
void EffectStackView2::slotMoveEffectUp(const QList<int> &indexes, bool up)