customtrackview.cpp 37.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/***************************************************************************
 *   Copyright (C) 2007 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 <QMouseEvent>
#include <QStylePainter>
#include <QGraphicsItem>
#include <QDomDocument>
24
#include <QScrollBar>
25

26
#include <KDebug>
27
#include <KLocale>
28
#include <KUrl>
29
#include <KCursor>
30 31 32 33

#include "customtrackview.h"
#include "clipitem.h"
#include "definitions.h"
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
34
#include "moveclipcommand.h"
35
#include "resizeclipcommand.h"
36
#include "addtimelineclipcommand.h"
37
#include "addeffectcommand.h"
38
#include "editeffectcommand.h"
39
#include "kdenlivesettings.h"
40
#include "transition.h"
41

42 43 44 45 46 47 48 49
//TODO:
// disable animation if user asked it in KDE's global settings
// http://lists.kde.org/?l=kde-commits&m=120398724717624&w=2
// needs something like below (taken from dolphin)
// #include <kglobalsettings.h>
// const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects;
// const int duration = animate ? 1500 : 1;

50
CustomTrackView::CustomTrackView(KdenliveDoc *doc, QGraphicsScene * projectscene, QWidget *parent)
51
        : QGraphicsView(projectscene, parent), m_tracksCount(0), m_cursorPos(0), m_dropItem(NULL), m_cursorLine(NULL), m_operationMode(NONE), m_startPos(QPointF()), m_dragItem(NULL), m_visualTip(NULL), m_moveOpMode(NONE), m_animation(NULL), m_projectDuration(0), m_scale(1.0), m_clickPoint(0), m_document(doc), m_autoScroll(KdenliveSettings::autoscroll()) {
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    if (doc) m_commandStack = doc->commandStack();
    else m_commandStack == NULL;
    setMouseTracking(true);
    setAcceptDrops(true);
    m_animationTimer = new QTimeLine(800);
    m_animationTimer->setFrameRange(0, 5);
    m_animationTimer->setUpdateInterval(100);
    m_animationTimer->setLoopCount(0);
    m_tipColor = QColor(0, 192, 0, 200);
    QColor border = QColor(255, 255, 255, 100);
    m_tipPen.setColor(border);
    m_tipPen.setWidth(3);

    setContentsMargins(0, 0, 0, 0);
    if (projectscene) {
        m_cursorLine = projectscene->addLine(0, 0, 0, 50);
        m_cursorLine->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIgnoresTransformations);
        m_cursorLine->setZValue(1000);
    }
}

73 74
void CustomTrackView::checkAutoScroll() {
    m_autoScroll = KdenliveSettings::autoscroll();
75 76 77
}

// virtual
78 79
void CustomTrackView::resizeEvent(QResizeEvent * event) {
    QGraphicsView::resizeEvent(event);
80 81
}

82
// virtual
83 84 85 86 87 88 89 90
void CustomTrackView::wheelEvent(QWheelEvent * e) {
    if (e->modifiers() == Qt::ControlModifier) {
        if (e->delta() > 0) emit zoomIn();
        else emit zoomOut();
    } else {
        if (e->delta() > 0) horizontalScrollBar()->setValue(horizontalScrollBar()->value() + horizontalScrollBar()->singleStep());
        else  horizontalScrollBar()->setValue(horizontalScrollBar()->value() - horizontalScrollBar()->singleStep());
    }
91 92 93
}


94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
// virtual
void CustomTrackView::mouseMoveEvent(QMouseEvent * event) {
    int pos = event->x();
    emit mousePosition(mapToScene(event->pos()).x() / m_scale);
    /*if (event->modifiers() == Qt::ControlModifier)
      setDragMode(QGraphicsView::ScrollHandDrag);
    else if (event->modifiers() == Qt::ShiftModifier)
      setDragMode(QGraphicsView::RubberBandDrag);
    else*/
    {

        if (m_dragItem) { //event->button() == Qt::LeftButton) {
            // a button was pressed, delete visual tips
            if (m_operationMode == MOVE) {
                double snappedPos = getSnapPointForPos(mapToScene(event->pos()).x() - m_clickPoint);
109
                kDebug() << "///////  MOVE CLIP, EVENT Y: ";//<<event->scenePos().y()<<", SCENE HEIGHT: "<<scene()->sceneRect().height();
110
                int moveTrack = (int)  mapToScene(event->pos() - QPoint(0, (m_dragItem->type() == TRANSITIONWIDGET ? 25 : 0))).y() / 50;
111 112 113 114 115 116 117
                int currentTrack = m_dragItem->track();

                if (moveTrack > m_tracksCount - 1) moveTrack = m_tracksCount - 1;
                else if (moveTrack < 0) moveTrack = 0;

                int offset = moveTrack - currentTrack;
                if (offset != 0) offset = 50 * offset;
118
                m_dragItem->moveTo(snappedPos / m_scale, m_scale, offset, moveTrack);
119
            } else if (m_operationMode == RESIZESTART) {
120 121
                double snappedPos = getSnapPointForPos(mapToScene(event->pos()).x());
                m_dragItem->resizeStart(snappedPos / m_scale, m_scale);
122
            } else if (m_operationMode == RESIZEEND) {
123 124
                double snappedPos = getSnapPointForPos(mapToScene(event->pos()).x());
                m_dragItem->resizeEnd(snappedPos / m_scale, m_scale);
125 126
            } else if (m_operationMode == FADEIN) {
                int pos = mapToScene(event->pos()).x() / m_scale;
127
                m_dragItem->setFadeIn(pos - m_dragItem->startPos().frames(m_document->fps()), m_scale);
128 129
            } else if (m_operationMode == FADEOUT) {
                int pos = mapToScene(event->pos()).x() / m_scale;
130
                m_dragItem->setFadeOut(m_dragItem->endPos().frames(m_document->fps()) - pos, m_scale);
131 132 133 134 135 136 137 138 139 140 141 142
            }

            if (m_animation) delete m_animation;
            m_animation = NULL;
            if (m_visualTip) delete m_visualTip;
            m_visualTip = NULL;
            QGraphicsView::mouseMoveEvent(event);
            return;
        }

        QList<QGraphicsItem *> itemList = items(event->pos());
        int i = 0;
143
        QGraphicsRectItem *item = NULL;
144
        for (int i = 0; i < itemList.count(); i++) {
145
            if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
146
                item = (QGraphicsRectItem*) itemList.at(i);
147 148 149 150
                break;
            }
        }
        if (item && event->buttons() == Qt::NoButton) {
151 152
            AbstractClipItem *clip = (AbstractClipItem*) item;
            OPERATIONTYPE opMode = opMode = clip->operationMode(mapToScene(event->pos()), m_scale);
153
            double size = 8;
154

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
            if (opMode == m_moveOpMode) {
                QGraphicsView::mouseMoveEvent(event);
                return;
            } else {
                if (m_visualTip) {
                    if (m_animation) delete m_animation;
                    m_animation = NULL;
                    m_animationTimer->stop();
                    delete m_visualTip;
                    m_visualTip = NULL;
                }
            }
            m_moveOpMode = opMode;
            if (opMode == MOVE) {
                setCursor(Qt::OpenHandCursor);
            } else if (opMode == RESIZESTART) {
171
                setCursor(KCursor("left_side", Qt::SizeHorCursor));
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
                kDebug() << "********  RESIZE CLIP START; WIDTH: " << size;
                if (m_visualTip == NULL) {
                    QPolygon polygon;
                    polygon << QPoint(clip->rect().x(), clip->rect().y() + clip->rect().height() / 2 - size * 2);
                    polygon << QPoint(clip->rect().x() + size * 2, clip->rect().y() + clip->rect().height() / 2);
                    polygon << QPoint(clip->rect().x(), clip->rect().y() + clip->rect().height() / 2 + size * 2);
                    polygon << QPoint(clip->rect().x(), clip->rect().y() + clip->rect().height() / 2 - size * 2);

                    m_visualTip = new QGraphicsPolygonItem(polygon);
                    ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
                    ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);
                    m_visualTip->setZValue(100);
                    m_animation = new QGraphicsItemAnimation;
                    m_animation->setItem(m_visualTip);
                    m_animation->setTimeLine(m_animationTimer);
                    m_visualTip->setPos(0, 0);
                    double scale = 2.0;
                    m_animation->setScaleAt(.5, scale, 1);
                    m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
                    scale = 1.0;
                    m_animation->setScaleAt(1, scale, 1);
                    m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
                    scene()->addItem(m_visualTip);
                    m_animationTimer->start();
                }
            } else if (opMode == RESIZEEND) {
198
                setCursor(KCursor("right_side", Qt::SizeHorCursor));
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
                if (m_visualTip == NULL) {
                    QPolygon polygon;
                    polygon << QPoint(clip->rect().x() + clip->rect().width(), clip->rect().y() + clip->rect().height() / 2 - size * 2);
                    polygon << QPoint(clip->rect().x() + clip->rect().width() - size * 2, clip->rect().y() + clip->rect().height() / 2);
                    polygon << QPoint(clip->rect().x() + clip->rect().width(), clip->rect().y() + clip->rect().height() / 2 + size * 2);
                    polygon << QPoint(clip->rect().x() + clip->rect().width(), clip->rect().y() + clip->rect().height() / 2 - size * 2);

                    m_visualTip = new QGraphicsPolygonItem(polygon);
                    ((QGraphicsPolygonItem*) m_visualTip)->setBrush(m_tipColor);
                    ((QGraphicsPolygonItem*) m_visualTip)->setPen(m_tipPen);

                    m_visualTip->setZValue(100);
                    m_animation = new QGraphicsItemAnimation;
                    m_animation->setItem(m_visualTip);
                    m_animation->setTimeLine(m_animationTimer);
                    m_visualTip->setPos(0, 0);
                    double scale = 2.0;
                    m_animation->setScaleAt(.5, scale, 1);
                    m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale - clip->rect().width(), 0));
                    scale = 1.0;
                    m_animation->setScaleAt(1, scale, 1);
                    m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
                    scene()->addItem(m_visualTip);
                    m_animationTimer->start();
                }
            } else if (opMode == FADEIN) {
                if (m_visualTip == NULL) {
                    m_visualTip = new QGraphicsEllipseItem(clip->rect().x() + clip->fadeIn() * m_scale - size, clip->rect().y() - 8, size * 2, 16);
                    ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
                    ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
                    m_visualTip->setZValue(100);
                    m_animation = new QGraphicsItemAnimation;
                    m_animation->setItem(m_visualTip);
                    m_animation->setTimeLine(m_animationTimer);
                    m_visualTip->setPos(0, 0);
                    double scale = 2.0;
                    m_animation->setScaleAt(.5, scale, scale);
                    m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale -  clip->fadeIn() * m_scale, clip->rect().y() - clip->rect().y() * scale));
                    scale = 1.0;
                    m_animation->setScaleAt(1, scale, scale);
                    m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, clip->rect().y() - clip->rect().y() * scale));
                    scene()->addItem(m_visualTip);
                    m_animationTimer->start();
                }
                setCursor(Qt::PointingHandCursor);
            } else if (opMode == FADEOUT) {
                if (m_visualTip == NULL) {
                    m_visualTip = new QGraphicsEllipseItem(clip->rect().x() + clip->rect().width() - clip->fadeOut() * m_scale - size, clip->rect().y() - 8, size*2, 16);
                    ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
                    ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
                    m_visualTip->setZValue(100);
                    m_animation = new QGraphicsItemAnimation;
                    m_animation->setItem(m_visualTip);
                    m_animation->setTimeLine(m_animationTimer);
                    m_visualTip->setPos(0, 0);
                    double scale = 2.0;
                    m_animation->setScaleAt(.5, scale, scale);
                    m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale - clip->rect().width() + clip->fadeOut() * m_scale, clip->rect().y() - clip->rect().y() * scale));
                    scale = 1.0;
                    m_animation->setScaleAt(1, scale, scale);
                    m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, clip->rect().y() - clip->rect().y() * scale));
                    scene()->addItem(m_visualTip);
                    m_animationTimer->start();
                }
                setCursor(Qt::PointingHandCursor);
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
            } else if (opMode == TRANSITIONSTART) {
                if (m_visualTip == NULL) {
                    m_visualTip = new QGraphicsEllipseItem(-5, -5 , 10, 10);
                    ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
                    ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
                    m_visualTip->setZValue(100);
                    m_animation = new QGraphicsItemAnimation;
                    m_animation->setItem(m_visualTip);
                    m_animation->setTimeLine(m_animationTimer);
                    m_visualTip->setPos(clip->rect().x() + 15, clip->rect().y() + clip->rect().height() / 2);
                    double scale = 2.0;
                    m_animation->setScaleAt(.5, scale, scale);
                    scale = 1.0;
                    m_animation->setScaleAt(1, scale, scale);
                    scene()->addItem(m_visualTip);
                    m_animationTimer->start();
                }
                setCursor(Qt::PointingHandCursor);
            } else if (opMode == TRANSITIONEND) {
                if (m_visualTip == NULL) {
                    m_visualTip = new QGraphicsEllipseItem(-5, -5 , 10, 10);
                    ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
                    ((QGraphicsEllipseItem*) m_visualTip)->setPen(m_tipPen);
                    m_visualTip->setZValue(100);
                    m_animation = new QGraphicsItemAnimation;
                    m_animation->setItem(m_visualTip);
                    m_animation->setTimeLine(m_animationTimer);
                    m_visualTip->setPos(clip->rect().x() + clip->rect().width() - 15 , clip->rect().y() + clip->rect().height() / 2);
                    double scale = 2.0;
                    m_animation->setScaleAt(.5, scale, scale);
                    scale = 1.0;
                    m_animation->setScaleAt(1, scale, scale);
                    scene()->addItem(m_visualTip);
                    m_animationTimer->start();
                }
                setCursor(Qt::PointingHandCursor);
300 301 302
            }
        } else {
            m_moveOpMode = NONE;
303
            if (event->buttons() != Qt::NoButton && event->modifiers() == Qt::NoModifier) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
304
                setCursorPos((int) mapToScene(event->pos().x(), 0).x() / m_scale);
305 306 307 308 309 310 311 312 313 314 315
            }
            if (m_visualTip) {
                if (m_animation) delete m_animation;
                m_animationTimer->stop();
                m_animation = NULL;
                delete m_visualTip;
                m_visualTip = NULL;

            }
            setCursor(Qt::ArrowCursor);
        }
