1 /***************************************************************************
2 geomeytrval.cpp - description
5 copyright : (C) 2008 by Marco Gittler
6 email : g.marco@freenet.de
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
18 #include "keyframeedit.h"
19 #include "doubleparameterwidget.h"
20 #include "kdenlivesettings.h"
23 #include <KGlobalSettings>
25 #include <QHeaderView>
27 KeyframeEdit::KeyframeEdit(QDomElement e, int minFrame, int maxFrame, int minVal, int maxVal, Timecode tc, int active_keyframe, QWidget* parent) :
35 m_active_keyframe(active_keyframe)
37 kDebug() << " / / / /MODIFIED KFR: " << m_active_keyframe;
40 // special case: keyframe for tracks, do not allow keyframes
41 button_add->setEnabled(false);
42 button_delete->setEnabled(false);
43 keyframe_seek->setEnabled(false);
44 widgetTable->setHidden(true);
46 m_params.append(e.cloneNode().toElement());
47 keyframe_list->setFont(KGlobalSettings::generalFont());
48 keyframe_seek->setChecked(KdenliveSettings::keyframeseek());
49 connect(keyframe_seek, SIGNAL(stateChanged(int)), this, SLOT(slotSetSeeking(int)));
51 buttonKeyframes->setIcon(KIcon("list-add"));
52 button_add->setIcon(KIcon("list-add"));
53 button_add->setToolTip(i18n("Add keyframe"));
54 button_delete->setIcon(KIcon("list-remove"));
55 button_delete->setToolTip(i18n("Delete keyframe"));
56 connect(keyframe_list, SIGNAL(itemSelectionChanged()), this, SLOT(slotAdjustKeyframeInfo()));
57 connect(keyframe_list, SIGNAL(cellChanged(int, int)), this, SLOT(slotGenerateParams(int, int)));
60 keyframe_list->resizeRowsToContents();
61 keyframe_list->resizeColumnsToContents();
62 //keyframe_list->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents);
63 connect(button_delete, SIGNAL(clicked()), this, SLOT(slotDeleteKeyframe()));
64 connect(button_add, SIGNAL(clicked()), this, SLOT(slotAddKeyframe()));
65 connect(buttonKeyframes, SIGNAL(clicked()), this, SLOT(slotKeyframeMode()));
66 //connect(keyframe_list, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(slotSaveCurrentParam(QTreeWidgetItem *, int)));
67 connect(keyframe_pos, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframePos(int)));
68 //connect(keyframe_val, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframeValue(int)));
69 keyframe_pos->setPageStep(1);
70 if (!keyframe_list->currentItem()) {
71 keyframe_list->setCurrentCell(0, 0);
72 keyframe_list->selectRow(0);
74 // ensure the keyframe list shows at least 3 lines
75 keyframe_list->setMinimumHeight(QFontInfo(keyframe_list->font()).pixelSize() * 9);
76 /*m_delegate = new KeyItemDelegate(minVal, maxVal);
77 keyframe_list->setItemDelegate(m_delegate);*/
79 // Do not show keyframe table if only one keyframe exists at the beginning
80 if (keyframe_list->rowCount() < 2 && getPos(0) == m_min && m_max != -1)
81 widgetTable->setHidden(true);
83 buttonKeyframes->setHidden(true);
86 KeyframeEdit::~KeyframeEdit()
88 keyframe_list->blockSignals(true);
89 keyframe_list->clear();
91 while ((child = m_slidersLayout->takeAt(0)) != 0) {
92 QWidget *wid = child->widget();
100 void KeyframeEdit::addParameter(QDomElement e)
102 keyframe_list->blockSignals(true);
103 m_params.append(e.cloneNode().toElement());
104 QDomNode na = e.firstChildElement("name");
105 QString paramName = i18n(na.toElement().text().toUtf8().data());
106 int columnId = keyframe_list->columnCount();
107 keyframe_list->insertColumn(columnId);
108 keyframe_list->setHorizontalHeaderItem(columnId, new QTableWidgetItem(paramName));
110 DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, 0,
111 m_params.at(columnId).attribute("min").toInt(), m_params.at(columnId).attribute("max").toInt(),
112 m_params.at(columnId).attribute("default").toInt(), m_params.at(columnId).attribute("suffix"), this);
113 connect(doubleparam, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframeValue(int)));
114 m_slidersLayout->addWidget(doubleparam, columnId, 0);
116 QStringList frames = e.attribute("keyframes").split(";", QString::SkipEmptyParts);
117 for (int i = 0; i < frames.count(); i++) {
118 int frame = frames.at(i).section(':', 0, 0).toInt();
121 for (j = 0; j < keyframe_list->rowCount(); j++) {
122 int currentPos = getPos(j);
123 if (frame == currentPos) {
124 keyframe_list->setItem(j, columnId, new QTableWidgetItem(frames.at(i).section(':', 1, 1)));
127 } else if (currentPos > frame) {
132 keyframe_list->insertRow(j);
133 keyframe_list->setVerticalHeaderItem(j, new QTableWidgetItem(getPosString(frame)));
134 keyframe_list->setItem(j, columnId, new QTableWidgetItem(frames.at(i).section(':', 1, 1)));
135 keyframe_list->resizeRowToContents(j);
138 keyframe_list->resizeColumnsToContents();
139 keyframe_list->blockSignals(false);
140 slotAdjustKeyframeInfo(false);
143 void KeyframeEdit::setupParam()
145 keyframe_list->blockSignals(true);
146 keyframe_list->clear();
147 int col = keyframe_list->columnCount();
148 QDomNode na = m_params.at(0).firstChildElement("name");
149 QString paramName = i18n(na.toElement().text().toUtf8().data());
150 kDebug() << " INSERT COL: " << col << ", " << paramName;
151 keyframe_list->insertColumn(col);
152 keyframe_list->setHorizontalHeaderItem(col, new QTableWidgetItem(paramName));
153 m_slidersLayout = new QGridLayout(param_sliders);
155 DoubleParameterWidget *doubleparam = new DoubleParameterWidget(paramName, 0,
156 m_params.at(0).attribute("min").toInt(), m_params.at(0).attribute("max").toInt(),
157 m_params.at(0).attribute("default").toInt(), m_params.at(0).attribute("suffix"), this);
158 connect(doubleparam, SIGNAL(valueChanged(int)), this, SLOT(slotAdjustKeyframeValue(int)));
159 m_slidersLayout->addWidget(doubleparam, 0, 0);
161 keyframe_list->setSelectionBehavior(QAbstractItemView::SelectRows);
162 keyframe_list->setSelectionMode(QAbstractItemView::SingleSelection);
164 QStringList frames = m_params.at(0).attribute("keyframes").split(";", QString::SkipEmptyParts);
165 setEnabled(frames.count() > 0);
166 for (int i = 0; i < frames.count(); i++) {
167 keyframe_list->insertRow(i);
168 int currentpos = frames.at(i).section(':', 0, 0).toInt();
169 keyframe_list->setVerticalHeaderItem(i, new QTableWidgetItem(getPosString(currentpos)));
170 keyframe_list->setItem(i, col, new QTableWidgetItem(frames.at(i).section(':', 1, 1)));
171 if ((m_active_keyframe > -1) && (m_active_keyframe == currentpos)) {
172 keyframe_list->setCurrentCell(i, 0);
173 keyframe_list->selectRow(i);
175 //item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled);
177 /*QTreeWidgetItem *first = keyframe_list->topLevelItem(0);
178 if (first) keyframe_list->setCurrentItem(first);*/
179 keyframe_list->blockSignals(false);
180 //keyframe_list->setCurrentCell(0, 0);
181 slotAdjustKeyframeInfo(false);
182 button_delete->setEnabled(keyframe_list->rowCount() > 1);
185 void KeyframeEdit::slotDeleteKeyframe()
187 if (keyframe_list->rowCount() < 2)
189 int col = keyframe_list->currentColumn();
190 int row = keyframe_list->currentRow();
191 keyframe_list->removeRow(keyframe_list->currentRow());
192 row = qMin(row, keyframe_list->rowCount() - 1);
193 keyframe_list->setCurrentCell(row, col);
194 keyframe_list->selectRow(row);
196 button_delete->setEnabled(keyframe_list->rowCount() > 1);
199 void KeyframeEdit::slotAddKeyframe()
201 keyframe_list->blockSignals(true);
202 QTableWidgetItem *item = keyframe_list->currentItem();
203 int row = keyframe_list->currentRow();
204 int col = keyframe_list->currentColumn();
206 int pos1 = getPos(row);
209 kDebug() << "// ADD KF: " << row << ", MAX: " << keyframe_list->rowCount() << ", POS: " << pos1;
210 if (row < (keyframe_list->rowCount() - 1)) {
211 result = pos1 + (getPos(row + 1) - pos1) / 2;
213 } else if (row == 0) {
221 int pos2 = getPos(row - 1);
222 result = pos2 + (pos1 - pos2) / 2;
225 keyframe_list->insertRow(newrow);
226 keyframe_list->setVerticalHeaderItem(newrow, new QTableWidgetItem(getPosString(result)));
227 for (int i = 0; i < keyframe_list->columnCount(); i++)
228 keyframe_list->setItem(newrow, i, new QTableWidgetItem(keyframe_list->item(item->row(), i)->text()));
230 keyframe_list->resizeRowsToContents();
231 //keyframe_list->resizeRowToContents(newrow);
232 slotAdjustKeyframeInfo();
233 keyframe_list->blockSignals(false);
235 button_delete->setEnabled(keyframe_list->rowCount() > 1);
236 keyframe_list->setCurrentCell(newrow, col);
237 keyframe_list->selectRow(newrow);
238 //slotGenerateParams(newrow, 0);
241 void KeyframeEdit::slotGenerateParams(int row, int column)
244 // position of keyframe changed
245 QTableWidgetItem *item = keyframe_list->item(row, 0);
249 int pos = getPos(row);
252 if (m_max != -1 && pos > m_max)
254 QString val = getPosString(pos);
255 if (val != keyframe_list->verticalHeaderItem(row)->text())
256 keyframe_list->verticalHeaderItem(row)->setText(val);
258 for (int col = 0; col < keyframe_list->horizontalHeader()->count(); col++) {
259 item = keyframe_list->item(row, col);
260 int v = item->text().toInt();
261 if (v >= m_params.at(col).attribute("max").toInt())
262 item->setText(m_params.at(col).attribute("max"));
263 if (v <= m_params.at(col).attribute("min").toInt())
264 item->setText(m_params.at(col).attribute("min"));
266 for (int i = 0; i < keyframe_list->rowCount(); i++) {
267 if (keyframe_list->item(i, col))
268 keyframes.append(QString::number(getPos(i)) + ':' + keyframe_list->item(i, col)->text() + ';');
270 m_params[col].setAttribute("keyframes", keyframes);
273 emit parameterChanged();
277 QTableWidgetItem *item = keyframe_list->item(row, column);
281 int pos = getPos(row);
284 if (m_max != -1 && pos > m_max)
286 /*QList<QTreeWidgetItem *> duplicates = keyframe_list->findItems(val, Qt::MatchExactly, 0);
287 duplicates.removeAll(item);
288 if (!duplicates.isEmpty()) {
289 // Trying to insert a keyframe at existing value, revert it
290 val = m_timecode.getTimecodeFromFrames(m_previousPos);
292 QString val = getPosString(pos);
293 if (val != keyframe_list->verticalHeaderItem(row)->text())
294 keyframe_list->verticalHeaderItem(row)->setText(val);
296 int v = item->text().toInt();
297 if (v >= m_params.at(column).attribute("max").toInt())
298 item->setText(m_params.at(column).attribute("max"));
299 if (v <= m_params.at(column).attribute("min").toInt())
300 item->setText(m_params.at(column).attribute("min"));
301 slotAdjustKeyframeInfo(false);
304 for (int i = 0; i < keyframe_list->rowCount(); i++) {
305 if (keyframe_list->item(i, column))
306 keyframes.append(QString::number(getPos(i)) + ':' + keyframe_list->item(i, column)->text() + ';');
308 m_params[column].setAttribute("keyframes", keyframes);
309 emit parameterChanged();
312 void KeyframeEdit::generateAllParams()
314 for (int col = 0; col < keyframe_list->columnCount(); col++) {
316 for (int i = 0; i < keyframe_list->rowCount(); i++) {
317 if (keyframe_list->item(i, col))
318 keyframes.append(QString::number(getPos(i)) + ':' + keyframe_list->item(i, col)->text() + ';');
320 m_params[col].setAttribute("keyframes", keyframes);
322 emit parameterChanged();
325 const QString KeyframeEdit::getValue(const QString &name)
327 for (int col = 0; col < keyframe_list->columnCount(); col++) {
328 QDomNode na = m_params.at(col).firstChildElement("name");
329 QString paramName = i18n(na.toElement().text().toUtf8().data());
330 //kDebug() << paramName << " == " << name;
331 if (paramName == name)
332 return m_params.at(col).attribute("keyframes");
337 void KeyframeEdit::slotAdjustKeyframeInfo(bool seek)
339 QTableWidgetItem *item = keyframe_list->currentItem();
344 QTableWidgetItem *above = keyframe_list->item(item->row() - 1, item->column());
345 QTableWidgetItem *below = keyframe_list->item(item->row() + 1, item->column());
347 min = getPos(above->row()) + 1;
349 max = getPos(below->row()) - 1;
351 keyframe_pos->blockSignals(true);
352 keyframe_pos->setRange(min, max);
353 keyframe_pos->setValue(getPos(item->row()));
354 keyframe_pos->blockSignals(false);
355 for (int col = 0; col < keyframe_list->columnCount(); col++) {
356 DoubleParameterWidget *doubleparam = static_cast <DoubleParameterWidget*>(m_slidersLayout->itemAtPosition(col, 0)->widget());
359 doubleparam->blockSignals(true);
360 if (keyframe_list->item(item->row(), col)) {
361 doubleparam->setValue(keyframe_list->item(item->row(), col)->text().toInt());
363 kDebug() << "Null pointer exception caught: http://www.kdenlive.org/mantis/view.php?id=1771";
365 doubleparam->blockSignals(false);
367 if (KdenliveSettings::keyframeseek() && seek)
368 emit seekToPos(keyframe_pos->value() - m_min);
371 void KeyframeEdit::slotAdjustKeyframePos(int value)
373 QTableWidgetItem *item = keyframe_list->currentItem();
374 keyframe_list->verticalHeaderItem(item->row())->setText(getPosString(value));
375 slotGenerateParams(item->row(), -1);
376 if (KdenliveSettings::keyframeseek())
377 emit seekToPos(value - m_min);
380 void KeyframeEdit::slotAdjustKeyframeValue(int /*value*/)
382 QTableWidgetItem *item = keyframe_list->currentItem();
383 for (int col = 0; col < keyframe_list->columnCount(); col++) {
384 DoubleParameterWidget *doubleparam = static_cast <DoubleParameterWidget*>(m_slidersLayout->itemAtPosition(col, 0)->widget());
387 int val = doubleparam->getValue();
388 QTableWidgetItem *nitem = keyframe_list->item(item->row(), col);
389 if (nitem->text().toInt() != val)
390 nitem->setText(QString::number(val));
392 //keyframe_list->item(item->row() - 1, item->column());
396 int KeyframeEdit::getPos(int row)
398 if (KdenliveSettings::frametimecode())
399 return keyframe_list->verticalHeaderItem(row)->text().toInt();
401 return m_timecode.getFrameCount(keyframe_list->verticalHeaderItem(row)->text());
404 QString KeyframeEdit::getPosString(int pos)
406 if (KdenliveSettings::frametimecode())
407 return QString::number(pos);
409 return m_timecode.getTimecodeFromFrames(pos);
412 void KeyframeEdit::slotSetSeeking(int state)
414 KdenliveSettings::setKeyframeseek(state == Qt::Checked);
417 void KeyframeEdit::updateTimecodeFormat()
419 for (int row = 0; row < keyframe_list->rowCount(); ++row) {
420 QString pos = keyframe_list->verticalHeaderItem(row)->text();
421 if (KdenliveSettings::frametimecode())
422 keyframe_list->verticalHeaderItem(row)->setText(QString::number(m_timecode.getFrameCount(pos)));
424 keyframe_list->verticalHeaderItem(row)->setText(m_timecode.getTimecodeFromFrames(pos.toInt()));
428 void KeyframeEdit::slotKeyframeMode()
430 widgetTable->setHidden(false);
431 buttonKeyframes->setHidden(true);
435 /*void KeyframeEdit::slotSaveCurrentParam(QTreeWidgetItem *item, int column)
437 if (item && column == 0) m_previousPos = m_timecode.getFrameCount(item->text(0));