]> git.sesse.net Git - kdenlive/blob - src/simplekeyframes/simpletimelinewidget.cpp
rotoscoping:
[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
21 #include <QPainter>
22 #include <QMouseEvent>
23
24
25 SimpleTimelineWidget::SimpleTimelineWidget(QWidget* parent) :
26         QWidget(parent),
27         m_min(0),
28         m_max(1),
29         m_position(0),
30         m_currentKeyframe(-1),
31         m_currentKeyframeOriginal(-1),
32         m_lineHeight(10),
33         m_scale(1)
34 {
35     setMouseTracking(true);
36     setMinimumSize(QSize(150, 20));
37     setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum));
38 }
39
40 void SimpleTimelineWidget::setKeyframes(QList <int> keyframes)
41 {
42     m_keyframes = keyframes;
43     m_currentKeyframe = m_currentKeyframeOriginal = -1;
44     update();
45 }
46
47 void SimpleTimelineWidget::slotSetPosition(int pos)
48 {
49     m_position = pos;
50     update();
51 }
52
53 void SimpleTimelineWidget::slotAddKeyframe(int pos, int select)
54 {
55     if (pos < 0)
56         pos = m_position;
57
58     m_keyframes.append(pos);
59     if (select)
60         m_currentKeyframe = m_currentKeyframeOriginal = pos;
61     update();
62
63     emit keyframeAdded(pos);
64 }
65
66 void SimpleTimelineWidget::slotAddRemove()
67 {
68     if (m_keyframes.contains(m_position))
69         slotRemoveKeyframe(m_position);
70     else
71         slotAddKeyframe(m_position);
72 }
73
74 void SimpleTimelineWidget::slotRemoveKeyframe(int pos)
75 {
76     m_keyframes.removeAll(pos);
77     if (m_currentKeyframe == pos)
78         m_currentKeyframe = m_currentKeyframeOriginal = -1;
79     update();
80     emit keyframeRemoved(pos);
81 }
82
83 void SimpleTimelineWidget::setRange(int min, int max)
84 {
85     m_min = min;
86     m_max = max;
87 }
88
89 void SimpleTimelineWidget::slotGoToNext()
90 {
91     foreach (const int &keyframe, m_keyframes) {
92         if (keyframe > m_position) {
93             slotSetPosition(keyframe);
94             emit positionChanged(keyframe);
95             return;
96         }
97     }
98
99     // no keyframe after current position
100     slotSetPosition(m_max);
101     emit positionChanged(m_max);
102 }
103
104 void SimpleTimelineWidget::slotGoToPrev()
105 {
106     for (int i = m_keyframes.count() - 1; i >= 0; --i) {
107         if (m_keyframes.at(i) < m_position) {
108             slotSetPosition(m_keyframes.at(i));
109             emit positionChanged(m_keyframes.at(i));
110             return;
111         }
112     }
113
114     // no keyframe before current position
115     slotSetPosition(m_min);
116     emit positionChanged(m_min);
117 }
118
119 void SimpleTimelineWidget::mousePressEvent(QMouseEvent* event)
120 {
121     if (qAbs(event->y() - m_lineHeight) < m_lineHeight / 5. && event->button() == Qt::LeftButton)  {
122         int pos = (event->x() - 5) / m_scale;
123         foreach(const int &keyframe, m_keyframes) {
124             if (qAbs(keyframe - pos) < 5) {
125                 m_currentKeyframeOriginal = keyframe;
126                 m_currentKeyframe = pos;
127                 update();
128                 return;
129             }
130         }
131     }
132
133     // no keyframe next to mouse
134     m_currentKeyframe = m_currentKeyframeOriginal = -1;
135     m_position = (event->x() - 5) / m_scale;
136     emit positionChanged(m_position);
137     update();
138 }
139
140 void SimpleTimelineWidget::mouseMoveEvent(QMouseEvent* event)
141 {
142     if (event->buttons() & Qt::LeftButton) {
143         int pos = qBound(m_min, (int)((event->x() - 5) / m_scale), m_max);
144         if (m_currentKeyframe >= 0) {
145             m_currentKeyframe = pos;
146             emit keyframeMoving(m_currentKeyframeOriginal, m_currentKeyframe);
147         } else {
148             m_position = pos;
149             emit positionChanged(pos);
150         }
151         update();
152         return;
153     }
154
155     // cursor
156 }
157
158 void SimpleTimelineWidget::mouseReleaseEvent(QMouseEvent* event)
159 {
160     if (m_currentKeyframe > 0) {
161         emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
162     }
163 }
164
165 void SimpleTimelineWidget::wheelEvent(QWheelEvent* event)
166 {
167     int change = event->delta() < 0 ? -1 : 1;
168     if (m_currentKeyframe > 0) {
169         m_currentKeyframe = qBound(m_min, m_currentKeyframe + change, m_max);
170         emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
171     } else {
172         m_position = qBound(m_min, m_position + change, m_max);
173         emit positionChanged(m_position);
174     }
175     update();
176 }
177
178 void SimpleTimelineWidget::paintEvent(QPaintEvent* event)
179 {
180     QPainter p(this);
181     int min = 5;
182     int max = width() - 6;
183     m_scale = (max - min) / (double)(m_max - m_min);
184     p.translate(min, m_lineHeight);
185
186     p.setPen(QPen(palette().foreground().color(), 1, Qt::SolidLine));
187
188     /*
189      * Time-"line"
190      */
191     p.drawLine(0, 0, max, 0);
192
193     /*
194      * current position
195      */
196     p.fillRect(QRectF(-1, -10, 3, 20).translated(m_position * m_scale, 0), QBrush(palette().foreground().color(), Qt::SolidPattern));
197
198     /*
199      * keyframes
200      */
201     p.setPen(QPen(palette().highlight().color(), 1, Qt::SolidLine));
202     p.setBrush(Qt::NoBrush);
203     QPolygonF keyframe = QPolygonF() << QPointF(0, -4) << QPointF(-4, 0) << QPointF(0, 4) << QPointF(4, 0);
204     QPolygonF tmp;
205     foreach (const int &pos, m_keyframes) {
206         tmp = keyframe;
207         tmp.translate(pos * m_scale, 0);
208         if (pos == m_currentKeyframe)
209             p.setBrush(QBrush(palette().highlight().color(), Qt::SolidPattern));
210
211         p.drawConvexPolygon(tmp);
212
213         if (pos == m_currentKeyframe)
214             p.setBrush(Qt::NoBrush);
215     }
216 }
217
218 #include "simpletimelinewidget.moc"