316
    }
317
    QGraphicsView::mouseMoveEvent(event);
318 319
}

320 321
// virtual
void CustomTrackView::mousePressEvent(QMouseEvent * event) {
322
    activateMonitor();
323 324 325 326 327 328 329 330 331 332 333 334 335 336
    int pos = event->x();
    if (event->modifiers() == Qt::ControlModifier) {
        setDragMode(QGraphicsView::ScrollHandDrag);
        QGraphicsView::mousePressEvent(event);
        return;
    } else if (event->modifiers() == Qt::ShiftModifier) {
        setDragMode(QGraphicsView::RubberBandDrag);
        QGraphicsView::mousePressEvent(event);
        return;
    } else {
        bool collision = false;
        QList<QGraphicsItem *> collisionList = items(event->pos());
        for (int i = 0; i < collisionList.size(); ++i) {
            QGraphicsItem *item = collisionList.at(i);
337
            if (item->type() == AVWIDGET || item->type() == TRANSITIONWIDGET) {
338 339 340 341 342 343 344 345
                // select item
                if (!item->isSelected()) {
                    QList<QGraphicsItem *> itemList = items();
                    for (int i = 0; i < itemList.count(); i++)
                        itemList.at(i)->setSelected(false);
                    item->setSelected(true);
                    update();
                }
346 347

                m_dragItem = (AbstractClipItem *) item;
348
                if (item->type() == AVWIDGET) {
349 350
                    emit clipItemSelected((ClipItem*) m_dragItem);
                }
351
                m_clickPoint = mapToScene(event->pos()).x() - m_dragItem->startPos().frames(m_document->fps()) * m_scale;
352
                m_operationMode = m_dragItem->operationMode(item->mapFromScene(mapToScene(event->pos())), m_scale);
353
                if (m_operationMode == MOVE) setCursor(Qt::ClosedHandCursor);
354
                if (m_operationMode == MOVE || m_operationMode == RESIZESTART)
355
                    m_startPos = QPointF(m_dragItem->startPos().frames(m_document->fps()), m_dragItem->track());
356
                else if (m_operationMode == RESIZEEND)
357
                    m_startPos = QPointF(m_dragItem->endPos().frames(m_document->fps()), m_dragItem->track());
358
                else if (m_operationMode == TRANSITIONSTART) {
359 360 361 362 363 364
                    Transition *tr = new Transition(
                        QRect(m_dragItem->startPos().frames(m_document->fps()) *m_scale , m_dragItem->rect().height() / 2,
                              GenTime(2.5).frames(m_document->fps()) *m_scale ,  m_dragItem->rect().height()
                             ),
                        (ClipItem*)m_dragItem, LUMA_TRANSITION, m_dragItem->startPos(), m_dragItem->startPos() + GenTime(2.5), m_document->fps());
                    tr->setTrack(m_dragItem->track());
365 366
                    scene()->addItem(tr);
                    //m_dragItem->addTransition(tra);
367
                }
368

369 370 371 372 373 374 375 376 377 378 379 380 381
                kDebug() << "//////// ITEM CLICKED: " << m_startPos;
                collision = true;
                break;
            }
        }
        if (!collision) {
            kDebug() << "//////// NO ITEM FOUND ON CLICK";
            m_dragItem = NULL;
            setCursor(Qt::ArrowCursor);
            QList<QGraphicsItem *> itemList = items();
            for (int i = 0; i < itemList.count(); i++)
                itemList.at(i)->setSelected(false);
            emit clipItemSelected(NULL);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
382
            setCursorPos((int) mapToScene(event->x(), 0).x() / m_scale);
383
        }
384
    }
385 386 387
    updateSnapPoints(m_dragItem);
    //kDebug()<<pos;
    //QGraphicsView::mousePressEvent(event);
388 389
}

