Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Allow changing keyframe type

parent bf407756
......@@ -240,6 +240,40 @@ bool KeyframeModel::updateKeyframe(GenTime pos, QVariant value)
return res;
}
KeyframeType convertFromMltType(mlt_keyframe_type type)
{
switch (type) {
case mlt_keyframe_linear:
return KeyframeType::Linear;
case mlt_keyframe_discrete:
return KeyframeType::Discrete;
case mlt_keyframe_smooth:
return KeyframeType::Curve;
}
return KeyframeType::Linear;
}
bool KeyframeModel::updateKeyframeType(GenTime pos, int type, Fun &undo, Fun &redo)
{
QWriteLocker locker(&m_lock);
Q_ASSERT(m_keyframeList.count(pos) > 0);
KeyframeType oldType = m_keyframeList[pos].first;
KeyframeType newType = convertFromMltType((mlt_keyframe_type) type);
QVariant value = m_keyframeList[pos].second;
// Check if keyframe is different
if (m_paramType == ParamType::KeyframeParam) {
if (oldType == newType) return true;
}
auto operation = updateKeyframe_lambda(pos, newType, value, true);
auto reverse = updateKeyframe_lambda(pos, oldType, value, true);
bool res = operation();
if (res) {
UPDATE_UNDO_REDO(operation, reverse, undo, redo);
}
return res;
}
Fun KeyframeModel::updateKeyframe_lambda(GenTime pos, KeyframeType type, QVariant value, bool notify)
{
QWriteLocker locker(&m_lock);
......@@ -250,7 +284,7 @@ Fun KeyframeModel::updateKeyframe_lambda(GenTime pos, KeyframeType type, QVarian
m_keyframeList[pos].first = type;
m_keyframeList[pos].second = value;
if (notify)
emit dataChanged(index(row), index(row), {ValueRole,NormalizedValueRole});
emit dataChanged(index(row), index(row), {ValueRole,NormalizedValueRole,TypeRole});
return true;
};
}
......@@ -515,18 +549,6 @@ mlt_keyframe_type convertToMltType(KeyframeType type)
}
return mlt_keyframe_linear;
}
KeyframeType convertFromMltType(mlt_keyframe_type type)
{
switch (type) {
case mlt_keyframe_linear:
return KeyframeType::Linear;
case mlt_keyframe_discrete:
return KeyframeType::Discrete;
case mlt_keyframe_smooth:
return KeyframeType::Curve;
}
return KeyframeType::Linear;
}
void KeyframeModel::parseAnimProperty(const QString &prop)
{
......
......@@ -44,7 +44,7 @@ class EffectItemModel;
enum class KeyframeType
{
Linear,
Linear = 0,
Discrete,
Curve
};
......@@ -106,6 +106,7 @@ public:
@param value is the new value of the param
*/
bool updateKeyframe(GenTime pos, QVariant value);
bool updateKeyframeType(GenTime pos, int type, Fun &undo, Fun &redo);
bool updateKeyframe(GenTime pos, QVariant value, Fun &undo, Fun &redo);
/* @brief Returns a keyframe data at given pos
......
......@@ -129,6 +129,23 @@ bool KeyframeModelList::updateKeyframe(GenTime pos, QVariant value, const QPersi
return res;
}
bool KeyframeModelList::updateKeyframeType(GenTime pos, int type, const QPersistentModelIndex &index)
{
QWriteLocker locker(&m_lock);
Q_ASSERT(m_parameters.count(index) > 0);
Fun undo = []() { return true; };
Fun redo = []() { return true; };
if (singleKeyframe()) {
bool ok = false;
Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok);
pos = kf.first;
}
bool res = m_parameters.at(index)->updateKeyframeType(pos, type, undo, redo);
if (res) {
PUSH_UNDO(undo, redo, i18n("Update keyframe"));
}
return res;
}
Keyframe KeyframeModelList::getKeyframe(const GenTime &pos, bool *ok) const
{
......
......@@ -81,6 +81,7 @@ public:
@param index is the index of the wanted keyframe
*/
bool updateKeyframe(GenTime pos, QVariant value, const QPersistentModelIndex &index);
bool updateKeyframeType(GenTime pos, int type, const QPersistentModelIndex &index);
/* @brief Returns a keyframe data at given pos
ok is a return parameter, set to true if everything went good
......
......@@ -87,6 +87,13 @@ void KeyframeView::slotAddRemove()
}
}
void KeyframeView::slotEditType(int type, const QPersistentModelIndex &index)
{
if (m_model->hasKeyframe(m_position)) {
m_model->updateKeyframeType(GenTime(m_position, pCore->getCurrentFps()), type, index);
}
}
void KeyframeView::slotRemoveKeyframe(int pos)
{
if (pos < 0) {
......@@ -258,9 +265,22 @@ void KeyframeView::paintEvent(QPaintEvent *event)
} else {
p.setBrush(m_colKeyframe);
}
int scaledPos = pos * m_scale;
p.drawLine(scaledPos, headOffset, scaledPos, m_lineHeight + (headOffset / 2));
p.drawEllipse(scaledPos - headOffset / 2, 0, headOffset, headOffset);
double scaledPos = pos * m_scale;
p.drawLine(QPointF(scaledPos, headOffset), QPointF(scaledPos, m_lineHeight + headOffset / 2.0));
switch (keyframe.second.first) {
case KeyframeType::Linear: {
QPolygonF position = QPolygonF() << QPointF(-headOffset / 2.0, headOffset / 2.0) << QPointF(0, 0) << QPointF(headOffset / 2.0, headOffset / 2.0) << QPointF(0, headOffset);
position.translate(scaledPos, 0);
p.drawPolygon(position);
break;
}
case KeyframeType::Discrete:
p.drawRect(QRectF(scaledPos - headOffset / 2.0, 0, headOffset, headOffset));
break;
default:
p.drawEllipse(QRectF(scaledPos - headOffset / 2.0, 0, headOffset, headOffset));
break;
}
}
p.setPen(palette().dark().color());
......
......@@ -53,6 +53,7 @@ public slots:
void slotGoToNext();
void slotGoToPrev();
void slotModelChanged();
void slotEditType(int type, const QPersistentModelIndex &index);
protected:
void paintEvent(QPaintEvent *event) override;
......
......@@ -29,9 +29,9 @@
#include "widgets/doublewidget.h"
#include "widgets/geometrywidget.h"
#include <QGridLayout>
#include <QVBoxLayout>
#include <QToolButton>
#include <KSelectAction>
#include <klocalizedstring.h>
KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, QWidget *parent)
......@@ -41,7 +41,7 @@ KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QMode
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_lay = new QGridLayout(this);
m_lay = new QVBoxLayout(this);
bool ok = false;
int duration = m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt(&ok);
......@@ -64,15 +64,37 @@ KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QMode
m_buttonNext->setIcon(KoIconUtils::themedIcon(QStringLiteral("media-skip-forward")));
m_buttonNext->setToolTip(i18n("Go to next keyframe"));
// Keyframe type widget
m_selectType = new KSelectAction(KoIconUtils::themedIcon(QStringLiteral("keyframes")), i18n("Keyframe interpolation"), this);
QAction *discrete = new QAction(KoIconUtils::themedIcon(QStringLiteral("discrete")), i18n("Discrete"), this);
discrete->setData((int)mlt_keyframe_discrete);
discrete->setCheckable(true);
m_selectType->addAction(discrete);
QAction *linear = new QAction(KoIconUtils::themedIcon(QStringLiteral("linear")), i18n("Linear"), this);
linear->setData((int)mlt_keyframe_linear);
linear->setCheckable(true);
m_selectType->addAction(linear);
QAction *curve = new QAction(KoIconUtils::themedIcon(QStringLiteral("smooth")), i18n("Smooth"), this);
curve->setData((int)mlt_keyframe_smooth);
curve->setCheckable(true);
m_selectType->addAction(curve);
m_selectType->setCurrentAction(linear);
connect(m_selectType, SIGNAL(triggered(QAction *)), this, SLOT(slotEditKeyframeType(QAction *)));
m_selectType->setToolBarMode(KSelectAction::ComboBoxMode);
QToolBar *toolbar = new QToolBar(this);
Monitor *monitor = pCore->getMonitor(m_model->monitorId);
m_time = new TimecodeDisplay(monitor->timecode(), this);
m_time->setRange(0, duration);
m_lay->addWidget(m_keyframeview, 0, 0, 1, -1);
m_lay->addWidget(m_buttonPrevious, 1, 0);
m_lay->addWidget(m_buttonAddDelete, 1, 1);
m_lay->addWidget(m_buttonNext, 1, 2);
m_lay->addWidget(m_time, 1, 3, Qt::AlignRight);
toolbar->addWidget(m_buttonPrevious);
toolbar->addWidget(m_buttonAddDelete);
toolbar->addWidget(m_buttonNext);
toolbar->addAction(m_selectType);
toolbar->addWidget(m_time);
m_lay->addWidget(m_keyframeview);
m_lay->addWidget(toolbar);
slotSetPosition(0, false);
connect(m_time, &TimecodeDisplay::timeCodeEditingFinished, [&](){slotSetPosition(-1, true);});
......@@ -103,6 +125,13 @@ void KeyframeWidget::monitorSeek(int pos)
m_keyframeview->slotSetPosition(qBound(in, pos, out) - in);
}
void KeyframeWidget::slotEditKeyframeType(QAction *action)
{
int type = action->data().toInt();
m_keyframeview->slotEditType(type, m_index);
}
void KeyframeWidget::slotRefreshParams()
{
int pos = getPosition();
......@@ -232,6 +261,6 @@ void KeyframeWidget::addParameter(const QPersistentModelIndex& index)
}
if (paramWidget) {
m_parameters[index] = paramWidget;
m_lay->addWidget(paramWidget, 1 + (int)m_parameters.size(), 0, 1, -1);
m_lay->addWidget(paramWidget);
}
}
......@@ -31,9 +31,10 @@ class AssetParameterModel;
class DoubleWidget;
class KeyframeView;
class KeyframeModelList;
class QGridLayout;
class QVBoxLayout;
class QToolButton;
class TimecodeDisplay;
class KSelectAction;
class KeyframeWidget : public AbstractParamWidget
{
......@@ -60,15 +61,17 @@ private slots:
void slotRefreshParams();
void slotAtKeyframe(bool atKeyframe, bool singleKeyframe);
void monitorSeek(int pos);
void slotEditKeyframeType(QAction *action);
private:
QGridLayout *m_lay;
QVBoxLayout *m_lay;
std::shared_ptr<KeyframeModelList> m_keyframes;
KeyframeView *m_keyframeview;
QToolButton *m_buttonAddDelete;
QToolButton *m_buttonPrevious;
QToolButton *m_buttonNext;
KSelectAction *m_selectType;
TimecodeDisplay *m_time;
std::unordered_map<QPersistentModelIndex, QWidget*> m_parameters;
......
......@@ -389,7 +389,7 @@ Rectangle {
Rectangle {
id: keyframe
property int frame : model.frame
property int type : model.type
property int frameType : model.type
x: model.frame * timeScale
height: parent.height * model.normalizedValue
anchors.bottom: parent.bottom
......@@ -455,13 +455,13 @@ Rectangle {
var ypos
for(var i = 0; i < keyframes.count; i++)
{
var type = keyframes.itemAt(i).frameType
xpos = keyframes.itemAt(i).x
if (type == 1) {
// discrete
paths.push(compline.createObject(keyframecanvas, {"x": xpos, "y": ypos} ))
}
ypos = parent.height - keyframes.itemAt(i).height
var type = keyframes.itemAt(i).type
if (type < 2) {
// linear
paths.push(compline.createObject(keyframecanvas, {"x": xpos, "y": ypos} ))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment