]> git.sesse.net Git - kdenlive/blob - src/cornerswidget.cpp
corners: Add keyframe by double-clicking on the monitor
[kdenlive] / src / cornerswidget.cpp
1 /***************************************************************************
2  *   Copyright (C) 2010 by Till Theato (root@ttill.de)                     *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20 #include "cornerswidget.h"
21 #include "monitor.h"
22 #include "monitorscene.h"
23 #include "monitorscenecontrolwidget.h"
24 #include "onmonitoritems/onmonitorcornersitem.h"
25 #include "renderer.h"
26 #include "kdenlivesettings.h"
27
28 #include <QGraphicsView>
29 #include <QGridLayout>
30
31 #include <KIcon>
32
33 inline int lerp( const int a, const int b, double t )
34 {
35     return a + (b - a) * t;
36 }
37
38 CornersWidget::CornersWidget(Monitor *monitor, QDomElement e, int minFrame, int maxFrame, Timecode tc, int activeKeyframe, QWidget* parent) :
39         KeyframeEdit(e, minFrame, maxFrame, tc, activeKeyframe, parent),
40         m_monitor(monitor),
41         m_showScene(true),
42         m_pos(0)
43 {
44     m_scene = monitor->getEffectScene();
45
46     m_item = new OnMonitorCornersItem(m_scene);
47     m_scene->addItem(m_item);
48
49     m_config = new MonitorSceneControlWidget(m_scene, this);
50     QGridLayout *l = static_cast<QGridLayout *>(layout());
51     l->addWidget(m_config->getShowHideButton(), 1, 1);
52     l->addWidget(m_config, 1, 2);
53
54     QToolButton *buttonShowLines = new QToolButton(m_config);
55     // TODO: Better Icons
56     buttonShowLines->setIcon(KIcon("insert-horizontal-rule"));
57     buttonShowLines->setToolTip(i18n("Show/Hide the lines connecting the corners"));
58     buttonShowLines->setCheckable(true);
59     buttonShowLines->setChecked(KdenliveSettings::onmonitoreffects_cornersshowlines());
60     connect(buttonShowLines, SIGNAL(toggled(bool)), this, SLOT(slotShowLines(bool)));
61     m_config->addWidget(buttonShowLines, 0, 2);
62     QToolButton *buttonShowControls = new QToolButton(m_config);
63     buttonShowControls->setIcon(KIcon("transform-move"));
64     buttonShowControls->setToolTip(i18n("Show additional controls"));
65     buttonShowControls->setCheckable(true);
66     buttonShowControls->setChecked(KdenliveSettings::onmonitoreffects_cornersshowcontrols());
67     connect(buttonShowControls, SIGNAL(toggled(bool)), this, SLOT(slotShowControls(bool)));
68     m_config->addWidget(buttonShowControls, 0, 3);
69
70     connect(m_config, SIGNAL(showScene(bool)), this, SLOT(slotShowScene(bool)));
71     connect(m_monitor, SIGNAL(renderPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
72     connect(m_scene, SIGNAL(actionFinished()), this, SLOT(slotUpdateProperties()));
73     connect(m_scene, SIGNAL(addKeyframe()), this, SLOT(slotInsertKeyframe()));
74
75     connect(keyframe_list, SIGNAL(cellChanged(int, int)), this, SLOT(slotUpdateItem()));
76 }
77
78 CornersWidget::~CornersWidget()
79 {
80     delete m_config;
81     m_scene->removeItem(m_item);
82     delete m_item;
83     if (m_monitor)
84         m_monitor->slotEffectScene(false);
85 }
86
87 void CornersWidget::addParameter(QDomElement e, int activeKeyframe)
88 {
89     KeyframeEdit::addParameter(e, activeKeyframe);
90
91     if (!m_item->polygon().count())
92         slotUpdateItem();
93 }
94
95 void CornersWidget::slotUpdateItem()
96 {
97     if (keyframe_list->columnCount() < 8)
98         return;
99
100     QTableWidgetItem *keyframe, *keyframeOld;
101     keyframe = keyframe_list->item(0, 0);
102     for (int row = 0; row < keyframe_list->rowCount(); ++row) {
103         keyframeOld = keyframe;
104         keyframe = keyframe_list->item(row, 0);
105         if (getPos(row) >= m_pos)
106             break;
107     }
108
109     QList<QPointF> points, pointsPrev, pointsNext;
110     pointsPrev = getPoints(keyframeOld);
111     pointsNext = getPoints(keyframe);
112     if (pointsPrev.count() != 4 || pointsNext.count() != 4)
113         return;
114
115     qreal position = (m_pos - getPos(keyframeOld->row())) / (qreal)( getPos(keyframe->row()) - getPos(keyframeOld->row()) + 1 );
116
117     if (keyframeOld  == keyframe) {
118         points = pointsNext;
119     } else {
120         for (int i = 0; i < 4; ++i)
121             points.append(QLineF(pointsPrev.at(i), pointsNext.at(i)).pointAt(position));
122     }
123
124     m_scene->blockSignals(true);
125     m_item->setPolygon(QPolygonF() << points.at(0) << points.at(1) << points.at(2) << points.at(3));
126     m_scene->blockSignals(false);
127
128     bool enable = getPos(keyframe->row()) == m_pos || keyframe_list->rowCount() == 1;
129     m_item->setEnabled(enable);
130     m_scene->setEnabled(enable);
131 }
132
133 void CornersWidget::slotUpdateProperties()
134 {
135     if (keyframe_list->columnCount() < 8)
136         return;
137
138     QPolygonF pol = m_item->polygon();
139
140     QTableWidgetItem *item = keyframe_list->currentItem();
141     double val;
142     for (int col = 0; col < 8; col++) {
143         if (col % 2 == 0)
144             val = pol.at(col / 2).x() / (double)m_monitor->render->frameRenderWidth();
145         else
146             val = pol.at(col / 2).y() / (double)m_monitor->render->renderHeight();
147         val *= 2000;
148         val += 2000;
149         QTableWidgetItem *nitem = keyframe_list->item(item->row(), col);
150         if (nitem->text().toInt() != (int)val)
151             nitem->setText(QString::number((int)val));
152     }
153
154     slotAdjustKeyframeInfo(false);
155 }
156
157 QList<QPointF> CornersWidget::getPoints(QTableWidgetItem* keyframe)
158 {
159     QList<QPointF> points;
160
161     if (!keyframe)
162         return points;
163
164     double val;
165     for (int col = 0; col < 8; col++) {
166         if (!keyframe_list->item(keyframe->row(), col))
167             return QList<QPointF>();
168         val = (keyframe_list->item(keyframe->row(), col)->text().toInt() - 2000) / 2000.;
169         if (col % 2 == 0)
170             points << QPointF(val * m_monitor->render->frameRenderWidth(), 0);
171         else
172             points[col / 2].setY(val * m_monitor->render->renderHeight());
173     }
174     return points;
175 }
176
177 void CornersWidget::slotCheckMonitorPosition(int renderPos)
178 {
179     if (m_showScene)
180         emit checkMonitorPosition(renderPos);
181 }
182
183 void CornersWidget::slotShowScene(bool show)
184 {
185     m_showScene = show;
186     if (!m_showScene)
187         m_monitor->slotEffectScene(false);
188     else
189         slotCheckMonitorPosition(m_monitor->render->seekFramePosition());
190 }
191
192 void CornersWidget::slotShowLines(bool show)
193 {
194     KdenliveSettings::setOnmonitoreffects_cornersshowlines(show);
195     m_item->update();
196 }
197
198 void CornersWidget::slotShowControls(bool show)
199 {
200     KdenliveSettings::setOnmonitoreffects_cornersshowcontrols(show);
201     m_item->update();
202 }
203
204 void CornersWidget::slotSyncPosition(int relTimelinePos)
205 {
206     if (keyframe_list->rowCount()) {
207         relTimelinePos = qBound(0, relTimelinePos, m_max);
208         if (relTimelinePos != m_pos) {
209             m_pos = relTimelinePos;
210             slotUpdateItem();
211         }
212     }
213 }
214
215 void CornersWidget::slotInsertKeyframe()
216 {
217     keyframe_list->blockSignals(true);
218
219     int row;
220     QTableWidgetItem *keyframe, *keyframeOld;
221     keyframe = keyframe_list->item(0, 0);
222     for (row = 0; row < keyframe_list->rowCount(); ++row) {
223         keyframeOld = keyframe;
224         keyframe = keyframe_list->item(row, 0);
225         if (getPos(row) >= m_pos)
226             break;
227     }
228
229     int pos2 = getPos(row);
230     if (pos2 == m_pos)
231         return;
232
233     int pos1 = 0;
234     if (row > 0)
235         pos1 = getPos(row - 1);
236
237     int col = keyframe_list->currentColumn();
238     double pos = (m_pos - pos1) / (double)(pos2 - pos1 + 1);
239
240     keyframe_list->insertRow(row);
241     keyframe_list->setVerticalHeaderItem(row, new QTableWidgetItem(getPosString(m_pos)));
242
243     QPolygonF pol = m_item->polygon();
244     double val;
245     for (int i = 0; i < keyframe_list->columnCount(); i++) {
246         if (i < 8) {
247             if (i % 2 == 0)
248                 val = pol.at(i / 2).x() / (double)m_monitor->render->frameRenderWidth();
249             else
250                 val = pol.at(i / 2).y() / (double)m_monitor->render->renderHeight();
251             val *= 2000;
252             val += 2000;
253             keyframe_list->setItem(row, i, new QTableWidgetItem(QString::number((int)val)));
254         } else {
255             keyframe_list->setItem(row, i, new QTableWidgetItem(QString::number(lerp(keyframe_list->item(keyframeOld->row(), i)->text().toInt(), keyframe_list->item(keyframe->row(), i)->text().toInt(), pos))));
256         }
257     }
258
259     keyframe_list->resizeRowsToContents();
260     slotAdjustKeyframeInfo();
261     keyframe_list->blockSignals(false);
262     generateAllParams();
263     button_delete->setEnabled(true);
264     keyframe_list->setCurrentCell(row, col);
265     keyframe_list->selectRow(row);
266 }
267
268 #include "cornerswidget.moc"