390 391 392 393
void CustomTrackView::activateMonitor() {
    emit activateDocumentMonitor();
}

394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
void CustomTrackView::dragEnterEvent(QDragEnterEvent * event) {
    if (event->mimeData()->hasFormat("kdenlive/producerslist")) {
        kDebug() << "///////////////  DRAG ENTERED, TEXT: " << event->mimeData()->data("kdenlive/producerslist");
        QStringList ids = QString(event->mimeData()->data("kdenlive/producerslist")).split(";");
        //TODO: drop of several clips
        for (int i = 0; i < ids.size(); ++i) {
        }
        DocClipBase *clip = m_document->getBaseClip(ids.at(0).toInt());
        if (clip == NULL) kDebug() << " WARNING))))))))) CLIP NOT FOUND : " << ids.at(0).toInt();
        addItem(clip, event->pos());
        event->acceptProposedAction();
    } else QGraphicsView::dragEnterEvent(event);
}

void CustomTrackView::slotRefreshEffects(ClipItem *clip) {
    int track = m_tracksCount - clip->track();
410
    GenTime pos = clip->startPos();
411 412 413
    m_document->renderer()->mltRemoveEffect(track, pos, "-1", false);
    for (int i = 0; i < clip->effectsCount(); i++) {
        m_document->renderer()->mltAddEffect(track, pos, clip->getEffectArgs(clip->effectAt(i)), false);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
414
    }
415
    m_document->renderer()->doRefresh();
416 417
}

