beziercurve/cubicbezierspline.cpp
dragvalue.cpp
monitoreditwidget.cpp
+ simplekeyframes/simpletimelinewidget.cpp
+ simplekeyframes/simplekeyframewidget.cpp
)
add_definitions(${KDE4_DEFINITIONS})
meetDependency(paramName, type, EffectsList::parameter(e, depends));
#ifdef QJSON
} else if (type == "roto-spline") {
- RotoWidget *roto = new RotoWidget(value, m_monitor, m_in, m_out, this);
+ RotoWidget *roto = new RotoWidget(value, m_monitor, m_in, m_out, m_timecode, this);
roto->slotShowScene(!disable);
connect(roto, SIGNAL(valueChanged()), this, SLOT(collectAllParameters()));
connect(roto, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
+ connect(roto, SIGNAL(seekToPos(int)), this, SIGNAL(seekTimeline(int)));
connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int)));
connect(this, SIGNAL(effectStateChanged(bool)), roto, SLOT(slotShowScene(bool)));
m_vbox->addWidget(roto);
{
// do only sync if this effect is keyframable
if (m_timePos->maximum() > 0 && KdenliveSettings::transitionfollowcursor()) {
- relTimelinePos = qMax(0, relTimelinePos);
- relTimelinePos = qMin(relTimelinePos, m_timePos->maximum());
+ relTimelinePos = qBound(0, relTimelinePos, m_timePos->maximum());
if (relTimelinePos != m_timePos->getValue())
slotPositionChanged(relTimelinePos, false);
}
Q_UNUSED(option);
Q_UNUSED(widget);
- painter->setPen(QPen(Qt::yellow, 1, Qt::SolidLine));
- painter->setBrush(QBrush(isSelected() ? Qt::red : Qt::yellow));
+ if (isEnabled()) {
+ painter->setPen(QPen(Qt::yellow, 1, Qt::SolidLine));
+ painter->setBrush(QBrush(isSelected() ? Qt::red : Qt::yellow));
+ } else {
+ painter->setPen(QPen(Qt::gray, 1, Qt::SolidLine));
+ painter->setBrush(QBrush(Qt::gray));
+ }
painter->setRenderHint(QPainter::Antialiasing);
double handleSize = 6 / painter->matrix().m11();
if (parentItem()) {
SplineItem *parent = qgraphicsitem_cast<SplineItem*>(parentItem());
if (parent)
- parent->updateSpline();
+ parent->updateSpline(true);
}
}
void BPointItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
-QGraphicsItem::mouseReleaseEvent(event);
+ if (parentItem()) {
+ SplineItem *parent = qgraphicsitem_cast<SplineItem*>(parentItem());
+ if (parent)
+ parent->updateSpline(false);
+ }
+ QGraphicsItem::mouseReleaseEvent(event);
}
void BPointItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
#include "splineitem.h"
#include "bpointitem.h"
#include "nearestpoint.h"
+#include "kdenlivesettings.h"
#include <QGraphicsScene>
#include <QCursor>
SplineItem::SplineItem(const QList< BPoint >& points, QGraphicsItem* parent, QGraphicsScene *scene) :
- QGraphicsPathItem(parent, scene)
+ QGraphicsPathItem(parent, scene),
+ m_closed(false),
+ m_editing(false)
{
QPen framepen(Qt::SolidLine);
framepen.setColor(Qt::yellow);
setBrush(Qt::NoBrush);
setAcceptHoverEvents(true);
- m_closed = true;
- if (points.isEmpty()) {
- m_closed = false;
- grabMouse();
- return;
- }
-
- QPainterPath path(points.at(0).p);
- int j;
- for (int i = 0; i < points.count(); ++i) {
- new BPointItem(points.at(i), this);
- j = (i + 1) % points.count();
- path.cubicTo(points.at(i).h2, points.at(j).h1, points.at(j).p);
- }
- setPath(path);
+ setPoints(points);
}
int SplineItem::type() const
return Type;
}
-void SplineItem::updateSpline()
+bool SplineItem::editing()
+{
+ return m_editing;
+}
+
+void SplineItem::updateSpline(bool editing)
{
QPainterPath path(qgraphicsitem_cast<BPointItem *>(childItems().at(0))->getPoint().p);
}
setPath(path);
- if (m_closed)
- emit changed();
+ m_editing = editing;
+
+ if (m_closed && (!editing || KdenliveSettings::monitorscene_directupdate()))
+ emit changed(editing);
}
QList <BPoint> SplineItem::getPoints()
return points;
}
+void SplineItem::setPoints(const QList< BPoint >& points)
+{
+ if (points.count() < 2) {
+ m_closed = false;
+ grabMouse();
+ return;
+ } else {
+ m_closed = true;
+ }
+
+ qDeleteAll(childItems());
+ childItems().clear();
+
+ QPainterPath path(points.at(0).p);
+ int j;
+ for (int i = 0; i < points.count(); ++i) {
+ new BPointItem(points.at(i), this);
+ j = (i + 1) % points.count();
+ path.cubicTo(points.at(i).h2, points.at(j).h1, points.at(j).p);
+ }
+ setPath(path);
+}
+
void SplineItem::removeChild(QGraphicsItem* child)
{
if (childItems().count() > 2) {
virtual int type() const;
- void updateSpline();
+ bool editing();
+
+ void updateSpline(bool editing = false);
QList <BPoint> getPoints();
+ void setPoints(const QList <BPoint> &points);
void removeChild(QGraphicsItem *child);
int getClosestPointOnCurve(QPointF point, double *tFinal);
bool m_closed;
+ bool m_editing;
signals:
- void changed();
+ void changed(bool editing);
};
#endif
#include "monitoreditwidget.h"
#include "onmonitoritems/rotoscoping/bpointitem.h"
#include "onmonitoritems/rotoscoping/splineitem.h"
+#include "simplekeyframes/simplekeyframewidget.h"
+#include "kdenlivesettings.h"
#include <qjson/parser.h>
#include <qjson/serializer.h>
+#include <QVBoxLayout>
-RotoWidget::RotoWidget(QString data, Monitor *monitor, int in, int out, QWidget* parent) :
+#include <KDebug>
+
+
+RotoWidget::RotoWidget(QString data, Monitor *monitor, int in, int out, Timecode t, QWidget* parent) :
QWidget(parent),
m_monitor(monitor),
m_showScene(true),
m_out(out),
m_pos(0)
{
+ QVBoxLayout *l = new QVBoxLayout(this);
+ m_keyframeWidget = new SimpleKeyframeWidget(t, in, out, this);
+ l->addWidget(m_keyframeWidget);
+
MonitorEditWidget *edit = monitor->getEffectEdit();
edit->showVisibilityButton(true);
m_scene = edit->getScene();
// :(
}
- int width = m_monitor->render->frameRenderWidth();
- int height = m_monitor->render->renderHeight();
- QList <BPoint> points;
- foreach (const QVariant &bpoint, m_data.toList()) {
- QList <QVariant> l = bpoint.toList();
- BPoint p;
- p.h1 = QPointF(l.at(0).toList().at(0).toDouble() * width, l.at(0).toList().at(1).toDouble() * height);
- p.p = QPointF(l.at(1).toList().at(0).toDouble() * width, l.at(1).toList().at(1).toDouble() * height);
- p.h2 = QPointF(l.at(2).toList().at(0).toDouble() * width, l.at(2).toList().at(1).toDouble() * height);
- points << p;
+
+ if (m_data.canConvert(QVariant::Map)) {
+ QList <int> keyframes;
+ QMap <QString, QVariant> map = m_data.toMap();
+ QMap <QString, QVariant>::const_iterator i = map.constBegin();
+ while (i != map.constEnd()) {
+ keyframes.append(i.key().toInt());
+ ++i;
+ }
+ m_keyframeWidget->setKeyframes(keyframes);
+ } else {
+ m_keyframeWidget->setKeyframes(QList <int>() << 0);
}
- m_item = new SplineItem(points, NULL, m_scene);
+ m_item = new SplineItem(QList <BPoint>(), NULL, m_scene);
- connect(m_item, SIGNAL(changed()), this, SLOT(slotUpdateData()));
+ connect(m_item, SIGNAL(changed(bool)), this, SLOT(slotUpdateData(bool)));
connect(edit, SIGNAL(showEdit(bool)), this, SLOT(slotShowScene(bool)));
connect(m_monitor, SIGNAL(renderPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
+ connect(m_keyframeWidget, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int)));
+ connect(m_keyframeWidget, SIGNAL(keyframeAdded(int)), this, SLOT(slotAddKeyframe(int)));
+ connect(m_keyframeWidget, SIGNAL(keyframeRemoved(int)), this, SLOT(slotRemoveKeyframe(int)));
+ connect(m_scene, SIGNAL(addKeyframe()), this, SLOT(slotAddKeyframe()));
+
+ slotPositionChanged(0, false);
}
RotoWidget::~RotoWidget()
{
+ delete m_keyframeWidget;
+
m_scene->removeItem(m_item);
delete m_item;
void RotoWidget::slotSyncPosition(int relTimelinePos)
{
- Q_UNUSED(relTimelinePos);
+ relTimelinePos = qBound(0, relTimelinePos, m_out);
+ m_keyframeWidget->slotSetPosition(relTimelinePos, false);
+ slotPositionChanged(relTimelinePos, false);
}
void RotoWidget::slotShowScene(bool show)
slotCheckMonitorPosition(m_monitor->render->seekFramePosition());
}
-void RotoWidget::slotUpdateData()
+void RotoWidget::slotUpdateData(int pos, bool editing)
{
+ Q_UNUSED(editing)
+
int width = m_monitor->render->frameRenderWidth();
int height = m_monitor->render->renderHeight();
pl << QVariant(QList <QVariant>() << QVariant(point[i].x() / width) << QVariant(point[i].y() / height));
vlist << QVariant(pl);
}
- m_data = QVariant(vlist);
+
+ if (m_data.canConvert(QVariant::Map)) {
+ QMap <QString, QVariant> map = m_data.toMap();
+ map[QString::number(pos < 0 ? m_keyframeWidget->getPosition() : pos)] = QVariant(vlist);
+ m_data = QVariant(map);
+ } else {
+ m_data = QVariant(vlist);
+ }
emit valueChanged();
}
+void RotoWidget::slotUpdateData(bool editing)
+{
+ slotUpdateData(-1, editing);
+}
+
QString RotoWidget::getSpline()
{
QJson::Serializer serializer;
return QString(serializer.serialize(m_data));
}
+void RotoWidget::slotPositionChanged(int pos, bool seek)
+{
+ if (m_item->editing())
+ return;
+
+ m_keyframeWidget->slotSetPosition(pos, false);
+
+ if (m_data.canConvert(QVariant::Map)) {
+ QMap <QString, QVariant> map = m_data.toMap();
+ QMap <QString, QVariant>::const_iterator i = map.constBegin();
+ int keyframe1, keyframe2;
+ keyframe1 = keyframe2 = i.key().toInt();
+ while (i.key().toInt() < pos && ++i != map.constEnd()) {
+ keyframe1 = keyframe2;
+ keyframe2 = i.key().toInt();
+ }
+
+ if (keyframe1 != keyframe2 && pos < keyframe2) {
+ QList <BPoint> p1 = getPoints(keyframe1);
+ QList <BPoint> p2 = getPoints(keyframe2);
+ QList <BPoint> p;
+ qreal relPos = (pos - keyframe1) / (qreal)(keyframe2 - keyframe1 + 1);
+
+ for (int i = 0; i < p1.count(); ++i) {
+ BPoint bp;
+ for (int j = 0; j < 3; ++j) {
+ if (p1.at(i)[j] != p2.at(i)[j])
+ bp[j] = QLineF(p1.at(i)[j], p2.at(i)[j]).pointAt(relPos);
+ else
+ bp[j] = p1.at(i)[j];
+ }
+ p.append(bp);
+ }
+
+ m_item->setPoints(p);
+ m_item->setEnabled(false);
+ m_scene->setEnabled(false);
+ } else {
+ m_item->setPoints(getPoints(keyframe2));
+ m_item->setEnabled(pos == keyframe2);
+ m_scene->setEnabled(pos == keyframe2);
+ }
+ } else {
+ m_item->setPoints(getPoints(-1));
+ m_item->setEnabled(true);
+ m_scene->setEnabled(true);
+ }
+
+ if (seek)
+ emit seekToPos(pos);
+}
+
+QList <BPoint> RotoWidget::getPoints(int keyframe)
+{
+ int width = m_monitor->render->frameRenderWidth();
+ int height = m_monitor->render->renderHeight();
+ QList <BPoint> points;
+ QList <QVariant> data;
+ if (keyframe >= 0)
+ data = m_data.toMap()[QString::number(keyframe)].toList();
+ else
+ data = m_data.toList();
+ foreach (const QVariant &bpoint, data) {
+ QList <QVariant> l = bpoint.toList();
+ BPoint p;
+ p.h1 = QPointF(l.at(0).toList().at(0).toDouble() * width, l.at(0).toList().at(1).toDouble() * height);
+ p.p = QPointF(l.at(1).toList().at(0).toDouble() * width, l.at(1).toList().at(1).toDouble() * height);
+ p.h2 = QPointF(l.at(2).toList().at(0).toDouble() * width, l.at(2).toList().at(1).toDouble() * height);
+ points << p;
+ }
+ return points;
+}
+
+void RotoWidget::slotAddKeyframe(int pos)
+{
+ if (!m_data.canConvert(QVariant::Map)) {
+ QVariant data = m_data;
+ QMap<QString, QVariant> map;
+ map[QString::number(m_in)] = data;
+ m_data = QVariant(map);
+ }
+
+ if (pos < 0)
+ m_keyframeWidget->addKeyframe();
+
+ slotUpdateData(pos);
+ m_item->setEnabled(true);
+ m_scene->setEnabled(true);
+}
+
+void RotoWidget::slotRemoveKeyframe(int pos)
+{
+ if (pos < 0)
+ pos = m_keyframeWidget->getPosition();
+
+ if (!m_data.canConvert(QVariant::Map) || m_data.toMap().count() < 2)
+ return;
+
+ m_data.toMap().remove(QString::number(pos));
+
+ if (m_data.toMap().count() == 1)
+ m_data = m_data.toMap().begin().value();
+
+ slotPositionChanged(m_keyframeWidget->getPosition(), false);
+}
+
#include "rotowidget.moc"
#define ROTOWIDGET_H
#include "bpoint.h"
+#include "timecode.h"
#include <QWidget>
class Monitor;
class MonitorScene;
class SplineItem;
+class SimpleKeyframeWidget;
class RotoWidget : public QWidget
{
Q_OBJECT
public:
- RotoWidget(QString data, Monitor *monitor, int in, int out, QWidget* parent = 0);
+ RotoWidget(QString data, Monitor *monitor, int in, int out, Timecode t, QWidget* parent = 0);
virtual ~RotoWidget();
QString getSpline();
signals:
void valueChanged();
void checkMonitorPosition(int);
+ void seekToPos(int pos);
private:
+ SimpleKeyframeWidget *m_keyframeWidget;
Monitor *m_monitor;
MonitorScene *m_scene;
bool m_showScene;
int m_out;
int m_pos;
+ QList <BPoint> getPoints(int keyframe);
+
private slots:
/** @brief Makes sure the monitor effect scene is only visible if the clip this geometry belongs to is visible.
* @param renderPos Postion of the Monitor / Timeline cursor */
void slotCheckMonitorPosition(int renderPos);
- void slotUpdateData();
+ void slotUpdateData(int pos = -1, bool editing = false);
+ void slotUpdateData(bool editing);
+
+ void slotPositionChanged(int pos, bool seek = true);
+
+ void slotAddKeyframe(int pos = -1);
+ void slotRemoveKeyframe(int pos = -1);
};
#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Till Theato (root@ttill.de) *
+ * This file is part of Kdenlive (www.kdenlive.org). *
+ * *
+ * Kdenlive is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Kdenlive is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include "simplekeyframes/simplekeyframewidget.h"
+#include "simpletimelinewidget.h"
+#include "timecodedisplay.h"
+
+#include <QToolButton>
+#include <QGridLayout>
+
+#include <KIcon>
+#include <KLocale>
+
+SimpleKeyframeWidget::SimpleKeyframeWidget(Timecode t, int in, int out, QWidget *parent) :
+ QWidget(parent)
+{
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ QGridLayout *l = new QGridLayout(this);
+
+ m_timeline = new SimpleTimelineWidget(this);
+ m_timeline->setRange(in ,out);
+
+ m_buttonAddDelete = new QToolButton(this);
+ m_buttonAddDelete->setAutoRaise(true);
+ m_buttonAddDelete->setIcon(KIcon("document-new"));
+ m_buttonAddDelete->setToolTip(i18n("Add keyframe"));
+
+ m_buttonPrevious = new QToolButton(this);
+ m_buttonPrevious->setAutoRaise(true);
+ m_buttonPrevious->setIcon(KIcon("media-skip-backward"));
+ m_buttonPrevious->setToolTip(i18n("Go to previous keyframe"));
+
+ m_buttonNext = new QToolButton(this);
+ m_buttonNext->setAutoRaise(true);
+ m_buttonNext->setIcon(KIcon("media-skip-forward"));
+ m_buttonNext->setToolTip(i18n("Go to next keyframe"));
+
+ m_time = new TimecodeDisplay(t, this);
+ m_time->setRange(in, out);
+
+ l->addWidget(m_timeline, 0, 0, 1, -1);
+ l->addWidget(m_buttonPrevious, 1, 0);
+ l->addWidget(m_buttonAddDelete, 1, 1);
+ l->addWidget(m_buttonNext, 1, 2);
+ l->addWidget(m_time, 1, 3, Qt::AlignRight);
+
+ connect(m_time, SIGNAL(editingFinished()), this, SLOT(slotSetPosition()));
+ connect(m_timeline, SIGNAL(positionChanged(int)), this, SLOT(slotSetPosition(int)));
+ connect(m_timeline, SIGNAL(keyframeAdded(int)), this, SIGNAL(keyframeAdded(int)));
+ connect(m_timeline, SIGNAL(keyframeRemoved(int)), this, SIGNAL(keyframeRemoved(int)));
+
+ connect(m_buttonAddDelete, SIGNAL(pressed()), m_timeline, SLOT(slotAddRemove()));
+ connect(m_buttonPrevious, SIGNAL(pressed()), m_timeline, SLOT(slotGoToPrev()));
+ connect(m_buttonNext, SIGNAL(pressed()), m_timeline, SLOT(slotGoToNext()));
+}
+
+SimpleKeyframeWidget::~SimpleKeyframeWidget()
+{
+ delete m_timeline;
+ delete m_buttonAddDelete;
+ delete m_buttonPrevious;
+ delete m_buttonNext;
+ //delete m_buttonSync;
+ delete m_time;
+}
+
+void SimpleKeyframeWidget::slotSetPosition(int pos, bool update)
+{
+ if (pos < 0) {
+ pos = m_time->getValue();
+ m_timeline->slotSetPosition(pos);
+ } else {
+ m_time->setValue(pos);
+ m_timeline->slotSetPosition(pos);
+ }
+
+ if (update)
+ emit positionChanged(pos);
+}
+
+int SimpleKeyframeWidget::getPosition()
+{
+ return m_time->getValue();
+}
+
+void SimpleKeyframeWidget::setKeyframes(const QList< int >& keyframes)
+{
+ m_timeline->setKeyframes(keyframes);
+}
+
+void SimpleKeyframeWidget::addKeyframe(int pos)
+{
+ blockSignals(true);
+ m_timeline->slotAddKeyframe(pos);
+ blockSignals(false);
+}
+
+
+#include "simplekeyframewidget.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Till Theato (root@ttill.de) *
+ * This file is part of Kdenlive (www.kdenlive.org). *
+ * *
+ * Kdenlive is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Kdenlive is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef SIMPLEKEYFRAMEWIDGET_H
+#define SIMPLEKEYFRAMEWIDGET_H
+
+#include "timecode.h"
+
+#include <QtCore>
+#include <QWidget>
+
+class SimpleTimelineWidget;
+class TimecodeDisplay;
+class QToolButton;
+
+
+class SimpleKeyframeWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SimpleKeyframeWidget(Timecode t, int in, int out, QWidget* parent = 0);
+ virtual ~SimpleKeyframeWidget();
+
+ int getPosition();
+ void setKeyframes(const QList <int> &keyframes);
+ void addKeyframe(int pos = -1);
+
+public slots:
+ void slotSetPosition(int pos = -1, bool update = true);
+
+signals:
+ void positionChanged(int pos);
+ void keyframeAdded(int pos);
+ void keyframeRemoved(int pos);
+
+private:
+ SimpleTimelineWidget *m_timeline;
+ QToolButton *m_buttonAddDelete;
+ QToolButton *m_buttonPrevious;
+ QToolButton *m_buttonNext;
+ //QToolButton *m_buttonSync;
+ TimecodeDisplay *m_time;
+};
+
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Till Theato (root@ttill.de) *
+ * This file is part of Kdenlive (www.kdenlive.org). *
+ * *
+ * Kdenlive is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Kdenlive is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include "simpletimelinewidget.h"
+
+#include <QPainter>
+#include <QMouseEvent>
+
+
+SimpleTimelineWidget::SimpleTimelineWidget(QWidget* parent) :
+ QWidget(parent),
+ m_min(0),
+ m_max(1),
+ m_position(0),
+ m_currentKeyframe(-1),
+ m_currentKeyframeOriginal(-1),
+ m_lineHeight(10),
+ m_scale(1)
+{
+ setMouseTracking(true);
+ setMinimumSize(QSize(150, 20));
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum));
+}
+
+void SimpleTimelineWidget::setKeyframes(QList <int> keyframes)
+{
+ m_keyframes = keyframes;
+ m_currentKeyframe = m_currentKeyframeOriginal = -1;
+ update();
+}
+
+void SimpleTimelineWidget::slotSetPosition(int pos)
+{
+ m_position = pos;
+ update();
+}
+
+void SimpleTimelineWidget::slotAddKeyframe(int pos, int select)
+{
+ if (pos < 0)
+ pos = m_position;
+
+ m_keyframes.append(pos);
+ if (select)
+ m_currentKeyframe = m_currentKeyframeOriginal = pos;
+ update();
+
+ emit keyframeAdded(pos);
+}
+
+void SimpleTimelineWidget::slotAddRemove()
+{
+ if (m_keyframes.contains(m_position))
+ slotRemoveKeyframe(m_position);
+ else
+ slotAddKeyframe(m_position);
+}
+
+void SimpleTimelineWidget::slotRemoveKeyframe(int pos)
+{
+ m_keyframes.removeAll(pos);
+ if (m_currentKeyframe == pos)
+ m_currentKeyframe = m_currentKeyframeOriginal = -1;
+ update();
+ emit keyframeRemoved(pos);
+}
+
+void SimpleTimelineWidget::setRange(int min, int max)
+{
+ m_min = min;
+ m_max = max;
+}
+
+void SimpleTimelineWidget::slotGoToNext()
+{
+ foreach (const int &keyframe, m_keyframes) {
+ if (keyframe > m_position) {
+ slotSetPosition(keyframe);
+ emit positionChanged(keyframe);
+ return;
+ }
+ }
+
+ // no keyframe after current position
+ slotSetPosition(m_max);
+ emit positionChanged(m_max);
+}
+
+void SimpleTimelineWidget::slotGoToPrev()
+{
+ for (int i = m_keyframes.count() - 1; i >= 0; --i) {
+ if (m_keyframes.at(i) < m_position) {
+ slotSetPosition(m_keyframes.at(i));
+ emit positionChanged(m_keyframes.at(i));
+ return;
+ }
+ }
+
+ // no keyframe before current position
+ slotSetPosition(m_min);
+ emit positionChanged(m_min);
+}
+
+void SimpleTimelineWidget::mousePressEvent(QMouseEvent* event)
+{
+ if (qAbs(event->y() - m_lineHeight) < m_lineHeight / 5. && event->button() == Qt::LeftButton) {
+ int pos = (event->x() - 5) / m_scale;
+ foreach(const int &keyframe, m_keyframes) {
+ if (qAbs(keyframe - pos) < 5) {
+ m_currentKeyframeOriginal = keyframe;
+ m_currentKeyframe = pos;
+ update();
+ return;
+ }
+ }
+ }
+
+ // no keyframe next to mouse
+ m_currentKeyframe = m_currentKeyframeOriginal = -1;
+ m_position = (event->x() - 5) / m_scale;
+ emit positionChanged(m_position);
+ update();
+}
+
+void SimpleTimelineWidget::mouseMoveEvent(QMouseEvent* event)
+{
+ if (event->buttons() & Qt::LeftButton) {
+ int pos = qBound(m_min, (int)((event->x() - 5) / m_scale), m_max);
+ if (m_currentKeyframe >= 0) {
+ m_currentKeyframe = pos;
+ emit keyframeMoving(m_currentKeyframeOriginal, m_currentKeyframe);
+ } else {
+ m_position = pos;
+ emit positionChanged(pos);
+ }
+ update();
+ return;
+ }
+
+ // cursor
+}
+
+void SimpleTimelineWidget::mouseReleaseEvent(QMouseEvent* event)
+{
+ if (m_currentKeyframe > 0) {
+ emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
+ }
+}
+
+void SimpleTimelineWidget::wheelEvent(QWheelEvent* event)
+{
+ int change = event->delta() < 0 ? -1 : 1;
+ if (m_currentKeyframe > 0) {
+ m_currentKeyframe = qBound(m_min, m_currentKeyframe + change, m_max);
+ emit keyframeMoved(m_currentKeyframeOriginal, m_currentKeyframe);
+ } else {
+ m_position = qBound(m_min, m_position + change, m_max);
+ emit positionChanged(m_position);
+ }
+ update();
+}
+
+void SimpleTimelineWidget::paintEvent(QPaintEvent* event)
+{
+ QPainter p(this);
+ int min = 5;
+ int max = width() - 6;
+ m_scale = (max - min) / (double)(m_max - m_min);
+ p.translate(min, m_lineHeight);
+
+ p.setPen(QPen(palette().foreground().color(), 1, Qt::SolidLine));
+
+ /*
+ * Time-"line"
+ */
+ p.drawLine(0, 0, max, 0);
+
+ /*
+ * current position
+ */
+ p.fillRect(QRectF(-1, -10, 3, 20).translated(m_position * m_scale, 0), QBrush(palette().foreground().color(), Qt::SolidPattern));
+
+ /*
+ * keyframes
+ */
+ p.setPen(QPen(palette().highlight().color(), 1, Qt::SolidLine));
+ p.setBrush(Qt::NoBrush);
+ QPolygonF keyframe = QPolygonF() << QPointF(0, -4) << QPointF(-4, 0) << QPointF(0, 4) << QPointF(4, 0);
+ QPolygonF tmp;
+ foreach (const int &pos, m_keyframes) {
+ tmp = keyframe;
+ tmp.translate(pos * m_scale, 0);
+ if (pos == m_currentKeyframe)
+ p.setBrush(QBrush(palette().highlight().color(), Qt::SolidPattern));
+
+ p.drawConvexPolygon(tmp);
+
+ if (pos == m_currentKeyframe)
+ p.setBrush(Qt::NoBrush);
+ }
+}
+
+#include "simpletimelinewidget.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Till Theato (root@ttill.de) *
+ * This file is part of Kdenlive (www.kdenlive.org). *
+ * *
+ * Kdenlive is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Kdenlive is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef SIMPLETIMELINEWIDGET_H
+#define SIMPLETIMELINEWIDGET_H
+
+#include <QtCore>
+#include <QWidget>
+
+class SimpleTimelineWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SimpleTimelineWidget(QWidget* parent = 0);
+ void setKeyframes(QList <int> keyframes);
+ void setRange(int min, int max);
+
+public slots:
+ void slotSetPosition(int pos);
+ void slotRemoveKeyframe(int pos);
+ void slotAddKeyframe(int pos = - 1, int select = false);
+ void slotAddRemove();
+ void slotGoToNext();
+ void slotGoToPrev();
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void wheelEvent(QWheelEvent *event);
+
+private:
+ int m_min;
+ int m_max;
+ int m_position;
+ int m_currentKeyframe;
+ int m_currentKeyframeOriginal;
+ QList <int> m_keyframes;
+ int m_lineHeight;
+ double m_scale;
+
+signals:
+ void positionChanged(int pos);
+
+ void keyframeSelected();
+ void keyframeMoving(int oldPos, int currentPos);
+ void keyframeMoved(int oldPos, int newPos);
+ void keyframeAdded(int pos);
+ void keyframeRemoved(int pos);
+};
+
+#endif