]> git.sesse.net Git - kdenlive/blob - src/transition.cpp
abstract class for clipitem (many func's from clipitem must move to abstractclipitem)
[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 <qdom.h>
20 #include <QPainter>
21
22 #include <kdebug.h>
23 #include <KIcon>
24 #include <klocale.h>
25
26 #include "transition.h"
27 #include "clipitem.h"
28 #include "kdenlivesettings.h"
29
30
31 Transition::Transition(const QRectF& rect , ClipItem * clipa, const TRANSITIONTYPE & type, const GenTime &startTime, const GenTime &endTime, double fps, bool inverted) : AbstractClipItem(rect) {
32     m_invertTransition = inverted;
33     m_singleClip = true;
34     m_transitionTrack = 0;
35     m_secondClip = NULL;
36     m_transitionType = type;
37     m_transitionName = getTransitionName(m_transitionType);
38     m_fps = fps;
39     GenTime duration = endTime - startTime;
40
41     // Default duration = 2.5 seconds
42     GenTime defaultTransitionDuration = GenTime(2.5);
43
44     m_referenceClip = clipa;
45     if (startTime < m_referenceClip->startPos()) m_transitionStart = GenTime(0.0);
46     else if (startTime > m_referenceClip->endPos()) m_transitionStart = m_referenceClip->duration() - defaultTransitionDuration;
47     else m_transitionStart = startTime - m_referenceClip->startPos();
48
49     if (m_transitionStart + duration > m_referenceClip->duration())
50         m_transitionDuration = m_referenceClip->duration() - m_transitionStart;
51     else m_transitionDuration = duration;
52     m_secondClip = 0;
53     setFlags(QGraphicsItem::ItemClipsToShape | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
54 }
55
56 // create a transition from XML
57 Transition::Transition(const QRectF& rect , ClipItem * clip, QDomElement transitionElement, double fps, GenTime offset) : AbstractClipItem(rect) {
58     if (offset == GenTime()) offset = clip->startPos();
59     m_referenceClip = clip;
60     m_singleClip = true;
61     m_secondClip = NULL;
62     m_transitionStart = GenTime(transitionElement.attribute("start", QString::null).toInt(), m_referenceClip->fps());
63     m_transitionDuration = GenTime(transitionElement.attribute("end", QString::null).toInt(), m_referenceClip->fps()) - m_transitionStart;
64     m_transitionTrack = transitionElement.attribute("transition_track", "0").toInt();
65     m_transitionStart = m_transitionStart - offset;
66
67     m_invertTransition = transitionElement.attribute("inverted", "0").toInt();
68     uint transType = transitionElement.attribute("type", "0").toInt();
69     if (transType == LUMA_TRANSITION) m_transitionType = LUMA_TRANSITION;
70     else if (transType == COMPOSITE_TRANSITION) m_transitionType = COMPOSITE_TRANSITION;
71     else if (transType == PIP_TRANSITION) m_transitionType = PIP_TRANSITION;
72     else if (transType == LUMAFILE_TRANSITION) m_transitionType = LUMAFILE_TRANSITION;
73     else if (transType == MIX_TRANSITION) m_transitionType = MIX_TRANSITION;
74
75     // load transition parameters
76     typedef QMap<QString, QString> ParamMap;
77     ParamMap params;
78     for (QDomNode n = transitionElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
79         QDomElement paramElement = n.toElement();
80         params[paramElement.tagName()] = paramElement.attribute("value", QString::null);
81     }
82     if (m_invertTransition) params["reverse"] = "1";
83     if (!params.isEmpty()) setTransitionParameters(params);
84
85     // Check if transition is valid (not outside of clip)
86     if (m_transitionStart > clip->duration())
87         m_transitionDuration = GenTime();
88
89 }
90
91 Transition::~Transition() {
92 }
93
94 void Transition::setTransitionType(TRANSITIONTYPE newType) {
95     m_transitionType = newType;
96     m_transitionName = getTransitionName(m_transitionType);
97 }
98
99 TRANSITIONTYPE Transition::transitionType() const {
100     return m_transitionType;
101 }
102
103 QString Transition::transitionTag()const {
104     switch (m_transitionType) {
105     case COMPOSITE_TRANSITION:
106         return "composite";
107     case PIP_TRANSITION:
108         return "composite";
109     case MIX_TRANSITION:
110         return "mix";
111     default:
112         return "luma";
113
114     }
115 }
116
117 QString Transition::getTransitionName(const TRANSITIONTYPE & type) {
118     if (type == COMPOSITE_TRANSITION) return i18n("Push");
119     else if (type == PIP_TRANSITION) return i18n("Pip");
120     else if (type == LUMAFILE_TRANSITION) return i18n("Wipe");
121     else if (type == MIX_TRANSITION) return i18n("Audio Fade");
122     return i18n("Crossfade");
123 }
124
125 TRANSITIONTYPE Transition::getTransitionForName(const QString & type) {
126     if (type == i18n("Push")) return COMPOSITE_TRANSITION;
127     else if (type == i18n("Pip")) return PIP_TRANSITION;
128     else if (type == i18n("Wipe")) return LUMAFILE_TRANSITION;
129     return LUMA_TRANSITION;
130 }
131
132
133 QString Transition::transitionName() const {
134     return m_transitionName;
135 }
136
137 void Transition::setTransitionParameters(const QMap < QString, QString > parameters) {
138     m_transitionParameters = parameters;
139 }
140
141 const QMap < QString, QString > Transition::transitionParameters() const {
142     return m_transitionParameters;
143 }
144
145 bool Transition::invertTransition() const {
146     if (!m_singleClip) {
147         if (m_referenceClip->startPos() < m_secondClip->startPos()) return true;
148         else return false;
149     }
150     return m_invertTransition;
151 }
152
153 QPixmap Transition::transitionPixmap() const {
154     KIcon icon;
155     if (m_transitionType == LUMA_TRANSITION) {
156         if (invertTransition()) icon = KIcon("kdenlive_trans_down");
157         else icon = KIcon("kdenlive_trans_up");
158     } else if (m_transitionType == COMPOSITE_TRANSITION) {
159         icon = KIcon("kdenlive_trans_wiper");
160     } else if (m_transitionType == LUMAFILE_TRANSITION) {
161         icon = KIcon("kdenlive_trans_luma");
162     } else icon = KIcon("kdenlive_trans_pip");
163     return icon.pixmap(QSize(15, 15));
164 }
165
166 int Transition::transitionTrack() const {
167     return m_transitionTrack;
168 }
169
170 void Transition::setTransitionTrack(int track) {
171     m_transitionTrack = track;
172 }
173
174 void Transition::setTransitionDirection(bool inv) {
175     m_invertTransition = inv;
176 }
177
178 int Transition::transitionStartTrack() const {
179     return m_referenceClip->track();
180 }
181
182 int Transition::transitionEndTrack() const {
183     if (!m_singleClip) return m_secondClip->track();
184     return m_referenceClip->track() + 1;
185     //TODO: calculate next video track
186 }
187
188 GenTime Transition::transitionDuration() const {
189     return transitionEndTime() - transitionStartTime();
190 }
191
192 GenTime Transition::transitionStartTime() const {
193     if (!m_singleClip) {
194         GenTime startb = m_secondClip->startPos();
195         GenTime starta = m_referenceClip->startPos();
196         if (startb > m_referenceClip->endPos()) return m_referenceClip->endPos() - GenTime(0.12);
197         if (startb > starta)
198             return startb;
199         return starta;
200     } else return m_referenceClip->startPos() + m_transitionStart;
201 }
202
203
204 GenTime Transition::transitionEndTime() const {
205     if (!m_singleClip) {
206         GenTime endb = m_secondClip->endPos();
207         GenTime enda = m_referenceClip->endPos();
208         if (m_secondClip->startPos() > enda) return enda;
209         if (endb < m_referenceClip->startPos()) return m_referenceClip->startPos() + GenTime(0.12);
210         else if (endb > enda) return enda;
211         else return endb;
212     } else {
213         if (m_transitionStart + m_transitionDuration > m_referenceClip->duration())
214             return m_referenceClip->endPos();
215         return m_referenceClip->startPos() + m_transitionStart + m_transitionDuration;
216     }
217 }
218 void Transition::paint(QPainter *painter,
219                        const QStyleOptionGraphicsItem *option,
220                        QWidget *widget) {
221     painter->fillRect(rect(), QBrush(Qt::green));
222 }
223
224 int Transition::type() const {
225     return 70001;
226 }
227 OPERATIONTYPE Transition::operationMode(QPointF pos, double scale) {
228     return MOVE;
229 }
230 void Transition::resizeTransitionStart(GenTime time) {
231     if (!m_singleClip) return; //cannot resize automatic transitions
232     if (time < m_referenceClip->startPos()) time = m_referenceClip->startPos();
233     // Transitions shouldn't be shorter than 3 frames, about 0.12 seconds
234     if (transitionEndTime().ms() - time.ms() < 120.0) time = transitionEndTime() - GenTime(0.12);
235     m_transitionDuration = m_transitionDuration - (time - m_referenceClip->startPos() - m_transitionStart);
236     m_transitionStart = time - m_referenceClip->startPos();
237 }
238
239 void Transition::resizeTransitionEnd(GenTime time) {
240     if (!m_singleClip) return; //cannot resize automatic transitions
241     if (time > m_referenceClip->endPos()) time = m_referenceClip->endPos();
242     // Transitions shouldn't be shorter than 3 frames, about 0.12 seconds
243     if (time.ms() - transitionStartTime().ms() < 120.0) time = transitionStartTime() + GenTime(0.12);
244     m_transitionDuration = time - (m_referenceClip->startPos() + m_transitionStart);
245 }
246
247 void Transition::moveTransition(GenTime time) {
248     if (!m_singleClip) return; //cannot move automatic transitions
249     if (m_transitionStart + time < GenTime(0.0)) m_transitionStart = GenTime(0.0);
250     else if (m_transitionStart + time > m_referenceClip->duration() - m_transitionDuration)
251         m_transitionStart = m_referenceClip->duration() - m_transitionDuration;
252     else m_transitionStart = m_transitionStart + time;
253     if (m_transitionStart < GenTime(0.0)) m_transitionStart = GenTime(0.0);
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 Transition *Transition::clone() {
267     return new Transition::Transition(rect(), m_referenceClip, this->toXML() , m_fps);
268     /*if (m_singleClip || m_secondClip == 0)
269         return new Transition::Transition(m_referenceClip);
270     else
271         //return new Transition::Transition(m_referenceClip, m_secondClip);
272     return new Transition::Transition(m_referenceClip, this->toXML());
273     */
274 }
275
276 Transition *Transition::reparent(ClipItem * clip) {
277     return new Transition::Transition(rect(), clip, this->toXML(), m_fps, m_referenceClip->startPos());
278 }
279
280 bool Transition::isValid() const {
281     return (m_transitionDuration != GenTime());
282 }
283
284 const ClipItem *Transition::referencedClip() const {
285     return m_referenceClip;
286 }
287
288 QDomElement Transition::toXML() {
289     QDomDocument doc;
290     QDomElement effect = doc.createElement("ktransition");
291     effect.setAttribute("type", transitionType());
292     effect.setAttribute("inverted", invertTransition());
293     effect.setAttribute("transition_track", m_transitionTrack);
294     effect.setAttribute("start", transitionStartTime().frames(m_referenceClip->fps()));
295     effect.setAttribute("end", transitionEndTime().frames(m_referenceClip->fps()));
296
297     if (m_secondClip) {
298         effect.setAttribute("clipb_starttime", m_secondClip->startPos().frames(m_referenceClip->fps()));
299         effect.setAttribute("clipb_track", transitionEndTrack());
300     }
301
302
303     QMap<QString, QString>::Iterator it;
304     for (it = m_transitionParameters.begin(); it != m_transitionParameters.end(); ++it) {
305         QDomElement param = doc.createElement(it.key());
306         param.setAttribute("value", it.value());
307         effect.appendChild(param);
308     }
309
310     return effect;
311 }
312
313 GenTime Transition::startPos() const {
314     return GenTime();
315 }
316
317 GenTime Transition::endPos() const {
318     return GenTime();
319 }
320
321 int Transition::track() const {
322     return 0;
323 }
324
325 GenTime Transition::duration() const {
326     return GenTime();
327 }