418 419 420 421 422 423 424
void CustomTrackView::addEffect(int track, GenTime pos, QDomElement effect) {
    ClipItem *clip = getClipItemAt(pos.frames(m_document->fps()) + 1, m_tracksCount - track);
    if (clip) {
        QMap <QString, QString> effectParams = clip->addEffect(effect);
        m_document->renderer()->mltAddEffect(track, pos, effectParams);
        emit clipItemSelected(clip);
    }
425 426
}

427 428 429 430 431 432 433 434
void CustomTrackView::deleteEffect(int track, GenTime pos, QDomElement effect) {
    QString index = effect.attribute("kdenlive_ix");
    m_document->renderer()->mltRemoveEffect(track, pos, index);
    ClipItem *clip = getClipItemAt(pos.frames(m_document->fps()) + 1, m_tracksCount - track);
    if (clip) {
        clip->deleteEffect(index);
        emit clipItemSelected(clip);
    }
435 436
}

437 438 439 440 441 442 443 444 445 446 447
void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track) {
    QList<QGraphicsItem *> itemList;
    if (track == -1)
        itemList = items();
    else {
        ClipItem *clip = getClipItemAt(pos.frames(m_document->fps()) + 1, track);
        if (clip) itemList.append(clip);
        else kDebug() << "------   wrning, clip eff not found";
    }
    kDebug() << "// REQUESTING EFFECT ON CLIP: " << pos.frames(25) << ", TRK: " << track;
    for (int i = 0; i < itemList.count(); i++) {
448
        if (itemList.at(i)->type() == AVWIDGET && (itemList.at(i)->isSelected() || track != -1)) {
449 450 451 452 453
            ClipItem *item = (ClipItem *)itemList.at(i);
            // the kdenlive_ix int is used to identify an effect in mlt's playlist, should
            // not be changed
            if (effect.attribute("kdenlive_ix").toInt() == 0)
                effect.setAttribute("kdenlive_ix", QString::number(item->effectsCounter()));
454
            AddEffectCommand *command = new AddEffectCommand(this, m_tracksCount - item->track(), item->startPos(), effect, true);
455 456
            m_commandStack->push(command);
        }
457
    }
458
    m_document->setModified(true);
459 460
}

