]> git.sesse.net Git - kdenlive/blob - src/simplekeyframes/simpletimelinewidget.cpp
rotoscoping: allow to move keyframes
[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_lineHeight(10),
36         m_scale(1)
37 {
38     setMouseTracking(true);
39     setMinimumSize(QSize(150, 20));
40     setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum));
41     setFont(KGlobalSettings::toolBarFont());
42     QPalette p = palette();
43     KColorScheme scheme(p.currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
44     m_colSelected = scheme.decoration(KColorScheme::HoverColor).color();
45     m_colKeyframe = scheme.foreground(KColorScheme::LinkText).color();
46     m_colKeyframeBg = scheme.shade(KColorScheme::MidShade);
47 }
48
49 void SimpleTimelineWidget::setKeyframes(QList <int> keyframes)
50 {
51     m_keyframes = keyframes;
52     qSort(m_keyframes);
53     m_currentKeyframe = m_currentKeyframeOriginal = -1;
54     update();
55 }
56
57 void SimpleTimelineWidget::slotSetPosition(int pos)
58 {
59     m_position = pos;
60     update();
61 }
62
63 void SimpleTimelineWidget::slotAddKeyframe(int pos, int select)
64 {
65     if (pos < 0)
66         pos = m_position;
67
68     m_keyframes.append(pos);
69     qSort(m_keyframes);
70     if (select)
71         m_currentKeyframe = m_currentKeyframeOriginal = pos;
72     update();
73
74     emit keyframeAdded(pos);
75 }
76
77 void SimpleTimelineWidget::slotAddRemove()
78 {
79     if (m_keyframes.contains(m_position))
80         slotRemoveKeyframe(m_position);
81     else
82         slotAddKeyframe(m_position);
83 }
84
85 void SimpleTimelineWidget::slotRemoveKeyframe(int pos)
86 {
87     m_keyframes.removeAll(pos);
88     if (m_currentKeyframe == pos)
89         m_currentKeyframe = m_currentKeyframeOriginal = -1;
90     update();
91     emit keyframeRemoved(pos);
92 }
93
94 void SimpleTimelineWidget::setDuration(int dur)
95 {
96     m_duration = dur;
97 }
98
99 void SimpleTimelineWidget::slotGoToNext()
100 {
101     foreach (const int &keyframe, m_keyframes) {
102         if (keyframe > m_position) {
103             slotSetPosition(keyframe);
104             emit positionChanged(keyframe);
105             return;
106         }
107     }
108
109     // no keyframe after current position
110     slotSetPosition(m_duration);
111     emit positionChanged(m_duration);
112 }
113
114 void SimpleTimelineWidget::slotGoToPrev()
115 {
116     for (int i = m_keyframes.count() - 1; i >= 0; --i) {
117         if (m_keyframes.at(i) < m_position) {
118             slotSetPosition(m_keyframes.at(i));
119             emit positionChanged(m_keyframes.at(i));
120             return;
121         }
122     }
123
124     // no keyframe before current position
125     slotSetPosition(0);
126     emit positionChanged(0);
127 }
128
129 void SimpleTimelineWidget::mousePressEvent(QMouseEvent* event)
130 {
131     int pos = event->x() / m_scale;
132     if (event->y() < m_lineHeight && event->button() == Qt::LeftButton)  {
133         foreach(const int &keyframe, m_keyframes) {
134             if (qAbs(keyframe - pos) < 5) {
135                 m_currentKeyframeOriginal = keyframe;
136                 m_keyframes[m_keyframes.indexOf(keyframe)] = pos;
137                 m_currentKeyframe = pos;
138                 update();
139                 return;
140             }
141         }
142     }
143
144     // no keyframe next to mouse
145     m_currentKeyframe = m_currentKeyframeOriginal = -1;
146     m_position = pos;
147     emit positionChanged(pos);
148     update();
149 }
150
151 void SimpleTimelineWidget::mouseMoveEvent(QMouseEvent* event)
152 {
153     if (event->buttons() & Qt::LeftButton) {
154         int pos = qBound(0, (int)(event->x() / m_scale), m_duration);
155         if (m_currentKeyframe >= 0) {
156             // should we maybe sort here?
157             m_keyframes[m_keyframes.indexOf(m_currentKeyframe)] = pos;
158             m_currentKeyframe = pos;
159             emit keyframeMoving(m_currentKeyframeOriginal, m_currentKeyframe);
160         } else {
161             m_position = pos;
162             emit positionChanged(pos);
163         }
164         update();
165         return;
166     }
167
168     // cursor
169 }
170
171 void SimpleTimelineWidget::mouseReleaseEvent(QMouseEvent* event)
172 {
173     Q_UNUSED(event)
174
175     if (m_currentKeyframe >= 0) {
176         qSort(m_keyframes);
177         emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
178     }
179 }
180
181 void SimpleTimelineWidget::wheelEvent(QWheelEvent* event)
182 {
183     int change = event->delta() < 0 ? -1 : 1;
184     if (m_currentKeyframe > 0) {
185         m_currentKeyframe = qBound(0, m_currentKeyframe + change, m_duration);
186         emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
187     } else {
188         m_position = qBound(0, m_position + change, m_duration);
189         emit positionChanged(m_position);
190     }
191     update();
192 }
193
194 void SimpleTimelineWidget::paintEvent(QPaintEvent* event)
195 {
196     Q_UNUSED(event)
197
198     QStylePainter p(this);
199     m_scale = width() / (double)(m_duration);
200     p.translate(0, m_lineHeight);
201
202     p.setPen(m_colKeyframe);
203     p.setBrush(m_colKeyframeBg);
204
205     /*
206      * keyframes
207      */
208     QPolygonF keyframe = QPolygonF() << QPointF(0, -10) << QPointF(-4, -6) << QPointF(0, -2) << QPointF(4, -6);
209     QPolygonF tmp;
210     foreach (const int &pos, m_keyframes) {
211         tmp = keyframe;
212         tmp.translate(pos * m_scale, 0);
213         if (pos == m_currentKeyframe)
214             p.setBrush(m_colSelected);
215
216         p.drawConvexPolygon(tmp);
217         p.drawLine(QLineF(0, -1, 0, 5).translated(pos * m_scale, 0));
218
219         if (pos == m_currentKeyframe)
220             p.setBrush(m_colKeyframeBg);
221     }
222
223     p.setPen(palette().dark().color());
224
225     /*
226      * Time-"line"
227      */
228     p.drawLine(0, 0, width(), 0);
229
230     /*
231      * current position
232      */
233     QPolygonF position = QPolygonF() << QPointF(0, 1) << QPointF(5, 6) << QPointF(-5, 6);
234     position.translate(m_position * m_scale, 0);
235     p.setBrush(palette().dark().color());
236     p.drawConvexPolygon(position);
237 }
238
239 #include "simpletimelinewidget.moc"