]> git.sesse.net Git - kdenlive/blob - src/customtrackview.cpp
ae047716e3088900f551a109188665a3da82e635
[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         else if (m_operationMode == FADEIN) {
115           int pos = mapToScene(event->pos()).x() / m_scale;
116           m_dragItem->setFadeIn(pos - m_dragItem->startPos(), m_scale);
117         }
118         else if (m_operationMode == FADEOUT) {
119           int pos = mapToScene(event->pos()).x() / m_scale;
120           m_dragItem->setFadeOut(m_dragItem->endPos() - pos, m_scale);
121         }
122
123         if (m_animation) delete m_animation;
124         m_animation = NULL;
125         if (m_visualTip) delete m_visualTip;
126         m_visualTip = NULL;
127         QGraphicsView::mouseMoveEvent(event);
128         return;
129       }
130
131     QList<QGraphicsItem *> itemList = items( event->pos());
132     int i = 0;
133     QGraphicsItem *item = NULL;
134     for (int i = 0; i < itemList.count(); i++) {
135       if (itemList.at(i)->type() == 70000) {
136         item = itemList.at(i);
137         break;
138       }
139     }
140     if (item) {
141       ClipItem *clip = (ClipItem*) item;
142       double size = mapToScene(QPoint(8, 0)).x();
143       OPERATIONTYPE opMode = clip->operationMode(mapToScene(event->pos()), m_scale);
144       if (opMode == m_moveOpMode) {
145         QGraphicsView::mouseMoveEvent(event);
146         return;
147       }
148       else {
149       if (m_visualTip) {
150         if (m_animation) delete m_animation;
151         m_animation = NULL;
152         delete m_visualTip;
153         m_visualTip = NULL;
154       }
155       }
156       m_moveOpMode = opMode;
157       if (opMode == MOVE) {
158         setCursor(Qt::OpenHandCursor);
159       }
160       else if (opMode == RESIZESTART) {
161         kDebug()<<"********  RESIZE CLIP START; WIDTH: "<<size;
162         if (m_visualTip == NULL) {
163           m_visualTip = new QGraphicsRectItem(clip->rect().x(), clip->rect().y(), size, clip->rect().height());
164           ((QGraphicsRectItem*) m_visualTip)->setBrush(m_tipColor);
165           ((QGraphicsRectItem*) m_visualTip)->setPen(QPen(Qt::transparent));
166           m_visualTip->setZValue (100);
167           m_animation = new QGraphicsItemAnimation;
168           m_animation->setItem(m_visualTip);
169           m_animation->setTimeLine(m_animationTimer);
170           m_visualTip->setPos(0, 0);
171           double scale = 2.0;
172           m_animation->setScaleAt(.5, scale, 1);
173           m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
174           scale = 1.0;
175           m_animation->setScaleAt(1, scale, 1);
176           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
177           scene()->addItem(m_visualTip);
178           m_animationTimer->start();
179         }
180         setCursor(Qt::SizeHorCursor);
181       }
182       else if (opMode == RESIZEEND) {
183         if (m_visualTip == NULL) {
184           m_visualTip = new QGraphicsRectItem(clip->rect().x() + clip->rect().width() - size, clip->rect().y(), size, clip->rect().height());
185           ((QGraphicsRectItem*) m_visualTip)->setBrush(m_tipColor);
186           ((QGraphicsRectItem*) m_visualTip)->setPen(QPen(Qt::transparent));
187           m_visualTip->setZValue (100);
188           m_animation = new QGraphicsItemAnimation;
189           m_animation->setItem(m_visualTip);
190           m_animation->setTimeLine(m_animationTimer);
191           m_visualTip->setPos(0, 0);
192           double scale = 2.0;
193           m_animation->setScaleAt(.5, scale, 1);
194           m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale - clip->rect().width(), 0));
195           scale = 1.0;
196           m_animation->setScaleAt(1, scale, 1);
197           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, 0));
198           scene()->addItem(m_visualTip);
199           m_animationTimer->start();
200         }
201         setCursor(Qt::SizeHorCursor);
202       }
203       else if (opMode == FADEIN) {
204         if (m_visualTip == NULL) {
205           m_visualTip = new QGraphicsEllipseItem(clip->rect().x() + clip->fadeIn() * m_scale - size, clip->rect().y() - 8, size * 2, 16);
206           ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
207           ((QGraphicsEllipseItem*) m_visualTip)->setPen(QPen(Qt::transparent));
208           m_visualTip->setZValue (100);
209           m_animation = new QGraphicsItemAnimation;
210           m_animation->setItem(m_visualTip);
211           m_animation->setTimeLine(m_animationTimer);
212           m_visualTip->setPos(0, 0);
213           double scale = 2.0;
214           m_animation->setScaleAt(.5, scale, scale);
215           m_animation->setPosAt(.5, QPointF(clip->rect().x() - clip->rect().x() * scale -  clip->fadeIn() * m_scale, clip->rect().y() - clip->rect().y() * scale));
216           scale = 1.0;
217           m_animation->setScaleAt(1, scale, scale);
218           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, clip->rect().y() - clip->rect().y() * scale));
219           scene()->addItem(m_visualTip);
220           m_animationTimer->start();
221         }
222         setCursor(Qt::PointingHandCursor);
223       }
224       else if (opMode == FADEOUT) {
225         if (m_visualTip == NULL) {
226           m_visualTip = new QGraphicsEllipseItem(clip->rect().x() + clip->rect().width() - clip->fadeOut() * m_scale - size, clip->rect().y() - 8, size*2, 16);
227           ((QGraphicsEllipseItem*) m_visualTip)->setBrush(m_tipColor);
228           ((QGraphicsEllipseItem*) m_visualTip)->setPen(QPen(Qt::transparent));
229           m_visualTip->setZValue (100);
230           m_animation = new QGraphicsItemAnimation;
231           m_animation->setItem(m_visualTip);
232           m_animation->setTimeLine(m_animationTimer);
233           m_visualTip->setPos(0, 0);
234           double scale = 2.0;
235           m_animation->setScaleAt(.5, scale, scale);      
236           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));
237           scale = 1.0;
238           m_animation->setScaleAt(1, scale, scale);
239           m_animation->setPosAt(1, QPointF(clip->rect().x() - clip->rect().x() * scale, clip->rect().y() - clip->rect().y() * scale));
240           scene()->addItem(m_visualTip);
241           m_animationTimer->start();
242         }
243         setCursor(Qt::PointingHandCursor);
244       }
245     }
246     else {
247       m_moveOpMode = NONE;
248       if (m_visualTip) {
249         if (m_animation) delete m_animation;
250         m_animation = NULL;
251         delete m_visualTip;
252         m_visualTip = NULL;
253       }
254       setCursor(Qt::ArrowCursor);
255     }
256   }
257   QGraphicsView::mouseMoveEvent(event);
258 }
259
260 // virtual 
261 void CustomTrackView::mousePressEvent ( QMouseEvent * event )
262 {
263   int pos = event->x();
264   if (event->modifiers() == Qt::ControlModifier) 
265     setDragMode(QGraphicsView::ScrollHandDrag);
266   else if (event->modifiers() == Qt::ShiftModifier) 
267     setDragMode(QGraphicsView::RubberBandDrag);
268   else {
269     bool collision = false;
270     QList<QGraphicsItem *> collisionList = items(event->pos());
271     for (int i = 0; i < collisionList.size(); ++i) {
272       QGraphicsItem *item = collisionList.at(i);
273       if (item->type() == 70000) {
274         m_dragItem = (ClipItem *) item;
275         m_clickPoint = mapToScene(event->pos()).x() - m_dragItem->startPos() * m_scale;
276         m_operationMode = m_dragItem->operationMode(item->mapFromScene(mapToScene(event->pos())), m_scale);
277         if (m_operationMode == MOVE || m_operationMode == RESIZESTART) m_startPos = QPointF(m_dragItem->startPos(), m_dragItem->track());
278         else if (m_operationMode == RESIZEEND) m_startPos = QPointF(m_dragItem->endPos(), m_dragItem->track());
279         kDebug()<<"//////// ITEM CLICKED: "<<m_startPos;
280         collision = true;
281         break;
282       }
283     }
284     if (!collision) {
285       kDebug()<<"//////// NO ITEM FOUND ON CLICK";
286       m_dragItem = NULL;
287       setCursor(Qt::ArrowCursor);
288       setCursorPos((int) mapToScene(event->x(), 0).x());
289       emit cursorMoved(cursorPos());
290     }
291   }
292   //kDebug()<<pos;
293   QGraphicsView::mousePressEvent(event);
294 }
295
296 void CustomTrackView::dragEnterEvent ( QDragEnterEvent * event )
297 {
298   if (event->mimeData()->hasText()) {
299     QString clip = event->mimeData()->text();
300     addItem(clip, event->pos());
301     event->acceptProposedAction();
302   }
303 }
304
305
306 void CustomTrackView::addItem(QString producer, QPoint pos)
307 {
308   QDomDocument doc;
309   doc.setContent(producer);
310   QDomElement elem = doc.documentElement();
311   int in = elem.attribute("in", 0).toInt();
312   int out = elem.attribute("out", 0).toInt() - in;
313   if (out == 0) out = elem.attribute("duration", 0).toInt();
314   kDebug()<<"ADDING CLIP: "<<producer<<", OUT: "<<out<<", POS: "<<mapToScene(pos);
315   int trackTop = ((int) mapToScene(pos).y()/50) * 50 + 1;
316   m_dropItem = new ClipItem(elem, ((int) mapToScene(pos).y()/50), in, QRectF(mapToScene(pos).x() * m_scale, trackTop, out * m_scale, 49), out);
317   scene()->addItem(m_dropItem);
318 }
319
320
321 void CustomTrackView::dragMoveEvent(QDragMoveEvent * event) {
322   event->setDropAction(Qt::IgnoreAction);
323   if (m_dropItem) {
324     int track = (int) mapToScene(event->pos()).y()/50; //) * (m_scale * 50) + m_scale;
325      kDebug()<<"+++++++++++++   DRAG MOVE, : "<<mapToScene(event->pos()).x()<<", SCAL: "<<m_scale;
326     m_dropItem->moveTo(mapToScene(event->pos()).x() / m_scale, m_scale, (track - m_dropItem->track()) * 50, track);
327   }
328        //if (item) {
329   event->setDropAction(Qt::MoveAction);
330   if (event->mimeData()->hasText()) {
331     event->acceptProposedAction();
332   }
333         //}
334 }
335
336 void CustomTrackView::dragLeaveEvent ( QDragLeaveEvent * event ) {
337   if (m_dropItem) {
338     delete m_dropItem;
339     m_dropItem = NULL;
340   }
341 }
342
343 void CustomTrackView::dropEvent ( QDropEvent * event ) {
344   if (m_dropItem) {
345     AddTimelineClipCommand *command = new AddTimelineClipCommand(this, m_dropItem->xml(), m_dropItem->track(), m_dropItem->startPos(), m_dropItem->rect(), m_dropItem->duration(), false);
346     m_commandStack->push(command);
347   }
348   m_dropItem = NULL;
349 }
350
351
352 QStringList CustomTrackView::mimeTypes () const
353 {
354     QStringList qstrList;
355     // list of accepted mime types for drop
356     qstrList.append("text/plain");
357     return qstrList;
358 }
359
360 Qt::DropActions CustomTrackView::supportedDropActions () const
361 {
362     // returns what actions are supported when dropping
363     return Qt::MoveAction;
364 }
365
366 void CustomTrackView::setDuration(int duration)
367 {
368   kDebug()<<"/////////////  PRO DUR: "<<duration<<", height: "<<50 * m_tracksCount;
369   m_projectDuration = duration;
370   scene()->setSceneRect(0, 0, m_projectDuration + 500, scene()->sceneRect().height()); //50 * m_tracksCount);
371 }
372
373
374 void CustomTrackView::addTrack ()
375 {
376   m_tracksCount++;
377   m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), 50 * m_tracksCount);
378   //setSceneRect(0, 0, sceneRect().width(), 50 * m_tracksCount);
379   //verticalScrollBar()->setMaximum(50 * m_tracksCount); 
380   //setFixedHeight(50 * m_tracksCount);
381 }
382
383 void CustomTrackView::removeTrack ()
384 {
385   m_tracksCount--;
386   m_cursorLine->setLine(m_cursorLine->line().x1(), 0, m_cursorLine->line().x1(), 50 * m_tracksCount);
387 }
388
389 void CustomTrackView::setCursorPos(int pos)
390 {
391   m_cursorPos = pos;
392   m_cursorLine->setPos(pos, 0);
393 }
394
395 int CustomTrackView::cursorPos()
396 {
397   return m_cursorPos;
398 }
399
400 void CustomTrackView::mouseReleaseEvent ( QMouseEvent * event )
401 {
402   QGraphicsView::mouseReleaseEvent(event);
403   setDragMode(QGraphicsView::NoDrag);
404   if (m_dragItem == NULL) return;
405   //kDebug()<<"/// MOVING CLIP: "<<m_startPos<<", END: "<<QPoint(m_dragItem->rect().x(),m_dragItem->rect().y());
406   if (m_operationMode == MOVE) {
407     // move clip
408     MoveClipCommand *command = new MoveClipCommand(this, m_startPos, QPointF(m_dragItem->startPos(), m_dragItem->track()), false);
409     m_commandStack->push(command);
410   }
411   else if (m_operationMode == RESIZESTART) {
412     // resize start
413     ResizeClipCommand *command = new ResizeClipCommand(this, m_startPos, QPointF(m_dragItem->startPos(), m_dragItem->track()), true, false);
414     m_commandStack->push(command);
415   }
416   else if (m_operationMode == RESIZEEND) {
417     // resize end
418     ResizeClipCommand *command = new ResizeClipCommand(this, m_startPos, QPointF(m_dragItem->endPos(), m_dragItem->track()), false, false);
419     m_commandStack->push(command);
420   }
421   m_operationMode = NONE;
422   m_dragItem = NULL; 
423 }
424
425 void CustomTrackView::deleteClip ( const QRectF &rect )
426 {
427   ClipItem *item = (ClipItem *) scene()->itemAt(rect.x() + 1, rect.y() + 1);
428   if (!item) {
429     kDebug()<<"----------------  ERROR, CANNOT find clip to move at: "<<rect.x();
430     return;
431   }
432   delete item;
433 }
434
435 void CustomTrackView::addClip ( QDomElement xml, int track, int startpos, const QRectF &rect, int duration )
436 {
437   QRect r(startpos * m_scale, 50 * track, duration * m_scale, 49); 
438   ClipItem *item = new ClipItem(xml, track, startpos, r, duration);
439   scene()->addItem(item);
440 }
441
442 void CustomTrackView::moveClip ( const QPointF &startPos, const QPointF &endPos )
443 {
444   ClipItem *item = (ClipItem *) scene()->itemAt((startPos.x() + 1) * m_scale, startPos.y() * 50 + 25);
445   if (!item) {
446     kDebug()<<"----------------  ERROR, CANNOT find clip to move at: "<<startPos.x() * m_scale * FRAME_SIZE + 1<<", "<<startPos.y() * 50 + 25;
447     return;
448   }
449   kDebug()<<"----------------  Move CLIP FROM: "<<startPos.x()<<", END:"<<endPos.x();
450   item->moveTo(endPos.x(), m_scale, (endPos.y() - startPos.y()) * 50, endPos.y());
451 }
452
453 void CustomTrackView::resizeClip ( const QPointF &startPos, const QPointF &endPos, bool resizeClipStart )
454 {
455   int offset;
456   if (resizeClipStart) offset = 1;
457   else offset = -1;
458   ClipItem *item = (ClipItem *) scene()->itemAt((startPos.x() + offset) * m_scale, startPos.y() * 50 + 25);
459   if (!item) {
460     kDebug()<<"----------------  ERROR, CANNOT find clip to resize at: "<<startPos;
461     return;
462   }
463   qreal diff = endPos.x() - startPos.x();
464   if (resizeClipStart) {
465     item->resizeStart(endPos.x(), m_scale);
466   }
467   else {
468     item->resizeEnd(endPos.x(), m_scale);
469   }
470 }
471
472
473 void CustomTrackView::setScale(double scaleFactor)
474 {
475   //scale(scaleFactor, scaleFactor);
476   m_scale = scaleFactor;
477   kDebug()<<" HHHHHHHH  SCALING: "<<m_scale;
478   QList<QGraphicsItem *> itemList = items();
479
480   for (int i = 0; i < itemList.count(); i++) {
481       if (itemList.at(i)->type() == 70000) {
482         ClipItem *clip = (ClipItem *)itemList.at(i);
483         clip->setRect(clip->startPos() * m_scale, clip->rect().y(), clip->duration() * m_scale, clip->rect().height());
484       }
485       /*else if (itemList.at(i)->type() == 70001) {
486         LabelItem *label = (LabelItem *)itemList.at(i);
487         QGraphicsItem *parent = label->parentItem();
488         QRectF r = label->boundingRect();
489         QRectF p = parent->boundingRect();
490         label->setPos(p.x() + p.width() / 2 - r.width() / 2, p.y() + p.height() / 2 - r.height() / 2);
491         //label->setRect(clip->startPos() * m_scale, clip->rect().y(), clip->duration() * m_scale, clip->rect().height());
492       }*/
493     }
494 }
495
496 void CustomTrackView::drawBackground ( QPainter * painter, const QRectF & rect )  
497 {
498   QColor base = palette().button().color();
499   painter->setPen(base);
500   painter->setClipRect(rect);
501   painter->drawLine(0, 0, rect.width(), 0);
502     for (uint i = 0; i < m_tracksCount;i++)
503     {
504     painter->drawLine(0, 50 * (i+1), width(), 50 * (i+1));
505       //painter->drawText(QRectF(10, 50 * i, 100, 50 * i + 49), Qt::AlignLeft, i18n(" Track ") + QString::number(i));
506     }
507   int lowerLimit = 50 * m_tracksCount;
508   if (height() > lowerLimit)
509   painter->fillRect(QRectF(0, lowerLimit, rect.width(), height() - lowerLimit), QBrush(base));
510 }
511 /*
512 void CustomTrackView::drawForeground ( QPainter * painter, const QRectF & rect )  
513 {
514   //kDebug()<<"/////  DRAWING FB: "<<rect.x()<<", width: "<<rect.width();
515   painter->fillRect(rect, QColor(50, rand() % 250,50,100));
516   painter->drawLine(m_cursorPos, rect.y(), m_cursorPos, rect.y() + rect.height());
517 }
518 */
519 #include "customtrackview.moc"