461
void CustomTrackView::slotDeleteEffect(ClipItem *clip, QDomElement effect) {
462
    AddEffectCommand *command = new AddEffectCommand(this, m_tracksCount - clip->track(), clip->startPos(), effect, false);
463
    m_commandStack->push(command);
464
    m_document->setModified(true);
465 466
}

467 468 469 470 471 472 473
void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement effect) {
    ClipItem *clip = getClipItemAt(pos.frames(m_document->fps()) + 1, m_tracksCount - track);
    if (clip) {
        QMap <QString, QString> effectParams = clip->getEffectArgs(effect);
        if (effectParams["disabled"] == "1") {
            QString index = effectParams["kdenlive_ix"];
            m_document->renderer()->mltRemoveEffect(track, pos, index);
474
        } else m_document->renderer()->mltEditEffect(m_tracksCount - clip->track(), clip->startPos(), effectParams);
475
    }
476
    m_document->setModified(true);
477 478
}

479 480 481
void CustomTrackView::slotChangeEffectState(ClipItem *clip, QDomElement effect, bool disable) {
    QDomElement oldEffect = effect.cloneNode().toElement();
    effect.setAttribute("disabled", disable);
482
    EditEffectCommand *command = new EditEffectCommand(this, m_tracksCount - clip->track(), clip->startPos(), oldEffect, effect, true);
483
    m_commandStack->push(command);
484
    m_document->setModified(true);
485
}
486

487
void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, QDomElement oldeffect, QDomElement effect) {
488
    EditEffectCommand *command = new EditEffectCommand(this, m_tracksCount - clip->track(), clip->startPos(), oldeffect, effect, true);
489
    m_commandStack->push(command);
490 491 492
}


493 494
void CustomTrackView::addItem(DocClipBase *clip, QPoint pos) {
    int in = 0;
495
    GenTime out = clip->duration();
496 497
    //kdDebug()<<"- - - -CREATING CLIP, duration = "<<out<<", URL: "<<clip->fileURL();
    int trackTop = ((int) mapToScene(pos).y() / 50) * 50 + 1;
498
    m_dropItem = new ClipItem(clip, ((int) mapToScene(pos).y() / 50), GenTime(), QRectF(mapToScene(pos).x() * m_scale, trackTop, out.frames(m_document->fps()) * m_scale, 49), out, m_document->fps());
499
    scene()->addItem(m_dropItem);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
500 501
}

502 503

void CustomTrackView::dragMoveEvent(QDragMoveEvent * event) {
504 505 506 507 508 509 510 511 512 513 514
    event->setDropAction(Qt::IgnoreAction);
    //kDebug()<<"+++++++++++++   DRAG MOVE, : "<<mapToScene(event->pos()).x()<<", SCAL: "<<m_scale;
    if (m_dropItem) {
        int track = (int) mapToScene(event->pos()).y() / 50; //) * (m_scale * 50) + m_scale;
        m_dropItem->moveTo(mapToScene(event->pos()).x() / m_scale, m_scale, (track - m_dropItem->track()) * 50, track);
        event->setDropAction(Qt::MoveAction);
        if (event->mimeData()->hasFormat("kdenlive/producerslist")) {
            event->acceptProposedAction();
        }
    } else {
        QGraphicsView::dragMoveEvent(event);
515
    }
516 517
}

