]> git.sesse.net Git - kdenlive/blob - src/keyframeedit.cpp
Allow to reset single effect parameters:
[kdenlive] / src / keyframeedit.cpp
1 /***************************************************************************
2                           geomeytrval.cpp  -  description
3                              -------------------
4     begin                : 03 Aug 2008
5     copyright            : (C) 2008 by Marco Gittler
6     email                : g.marco@freenet.de
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include "keyframeedit.h"
19 #include "doubleparameterwidget.h"
20 #include "kdenlivesettings.h"
21
22 #include <KDebug>
23 #include <KGlobalSettings>
24
25 #include <QHeaderView>
26
27
28 KeyframeEdit::KeyframeEdit(QDomElement e, int minFrame, int maxFrame, int minVal, int maxVal, Timecode tc, int active_keyframe, QWidget* parent) :
29         QWidget(parent),
30         m_min(minFrame),
31         m_max(maxFrame),
32         m_minVal(minVal),
33         m_maxVal(maxVal),
34         m_timecode(tc),
35         m_previousPos(0),
36         m_active_keyframe(active_keyframe)
37 {
38     kDebug() << " / / / /MODIFIED KFR: " << m_active_keyframe;
39     setupUi(this);
40     m_params.append(e.cloneNode().toElement());
41     keyframe_list->setFont(KGlobalSettings::generalFont());
42     keyframe_seek->setChecked(KdenliveSettings::keyframeseek());
43     connect(keyframe_seek, SIGNAL(stateChanged(int)), this, SLOT(slotSetSeeking(int)));
44
45     button_add->setIcon(KIcon("list-add"));
46     button_add->setToolTip(i18n("Add keyframe"));
47     button_delete->setIcon(KIcon("list-remove"));
48     button_delete->setToolTip(i18n("Delete keyframe"));
49     connect(keyframe_list, SIGNAL(itemSelectionChanged()), this, SLOT(slotAdjustKeyframeInfo()));
50     connect(keyframe_list, SIGNAL(cellChanged(int, int)), this, SLOT(slotGenerateParams(int, int)));
51     setupParam();
52
53     keyframe_list->resizeRowsToContents();
54     keyframe_list->resizeColumnsToContents();
55     //keyframe_list->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents);
56     connect(button_delete, SIGNAL(clicked()), this, SLOT(slotDeleteKeyframe()));
57     connect(button_add, SIGNAL(clicked()), this, SLOT(slotAddKeyframe()));
58     //connect(keyframe_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(slotSaveCurrentParam(QTreeWidgetItem *, int)));
59     connect(keyframe_pos, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframePos(int)));
60     //connect(keyframe_val, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframeValue(int)));
61     keyframe_pos->setPageStep(1);
62     if (!keyframe_list->currentItem()) {
63         keyframe_list->setCurrentCell(0, 0);
64         keyframe_list->selectRow(0);
65     }
66     /*m_delegate = new KeyItemDelegate(minVal, maxVal);
67     keyframe_list->setItemDelegate(m_delegate);*/
68 }
69
70 KeyframeEdit::~KeyframeEdit()
71 {
72     keyframe_list->blockSignals(true);
73     keyframe_list->clear();
74     QLayoutItem *child;
75     while ((child = m_slidersLayout->takeAt(0)) != 0) {
76         QWidget *wid = child->widget();
77         delete child;
78         if (wid)
79             delete wid;
80     }
81     //delete m_delegate;
82 }
83
84 void KeyframeEdit::addParameter(QDomElement e)
85 {
86     keyframe_list->blockSignals(true);
87     m_params.append(e.cloneNode().toElement());
88     QDomNode na = e.firstChildElement("name");
89     QString paramName = i18n(na.toElement().text().toUtf8().data());
90     int columnId = keyframe_list->columnCount();
91     keyframe_list->insertColumn(columnId);
92     keyframe_list->setHorizontalHeaderItem(columnId, new QTableWidgetItem(paramName));
93
94     DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, 0,
95                                                                    m_params.at(columnId).attribute("min").toInt(), m_params.at(columnId).attribute("max").toInt(),
96                                                                    m_params.at(columnId).attribute("default").toInt(), m_params.at(columnId).attribute("suffix"), this);
97     connect(doubleparam, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframeValue(int)));
98     m_slidersLayout->addWidget(doubleparam, columnId, 0);
99
100     QStringList frames = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
101     for (int i = 0; i < frames.count(); i++) {
102         int frame = frames.at(i).section(':', 0, 0).toInt();
103         bool found = false;
104         int j;
105         for (j = 0; j < keyframe_list->rowCount(); j++) {
106             int currentPos = getPos(j);
107             if (frame == currentPos) {
108                 keyframe_list->setItem(j, columnId, new QTableWidgetItem(frames.at(i).section(':', 1, 1)));
109                 found = true;
110                 break;
111             } else if (currentPos > frame) {
112                 break;
113             }
114         }
115         if (!found) {
116             keyframe_list->insertRow(j);
117             keyframe_list->setVerticalHeaderItem(j, new QTableWidgetItem(getPosString(frame)));
118             keyframe_list->setItem(j, columnId, new QTableWidgetItem(frames.at(i).section(':', 1, 1)));
119             keyframe_list->resizeRowToContents(j);
120         }
121     }
122     keyframe_list->resizeColumnsToContents();
123     keyframe_list->blockSignals(false);
124     slotAdjustKeyframeInfo(false);
125 }
126
127 void KeyframeEdit::setupParam()
128 {
129     keyframe_list->blockSignals(true);
130     keyframe_list->clear();
131     int col = keyframe_list->columnCount();
132     QDomNode na = m_params.at(0).firstChildElement("name");
133     QString paramName = i18n(na.toElement().text().toUtf8().data());
134     kDebug() << " INSERT COL: " << col << ", " << paramName;
135     keyframe_list->insertColumn(col);
136     keyframe_list->setHorizontalHeaderItem(col, new QTableWidgetItem(paramName));
137     m_slidersLayout = new QGridLayout(param_sliders);
138
139     DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, 0,
140                                                                    m_params.at(0).attribute("min").toInt(), m_params.at(0).attribute("max").toInt(),
141                                                                    m_params.at(0).attribute("default").toInt(), m_params.at(0).attribute("suffix"), this);
142     connect(doubleparam, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframeValue(int)));
143     m_slidersLayout->addWidget(doubleparam, 0, 0);
144
145     keyframe_list->setSelectionBehavior(QAbstractItemView::SelectRows);
146     keyframe_list->setSelectionMode(QAbstractItemView::SingleSelection);
147
148     QStringList frames = m_params.at(0).attribute("keyframes").split(";", QString::SkipEmptyParts);
149     for (int i = 0; i < frames.count(); i++) {
150         keyframe_list->insertRow(i);
151         int currentpos = frames.at(i).section(':', 0, 0).toInt();
152         keyframe_list->setVerticalHeaderItem(i, new QTableWidgetItem(getPosString(currentpos)));
153         keyframe_list->setItem(i, col, new QTableWidgetItem(frames.at(i).section(':', 1, 1)));
154         if ((m_active_keyframe > -1) && (m_active_keyframe == currentpos)) {
155             keyframe_list->setCurrentCell(i, 0);
156             keyframe_list->selectRow(i);
157         }
158         //item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled);
159     }
160     /*QTreeWidgetItem *first = keyframe_list->topLevelItem(0);
161     if (first) keyframe_list->setCurrentItem(first);*/
162     keyframe_list->blockSignals(false);
163     //keyframe_list->setCurrentCell(0, 0);
164     slotAdjustKeyframeInfo(false);
165     button_delete->setEnabled(keyframe_list->rowCount() > 1);
166 }
167
168 void KeyframeEdit::slotDeleteKeyframe()
169 {
170     if (keyframe_list->rowCount() < 2)
171         return;
172     int col = keyframe_list->currentColumn();
173     int row = keyframe_list->currentRow();
174     keyframe_list->removeRow(keyframe_list->currentRow());
175     row = qMin(row, keyframe_list->rowCount() - 1);
176     keyframe_list->setCurrentCell(row, col);
177     keyframe_list->selectRow(row);
178     generateAllParams();
179     button_delete->setEnabled(keyframe_list->rowCount() > 1);
180 }
181
182 void KeyframeEdit::slotAddKeyframe()
183 {
184     keyframe_list->blockSignals(true);
185     QTableWidgetItem *item = keyframe_list->currentItem();
186     int row = keyframe_list->currentRow();
187     int col = keyframe_list->currentColumn();
188     int newrow = row;
189     int pos1 = getPos(row);
190
191     int result;
192     kDebug() << "// ADD KF: " << row << ", MAX: " << keyframe_list->rowCount() << ", POS: " << pos1;
193     if (row < (keyframe_list->rowCount() - 1)) {
194         result = pos1 + (getPos(row + 1) - pos1) / 2;
195         newrow++;
196     } else if (row == 0) {
197         if (pos1 == m_min) {
198             result = m_max - 1;
199             newrow++;
200         } else {
201             result = m_min;
202         }
203     } else {
204         int pos2 = getPos(row - 1);
205         result = pos2 + (pos1 - pos2) / 2;
206     }
207
208     keyframe_list->insertRow(newrow);
209     keyframe_list->setVerticalHeaderItem(newrow, new QTableWidgetItem(getPosString(result)));
210     for (int i = 0; i < keyframe_list->columnCount(); i++)
211         keyframe_list->setItem(newrow, i, new QTableWidgetItem(keyframe_list->item(item->row(), i)->text()));
212
213     keyframe_list->resizeRowsToContents();
214     //keyframe_list->resizeRowToContents(newrow);
215     slotAdjustKeyframeInfo();
216     keyframe_list->blockSignals(false);
217     generateAllParams();
218     button_delete->setEnabled(keyframe_list->rowCount() > 1);
219     keyframe_list->setCurrentCell(newrow, col);
220     keyframe_list->selectRow(newrow);
221     //slotGenerateParams(newrow, 0);
222 }
223
224 void KeyframeEdit::slotGenerateParams(int row, int column)
225 {
226     if (column == -1) {
227         // position of keyframe changed
228         QTableWidgetItem *item = keyframe_list->item(row, 0);
229         if (item == NULL)
230             return;
231
232         int pos = getPos(row);
233         if (pos <= m_min)
234             pos = m_min;
235         if (pos > m_max)
236             pos = m_max;
237         QString val = getPosString(pos);
238         if (val != keyframe_list->verticalHeaderItem(row)->text())
239             keyframe_list->verticalHeaderItem(row)->setText(val);
240
241         for (int col = 0; col < keyframe_list->horizontalHeader()->count(); col++) {
242             item = keyframe_list->item(row, col);
243             int v = item->text().toInt();
244             if (v >= m_params.at(col).attribute("max").toInt())
245                 item->setText(m_params.at(col).attribute("max"));
246             if (v <= m_params.at(col).attribute("min").toInt())
247                 item->setText(m_params.at(col).attribute("min"));
248             QString keyframes;
249             for (int i = 0; i < keyframe_list->rowCount(); i++) {
250                 if (keyframe_list->item(i, col))
251                     keyframes.append(QString::number(getPos(i)) + ':' + keyframe_list->item(i, col)->text() + ';');
252             }
253             m_params[col].setAttribute("keyframes", keyframes);
254         }
255
256         emit parameterChanged();
257         return;
258
259     }
260     QTableWidgetItem *item = keyframe_list->item(row, column);
261     if (item == NULL)
262         return;
263
264     int pos = getPos(row);
265     if (pos <= m_min)
266         pos = m_min;
267     if (pos > m_max)
268         pos = m_max;
269     /*QList<QTreeWidgetItem *> duplicates = keyframe_list->findItems(val, Qt::MatchExactly, 0);
270     duplicates.removeAll(item);
271     if (!duplicates.isEmpty()) {
272         // Trying to insert a keyframe at existing value, revert it
273         val = m_timecode.getTimecodeFromFrames(m_previousPos);
274     }*/
275     QString val = getPosString(pos);
276     if (val != keyframe_list->verticalHeaderItem(row)->text())
277         keyframe_list->verticalHeaderItem(row)->setText(val);
278
279     int v = item->text().toInt();
280     if (v >= m_params.at(column).attribute("max").toInt())
281         item->setText(m_params.at(column).attribute("max"));
282     if (v <= m_params.at(column).attribute("min").toInt())
283         item->setText(m_params.at(column).attribute("min"));
284     slotAdjustKeyframeInfo(false);
285
286     QString keyframes;
287     for (int i = 0; i < keyframe_list->rowCount(); i++) {
288         if (keyframe_list->item(i, column))
289             keyframes.append(QString::number(getPos(i)) + ':' + keyframe_list->item(i, column)->text() + ';');
290     }
291     m_params[column].setAttribute("keyframes", keyframes);
292     emit parameterChanged();
293 }
294
295 void KeyframeEdit::generateAllParams()
296 {
297     for (int col = 0; col < keyframe_list->columnCount(); col++) {
298         QString keyframes;
299         for (int i = 0; i < keyframe_list->rowCount(); i++) {
300             if (keyframe_list->item(i, col))
301                 keyframes.append(QString::number(getPos(i)) + ':' + keyframe_list->item(i, col)->text() + ';');
302         }
303         m_params[col].setAttribute("keyframes", keyframes);
304     }
305     emit parameterChanged();
306 }
307
308 const QString KeyframeEdit::getValue(const QString &name)
309 {
310     for (int col = 0; col < keyframe_list->columnCount(); col++) {
311         QDomNode na = m_params.at(col).firstChildElement("name");
312         QString paramName = i18n(na.toElement().text().toUtf8().data());
313         kDebug() << paramName << " == " << name;
314         if (paramName == name)
315             return m_params.at(col).attribute("keyframes");
316     }
317     return QString();
318 }
319
320 void KeyframeEdit::slotAdjustKeyframeInfo(bool seek)
321 {
322     QTableWidgetItem *item = keyframe_list->currentItem();
323     if (!item)
324         return;
325     int min = m_min;
326     int max = m_max;
327     QTableWidgetItem *above = keyframe_list->item(item->row() - 1, item->column());
328     QTableWidgetItem *below = keyframe_list->item(item->row() + 1, item->column());
329     if (above)
330         min = getPos(above->row()) + 1;
331     if (below)
332         max = getPos(below->row()) - 1;
333
334     keyframe_pos->blockSignals(true);
335     keyframe_pos->setRange(min, max);
336     keyframe_pos->setValue(getPos(item->row()));
337     keyframe_pos->blockSignals(false);
338     for (int col = 0; col < keyframe_list->columnCount(); col++) {
339         DoubleParameterWidget *doubleparam = static_cast <DoubleParameterWidget*>(m_slidersLayout->itemAtPosition(col, 0)->widget());
340         if (!doubleparam)
341             continue;
342         doubleparam->blockSignals(true);
343         doubleparam->setValue(keyframe_list->item(item->row(), col)->text().toInt());
344         doubleparam->blockSignals(false);
345     }
346     if (KdenliveSettings::keyframeseek() && seek)
347         emit seekToPos(keyframe_pos->value() - m_min);
348 }
349
350 void KeyframeEdit::slotAdjustKeyframePos(int value)
351 {
352     QTableWidgetItem *item = keyframe_list->currentItem();
353     keyframe_list->verticalHeaderItem(item->row())->setText(getPosString(value));
354     slotGenerateParams(item->row(), -1);
355     if (KdenliveSettings::keyframeseek())
356         emit seekToPos(value - m_min);
357 }
358
359 void KeyframeEdit::slotAdjustKeyframeValue(int /*value*/)
360 {
361     QTableWidgetItem *item = keyframe_list->currentItem();
362     for (int col = 0; col < keyframe_list->columnCount(); col++) {
363         DoubleParameterWidget *doubleparam = static_cast <DoubleParameterWidget*>(m_slidersLayout->itemAtPosition(col, 0)->widget());
364         if (!doubleparam)
365             continue;
366         int val = doubleparam->getValue();
367         QTableWidgetItem *nitem = keyframe_list->item(item->row(), col);
368         if (nitem->text().toInt() != val)
369             nitem->setText(QString::number(val));
370     }
371     //keyframe_list->item(item->row() - 1, item->column());
372
373 }
374
375 int KeyframeEdit::getPos(int row)
376 {
377     if (KdenliveSettings::frametimecode())
378         return keyframe_list->verticalHeaderItem(row)->text().toInt();
379     else
380         return m_timecode.getFrameCount(keyframe_list->verticalHeaderItem(row)->text());
381 }
382
383 QString KeyframeEdit::getPosString(int pos)
384 {
385     if (KdenliveSettings::frametimecode())
386         return QString::number(pos);
387     else
388         return m_timecode.getTimecodeFromFrames(pos);
389 }
390
391 void KeyframeEdit::slotSetSeeking(int state)
392 {
393     KdenliveSettings::setKeyframeseek(state == Qt::Checked);
394 }
395
396 void KeyframeEdit::updateTimecodeFormat()
397 {
398     for (int row = 0; row < keyframe_list->rowCount(); ++row) {
399         QString pos = keyframe_list->verticalHeaderItem(row)->text();
400         if (KdenliveSettings::frametimecode())
401             keyframe_list->verticalHeaderItem(row)->setText(QString::number(m_timecode.getFrameCount(pos)));
402         else
403             keyframe_list->verticalHeaderItem(row)->setText(m_timecode.getTimecodeFromFrames(pos.toInt()));
404     }
405 }
406
407 /*void KeyframeEdit::slotSaveCurrentParam(QTreeWidgetItem *item, int column)
408 {
409     if (item && column == 0) m_previousPos = m_timecode.getFrameCount(item->text(0));
410 }*/
411