]> git.sesse.net Git - kdenlive/blob - src/cornerswidget.cpp
on-monitor editing: show controls next to the edit 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 "monitoreditwidget.h"
24 #include "onmonitoritems/onmonitorcornersitem.h"
25 #include "renderer.h"
26 #include "kdenlivesettings.h"
27
28 #include <QGraphicsView>
29 #include <QGridLayout>
30 #include <QToolButton>
31
32 #include <KIcon>
33
34 inline int lerp( const int a, const int b, double t )
35 {
36     return a + (b - a) * t;
37 }
38
39 CornersWidget::CornersWidget(Monitor *monitor, QDomElement e, int minFrame, int maxFrame, Timecode tc, int activeKeyframe, QWidget* parent) :
40         KeyframeEdit(e, minFrame, maxFrame, tc, activeKeyframe, parent),
41         m_monitor(monitor),
42         m_showScene(true),
43         m_pos(0)
44 {
45     MonitorEditWidget *edit = monitor->getEffectEdit();
46     edit->showVisibilityButton(true);
47     m_scene = edit->getScene();
48
49     m_item = new OnMonitorCornersItem(m_scene);
50     m_scene->addItem(m_item);
51
52     // TODO: Better Icons
53     QToolButton *buttonShowControls = new QToolButton();
54     buttonShowControls->setIcon(KIcon("transform-move"));
55     buttonShowControls->setToolTip(i18n("Show additional controls"));
56     buttonShowControls->setCheckable(true);
57     buttonShowControls->setAutoRaise(true);
58     buttonShowControls->setChecked(KdenliveSettings::onmonitoreffects_cornersshowcontrols());
59     connect(buttonShowControls, SIGNAL(toggled(bool)), this, SLOT(slotShowControls(bool)));
60     edit->addCustomControl(buttonShowControls);
61
62     QToolButton *buttonShowLines = new QToolButton();
63     buttonShowLines->setIcon(KIcon("insert-horizontal-rule"));
64     buttonShowLines->setToolTip(i18n("Show/Hide the lines connecting the corners"));
65     buttonShowLines->setCheckable(true);
66     buttonShowControls->setAutoRaise(true);
67     buttonShowLines->setChecked(KdenliveSettings::onmonitoreffects_cornersshowlines());
68     connect(buttonShowLines, SIGNAL(toggled(bool)), this, SLOT(slotShowLines(bool)));
69     edit->addCustomControl(buttonShowLines);
70
71     connect(edit, SIGNAL(showEdit(bool)), this, SLOT(slotShowScene(bool)));
72     connect(m_monitor, SIGNAL(renderPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
73     connect(m_scene, SIGNAL(actionFinished()), this, SLOT(slotUpdateProperties()));
74     connect(m_scene, SIGNAL(addKeyframe()), this, SLOT(slotInsertKeyframe()));
75
76     connect(keyframe_list, SIGNAL(cellChanged(int, int)), this, SLOT(slotUpdateItem()));
77 }
78
79 CornersWidget::~CornersWidget()
80 {
81     m_scene->removeItem(m_item);
82     delete m_item;
83     if (m_monitor) {
84         MonitorEditWidget *edit = m_monitor->getEffectEdit();
85         edit->showVisibilityButton(false);
86         edit->removeCustomControls();
87         m_monitor->slotEffectScene(false);
88     }
89 }
90
91 void CornersWidget::addParameter(QDomElement e, int activeKeyframe)
92 {
93     KeyframeEdit::addParameter(e, activeKeyframe);
94
95     if (!m_item->polygon().count())
96         slotUpdateItem();
97 }
98
99 void CornersWidget::slotUpdateItem()
100 {
101     if (keyframe_list->columnCount() < 8)
102         return;
103
104     QTableWidgetItem *keyframe, *keyframeOld;
105     keyframe = keyframeOld = keyframe_list->item(0, 0);
106     for (int row = 0; row < keyframe_list->rowCount(); ++row) {
107         keyframeOld = keyframe;
108         keyframe = keyframe_list->item(row, 0);
109         if (getPos(row) >= m_pos)
110             break;
111     }
112
113     QList<QPointF> points, pointsPrev, pointsNext;
114     pointsPrev = getPoints(keyframeOld);
115     pointsNext = getPoints(keyframe);
116     if (pointsPrev.count() != 4 || pointsNext.count() != 4)
117         return;
118
119     qreal position = (m_pos - getPos(keyframeOld->row())) / (qreal)( getPos(keyframe->row()) - getPos(keyframeOld->row()) + 1 );
120
121     if (keyframeOld  == keyframe) {
122         points = pointsNext;
123     } else {
124         for (int i = 0; i < 4; ++i)
125             points.append(QLineF(pointsPrev.at(i), pointsNext.at(i)).pointAt(position));
126     }
127
128     m_scene->blockSignals(true);
129     m_item->setPolygon(QPolygonF() << points.at(0) << points.at(1) << points.at(2) << points.at(3));
130     m_scene->blockSignals(false);
131
132     bool enable = getPos(keyframe->row()) == m_pos || keyframe_list->rowCount() == 1;
133     m_item->setEnabled(enable);
134     m_scene->setEnabled(enable);
135 }
136
137 void CornersWidget::slotUpdateProperties()
138 {
139     if (keyframe_list->columnCount() < 8)
140         return;
141
142     QPolygonF pol = m_item->polygon();
143
144     QTableWidgetItem *item = keyframe_list->currentItem();
145     double val;
146     for (int col = 0; col < 8; col++) {
147         if (col % 2 == 0)
148             val = pol.at(col / 2).x() / (double)m_monitor->render->frameRenderWidth();
149         else
150             val = pol.at(col / 2).y() / (double)m_monitor->render->renderHeight();
151         val *= 2000;
152         val += 2000;
153         QTableWidgetItem *nitem = keyframe_list->item(item->row(), col);
154         if (nitem->text().toInt() != (int)val)
155             nitem->setText(QString::number((int)val));
156     }
157
158     slotAdjustKeyframeInfo(false);
159 }
160
161 QList<QPointF> CornersWidget::getPoints(QTableWidgetItem* keyframe)
162 {
163     QList<QPointF> points;
164
165     if (!keyframe)
166         return points;
167
168     double val;
169     for (int col = 0; col < 8; col++) {
170         if (!keyframe_list->item(keyframe->row(), col))
171             return QList<QPointF>();
172         val = (keyframe_list->item(keyframe->row(), col)->text().toInt() - 2000) / 2000.;
173         if (col % 2 == 0)
174             points << QPointF(val * m_monitor->render->frameRenderWidth(), 0);
175         else
176             points[col / 2].setY(val * m_monitor->render->renderHeight());
177     }
178     return points;
179 }
180
181 void CornersWidget::slotCheckMonitorPosition(int renderPos)
182 {
183     if (m_showScene)
184         emit checkMonitorPosition(renderPos);
185 }
186
187 void CornersWidget::slotShowScene(bool show)
188 {
189     m_showScene = show;
190     if (!m_showScene)
191         m_monitor->slotEffectScene(false);
192     else
193         slotCheckMonitorPosition(m_monitor->render->seekFramePosition());
194 }
195
196 void CornersWidget::slotShowLines(bool show)
197 {
198     KdenliveSettings::setOnmonitoreffects_cornersshowlines(show);
199     m_item->update();
200 }
201
202 void CornersWidget::slotShowControls(bool show)
203 {
204     KdenliveSettings::setOnmonitoreffects_cornersshowcontrols(show);
205     m_item->update();
206 }
207
208 void CornersWidget::slotSyncPosition(int relTimelinePos)
209 {
210     if (keyframe_list->rowCount()) {
211         relTimelinePos = qBound(0, relTimelinePos, m_max);
212         if (relTimelinePos != m_pos) {
213             m_pos = relTimelinePos;
214             slotUpdateItem();
215         }
216     }
217 }
218
219 void CornersWidget::slotInsertKeyframe()
220 {
221     keyframe_list->blockSignals(true);
222
223     int row;
224     QTableWidgetItem *keyframe, *keyframeOld;
225     keyframe = keyframeOld = keyframe_list->item(0, 0);
226     for (row = 0; row < keyframe_list->rowCount(); ++row) {
227         keyframeOld = keyframe;
228         keyframe = keyframe_list->item(row, 0);
229         if (getPos(row) >= m_pos)
230             break;
231     }
232
233
234     int pos2;
235     if (row == keyframe_list->rowCount()) {
236         pos2 = m_max;
237     } else {
238         pos2 = getPos(row);
239         if (pos2 == m_pos)
240             return;
241     }
242
243     int pos1 = 0;
244     if (row > 0)
245         pos1 = getPos(row - 1);
246
247     int col = keyframe_list->currentColumn();
248     double pos = (m_pos - pos1) / (double)(pos2 - pos1 + 1);
249
250     keyframe_list->insertRow(row);
251     keyframe_list->setVerticalHeaderItem(row, new QTableWidgetItem(getPosString(m_pos)));
252
253     QPolygonF pol = m_item->polygon();
254     double val;
255     for (int i = 0; i < keyframe_list->columnCount(); i++) {
256         if (i < 8) {
257             if (i % 2 == 0)
258                 val = pol.at(i / 2).x() / (double)m_monitor->render->frameRenderWidth();
259             else
260                 val = pol.at(i / 2).y() / (double)m_monitor->render->renderHeight();
261             val *= 2000;
262             val += 2000;
263             keyframe_list->setItem(row, i, new QTableWidgetItem(QString::number((int)val)));
264         } else {
265             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))));
266         }
267     }
268
269     keyframe_list->resizeRowsToContents();
270     slotAdjustKeyframeInfo();
271     keyframe_list->blockSignals(false);
272     generateAllParams();
273     button_delete->setEnabled(true);
274     keyframe_list->setCurrentCell(row, col);
275     keyframe_list->selectRow(row);
276 }
277
278 #include "cornerswidget.moc"