518 519 520 521 522
void CustomTrackView::dragLeaveEvent(QDragLeaveEvent * event) {
    if (m_dropItem) {
        delete m_dropItem;
        m_dropItem = NULL;
    } else QGraphicsView::dragLeaveEvent(event);
523 524
}

525 526 527 528 529 530 531
void CustomTrackView::dropEvent(QDropEvent * event) {
    if (m_dropItem) {
        AddTimelineClipCommand *command = new AddTimelineClipCommand(this, m_dropItem->xml(), m_dropItem->clipProducer(), m_dropItem->track(), m_dropItem->startPos(), m_dropItem->rect(), m_dropItem->duration(), false, false);
        m_commandStack->push(command);
        m_dropItem->baseClip()->addReference();
        m_document->updateClip(m_dropItem->baseClip()->getId());
        // kDebug()<<"IIIIIIIIIIIIIIIIIIIIIIII TRAX CNT: "<<m_tracksCount<<", DROP: "<<m_dropItem->track();
532
        m_document->renderer()->mltInsertClip(m_tracksCount - m_dropItem->track(), m_dropItem->startPos(), m_dropItem->xml());
533
        m_document->setModified(true);
534 535
    } else QGraphicsView::dropEvent(event);
    m_dropItem = NULL;
536 537 538
}


539
QStringList CustomTrackView::mimeTypes() const {
540 541 542
    QStringList qstrList;
    // list of accepted mime types for drop
    qstrList.append("text/plain");
543
    qstrList.append("kdenlive/producerslist");
544 545 546
    return qstrList;
}

547
Qt::DropActions CustomTrackView::supportedDropActions() const {
548 549 550 551
    // returns what actions are supported when dropping
    return Qt::MoveAction;
}

552 553 554 555
void CustomTrackView::setDuration(int duration) {
    kDebug() << "/////////////  PRO DUR: " << duration << ", height: " << 50 * m_tracksCount;
    m_projectDuration = duration;
    scene()->setSceneRect(0, 0, (m_projectDuration + 500) * m_scale, scene()->sceneRect().height()); //50 * m_tracksCount);
556 557 558
}


559 560 561 562 563 564
void CustomTrackView::addTrack() {
    m_tracksCount++;
    m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), 50 * m_tracksCount);
    //setSceneRect(0, 0, sceneRect().width(), 50 * m_tracksCount);
    //verticalScrollBar()->setMaximum(50 * m_tracksCount);
    //setFixedHeight(50 * m_tracksCount);
565 566
}

567 568 569
void CustomTrackView::removeTrack() {
    m_tracksCount--;
    m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), 50 * m_tracksCount);
570 571
}

572 573 574
void CustomTrackView::deleteClip(int clipId) {
    QList<QGraphicsItem *> itemList = items();
    for (int i = 0; i < itemList.count(); i++) {
575
        if (itemList.at(i)->type() == AVWIDGET) {
576 577 578 579 580 581 582
            ClipItem *item = (ClipItem *)itemList.at(i);
            if (item->clipProducer() == clipId) {
                AddTimelineClipCommand *command = new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->track(), item->startPos(), item->rect(), item->duration(), true, true);
                m_commandStack->push(command);
                //delete item;
            }
        }
583 584 585
    }
}

586
void CustomTrackView::setCursorPos(int pos, bool seek) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
587
    emit cursorMoved(m_cursorPos * m_scale, pos * m_scale);
588
    m_cursorPos = pos;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
589 590
    m_cursorLine->setPos(pos * m_scale, 0);
    if (seek) m_document->renderer()->seek(GenTime(pos, m_document->fps()));
591
    else if (m_autoScroll && m_scale < 50) checkScrolling();
592 593
}

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
594 595 596 597
void CustomTrackView::updateCursorPos() {
    m_cursorLine->setPos(m_cursorPos * m_scale, 0);
}

598
int CustomTrackView::cursorPos() {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
599
    return m_cursorPos * m_scale;
600 601
}

602 603 604 605 606
void CustomTrackView::checkScrolling() {
    QRect rectInView = viewport()->rect();
    int delta = rectInView.width() / 3;
    int max = rectInView.right() + horizontalScrollBar()->value() - delta;
    //kDebug() << "CURSOR POS: "<<m_cursorPos<< "Scale: "<<m_scale;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
607
    if (m_cursorPos * m_scale >= max) horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 1 + m_scale);
608 609
}

