]> git.sesse.net Git - kdenlive/blob - src/customtrackview.cpp
94ae3628851d01754a51489e6e65356e547118c1
[kdenlive] / src / customtrackview.cpp
1 /***************************************************************************
2  *   Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20 #include <QMouseEvent>
21 #include <QStylePainter>
22 #include <QGraphicsItem>
23 #include <QDomDocument>
24 #include <QScrollBar>
25
26 #include <KDebug>
27 #include <KLocale>
28 #include <KUrl>
29
30 #include "customtrackview.h"
31 #include "clipitem.h"
32 #include "definitions.h"
33 #include "moveclipcommand.h"
34 #include "resizeclipcommand.h"
35 #include "addtimelineclipcommand.h"
36
37 CustomTrackView::CustomTrackView(KUndoStack *commandStack, QGraphicsScene * projectscene, QWidget *parent)
38     : QGraphicsView(projectscene, parent), m_commandStack(commandStack), 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)
39 {
40   setMouseTracking(true);
41   setAcceptDrops(true);
42   m_animationTimer = new QTimeLine(800);
43   m_animationTimer->setFrameRange(0, 5);
44   m_animationTimer->setUpdateInterval(100);
45   m_animationTimer->setLoopCount(0);
46   m_tipColor = QColor(230, 50, 0, 150);
47   setContentsMargins(0, 0, 0, 0);
48   if (projectscene) {
49     m_cursorLine = projectscene->addLine(0, 0, 0, 50);
50     m_cursorLine->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIgnoresTransformations);
51     m_cursorLine->setZValue(1000);
52   }
53 }
54
55 void CustomTrackView::initView()
56 {
57
58 }
59
60 // virtual
61 void CustomTrackView::resizeEvent ( QResizeEvent * event )
62 {
63   QGraphicsView::resizeEvent(event);
64 }
65
66 // virtual
67 void CustomTrackView::wheelEvent ( QWheelEvent * e ) 
68 {
69   if (e->modifiers() == Qt::ControlModifier) {
70     if (e->delta() > 0) emit zoomIn();
71     else emit zoomOut();
72   }
73   else {
74     if (e->delta() > 0) horizontalScrollBar()->setValue (horizontalScrollBar()->value() + horizontalScrollBar()->singleStep ());
75     else  horizontalScrollBar()->setValue (horizontalScrollBar()->value() - horizontalScrollBar()->singleStep ());
76   }
77 }
78
79
80 // virtual 
81 void CustomTrackView::mouseMoveEvent ( QMouseEvent * event )
82 {
83   int pos = event->x();
84   /*if (event->modifiers() == Qt::ControlModifier)
85     setDragMode(QGraphicsView::ScrollHandDrag);
86   else if (event->modifiers() == Qt::ShiftModifier) 
87     setDragMode(QGraphicsView::RubberBandDrag);
88   else*/ {
89
90       if (m_dragItem) { //event->button() == Qt::LeftButton) {
91         // a button was pressed, delete visual tips
92
93         if (m_operationMode == MOVE) {
94           int moveX = mapToScene(event->pos()).x();
95           //kDebug()<<"///////  MOVE CLIP, EVENT Y: "<<event->scenePos().y()<<", SCENE HEIGHT: "<<scene()->sceneRect().height();
96           int moveTrack = (int)  mapToScene(event->pos()).y() / 50;
97           int currentTrack = m_dragItem->track();
98
99           if (moveTrack > m_tracksCount - 1) moveTrack = m_tracksCount - 1;
100           else if (moveTrack < 0) moveTrack = 0;
101
102           int offset = moveTrack - currentTrack;
103           if (offset != 0) offset = 50 * offset;
104           m_dragItem->moveTo((moveX - m_clickPoint) / m_scale, m_scale, offset, moveTrack);
105         }
106         else if (m_operationMode == RESIZESTART) {
107           int pos = mapToScene(event->pos()).x();
108           m_dragItem->resizeStart(pos / m_scale, m_scale);
109         }
110         else if (m_operationMode == RESIZEEND) {
111           int pos = mapToScene(event->pos()).x();
112           m_dragItem->resizeEnd(pos / m_scale, m_scale);
113         }
114         if (m_animation) delete m_animation;
115         m_animation = NULL;
116         if (m_visualTip) delete m_visualTip;
117         m_visualTip = NULL;
118         QGraphicsView::mouseMoveEvent(event);
119         return;
120       }
121
122     QList<QGraphicsItem *> itemList = items( event->pos());
123     int i = 0;
124     QGraphicsItem *item = NULL;
125     for (int i = 0; i < itemList.count(); i++) {
126       if (itemList.at(i)->type() == 70000) {
127         item = itemList.at(i);
128         break;
129       }
130     }
131     if (item) {
132       ClipItem *clip = (ClipItem*) item;
133       double size = mapToScene(QPoint(8, 0)).x();
134       OPERATIONTYPE opMode = clip->operationMode(mapToScene(event->pos()));
135       if (opMode == m_moveOpMode) {
136         QGraphicsView::mouseMoveEvent(event);
137         return;
138       }
139       else {
140       if (m_visualTip) {
141         if (m_animation) delete m_animation;
142         m_animation = NULL;
143         delete m_visualTip;
144         m_visualTip = NULL;
145       }
146       }
147       m_moveOpMode = opMode;
148       if (opMode == MOVE) {
149         setCursor(Qt::OpenHandCursor);
150       }
151       else if (opMode == RESIZESTART) {
152         kDebug()<<"********  RESIZE CLIP START; WIDTH: "<<size;
153         if (m_visualTip == NULL) {
154           m_visualTip = new QGraphicsRectItem(clip->rect().x(), clip->rect().y(), size, clip->rect().height());
155           ((QGraphicsRectItem*) m_visualTip)->setBrush(m_tipColor);
156           ((QGraphicsRectItem*) m_visualTip)->setPen(QPen(Qt::transparent));
157           m_visualTip->setZValue (100);
158           m_animation = new QGraphicsItemAnimation;
159           m_animation->setItem(m_visualTip);
160           m_animation->setTimeLine(m_animationTimer);
161           m_visualTip->setPos(0, 0);
162           double scale = 2.0;
163           m_animation->setScaleAt(.5, scale, 1);
164           m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
165           scale = 1.0;
166           m_animation->setScaleAt(1, scale, 1);
167           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
168           scene()->addItem(m_visualTip);
169           m_animationTimer->start();
170         }
171         setCursor(Qt::SizeHorCursor);
172       }
173       else if (opMode == RESIZEEND) {
174         if (m_visualTip == NULL) {
175           m_visualTip = new QGraphicsRectItem(clip->rect().x() + clip->rect().width() - size, clip->rect().y(), size, clip->rect().height());
176           ((QGraphicsRectItem*) m_visualTip)->setBrush(m_tipColor);
177           ((QGraphicsRectItem*) m_visualTip)->setPen(QPen(Qt::transparent));
178           m_visualTip->setZValue (100);
179           m_animation = new QGraphicsItemAnimation;
180           m_animation->setItem(m_visualTip);
181           m_animation->setTimeLine(m_animationTimer);
182           m_visualTip->setPos(0, 0);
183           double scale = 2.0;
184           m_animation->setScaleAt(.5, scale, 1);
185           m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale - clip->rect().width(), 0));
186           scale = 1.0;
187           m_animation->setScaleAt(1, scale, 1);
188           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
189           scene()->addItem(m_visualTip);
190           m_animationTimer->start();
191         }
192         setCursor(Qt::SizeHorCursor);
193       }
194       else if (opMode == FADEIN) {
195         if (m_visualTip == NULL) {
196           m_visualTip = new QGraphicsEllipseItem(clip->rect().x() - size, clip->rect().y() - 8, size * 2, 16);
197           ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
198           ((QGraphicsEllipseItem*) m_visualTip)->setPen(QPen(Qt::transparent));
199           m_visualTip->setZValue (100);
200           m_animation = new QGraphicsItemAnimation;
201           m_animation->setItem(m_visualTip);
202           m_animation->setTimeLine(m_animationTimer);
203           m_visualTip->setPos(0, 0);
204           double scale = 2.0;
205           m_animation->setScaleAt(.5, scale, scale);
206           m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale, clip->rect().y() - clip->rect().y() * scale));
207           scale = 1.0;
208           m_animation->setScaleAt(1, scale, scale);
209           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, clip->rect().y() - clip->rect().y() * scale));
210           scene()->addItem(m_visualTip);
211           m_animationTimer->start();
212         }
213         setCursor(Qt::PointingHandCursor);
214       }
215       else if (opMode == FADEOUT) {
216         if (m_visualTip == NULL) {
217           m_visualTip = new QGraphicsEllipseItem(clip->rect().x() + clip->rect().width() - size, clip->rect().y() - 8, size*2, 16);
218           ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
219           ((QGraphicsEllipseItem*) m_visualTip)->setPen(QPen(Qt::transparent));
220           m_visualTip->setZValue (100);
221           m_animation = new QGraphicsItemAnimation;
222           m_animation->setItem(m_visualTip);
223           m_animation->setTimeLine(m_animationTimer);
224           m_visualTip->setPos(0, 0);
225           double scale = 2.0;
226           m_animation->setScaleAt(.5, scale, scale);      
227           m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale - clip->rect().width(), clip->rect().y() - clip->rect().y() * scale));
228           scale = 1.0;
229           m_animation->setScaleAt(1, scale, scale);
230           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, clip->rect().y() - clip->rect().y() * scale));
231           scene()->addItem(m_visualTip);
232           m_animationTimer->start();
233         }
234         setCursor(Qt::PointingHandCursor);
235       }
236     }
237     else {
238       m_moveOpMode = NONE;
239       if (m_visualTip) {
240         if (m_animation) delete m_animation;
241         m_animation = NULL;
242         delete m_visualTip;
243         m_visualTip = NULL;
244       }
245       setCursor(Qt::ArrowCursor);
246     }
247   }
248   QGraphicsView::mouseMoveEvent(event);
249 }
250
251 // virtual 
252 void CustomTrackView::mousePressEvent ( QMouseEvent * event )
253 {
254   int pos = event->x();
255   if (event->modifiers() == Qt::ControlModifier) 
256     setDragMode(QGraphicsView::ScrollHandDrag);
257   else if (event->modifiers() == Qt::ShiftModifier) 
258     setDragMode(QGraphicsView::RubberBandDrag);
259   else {
260     bool collision = false;
261     QList<QGraphicsItem *> collisionList = items(event->pos());
262     for (int i = 0; i < collisionList.size(); ++i) {
263       QGraphicsItem *item = collisionList.at(i);
264       if (item->type() == 70000) {
265         m_dragItem = (ClipItem *) item;
266         m_clickPoint = mapToScene(event->pos()).x() - m_dragItem->startPos() * m_scale;
267         m_operationMode = m_dragItem->operationMode(item->mapFromScene(mapToScene(event->pos())));
268         if (m_operationMode == MOVE || m_operationMode == RESIZESTART) m_startPos = QPointF(m_dragItem->startPos(), m_dragItem->track());
269         else if (m_operationMode == RESIZEEND) m_startPos = QPointF(m_dragItem->endPos(), m_dragItem->track());
270         kDebug()<<"//////// ITEM CLICKED: "<<m_startPos;
271         collision = true;
272         break;
273       }
274     }
275     if (!collision) {
276       kDebug()<<"//////// NO ITEM FOUND ON CLICK";
277       m_dragItem = NULL;
278       setCursor(Qt::ArrowCursor);
279       setCursorPos((int) mapToScene(event->x(), 0).x());
280       emit cursorMoved(cursorPos());
281     }
282   }
283   //kDebug()<<pos;
284   QGraphicsView::mousePressEvent(event);
285 }
286
287 void CustomTrackView::dragEnterEvent ( QDragEnterEvent * event )
288 {
289   if (event->mimeData()->hasText()) {
290     QString clip = event->mimeData()->text();
291     addItem(clip, event->pos());
292     event->acceptProposedAction();
293   }
294 }
295
296
297 void CustomTrackView::addItem(QString producer, QPoint pos)
298 {
299   QDomDocument doc;
300   doc.setContent(producer);
301   QDomElement elem = doc.documentElement();
302   int in = elem.attribute("in", 0).toInt();
303   int out = elem.attribute("duration", 0).toInt();
304   if (out == 0) out = elem.attribute("out", 0).toInt() - in;
305   kDebug()<<"ADDING CLIP: "<<producer<<", OUT: "<<out<<", POS: "<<mapToScene(pos);
306   int trackTop = ((int) mapToScene(pos).y()/50) * 50 + 1;
307   m_dropItem = new ClipItem(elem, ((int) mapToScene(pos).y()/50), in, QRectF(mapToScene(pos).x() * m_scale, trackTop, out * m_scale, 49));
308   scene()->addItem(m_dropItem);
309 }
310
311
312 void CustomTrackView::dragMoveEvent(QDragMoveEvent * event) {
313   event->setDropAction(Qt::IgnoreAction);
314   if (m_dropItem) {
315     int track = (int) mapToScene(event->pos()).y()/50; //) * (m_scale * 50) + m_scale;
316      kDebug()<<"+++++++++++++   DRAG MOVE, : "<<mapToScene(event->pos()).x()<<", SCAL: "<<m_scale;
317     m_dropItem->moveTo(mapToScene(event->pos()).x() / m_scale, m_scale, (track - m_dropItem->track()) * 50, track);
318   }
319        //if (item) {
320   event->setDropAction(Qt::MoveAction);
321   if (event->mimeData()->hasText()) {
322     event->acceptProposedAction();
323   }
324         //}
325 }
326
327 void CustomTrackView::dragLeaveEvent ( QDragLeaveEvent * event ) {
328   if (m_dropItem) {
329     delete m_dropItem;
330     m_dropItem = NULL;
331   }
332 }
333
334 void CustomTrackView::dropEvent ( QDropEvent * event ) {
335   if (m_dropItem) {
336     AddTimelineClipCommand *command = new AddTimelineClipCommand(this, m_dropItem->xml(), m_dropItem->track(), m_dropItem->startPos(), m_dropItem->rect(), m_dropItem->duration(), false);
337     m_commandStack->push(command);
338   }
339   m_dropItem = NULL;
340 }
341
342
343 QStringList CustomTrackView::mimeTypes () const
344 {
345     QStringList qstrList;
346     // list of accepted mime types for drop
347     qstrList.append("text/plain");
348     return qstrList;
349 }
350
351 Qt::DropActions CustomTrackView::supportedDropActions () const
352 {
353     // returns what actions are supported when dropping
354     return Qt::MoveAction;
355 }
356
357 void CustomTrackView::setDuration(int duration)
358 {
359   kDebug()<<"/////////////  PRO DUR: "<<duration<<", height: "<<50 * m_tracksCount;
360   m_projectDuration = duration;
361   scene()->setSceneRect(0, 0, m_projectDuration + 500, scene()->sceneRect().height()); //50 * m_tracksCount);
362 }
363
364
365 void CustomTrackView::addTrack ()
366 {
367   m_tracksCount++;
368   m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), 50 * m_tracksCount);
369   //setSceneRect(0, 0, sceneRect().width(), 50 * m_tracksCount);
370   //verticalScrollBar()->setMaximum(50 * m_tracksCount); 
371   //setFixedHeight(50 * m_tracksCount);
372 }
373
374 void CustomTrackView::removeTrack ()
375 {
376   m_tracksCount--;
377   m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), 50 * m_tracksCount);
378 }
379
380 void CustomTrackView::setCursorPos(int pos)
381 {
382   m_cursorPos = pos;
383   m_cursorLine->setPos(pos, 0);
384 }
385
386 int CustomTrackView::cursorPos()
387 {
388   return m_cursorPos;
389 }
390
391 void CustomTrackView::mouseReleaseEvent ( QMouseEvent * event )
392 {
393   QGraphicsView::mouseReleaseEvent(event);
394   setDragMode(QGraphicsView::NoDrag);
395   if (m_dragItem == NULL) return;
396   //kDebug()<<"/// MOVING CLIP: "<<m_startPos<<", END: "<<QPoint(m_dragItem->rect().x(),m_dragItem->rect().y());
397   if (m_operationMode == MOVE) {
398     // move clip
399     MoveClipCommand *command = new MoveClipCommand(this, m_startPos, QPointF(m_dragItem->startPos(), m_dragItem->track()), false);
400     m_commandStack->push(command);
401   }
402   else if (m_operationMode == RESIZESTART) {
403     // resize start
404     ResizeClipCommand *command = new ResizeClipCommand(this, m_startPos, QPointF(m_dragItem->startPos(), m_dragItem->track()), true, false);
405     m_commandStack->push(command);
406   }
407   else if (m_operationMode == RESIZEEND) {
408     // resize end
409     ResizeClipCommand *command = new ResizeClipCommand(this, m_startPos, QPointF(m_dragItem->endPos(), m_dragItem->track()), false, false);
410     m_commandStack->push(command);
411   }
412   m_dragItem = NULL; 
413 }
414
415 void CustomTrackView::deleteClip ( const QRectF &rect )
416 {
417   ClipItem *item = (ClipItem *) scene()->itemAt(rect.x() + 1, rect.y() + 1);
418   if (!item) {
419     kDebug()<<"----------------  ERROR, CANNOT find clip to move at: "<<rect.x();
420     return;
421   }
422   delete item;
423 }
424
425 void CustomTrackView::addClip ( QDomElement xml, int track, int startpos, const QRectF &rect, int duration )
426 {
427   QRect r(startpos * m_scale, 50 * track, duration * m_scale, 49); 
428   ClipItem *item = new ClipItem(xml, track, startpos, r, duration);
429   scene()->addItem(item);
430 }
431
432 void CustomTrackView::moveClip ( const QPointF &startPos, const QPointF &endPos )
433 {
434   ClipItem *item = (ClipItem *) scene()->itemAt((startPos.x() + 1) * m_scale, startPos.y() * 50 + 25);
435   if (!item) {
436     kDebug()<<"----------------  ERROR, CANNOT find clip to move at: "<<startPos.x() * m_scale * FRAME_SIZE + 1<<", "<<startPos.y() * 50 + 25;
437     return;
438   }
439   kDebug()<<"----------------  Move CLIP FROM: "<<startPos.x()<<", END:"<<endPos.x();
440   item->moveTo(endPos.x(), m_scale, (endPos.y() - startPos.y()) * 50, endPos.y());
441 }
442
443 void CustomTrackView::resizeClip ( const QPointF &startPos, const QPointF &endPos, bool resizeClipStart )
444 {
445   int offset;
446   if (resizeClipStart) offset = 1;
447   else offset = -1;
448   ClipItem *item = (ClipItem *) scene()->itemAt((startPos.x() + offset) * m_scale, startPos.y() * 50 + 25);
449   if (!item) {
450     kDebug()<<"----------------  ERROR, CANNOT find clip to resize at: "<<startPos;
451     return;
452   }
453   qreal diff = endPos.x() - startPos.x();
454   if (resizeClipStart) {
455     item->resizeStart(endPos.x(), m_scale);
456   }
457   else {
458     item->resizeEnd(endPos.x(), m_scale);
459   }
460 }
461
462
463 void CustomTrackView::setScale(double scaleFactor)
464 {
465   //scale(scaleFactor, scaleFactor);
466   m_scale = scaleFactor;
467   kDebug()<<" HHHHHHHH  SCALING: "<<m_scale;
468   QList<QGraphicsItem *> itemList = items();
469
470   for (int i = 0; i < itemList.count(); i++) {
471       if (itemList.at(i)->type() == 70000) {
472         ClipItem *clip = (ClipItem *)itemList.at(i);
473         clip->setRect(clip->startPos() * m_scale, clip->rect().y(), clip->duration() * m_scale, clip->rect().height());
474       }
475       /*else if (itemList.at(i)->type() == 70001) {
476         LabelItem *label = (LabelItem *)itemList.at(i);
477         QGraphicsItem *parent = label->parentItem();
478         QRectF r = label->boundingRect();
479         QRectF p = parent->boundingRect();
480         label->setPos(p.x() + p.width() / 2 - r.width() / 2, p.y() + p.height() / 2 - r.height() / 2);
481         //label->setRect(clip->startPos() * m_scale, clip->rect().y(), clip->duration() * m_scale, clip->rect().height());
482       }*/
483     }
484 }
485
486 void CustomTrackView::drawBackground ( QPainter * painter, const QRectF & rect )  
487 {
488   QColor base = palette().button().color();
489   painter->setPen(base);
490   painter->setClipRect(rect);
491   painter->drawLine(0, 0, rect.width(), 0);
492     for (uint i = 0; i < m_tracksCount;i++)
493     {
494     painter->drawLine(0, 50 * (i+1), width(), 50 * (i+1));
495       //painter->drawText(QRectF(10, 50 * i, 100, 50 * i + 49), Qt::AlignLeft, i18n(" Track ") + QString::number(i));
496     }
497   int lowerLimit = 50 * m_tracksCount;
498   if (height() > lowerLimit)
499   painter->fillRect(QRectF(0, lowerLimit, rect.width(), height() - lowerLimit), QBrush(base));
500 }
501 /*
502 void CustomTrackView::drawForeground ( QPainter * painter, const QRectF & rect )  
503 {
504   //kDebug()<<"/////  DRAWING FB: "<<rect.x()<<", width: "<<rect.width();
505   painter->fillRect(rect, QColor(50, rand() % 250,50,100));
506   painter->drawLine(m_cursorPos, rect.y(), m_cursorPos, rect.y() + rect.height());
507 }
508 */
509 #include "customtrackview.moc"