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