610 611 612 613
void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) {
    QGraphicsView::mouseReleaseEvent(event);
    setDragMode(QGraphicsView::NoDrag);
    if (m_dragItem == NULL) return;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
614
    if (m_operationMode == MOVE) setCursor(Qt::OpenHandCursor);
615
    if (m_operationMode == MOVE && m_startPos.x() != m_dragItem->startPos().frames(m_document->fps())) {
616
        // move clip
617
        MoveClipCommand *command = new MoveClipCommand(this, m_startPos, QPointF(m_dragItem->startPos().frames(m_document->fps()), m_dragItem->track()), false);
618
        m_commandStack->push(command);
619
        m_document->renderer()->mltMoveClip(m_tracksCount - m_startPos.y(), m_tracksCount - m_dragItem->track(), m_startPos.x(), m_dragItem->startPos().frames(m_document->fps()));
620 621
    } else if (m_operationMode == RESIZESTART) {
        // resize start
622
        ResizeClipCommand *command = new ResizeClipCommand(this, m_startPos, QPointF(m_dragItem->startPos().frames(m_document->fps()), m_dragItem->track()), true, false);
623

624
        m_document->renderer()->mltResizeClipStart(m_tracksCount - m_dragItem->track(), m_dragItem->endPos(), m_dragItem->startPos(), GenTime(m_startPos.x(), m_document->fps()), m_dragItem->cropStart(), m_dragItem->cropStart() + m_dragItem->endPos() - m_dragItem->startPos());
625 626 627 628
        m_commandStack->push(command);
        m_document->renderer()->doRefresh();
    } else if (m_operationMode == RESIZEEND) {
        // resize end
629
        ResizeClipCommand *command = new ResizeClipCommand(this, m_startPos, QPointF(m_dragItem->endPos().frames(m_document->fps()), m_dragItem->track()), false, false);
630

631
        m_document->renderer()->mltResizeClipEnd(m_tracksCount - m_dragItem->track(), m_dragItem->startPos(), m_dragItem->cropStart(), m_dragItem->cropStart() + m_dragItem->endPos() - m_dragItem->startPos());
632 633 634
        m_commandStack->push(command);
        m_document->renderer()->doRefresh();
    }
635
    m_document->setModified(true);
636 637
    m_operationMode = NONE;
    m_dragItem = NULL;
638 639
}

640
void CustomTrackView::deleteClip(int track, GenTime startpos, const QRectF &rect) {
641 642 643 644 645 646 647 648
    ClipItem *item = getClipItemAt(startpos, track);
    if (!item) {
        kDebug() << "----------------  ERROR, CANNOT find clip to move at: " << rect.x();
        return;
    }
    item->baseClip()->removeReference();
    m_document->updateClip(item->baseClip()->getId());
    delete item;
649
    m_document->renderer()->mltRemoveClip(m_tracksCount - track, startpos);
650
    m_document->renderer()->doRefresh();
651 652
}

653 654
void CustomTrackView::addClip(QDomElement xml, int clipId, int track, GenTime startpos, const QRectF &rect, GenTime duration) {
    QRect r(startpos.frames(m_document->fps()) * m_scale, 50 * track, duration.frames(m_document->fps()) * m_scale, 49);
655
    DocClipBase *baseclip = m_document->clipManager()->getClipById(clipId);
656
    ClipItem *item = new ClipItem(baseclip, track, startpos, r, duration, m_document->fps());
657 658 659
    scene()->addItem(item);
    baseclip->addReference();
    m_document->updateClip(baseclip->getId());
660
    m_document->renderer()->mltInsertClip(m_tracksCount - track, startpos, xml);
661
    m_document->renderer()->doRefresh();
662 663
}

664 665
ClipItem *CustomTrackView::getClipItemAt(int pos, int track) {
    return (ClipItem *) scene()->itemAt(pos * m_scale, track * 50 + 25);
666 667
}

668 669 670 671
ClipItem *CustomTrackView::getClipItemAt(GenTime pos, int track) {
    return (ClipItem *) scene()->itemAt(pos.frames(m_document->fps()) * m_scale, track * 50 + 25);
}

672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
void CustomTrackView::moveClip(const QPointF &startPos, const QPointF &endPos) {
    ClipItem *item = getClipItemAt(startPos.x() + 1, startPos.y());
    if (!item) {
        kDebug() << "----------------  ERROR, CANNOT find clip to move at: " << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * 50 + 25;
        return;
    }
    kDebug() << "----------------  Move CLIP FROM: " << startPos.x() << ", END:" << endPos.x();
    item->moveTo(endPos.x(), m_scale, (endPos.y() - startPos.y()) * 50, endPos.y());
    m_document->renderer()->mltMoveClip(m_tracksCount - startPos.y(), m_tracksCount - endPos.y(), startPos.x(), endPos.x());
}

