]> git.sesse.net Git - kdenlive/blob - src/clipitem.cpp
398727e1e2965355283abf278841ab05325995d2
[kdenlive] / src / clipitem.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
21
22 #include <QPainter>
23 #include <QTimer>
24 #include <QStyleOptionGraphicsItem>
25 #include <QGraphicsScene>
26 #include <QGraphicsView>
27 #include <QScrollBar>
28 #include <KDebug>
29
30 #include <mlt++/Mlt.h>
31
32 #include "clipitem.h"
33 #include "renderer.h"
34 #include "kdenlivesettings.h"
35
36 ClipItem::ClipItem(DocClipBase *clip, int track, int startpos, const QRectF & rect, int duration)
37 : QGraphicsRectItem(rect), m_clip(clip), m_resizeMode(NONE), m_grabPoint(0), m_maxTrack(0), m_track(track), m_startPos(startpos), m_hasThumbs(false), startThumbTimer(NULL), endThumbTimer(NULL), m_startFade(0), m_endFade(0), m_effectsCounter(0),audioThumbWasDrawn(false),audioThumbReady(false), m_opacity(1.0), m_timeLine(0)
38 {
39   //setToolTip(name);
40   kDebug()<<"*******  CREATING NEW TML CLIP, DUR: "<<duration;
41   m_xml = clip->toXML();
42   m_clipName = clip->name();
43   m_producer = clip->getId();
44   m_clipType = clip->clipType();
45   m_cropStart = 0;
46   m_maxDuration = duration;
47   if (duration != -1) m_cropDuration = duration;
48   else m_cropDuration = m_maxDuration;
49   setAcceptDrops (true);
50
51 /*
52   m_cropStart = xml.attribute("in", 0).toInt();
53   m_maxDuration = xml.attribute("duration", 0).toInt();
54   if (m_maxDuration == 0) m_maxDuration = xml.attribute("out", 0).toInt() - m_cropStart;
55
56   if (duration != -1) m_cropDuration = duration;
57   else m_cropDuration = m_maxDuration;*/
58
59
60   setFlags(QGraphicsItem::ItemClipsToShape | QGraphicsItem::ItemClipsChildrenToShape | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
61   connect (this , SIGNAL (prepareAudioThumb(double,QPainterPath,int,int)) , this, SLOT (slotPrepareAudioThumb(double,QPainterPath,int,int)));
62   setBrush(QColor(100, 100, 150));
63   if (m_clipType == VIDEO || m_clipType == AV) {
64     m_hasThumbs = true;
65     connect(this, SIGNAL(getThumb(int, int)), clip->thumbProducer(), SLOT(extractImage(int, int)));
66     connect(clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap))); 
67     connect(clip, SIGNAL (gotAudioData()), this, SLOT (slotGotAudioData()));
68     QTimer::singleShot(300, this, SLOT(slotFetchThumbs()));
69
70     startThumbTimer = new QTimer(this);
71     startThumbTimer->setSingleShot(true);
72     connect(startThumbTimer, SIGNAL(timeout()), this, SLOT(slotGetStartThumb()));
73     endThumbTimer = new QTimer(this);
74     endThumbTimer->setSingleShot(true);
75     connect(endThumbTimer, SIGNAL(timeout()), this, SLOT(slotGetEndThumb()));
76
77   }
78   else if (m_clipType == COLOR) {
79     QString colour = m_xml.attribute("colour");
80     colour = colour.replace(0, 2, "#");
81     setBrush(QColor(colour.left(7)));
82   }
83   else if (m_clipType == IMAGE) {
84     m_startPix = KThumb::getImage(KUrl(m_xml.attribute("resource")), 50 * KdenliveSettings::project_display_ratio(), 50);
85   }
86 }
87
88
89 ClipItem::~ClipItem()
90 {
91   if (startThumbTimer) delete startThumbTimer;
92   if (endThumbTimer) delete endThumbTimer;
93 }
94
95 void ClipItem::slotFetchThumbs()
96 {
97   emit getThumb(m_cropStart, m_cropStart + m_cropDuration);
98 }
99
100 void ClipItem::slotGetStartThumb()
101 {
102   emit getThumb(m_cropStart, -1);
103 }
104
105 void ClipItem::slotGetEndThumb()
106 {
107   emit getThumb(-1, m_cropStart + m_cropDuration);
108 }
109
110 void ClipItem::slotThumbReady(int frame, QPixmap pix)
111 {
112   if (frame == m_cropStart) m_startPix = pix;
113   else m_endPix = pix;
114   update();
115 }
116
117 void ClipItem::slotGotAudioData(){
118   audioThumbReady=true;
119   update();
120 }
121
122 int ClipItem::type () const
123 {
124   return 70000;
125 }
126
127 DocClipBase *ClipItem::baseClip()
128 {
129   return m_clip;
130 }
131
132 QDomElement ClipItem::xml() const
133 {
134   return m_xml;
135 }
136
137 int ClipItem::clipType()
138 {
139   return m_clipType;
140 }
141
142 QString ClipItem::clipName()
143 {
144   return m_clipName;
145 }
146
147 int ClipItem::clipProducer()
148 {
149   return m_producer;
150 }
151
152 int ClipItem::maxDuration()
153 {
154   return m_maxDuration;
155 }
156
157 int ClipItem::duration()
158 {
159   return m_cropDuration;
160 }
161
162 int ClipItem::startPos()
163 {
164   return m_startPos;
165 }
166
167 int ClipItem::cropStart()
168 {
169   return m_cropStart;
170 }
171
172 int ClipItem::endPos()
173 {
174   return m_startPos + m_cropDuration;
175 }
176
177 void ClipItem::flashClip()
178 {
179   if (m_timeLine == 0) {
180     m_timeLine = new QTimeLine(750, this);
181     connect(m_timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(animate(qreal)));
182   }
183   m_timeLine->start();
184 }
185
186 void ClipItem::animate(qreal value)
187 {
188   m_opacity = value;
189   update();
190 }
191
192 // virtual 
193  void ClipItem::paint(QPainter *painter,
194                            const QStyleOptionGraphicsItem *option,
195                            QWidget *widget)
196  {
197     painter->setOpacity(m_opacity);
198     QRectF br = rect();
199          QRect rectInView;//this is the rect that is visible by the user
200          if (scene()->views().size()>0){ 
201                 rectInView=scene()->views()[0]->viewport()->rect();
202                 rectInView.moveTo(scene()->views()[0]->horizontalScrollBar()->value(),scene()->views()[0]->verticalScrollBar()->value());
203                 rectInView.adjust(-10,-10,10,10);//make view rect 10 pixel greater on each site, or repaint after scroll event
204                  //kDebug() << scene()->views()[0]->viewport()->rect() << " " <<  scene()->views()[0]->horizontalScrollBar()->value();
205          }
206          if (rectInView.isNull())
207                  return;
208          QPainterPath clippath;
209          clippath.addRect(rectInView);
210          int startpixel=rectInView.x()-rect().x();//start and endpixel that is viewable from rect()
211          if (startpixel<0)
212                  startpixel=0;
213          int endpixel=rectInView.width()+rectInView.x();
214          if (endpixel<0)
215                  endpixel=0;
216          
217     painter->setRenderHints(QPainter::Antialiasing);
218     QPainterPath roundRectPathUpper,roundRectPathLower;
219     double roundingY = 20;
220     double roundingX = 20;
221     double offset = 1;
222     painter->setClipRect(option->exposedRect);
223     if (roundingX > br.width() / 2) roundingX = br.width() / 2;
224     //kDebug()<<"-----PAINTING, SCAL: "<<scale<<", height: "<<br.height();
225          roundRectPathUpper.moveTo(br.x() + br .width() - offset, br.y() + br.height()/2 - offset);
226          roundRectPathUpper.arcTo(br.x() + br .width() - roundingX - offset, br.y(), roundingX, roundingY, 0.0, 90.0);
227          roundRectPathUpper.lineTo(br.x() + roundingX, br.y());
228          roundRectPathUpper.arcTo(br.x() + offset, br.y(), roundingX, roundingY, 90.0, 90.0);
229          roundRectPathUpper.lineTo(br.x() + offset, br.y() + br.height()/2 - offset);
230          roundRectPathUpper.closeSubpath();
231          
232          roundRectPathLower.moveTo(br.x() + offset, br.y() + br.height()/2 - offset);
233          roundRectPathLower.arcTo(br.x() + offset, br.y() + br.height() - roundingY - offset, roundingX, roundingY, 180.0, 90.0);
234          roundRectPathLower.lineTo(br.x() + br .width() - roundingX, br.y() + br.height() - offset);
235          roundRectPathLower.arcTo(br.x() + br .width() - roundingX - offset, br.y() + br.height() - roundingY - offset, roundingX, roundingY, 270.0, 90.0);
236          roundRectPathLower.lineTo(br.x() + br .width() - offset, br.y()+ br.height()/2 - offset);
237          roundRectPathLower.closeSubpath();
238          
239          painter->setClipPath(roundRectPathUpper.united(roundRectPathLower).intersected(clippath), Qt::IntersectClip);
240          //painter->fillPath(roundRectPath, brush()); //, QBrush(QColor(Qt::red)));
241          painter->fillRect(br.intersected(rectInView), brush());
242     //painter->fillRect(QRectF(br.x() + br.width() - m_endPix.width(), br.y(), m_endPix.width(), br.height()), QBrush(QColor(Qt::black)));
243
244     // draw thumbnails
245     if (!m_startPix.isNull()) {
246       if (m_clipType == IMAGE) {
247         painter->drawPixmap(QPointF(br.x() + br.width() - m_startPix.width(), br.y()), m_startPix);
248         QLineF l(br.x() + br.width() - m_startPix.width(), br.y(), br.x() + br.width() - m_startPix.width(), br.y() + br.height());
249         painter->drawLine(l);
250       } else {
251         painter->drawPixmap(QPointF(br.x() + br.width() - m_endPix.width(), br.y()), m_endPix);
252         QLineF l(br.x() + br.width() - m_endPix.width(), br.y(), br.x() + br.width() - m_endPix.width(), br.y() + br.height());
253         painter->drawLine(l);
254       }
255
256       painter->drawPixmap(QPointF(br.x(), br.y()), m_startPix);
257       QLineF l2(br.x() + m_startPix.width(), br.y(), br.x() + m_startPix.width(), br.y() + br.height());
258       painter->drawLine(l2);
259     }
260          if ( ( m_clipType == AV || m_clipType==AUDIO ||true) && audioThumbReady ){
261                  
262                  QPainterPath path= m_clipType==AV ? roundRectPathLower : roundRectPathUpper.united(roundRectPathLower);
263                  painter->fillPath(path,QBrush(QColor(200,200,200,127)));
264                  
265                  int channels=2;
266                  double pixelForOneFrame=(double)br.width()/duration();
267
268                  emit prepareAudioThumb(pixelForOneFrame,path,startpixel,endpixel+200);//200 more for less missing parts before repaint after scrolling
269
270                  for (int startCache=startpixel-startpixel%100; startCache < endpixel+300;startCache+=100){
271                          if (audioThumbCachePic.contains(startCache) && !audioThumbCachePic[startCache].isNull() )
272                                  painter->drawPixmap(path.boundingRect().x()+startCache,path.boundingRect().y(),audioThumbCachePic[startCache]);
273                  }
274
275         }
276
277     // draw start / end fades
278     double scale = br.width() / m_cropDuration;
279     QBrush fades;
280     if (isSelected()) {
281       fades = QBrush(QColor(200, 50, 50, 150));
282     }
283     else fades = QBrush(QColor(200, 200, 200, 200));
284
285     if (m_startFade != 0) {
286       QPainterPath fadeInPath;
287       fadeInPath.moveTo(br.x() - offset, br.y());
288       fadeInPath.lineTo(br.x() - offset, br.y() + br.height());
289       fadeInPath.lineTo(br.x() + m_startFade * scale, br.y());
290       fadeInPath.closeSubpath();
291       painter->fillPath(fadeInPath, fades);
292       if (isSelected()) {
293         QLineF l(br.x() + m_startFade * scale, br.y(), br.x(), br.y() + br.height());
294         painter->drawLine(l);
295       }
296     }
297     if (m_endFade != 0) {
298       QPainterPath fadeOutPath;
299       fadeOutPath.moveTo(br.x() + br.width(), br.y());
300       fadeOutPath.lineTo(br.x() + br.width(), br.y() + br.height());
301       fadeOutPath.lineTo(br.x() + br.width() - m_endFade * scale, br.y());
302       fadeOutPath.closeSubpath();
303       painter->fillPath(fadeOutPath, fades);
304       if (isSelected()) {
305         QLineF l(br.x() + br.width() - m_endFade * scale, br.y(), br.x() + br.width(), br.y() + br.height());
306         painter->drawLine(l);
307       }
308     }
309
310     QPen pen = painter->pen();
311     pen.setColor(Qt::white);
312     //pen.setStyle(Qt::DashDotDotLine); //Qt::DotLine);
313     // Draw clip name
314     QString effects = effectNames().join(" / ");
315     if (!effects.isEmpty()) {
316       painter->setPen(pen);
317       QFont font = painter->font();
318       QFont smallFont = font;
319       smallFont.setPointSize(8);
320       painter->setFont(smallFont);
321       QRectF txtBounding = painter->boundingRect(br, Qt::AlignLeft | Qt::AlignTop, " " + effects + " ");
322       painter->fillRect(txtBounding, QBrush(QColor(0,0,0,150)));
323       painter->drawText(txtBounding, Qt::AlignCenter, effects);
324       pen.setColor(Qt::black);
325       painter->setPen(pen);
326       painter->setFont(font);
327     }
328
329     if (isSelected())  painter->fillRect(br.intersected(rectInView), QBrush(QColor(200,20,0,80)));
330     pen.setColor(Qt::red);
331     //pen.setStyle(Qt::DashDotDotLine); //Qt::DotLine);
332     if (isSelected()) painter->setPen(pen);
333     painter->setClipRect(option->exposedRect);
334     painter->drawPath(roundRectPathUpper.united(roundRectPathLower).intersected(clippath));
335
336     QRectF txtBounding = painter->boundingRect(br, Qt::AlignCenter, " " + m_clipName + " ");
337     painter->fillRect(txtBounding, QBrush(QColor(255,255,255,150)));
338     painter->drawText(txtBounding, Qt::AlignCenter, m_clipName);
339
340
341          //painter->fillRect(startpixel,0,startpixel+endpixel,(int)br.height(),  QBrush(QColor(255,255,255,150)));
342     //painter->fillRect(QRect(br.x(), br.y(), roundingX, roundingY), QBrush(QColor(Qt::green)));
343
344     /*QRectF recta(rect().x(), rect().y(), scale,rect().height());
345     painter->drawRect(recta);
346     painter->drawLine(rect().x() + 1, rect().y(), rect().x() + 1, rect().y() + rect().height());
347     painter->drawLine(rect().x() + rect().width(), rect().y(), rect().x() + rect().width(), rect().y() + rect().height());
348     painter->setPen(QPen(Qt::black, 1.0));
349     painter->drawLine(rect().x(), rect().y(), rect().x() + rect().width(), rect().y());
350     painter->drawLine(rect().x(), rect().y() + rect().height(), rect().x() + rect().width(), rect().y() + rect().height());*/
351
352     //QGraphicsRectItem::paint(painter, option, widget);
353     //QPen pen(Qt::green, 1.0 / size.x() + 0.5);
354     //painter->setPen(pen);
355     //painter->drawLine(rect().x(), rect().y(), rect().x() + rect().width(), rect().y());
356     //kDebug()<<"ITEM REPAINT RECT: "<<boundingRect().width();
357     //painter->drawText(rect(), Qt::AlignCenter, m_name);
358     // painter->drawRect(boundingRect());
359      //painter->drawRoundRect(-10, -10, 20, 20);
360  }
361
362
363 OPERATIONTYPE ClipItem::operationMode(QPointF pos, double scale)
364 {
365     if (abs(pos.x() - (rect().x() + scale * m_startFade)) < 6 && abs(pos.y() - rect().y()) < 6) return FADEIN;
366     else if (abs(pos.x() - rect().x()) < 6) return RESIZESTART;
367     else if (abs(pos.x() - (rect().x() + rect().width() - scale * m_endFade)) < 6 && abs(pos.y() - rect().y()) < 6) return FADEOUT;
368     else if (abs(pos.x() - (rect().x() + rect().width())) < 6) return RESIZEEND;
369     return MOVE;
370 }
371
372 void ClipItem::slotPrepareAudioThumb(double pixelForOneFrame,QPainterPath path,int startpixel, int endpixel){
373         int channels=2;
374         
375         QRectF re=path.boundingRect();
376         
377         //if ( (!audioThumbWasDrawn || framePixelWidth!=pixelForOneFrame ) && !baseClip()->audioFrameChache.isEmpty()){
378         
379                 for (int startCache=startpixel-startpixel%100;startCache+100<endpixel ;startCache+=100){
380                         //kDebug() << "creating " << startCache;
381                         //if (framePixelWidth!=pixelForOneFrame  || 
382                         if (framePixelWidth==pixelForOneFrame && audioThumbCachePic.contains(startCache))
383                                 continue;
384                         if (audioThumbCachePic[startCache].isNull() || framePixelWidth!=pixelForOneFrame){
385                                 audioThumbCachePic[startCache]=QPixmap(100,re.height());
386                                 audioThumbCachePic[startCache].fill(QColor(200,200,200,127));
387                         }
388                         bool fullAreaDraw=pixelForOneFrame<10;
389                         QMap<int,QPainterPath > positiveChannelPaths;
390                         QMap<int,QPainterPath > negativeChannelPaths;
391                         QPainter pixpainter(&audioThumbCachePic[startCache]);
392                         QPen audiopen;
393                         audiopen.setWidth(0);
394                         pixpainter.setPen(audiopen);
395                         pixpainter.setRenderHint(QPainter::Antialiasing,true);
396                         //pixpainter.drawLine(0,0,100,re.height());
397                         int channelHeight=audioThumbCachePic[startCache].height()/channels;
398                         
399                         for (int i=0;i<channels;i++){
400                                 
401                                 positiveChannelPaths[i].moveTo(0,channelHeight*i+ channelHeight/2);
402                                 negativeChannelPaths[i].moveTo(0,channelHeight*i+ channelHeight/2);
403                         }
404                         
405                         for (int samples=0;samples<=100;samples++){
406                                 double frame=(double)(samples+startCache-0)/pixelForOneFrame;
407                                 int sample=(frame-(int)(frame))*20 ;// AUDIO_FRAME_SIZE
408                                 if (frame<0 || sample< 0 || sample>19 )
409                                         continue;
410                                 QMap<int,QByteArray> frame_channel_data=baseClip()->audioFrameChache[(int)frame];
411                                 
412                                 for (int channel=0;channel<channels && frame_channel_data[channel].size()> 0;channel++){
413                                         
414                                         int y=channelHeight*channel+ channelHeight/2;
415                                         int delta=(int)(frame_channel_data[channel][sample] -127/2 )  * channelHeight/ 64;
416                                         if (fullAreaDraw){
417                                                 positiveChannelPaths[channel].lineTo(samples,0.1+y+qAbs( delta ));      
418                                                 negativeChannelPaths[channel].lineTo(samples,0.1+y-qAbs( delta ));
419                                         }else{
420                                                 positiveChannelPaths[channel].lineTo(samples,0.1+y+delta);      
421                                                 negativeChannelPaths[channel].lineTo(samples,0.1+y-delta);
422                                         }
423                                 }
424                         }
425                         for (int i=0;i<channels;i++){
426                                 if (fullAreaDraw){
427                                         pixpainter.fillPath(positiveChannelPaths[i].united(negativeChannelPaths[i]),QBrush(Qt::SolidPattern));//or singleif looks better
428                                         pixpainter.setBrush(QBrush(QColor(200,200,100,200)));
429                                         pixpainter.drawPath(positiveChannelPaths[i].united(negativeChannelPaths[i]));//or singleif looks better
430                                 }else
431                                         pixpainter.drawPath(positiveChannelPaths[i]);
432                         }
433                 }
434                 //audioThumbWasDrawn=true;
435                 framePixelWidth=pixelForOneFrame;
436                         
437         //}
438 }
439
440 int ClipItem::fadeIn() const
441 {
442   return m_startFade;
443 }
444
445 int ClipItem::fadeOut() const
446 {
447   return m_endFade;
448 }
449
450 void ClipItem::setFadeIn(int pos, double scale)
451 {
452   int oldIn = m_startFade;
453   if (pos < 0) pos = 0;
454   if (pos > m_cropDuration) pos = m_cropDuration / 2;
455   m_startFade = pos;
456   if (oldIn > pos) update(rect().x(), rect().y(), oldIn * scale, rect().height()); 
457   else update(rect().x(), rect().y(), pos * scale, rect().height());
458 }
459
460 void ClipItem::setFadeOut(int pos, double scale)
461 {
462   int oldOut = m_endFade;
463   if (pos < 0) pos = 0;
464   if (pos > m_cropDuration) pos = m_cropDuration / 2;
465   m_endFade = pos;
466   if (oldOut > pos) update(rect().x() + rect().width() - pos * scale, rect().y(), pos * scale, rect().height()); 
467   else update(rect().x() + rect().width() - oldOut * scale, rect().y(), oldOut * scale, rect().height());
468
469 }
470
471
472 // virtual
473  void ClipItem::mousePressEvent ( QGraphicsSceneMouseEvent * event ) 
474  {
475     /*m_resizeMode = operationMode(event->pos());
476     if (m_resizeMode == MOVE) {
477       m_maxTrack = scene()->sceneRect().height();
478       m_grabPoint = (int) (event->pos().x() - rect().x());
479     }*/
480     QGraphicsRectItem::mousePressEvent(event);
481  }
482
483 // virtual
484  void ClipItem::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event ) 
485  {
486     m_resizeMode = NONE;
487     QGraphicsRectItem::mouseReleaseEvent(event);
488  }
489
490  void ClipItem::moveTo(int x, double scale, double offset, int newTrack)
491  {
492   double origX = rect().x();
493   double origY = rect().y();
494   bool success = true;
495   if (x < 0) return;
496   setRect(x * scale, origY + offset, rect().width(), rect().height());
497   QList <QGraphicsItem *> collisionList = collidingItems(Qt::IntersectsItemBoundingRect);
498   if (collisionList.size() == 0) m_track = newTrack;
499   for (int i = 0; i < collisionList.size(); ++i) {
500     QGraphicsItem *item = collisionList.at(i);
501     if (item->type() == 70000)
502     {
503         if (offset == 0)
504         {
505           QRectF other = ((QGraphicsRectItem *)item)->rect();
506           if (x < m_startPos) {
507             kDebug()<<"COLLISION, MOVING TO------";
508             m_startPos = ((ClipItem *)item)->endPos() + 1;
509             origX = m_startPos * scale; 
510           }
511           else {
512             kDebug()<<"COLLISION, MOVING TO+++";
513             m_startPos = ((ClipItem *)item)->startPos() - m_cropDuration;
514             origX = m_startPos * scale; 
515           }
516         }
517         setRect(origX, origY, rect().width(), rect().height());
518         offset = 0;
519         origX = rect().x();
520         success = false;
521         break;
522       }
523     }
524     if (success) {
525         m_track = newTrack;
526         m_startPos = x;
527     }
528 /*    QList <QGraphicsItem *> childrenList = QGraphicsItem::children();
529     for (int i = 0; i < childrenList.size(); ++i) {
530       childrenList.at(i)->moveBy(rect().x() - origX , offset);
531     }*/
532  }
533
534 void ClipItem::resizeStart(int posx, double scale)
535 {
536     int durationDiff = posx - m_startPos;
537     if (durationDiff == 0) return;
538     kDebug()<<"-- RESCALE: CROP="<<m_cropStart<<", DIFF = "<<durationDiff;
539     if (m_cropStart + durationDiff < 0) {
540       durationDiff = -m_cropStart;
541     }
542     else if (durationDiff >= m_cropDuration) {
543       durationDiff = m_cropDuration - 3;
544     }
545     m_startPos += durationDiff;
546     m_cropStart += durationDiff;
547     m_cropDuration -= durationDiff;
548     setRect(m_startPos * scale, rect().y(), m_cropDuration * scale, rect().height());
549     QList <QGraphicsItem *> collisionList = collidingItems(Qt::IntersectsItemBoundingRect);
550     for (int i = 0; i < collisionList.size(); ++i) {
551       QGraphicsItem *item = collisionList.at(i);
552       if (item->type() == 70000)
553       {
554         int diff = ((ClipItem *)item)->endPos() + 1 - m_startPos;
555         setRect((m_startPos + diff) * scale, rect().y(), (m_cropDuration - diff) * scale, rect().height());
556         m_startPos += diff;
557         m_cropStart += diff;
558         m_cropDuration -= diff;
559         break;
560       }
561     }
562     if (m_hasThumbs) startThumbTimer->start(100);
563 }
564
565 void ClipItem::resizeEnd(int posx, double scale)
566 {
567     int durationDiff = posx - endPos();
568     if (durationDiff == 0) return;
569     kDebug()<<"-- RESCALE: CROP="<<m_cropStart<<", DIFF = "<<durationDiff;
570     if (m_cropDuration + durationDiff <= 0) {
571       durationDiff = - (m_cropDuration - 3);
572     }
573     else if (m_cropDuration + durationDiff >= m_maxDuration) {
574       durationDiff = m_maxDuration - m_cropDuration;
575     }
576     m_cropDuration += durationDiff;
577     setRect(m_startPos * scale, rect().y(), m_cropDuration * scale, rect().height());
578     QList <QGraphicsItem *> collisionList = collidingItems(Qt::IntersectsItemBoundingRect);
579     for (int i = 0; i < collisionList.size(); ++i) {
580       QGraphicsItem *item = collisionList.at(i);
581       if (item->type() == 70000)
582       {
583         int diff = ((ClipItem *)item)->startPos() - 1 - startPos();
584         m_cropDuration = diff;
585         setRect(m_startPos * scale, rect().y(), m_cropDuration * scale, rect().height());
586         break;
587       }
588     }
589     if (m_hasThumbs) endThumbTimer->start(100);
590 }
591
592 // virtual
593  void ClipItem::mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) 
594  {
595  }
596
597 int ClipItem::track()
598 {
599   return  m_track;
600 }
601
602 void ClipItem::setTrack(int track)
603 {
604   m_track = track;
605 }
606
607 int ClipItem::effectsCounter()
608 {
609   return m_effectsCounter++;
610 }
611
612 int ClipItem::effectsCount()
613 {
614   return m_effectList.size();
615 }
616
617 QStringList ClipItem::effectNames()
618 {
619   return m_effectList.effectNames();
620 }
621
622 QDomElement ClipItem::effectAt(int ix)
623 {
624   return m_effectList.at(ix);
625 }
626
627 void ClipItem::setEffectAt(int ix, QDomElement effect)
628 {
629   kDebug()<<"CHange EFFECT AT: "<<ix<<", CURR: "<<m_effectList.at(ix).attribute("tag")<<", NEW: "<<effect.attribute("tag");
630   m_effectList.insert(ix, effect);
631   m_effectList.removeAt(ix + 1);
632   update(boundingRect());
633 }
634
635 QMap <QString, QString> ClipItem::addEffect(QDomElement effect)
636 {
637   QMap <QString, QString> effectParams;
638   m_effectList.append(effect);
639   effectParams["tag"] = effect.attribute("tag");
640   effectParams["kdenlive_ix"] = effect.attribute("kdenlive_ix");
641   QDomNodeList params = effect.elementsByTagName("parameter");
642   for (int i = 0; i < params.count(); i++) {
643     QDomElement e = params.item(i).toElement();
644     if (!e.isNull())
645       effectParams[e.attribute("name")] = e.attribute("value");
646   }
647   flashClip();
648   update(boundingRect());
649   return effectParams;
650 }
651
652 QMap <QString, QString> ClipItem::getEffectArgs(QDomElement effect)
653 {
654   QMap <QString, QString> effectParams;
655   effectParams["tag"] = effect.attribute("tag");
656   effectParams["kdenlive_ix"] = effect.attribute("kdenlive_ix");
657   QDomNodeList params = effect.elementsByTagName("parameter");
658   for (int i = 0; i < params.count(); i++) {
659     QDomElement e = params.item(i).toElement();
660           if (e.attribute("name").contains(";")){
661                   QString format=e.attribute("format");
662                   QStringList separators=format.split("%d",QString::SkipEmptyParts);
663                   QStringList values=e.attribute("value").split(QRegExp("[,:;x]"));
664                   QString neu;
665                   QTextStream txtNeu(&neu);
666                   if (values.size()>0)
667                           txtNeu << (int)values[0].toDouble();
668                   for (int i=0;i<separators.size() && i+1<values.size();i++){
669                           txtNeu << separators[i];
670                           txtNeu << (int)(values[i+1].toDouble());
671                   }
672                   effectParams["start"]=neu; 
673           }else
674     if (!e.isNull())
675       effectParams[e.attribute("name")] = e.attribute("value");
676   }
677   return effectParams;
678 }
679
680 void ClipItem::deleteEffect(QString index)
681 {
682   for (int i = 0; i < m_effectList.size(); ++i) {
683     if (m_effectList.at(i).attribute("kdenlive_ix") == index) {
684       m_effectList.removeAt(i);
685       break;
686     }
687   }
688   flashClip();
689   update(boundingRect());
690 }
691
692
693 // virtual 
694 /*
695 void CustomTrackView::mousePressEvent ( QMouseEvent * event )
696 {
697   int pos = event->x();
698   if (event->modifiers() == Qt::ControlModifier) 
699     setDragMode(QGraphicsView::ScrollHandDrag);
700   else if (event->modifiers() == Qt::ShiftModifier) 
701     setDragMode(QGraphicsView::RubberBandDrag);
702   else {
703     QGraphicsItem * item = itemAt(event->pos());
704     if (item) {
705     }
706     else emit cursorMoved((int) mapToScene(event->x(), 0).x());
707   }
708   kDebug()<<pos;
709   QGraphicsView::mousePressEvent(event);
710 }
711
712 void CustomTrackView::mouseReleaseEvent ( QMouseEvent * event )
713 {
714   QGraphicsView::mouseReleaseEvent(event);
715   setDragMode(QGraphicsView::NoDrag);
716 }
717 */
718
719 #include "clipitem.moc"