]> git.sesse.net Git - kdenlive/blob - src/transition.cpp
start work on automatic transitions
[kdenlive] / src / transition.cpp
1 /***************************************************************************
2                           transition.cpp  -  description
3                              -------------------
4     begin                : Tue Jan 24 2006
5     copyright            : (C) 2006 by Jean-Baptiste Mardelle
6     email                : jb@ader.ch
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include <QBrush>
19 #include <QDomElement>
20 #include <QPainter>
21 #include <QGraphicsScene>
22 #include <QGraphicsView>
23 #include <QScrollBar>
24 #include <QStyleOptionGraphicsItem>
25
26 #include <kdebug.h>
27 #include <KIcon>
28 #include <klocale.h>
29
30 #include "transition.h"
31 #include "clipitem.h"
32 #include "kdenlivesettings.h"
33 #include "customtrackscene.h"
34 #include "mainwindow.h"
35
36 Transition::Transition(const ItemInfo info, int transitiontrack, double fps, QDomElement params, bool automaticTransition) : AbstractClipItem(info, QRectF(), fps), m_gradient(QLinearGradient(0, 0, 0, 0)), m_automaticTransition(automaticTransition), m_forceTransitionTrack(false) {
37     setZValue(2);
38     setRect(0, 0, (info.endPos - info.startPos).frames(fps) - 0.02, (qreal)(KdenliveSettings::trackheight() / 3 * 2 - 1));
39     setPos(info.startPos.frames(fps), (qreal)(info.track * KdenliveSettings::trackheight() + KdenliveSettings::trackheight() / 3 * 2));
40
41     m_singleClip = true;
42     m_transitionTrack = transitiontrack;
43     m_secondClip = NULL;
44     m_cropStart = GenTime();
45     m_maxDuration = GenTime(10000, fps);
46
47     m_gradient.setColorAt(0, QColor(200, 200, 0, 150));
48     m_gradient.setColorAt(1, QColor(200, 200, 200, 120));
49
50     //m_referenceClip = clipa;
51     if (params.isNull()) {
52         m_parameters = MainWindow::transitions.getEffectByName("Luma").cloneNode().toElement();
53     } else {
54         m_parameters = params;
55     }
56     if (m_automaticTransition) m_parameters.setAttribute("automatic", 1);
57     else if (m_parameters.attribute("automatic") == "1") m_automaticTransition = true;
58     if (m_parameters.attribute("force_track") == "1") m_forceTransitionTrack = true;
59     m_name = m_parameters.elementsByTagName("name").item(0).toElement().text();
60     m_secondClip = 0;
61     setFlags(QGraphicsItem::ItemClipsToShape | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
62
63     //m_referenceClip->addTransition(this);
64 }
65
66 Transition::~Transition() {
67 }
68
69 Transition *Transition::clone() {
70     QDomElement xml = toXML().cloneNode().toElement();
71     Transition *tr = new Transition(info(), transitionEndTrack(), m_fps, xml);
72     return tr;
73 }
74
75 QString Transition::transitionName() const {
76     return m_name;
77 }
78
79 QString Transition::transitionTag() const {
80     return m_parameters.attribute("tag");
81 }
82
83 bool Transition::isAutomatic() const {
84     return m_automaticTransition;
85 }
86
87 void Transition::setAutomatic(bool automatic) {
88     m_automaticTransition = automatic;
89     if (automatic) m_parameters.setAttribute("automatic", 1);
90     else m_parameters.removeAttribute("automatic");
91     update();
92 }
93
94 void Transition::setTransitionParameters(const QDomElement params) {
95     m_parameters = params;
96     if (m_parameters.attribute("force_track") == "1") setForcedTrack(true, m_parameters.attribute("transition_btrack").toInt());
97     else if (m_parameters.attribute("force_track") == "0") setForcedTrack(false, m_parameters.attribute("transition_btrack").toInt());
98     m_name = m_parameters.elementsByTagName("name").item(0).toElement().text();
99     update();
100 }
101
102
103 bool Transition::invertedTransition() const {
104     return false; //m_parameters.attribute("reverse").toInt();
105 }
106
107 QPixmap Transition::transitionPixmap() const {
108     KIcon icon;
109     QString tag = transitionTag();
110     if (tag == "luma") {
111         if (invertedTransition()) icon = KIcon("kdenlive_trans_up");
112         else icon = KIcon("kdenlive_trans_down");
113     } else if (tag == "composite") {
114         icon = KIcon("kdenlive_trans_wiper");
115     } else if (tag == "lumafile") {
116         icon = KIcon("kdenlive_trans_luma");
117     } else icon = KIcon("kdenlive_trans_pip");
118     return icon.pixmap(QSize(15, 15));
119 }
120
121
122 void Transition::setTransitionDirection(bool inv) {
123     //m_parameters.setAttribute("reverse", inv);
124 }
125
126 int Transition::transitionEndTrack() const {
127     return m_transitionTrack;
128 }
129
130 void Transition::updateTransitionEndTrack(int newtrack) {
131     if (!m_forceTransitionTrack) m_transitionTrack = newtrack;
132 }
133
134 void Transition::setForcedTrack(bool force, int track) {
135     m_forceTransitionTrack = force;
136     m_transitionTrack = track;
137 }
138
139 bool Transition::forcedTrack() const {
140     return m_forceTransitionTrack;
141 }
142
143 void Transition::paint(QPainter *painter,
144                        const QStyleOptionGraphicsItem *option,
145                        QWidget *widget) {
146     const double scale = option->matrix.m11();
147     QRectF exposed = option->exposedRect;
148     painter->setClipRect(exposed);
149     QRectF br = rect();
150     QRectF mapped = painter->matrix().mapRect(br);
151     m_gradient.setStart(0, br.y());
152     m_gradient.setFinalStop(0, br.bottom());
153     painter->fillRect(br, m_gradient);
154
155     int top = (int)(br.y() + br.height() / 2 - 7);
156     QPointF p1(br.x(), br.y() + br.height() / 2 - 7);
157     painter->setMatrixEnabled(false);
158     //painter->drawPixmap(painter->matrix().map(p1) + QPointF(5, 0), transitionPixmap());
159     QString text = transitionName();
160     if (m_forceTransitionTrack) text.append("|>");
161     if (m_automaticTransition) text.prepend('+');
162     QRectF txtBounding = painter->boundingRect(mapped, Qt::AlignHCenter | Qt::AlignVCenter, " " + text + " ");
163     painter->fillRect(txtBounding, QBrush(QColor(50, 50, 0, 150)));
164     txtBounding.translate(QPointF(1, 1));
165     painter->setPen(QColor(255, 255, 255, 255));
166     painter->drawText(txtBounding, Qt::AlignCenter, text);
167
168     /*    painter->setPen(QColor(0, 0, 0, 180));
169         top += painter->fontInfo().pixelSize();
170         QPointF p2(br.x(), top);
171         painter->drawText(painter->matrix().map(p2) + QPointF(26, 1), transitionName());
172         painter->setPen(QColor(255, 255, 255, 180));
173         QPointF p3(br.x(), top);
174         painter->drawText(painter->matrix().map(p3) + QPointF(25, 0), transitionName());*/
175     painter->setMatrixEnabled(true);
176     QPen pen = painter->pen();
177     if (isSelected()) {
178         pen.setColor(Qt::red);
179         //pen.setWidth(2);
180     } else {
181         pen.setColor(Qt::black);
182         //pen.setWidth(1);
183     }
184     // expand clip rect to allow correct painting of clip border
185     exposed.setRight(exposed.right() + 1 / scale + 0.5);
186     exposed.setBottom(exposed.bottom() + 1);
187     painter->setClipRect(exposed);
188     painter->setPen(pen);
189     painter->drawRect(br);
190 }
191
192 int Transition::type() const {
193     return TRANSITIONWIDGET;
194 }
195
196 //virtual
197 QVariant Transition::itemChange(GraphicsItemChange change, const QVariant &value) {
198     if (change == ItemPositionChange && scene()) {
199         // calculate new position.
200         QPointF newPos = value.toPointF();
201         int xpos = projectScene()->getSnapPointForPos((int) newPos.x(), KdenliveSettings::snaptopoints());
202         xpos = qMax(xpos, 0);
203         newPos.setX(xpos);
204         int newTrack = newPos.y() / KdenliveSettings::trackheight();
205         newTrack = qMin(newTrack, projectScene()->tracksCount() - 1);
206         newTrack = qMax(newTrack, 0);
207         newPos.setY((int)(newTrack * KdenliveSettings::trackheight() + KdenliveSettings::trackheight() / 3 * 2));
208         // Only one clip is moving
209         QRectF sceneShape = rect();
210         sceneShape.translate(newPos);
211         QList<QGraphicsItem*> items = scene()->items(sceneShape, Qt::IntersectsItemShape);
212         items.removeAll(this);
213
214         if (!items.isEmpty()) {
215             for (int i = 0; i < items.count(); i++) {
216                 if (items.at(i)->type() == type()) {
217                     // Collision! Don't move.
218                     //kDebug()<<"/// COLLISION WITH ITEM: "<<items.at(i)->boundingRect()<<", POS: "<<items.at(i)->pos()<<", ME: "<<newPos;
219                     QPointF otherPos = items.at(i)->pos();
220                     if ((int) otherPos.y() != (int) pos().y()) return pos();
221                     //kDebug()<<"////  CURRENT Y: "<<pos().y()<<", COLLIDING Y: "<<otherPos.y();
222                     if (pos().x() < otherPos.x()) {
223                         int npos = (static_cast < AbstractClipItem* >(items.at(i))->startPos() - m_cropDuration).frames(m_fps);
224                         newPos.setX(npos);
225                     } else {
226                         // get pos just after colliding clip
227                         int npos = static_cast < AbstractClipItem* >(items.at(i))->endPos().frames(m_fps);
228                         newPos.setX(npos);
229                     }
230                     m_track = newTrack;
231                     //kDebug()<<"// ITEM NEW POS: "<<newPos.x()<<", mapped: "<<mapToScene(newPos.x(), 0).x();
232                     m_startPos = GenTime((int) newPos.x(), m_fps);
233                     return newPos;
234                 }
235             }
236         }
237         m_track = newTrack;
238         m_startPos = GenTime((int) newPos.x(), m_fps);
239         //kDebug()<<"// ITEM NEW POS: "<<newPos.x()<<", mapped: "<<mapToScene(newPos.x(), 0).x();
240         return newPos;
241     }
242     return QGraphicsItem::itemChange(change, value);
243 }
244
245
246 OPERATIONTYPE Transition::operationMode(QPointF pos) {
247     const double scale = projectScene()->scale();
248     double maximumOffset = 6 / scale;
249
250     QRectF rect = sceneBoundingRect();
251     if (qAbs((int)(pos.x() - rect.x())) < maximumOffset) return RESIZESTART;
252     else if (qAbs((int)(pos.x() - (rect.right()))) < maximumOffset) return RESIZEEND;
253     return MOVE;
254 }
255
256 bool Transition::hasClip(const ClipItem * clip) const {
257     if (clip == m_secondClip) return true;
258     return false;
259 }
260
261 bool Transition::belongsToClip(const ClipItem * clip) const {
262     if (clip == m_referenceClip) return true;
263     return false;
264 }
265
266 /*
267 Transition *Transition::clone() {
268     return new Transition::Transition(rect(), m_referenceClip, this->toXML() , m_fps);
269 }*/
270
271 /*
272 Transition *Transition::reparent(ClipItem * clip) {
273     return new Transition::Transition(rect(), clip, this->toXML(), m_fps, m_referenceClip->startPos());
274 }*/
275
276 bool Transition::isValid() const {
277     return true; //(m_transitionDuration != GenTime());
278 }
279
280 const ClipItem *Transition::referencedClip() const {
281     return m_referenceClip;
282 }
283
284 QDomElement Transition::toXML() {
285     m_parameters.setAttribute("type", transitionTag());
286     //m_transitionParameters.setAttribute("inverted", invertTransition());
287     m_parameters.setAttribute("transition_atrack", track());
288     m_parameters.setAttribute("transition_btrack", m_transitionTrack);
289     m_parameters.setAttribute("start", startPos().frames(m_fps));
290     m_parameters.setAttribute("end", endPos().frames(m_fps));
291     m_parameters.setAttribute("force_track", m_forceTransitionTrack);
292
293     if (m_secondClip) {
294         m_parameters.setAttribute("clipb_starttime", m_secondClip->startPos().frames(m_referenceClip->fps()));
295         m_parameters.setAttribute("clipb_track", transitionEndTrack());
296     }
297
298     return m_parameters;
299 }
300