void CustomTrackView::resizeClip(const QPointF &startPos, const QPointF &endPos, bool resizeClipStart) {
    int offset;
    if (resizeClipStart) offset = 1;
    else offset = -1;
    ClipItem *item = getClipItemAt(startPos.x() + offset, startPos.y());
    if (!item) {
        kDebug() << "----------------  ERROR, CANNOT find clip to resize at: " << startPos;
        return;
    }
    qreal diff = endPos.x() - startPos.x();
    if (resizeClipStart) {
694
        m_document->renderer()->mltResizeClipStart(m_tracksCount - item->track(), item->endPos(), GenTime(endPos.x(), m_document->fps()), item->startPos(), item->cropStart() + GenTime(diff, m_document->fps()), item->cropStart() + GenTime(diff, m_document->fps()) + item->endPos() - GenTime(endPos.x(), m_document->fps()));
695 696
        item->resizeStart(endPos.x(), m_scale);
    } else {
697
        m_document->renderer()->mltResizeClipEnd(m_tracksCount - item->track(), item->startPos(), item->cropStart(), item->cropStart() + GenTime(endPos.x(), m_document->fps()) - item->startPos());
698 699 700
        item->resizeEnd(endPos.x(), m_scale);
    }
    m_document->renderer()->doRefresh();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
701 702
}

703 704
double CustomTrackView::getSnapPointForPos(double pos) {
    for (int i = 0; i < m_snapPoints.size(); ++i) {
705
        if (abs(pos - m_snapPoints.at(i).frames(m_document->fps()) * m_scale) < 10) {
706
            //kDebug()<<" FOUND SNAP POINT AT: "<<m_snapPoints.at(i)<<", current pos: "<<pos / m_scale;
707
            return m_snapPoints.at(i).frames(m_document->fps()) * m_scale + 0.5;
708
        }
709
        if (m_snapPoints.at(i).frames(m_document->fps() * m_scale) > pos) break;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
710
    }
711
    return pos;
712 713
}

714
void CustomTrackView::updateSnapPoints(AbstractClipItem *selected) {
715
    m_snapPoints.clear();
716 717
    GenTime offset;
    if (selected) offset = selected->duration();
718 719
    QList<QGraphicsItem *> itemList = items();
    for (int i = 0; i < itemList.count(); i++) {
720
        if (itemList.at(i)->type() == AVWIDGET && itemList.at(i) != selected) {
721
            ClipItem *item = (ClipItem *)itemList.at(i);
722 723
            GenTime start = item->startPos();
            GenTime end = item->endPos();
724 725
            m_snapPoints.append(start);
            m_snapPoints.append(end);
726 727 728
            if (offset != GenTime()) {
                if (start > offset) m_snapPoints.append(start - offset);
                if (end > offset) m_snapPoints.append(end - offset);
729 730
            }
        }
731
    }
732
    qSort(m_snapPoints);
733 734
    //for (int i = 0; i < m_snapPoints.size(); ++i)
    //    kDebug() << "SNAP POINT: " << m_snapPoints.at(i).frames(25);
735 736
}

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

738 739
void CustomTrackView::setScale(double scaleFactor) {
    //scale(scaleFactor, scaleFactor);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
740
    double pos = cursorPos() / m_scale;
741 742 743 744 745
    m_scale = scaleFactor;
    kDebug() << " HHHHHHHH  SCALING: " << m_scale;
    QList<QGraphicsItem *> itemList = items();

    for (int i = 0; i < itemList.count(); i++) {
746
        if (itemList.at(i)->type() == AVWIDGET || itemList.at(i)->type() == TRANSITIONWIDGET) {
747
            AbstractClipItem *clip = (AbstractClipItem *)itemList.at(i);
748
            clip->setRect(clip->startPos().frames(m_document->fps()) * m_scale, clip->rect().y(), clip->duration().frames(m_document->fps()) * m_scale, clip->rect().height());
749
        }
750
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
751 752 753
    updateCursorPos();
    centerOn(QPointF(cursorPos(), 50));
    scene()->setSceneRect(0, 0, (m_projectDuration + 500) * m_scale, scene()->sceneRect().height());
754 755
}

756
void CustomTrackView::drawBackground(QPainter * painter, const QRectF & rect) {
757 758
    QRect rectInView = viewport()->rect();
    rectInView.moveTo(horizontalScrollBar()->value(), verticalScrollBar()->value());
759 760 761 762 763 764 765 766 767 768 769

    QColor base = palette().button().color();
    painter->setClipRect(rect);
    painter->drawLine(rectInView.left(), 0, rectInView.right(), 0);
    for (uint i = 0; i < m_tracksCount;i++) {
        painter->drawLine(rectInView.left(), 50 * (i + 1), rectInView.right(), 50 * (i + 1));
        painter->drawText(QRectF(10, 50 * i, 100, 50 * i + 49), Qt::AlignLeft, i18n(" Track ") + QString::number(i + 1));
    }
    int lowerLimit = 50 * m_tracksCount + 1;
    if (height() > lowerLimit)
        painter->fillRect(QRectF(rectInView.left(), lowerLimit, rectInView.width(), height() - lowerLimit), QBrush(base));
770
}
771
/*
772
void CustomTrackView::drawForeground ( QPainter * painter, const QRectF & rect )
773 774
{
  //kDebug()<<"/////  DRAWING FB: "<<rect.x()<<", width: "<<rect.width();
775
  painter->fillRect(rect, QColor(50, rand() % 250,50,100));
776 777
  painter->drawLine(m_cursorPos, rect.y(), m_cursorPos, rect.y() + rect.height());
}
778
*/
779
#include "customtrackview.moc"