]> git.sesse.net Git - kdenlive/blob - src/simplekeyframes/simpletimelinewidget.cpp
Rotoscoping timeline: mouse wheel can only move cursor.
[kdenlive] / src / simplekeyframes / simpletimelinewidget.cpp
1 /***************************************************************************
2  *   Copyright (C) 2011 by Till Theato (root@ttill.de)                     *
3  *   This file is part of Kdenlive (www.kdenlive.org).                     *
4  *                                                                         *
5  *   Kdenlive is free software: you can redistribute it and/or modify      *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation, either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   Kdenlive is distributed in the hope that it will be useful,           *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with Kdenlive.  If not, see <http://www.gnu.org/licenses/>.     *
17  ***************************************************************************/
18
19 #include "simpletimelinewidget.h"
20 #include "kdenlivesettings.h"
21
22 #include <QStylePainter>
23 #include <QMouseEvent>
24
25 #include <KGlobalSettings>
26 #include <KColorScheme>
27
28
29 SimpleTimelineWidget::SimpleTimelineWidget(QWidget* parent) :
30         QWidget(parent),
31         m_duration(1),
32         m_position(0),
33         m_currentKeyframe(-1),
34         m_currentKeyframeOriginal(-1),
35         m_hoverKeyframe(-1),
36         m_lineHeight(10),
37         m_scale(1)
38 {
39     setMouseTracking(true);
40     setMinimumSize(QSize(150, 20));
41     setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum));
42     setFont(KGlobalSettings::toolBarFont());
43     QPalette p = palette();
44     KColorScheme scheme(p.currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
45     m_colSelected = scheme.decoration(KColorScheme::HoverColor).color();
46     m_colKeyframe = scheme.foreground(KColorScheme::LinkText).color();
47     m_colKeyframeBg = scheme.shade(KColorScheme::MidShade);
48 }
49
50 void SimpleTimelineWidget::setKeyframes(QList <int> keyframes)
51 {
52     m_keyframes = keyframes;
53     qSort(m_keyframes);
54     m_currentKeyframe = m_currentKeyframeOriginal = -1;
55     emit atKeyframe(m_keyframes.contains(m_position));
56     update();
57 }
58
59 void SimpleTimelineWidget::slotSetPosition(int pos)
60 {
61     if (pos != m_position) {
62         m_position = pos;
63         emit atKeyframe(m_keyframes.contains(m_position));
64         update();
65     }
66 }
67
68 void SimpleTimelineWidget::slotAddKeyframe(int pos, int select)
69 {
70     if (pos < 0)
71         pos = m_position;
72
73     m_keyframes.append(pos);
74     qSort(m_keyframes);
75     if (select)
76         m_currentKeyframe = m_currentKeyframeOriginal = pos;
77     update();
78
79     emit keyframeAdded(pos);
80     if (pos == m_position)
81         emit atKeyframe(true);
82 }
83
84 void SimpleTimelineWidget::slotAddRemove()
85 {
86     if (m_keyframes.contains(m_position))
87         slotRemoveKeyframe(m_position);
88     else
89         slotAddKeyframe(m_position);
90 }
91
92 void SimpleTimelineWidget::slotRemoveKeyframe(int pos)
93 {
94     m_keyframes.removeAll(pos);
95     if (m_currentKeyframe == pos)
96         m_currentKeyframe = m_currentKeyframeOriginal = -1;
97     update();
98     emit keyframeRemoved(pos);
99     if (pos == m_position)
100         emit atKeyframe(false);
101 }
102
103 void SimpleTimelineWidget::setDuration(int dur)
104 {
105     m_duration = dur;
106 }
107
108 void SimpleTimelineWidget::slotGoToNext()
109 {
110     foreach (const int &keyframe, m_keyframes) {
111         if (keyframe > m_position) {
112             slotSetPosition(keyframe);
113             emit positionChanged(keyframe);
114             emit atKeyframe(true);
115             return;
116         }
117     }
118
119     // no keyframe after current position
120     slotSetPosition(m_duration);
121     emit positionChanged(m_duration);
122     emit atKeyframe(false);
123 }
124
125 void SimpleTimelineWidget::slotGoToPrev()
126 {
127     for (int i = m_keyframes.count() - 1; i >= 0; --i) {
128         if (m_keyframes.at(i) < m_position) {
129             slotSetPosition(m_keyframes.at(i));
130             emit positionChanged(m_keyframes.at(i));
131             emit atKeyframe(true);
132             return;
133         }
134     }
135
136     // no keyframe before current position
137     slotSetPosition(0);
138     emit positionChanged(0);
139     emit atKeyframe(false);
140 }
141
142 void SimpleTimelineWidget::mousePressEvent(QMouseEvent* event)
143 {
144     int pos = event->x() / m_scale;
145     if (event->y() < m_lineHeight && event->button() == Qt::LeftButton)  {
146         foreach(const int &keyframe, m_keyframes) {
147             if (qAbs(keyframe - pos) < 5) {
148                 m_currentKeyframeOriginal = keyframe;
149                 m_keyframes[m_keyframes.indexOf(keyframe)] = pos;
150                 m_currentKeyframe = pos;
151                 update();
152                 return;
153             }
154         }
155     }
156
157     // no keyframe next to mouse
158     m_currentKeyframe = m_currentKeyframeOriginal = -1;
159     m_position = pos;
160     emit positionChanged(pos);
161     emit atKeyframe(m_keyframes.contains(pos));
162     update();
163 }
164
165 void SimpleTimelineWidget::mouseMoveEvent(QMouseEvent* event)
166 {
167     int pos = qBound(0, (int)(event->x() / m_scale), m_duration);
168     if (event->buttons() & Qt::LeftButton) {
169         if (m_currentKeyframe >= 0) {
170             if (!m_keyframes.contains(pos)) {
171                 // snap to position cursor
172                 if (KdenliveSettings::snaptopoints() && qAbs(pos - m_position) < 5 && !m_keyframes.contains(m_position))
173                     pos = m_position;
174                 // should we maybe sort here?
175                 m_keyframes[m_keyframes.indexOf(m_currentKeyframe)] = pos;
176                 m_currentKeyframe = pos;
177                 emit keyframeMoving(m_currentKeyframeOriginal, m_currentKeyframe);
178                 emit atKeyframe(m_keyframes.contains(m_position));
179             }
180         } else {
181             m_position = pos;
182             emit positionChanged(pos);
183             emit atKeyframe(m_keyframes.contains(pos));
184         }
185         update();
186         return;
187     } else {
188         if (event->y() < m_lineHeight) {
189             foreach(const int &keyframe, m_keyframes) {
190                 if (qAbs(keyframe - pos) < 5) {
191                     m_hoverKeyframe = keyframe;
192                     setCursor(Qt::PointingHandCursor);
193                     update();
194                     return;
195                 }
196             }
197         }
198
199         if (m_hoverKeyframe != -1) {
200             m_hoverKeyframe = -1;
201             setCursor(Qt::ArrowCursor);
202             update();
203         }
204     }
205 }
206
207 void SimpleTimelineWidget::mouseReleaseEvent(QMouseEvent* event)
208 {
209     Q_UNUSED(event)
210
211     if (m_currentKeyframe >= 0) {
212         qSort(m_keyframes);
213         emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
214     }
215 }
216
217 void SimpleTimelineWidget::mouseDoubleClickEvent(QMouseEvent* event)
218 {
219     if (event->button() == Qt::LeftButton && event->y() < m_lineHeight) {
220         int pos = qBound(0, (int)(event->x() / m_scale), m_duration);
221         foreach(const int &keyframe, m_keyframes) {
222             if (qAbs(keyframe - pos) < 5) {
223                 m_keyframes.removeAll(keyframe);
224                 if (keyframe == m_currentKeyframe)
225                     m_currentKeyframe = m_currentKeyframeOriginal = -1;
226                 emit keyframeRemoved(keyframe);
227                 if (keyframe == m_position)
228                     emit atKeyframe(false);
229                 return;
230             }
231         }
232
233         // add new keyframe
234         m_keyframes.append(pos);
235         qSort(m_keyframes);
236         emit keyframeAdded(pos);
237         if (pos == m_position)
238             emit atKeyframe(true);
239     } else {
240         QWidget::mouseDoubleClickEvent(event);
241     }
242 }
243
244 void SimpleTimelineWidget::wheelEvent(QWheelEvent* event)
245 {
246     int change = event->delta() < 0 ? -1 : 1;
247     /*if (m_currentKeyframe > 0) {
248         m_currentKeyframe = qBound(0, m_currentKeyframe + change, m_duration);
249         emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
250     } else { */
251         m_position = qBound(0, m_position + change, m_duration);
252         emit positionChanged(m_position);
253 //     }
254     emit atKeyframe(m_keyframes.contains(m_position));
255     update();
256 }
257
258 void SimpleTimelineWidget::paintEvent(QPaintEvent* event)
259 {
260     Q_UNUSED(event)
261
262     QStylePainter p(this);
263     m_scale = width() / (double)(m_duration);
264     p.translate(0, m_lineHeight);
265
266     p.setPen(m_colKeyframe);
267     p.setBrush(m_colKeyframeBg);
268
269     /*
270      * keyframes
271      */
272     QPolygonF keyframe = QPolygonF() << QPointF(0, -10) << QPointF(-4, -6) << QPointF(0, -2) << QPointF(4, -6);
273     QPolygonF tmp;
274     foreach (const int &pos, m_keyframes) {
275         tmp = keyframe;
276         tmp.translate(pos * m_scale, 0);
277         if (pos == m_currentKeyframe || pos == m_hoverKeyframe)
278             p.setBrush(m_colSelected);
279
280         p.drawConvexPolygon(tmp);
281         p.drawLine(QLineF(0, -1, 0, 5).translated(pos * m_scale, 0));
282
283         if (pos == m_currentKeyframe || pos == m_hoverKeyframe)
284             p.setBrush(m_colKeyframeBg);
285     }
286
287     p.setPen(palette().dark().color());
288
289     /*
290      * Time-"line"
291      */
292     p.drawLine(0, 0, width(), 0);
293
294     /*
295      * current position
296      */
297     QPolygonF position = QPolygonF() << QPointF(0, 1) << QPointF(5, 6) << QPointF(-5, 6);
298     position.translate(m_position * m_scale, 0);
299     p.setBrush(palette().dark().color());
300     p.drawConvexPolygon(position);
301 }
302
303 #include "simpletimelinewidget.moc"