Commit c668fbac authored by Nicolas Carion's avatar Nicolas Carion

First tentative of working keyframe view (needs to be improved)

parent 6b976ce1
......@@ -26,17 +26,18 @@
#include "macros.hpp"
#include <QDebug>
#include <mlt++/Mlt.h>
KeyframeModel::KeyframeModel(double init_value, std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, QObject *parent)
KeyframeModel::KeyframeModel(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, QObject *parent)
: QAbstractListModel(parent)
, m_model(std::move(model))
, m_undoStack(std::move(undo_stack))
, m_index(index)
, m_lock(QReadWriteLock::Recursive)
{
m_keyframeList.insert({GenTime(), {KeyframeType::Linear, init_value}});
setup();
refresh();
}
......@@ -429,6 +430,66 @@ 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)
{
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Mlt::Properties mlt_prop;
mlt_prop.set("key", prop.toUtf8().constData());
Mlt::Animation *anim = mlt_prop.get_anim("key");
for (int i = 0; i < anim->key_count(); ++i) {
int frame;
mlt_keyframe_type type;
anim->key_get(i, frame, type);
double value = mlt_prop.anim_get_double("key", frame);
addKeyframe(GenTime(frame, pCore->getCurrentFps()), convertFromMltType(type), value, undo, redo);
}
delete anim;
/*
std::vector<std::pair<QString, KeyframeType> > separators({QStringLiteral("="), QStringLiteral("|="), QStringLiteral("~=")});
QStringList list = prop.split(';', QString::SkipEmptyParts);
for (const auto& k : list) {
bool found = false;
KeyframeType type;
QStringList values;
for (const auto &sep : separators) {
if (k.contains(sep.first)) {
found = true;
type = sep.second;
values = k.split(sep.first);
break;
}
}
if (!found || values.size() != 2) {
qDebug() << "ERROR while parsing value of keyframe"<<k<<"in value"<<prop;
continue;
}
QString sep;
if ()
}
*/
}
double KeyframeModel::getInterpolatedValue(int p) const
{
......@@ -464,7 +525,26 @@ void KeyframeModel::sendModification() const
if (auto ptr = m_model.lock()) {
Q_ASSERT(m_index.isValid());
QString name = ptr->data(m_index, AssetParameterModel::NameRole).toString();
ptr->setParameter(name, getAnimProperty());
auto type = ptr->data(m_index, AssetParameterModel::TypeRole).value<ParamType>();
if (type == ParamType::KeyframeParam) {
ptr->setParameter(name, getAnimProperty());
} else {
Q_ASSERT(false); //Not implemented, TODO
}
ptr->dataChanged(m_index, m_index);
}
}
void KeyframeModel::refresh()
{
if (auto ptr = m_model.lock()) {
Q_ASSERT(m_index.isValid());
auto type = ptr->data(m_index, AssetParameterModel::TypeRole).value<ParamType>();
if (type == ParamType::KeyframeParam) {
parseAnimProperty(ptr->data(m_index, AssetParameterModel::ValueRole).toString());
} else {
Q_ASSERT(false); //Not implemented, TODO
}
ptr->dataChanged(m_index, m_index);
}
}
......@@ -60,7 +60,7 @@ public:
@param model is the asset this parameter belong to
@param index is the index of this parameter in its model
*/
explicit KeyframeModel(double init_value, std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, QObject *parent = nullptr);
explicit KeyframeModel(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, QObject *parent = nullptr);
enum { TypeRole = Qt::UserRole + 1, PosRole, FrameRole, ValueRole};
friend class KeyframeModelList;
......@@ -130,13 +130,8 @@ public:
Q_INVOKABLE bool hasKeyframe(int frame) const;
Q_INVOKABLE bool hasKeyframe(const GenTime &pos) const;
/** @brief returns the keyframes as a Mlt Anim Property string.
It is defined as pairs of frame and value, separated by ;
Example : "0|=50; 50|=100; 100=200; 200~=60;"
Spaces are ignored by Mlt.
|= represents a discrete keyframe, = a linear one and ~= a Catmull-Rom spline
*/
QString getAnimProperty() const;
/* @brief Read the value from the model and update itself accordingly */
void refresh();
/* @brief Return the interpolated value at given pos */
double getInterpolatedValue(int pos) const;
......@@ -163,6 +158,17 @@ protected:
/* @brief Commit the modification to the model */
void sendModification() const;
/** @brief returns the keyframes as a Mlt Anim Property string.
It is defined as pairs of frame and value, separated by ;
Example : "0|=50; 50|=100; 100=200; 200~=60;"
Spaces are ignored by Mlt.
|= represents a discrete keyframe, = a linear one and ~= a Catmull-Rom spline
*/
QString getAnimProperty() const;
/* @brief this function does the opposite: given a MLT representation of an animation, build the corresponding model */
void parseAnimProperty(const QString &prop);
private:
std::weak_ptr<AssetParameterModel> m_model;
......
......@@ -30,18 +30,18 @@
#include <QDebug>
KeyframeModelList::KeyframeModelList(double init_value, std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack)
KeyframeModelList::KeyframeModelList(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack)
: m_model(model)
, m_undoStack(undo_stack)
, m_lock(QReadWriteLock::Recursive)
{
addParameter(index, init_value);
addParameter(index);
connect(m_parameters.begin()->second.get(), &KeyframeModel::modelChanged, this, &KeyframeModelList::modelChanged);
}
void KeyframeModelList::addParameter(const QModelIndex &index, double init_value)
void KeyframeModelList::addParameter(const QModelIndex &index)
{
std::shared_ptr<KeyframeModel> parameter (new KeyframeModel(init_value, m_model, index, m_undoStack));
std::shared_ptr<KeyframeModel> parameter (new KeyframeModel(m_model, index, m_undoStack));
m_parameters.insert({index, std::move(parameter)});
}
......@@ -157,3 +157,9 @@ bool KeyframeModelList::hasKeyframe(int frame) const
return m_parameters.begin()->second->hasKeyframe(frame);
}
void KeyframeModelList::refresh()
{
for (const auto& param : m_parameters) {
param.second->refresh();
}
}
......@@ -52,10 +52,10 @@ public:
/* @brief Construct a keyframe list bound to the given asset
@param init_value and index correspond to the first parameter
*/
explicit KeyframeModelList(double init_value, std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack);
explicit KeyframeModelList(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack);
/* @brief Add a keyframable parameter to be managed by this model */
void addParameter(const QModelIndex &index, double init_value);
void addParameter(const QModelIndex &index);
/* @brief Adds a keyframe at the given position. If there is already one then we update it.
@param pos defines the position of the keyframe, relative to the clip
......@@ -108,6 +108,8 @@ public:
*/
Q_INVOKABLE bool hasKeyframe(int frame) const;
void refresh();
protected:
/** @brief Helper function to apply a given operation on all parameters */
......
......@@ -82,6 +82,7 @@ AssetParameterModel::AssetParameterModel(Mlt::Properties *asset, const QDomEleme
if (isFixed) {
m_fixedParams[name] = value;
}
qDebug() << "PARAMETER"<<name<<type<<value<<isFixed;
setParameter(name, value);
if (isFixed) {
// fixed parameters are not displayed so we don't store them.
......@@ -96,6 +97,7 @@ AssetParameterModel::AssetParameterModel(Mlt::Properties *asset, const QDomEleme
m_params[name] = currentRow;
m_rows.push_back(name);
}
qDebug() << "END parsing of "<<name<<". Number of found parameters"<<m_rows.size();
}
void AssetParameterModel::setParameter(const QString &name, const QString &value)
......
......@@ -23,6 +23,7 @@
#include "boolparamwidget.hpp"
#include "doubleparamwidget.hpp"
#include "keyframeedit.h"
#include "keyframewidget.hpp"
#include "listparamwidget.h"
#include "positioneditwidget.hpp"
......@@ -78,13 +79,16 @@ AbstractParamWidget *AbstractParamWidget::construct(const std::shared_ptr<AssetP
case ParamType::Bool:
widget = new BoolParamWidget(model, index, parent);
break;
case ParamType::KeyframeParam:
widget = new KeyframeWidget(model, index, parent);
break;
case ParamType::Geometry:
case ParamType::Animated:
case ParamType::RestrictedAnim:
case ParamType::AnimatedRect:
// widget = new AnimationWidget(model, index, range, parent);
// break;
case ParamType::KeyframeParam:
// case ParamType::KeyframeParam:
// widget = new KeyframeEdit(model, index, parent);
// break;
case ParamType::Position:
......
......@@ -20,25 +20,30 @@
#include "keyframewidget.hpp"
#include "assets/keyframes/view/keyframeview.hpp"
#include "assets/keyframes/model/keyframemodellist.hpp"
#include "assets/model/assetparametermodel.hpp"
#include "core.h"
#include "monitor/monitor.h"
#include "timecode.h"
#include "timecodedisplay.h"
#include "utils/KoIconUtils.h"
#include "core.h"
#include <QGridLayout>
#include <QToolButton>
#include <klocalizedstring.h>
KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, double init_value, const Timecode &t, int duration, QWidget *parent)
: QWidget(parent)
, m_model(model)
, m_index(index)
, m_keyframes(new KeyframeModelList(init_value, model, index, pCore->undoStack()))
KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, QWidget *parent)
: AbstractParamWidget(std::move(model), index, parent)
{
m_keyframes = std::shared_ptr<KeyframeModelList>(new KeyframeModelList(model, index, pCore->undoStack()));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
auto *l = new QGridLayout(this);
bool ok = false;
int duration = m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt(&ok);
Q_ASSERT(ok);
m_keyframeview = new KeyframeView(m_keyframes, this);
m_keyframeview->setDuration(duration);
......@@ -57,7 +62,8 @@ 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"));
m_time = new TimecodeDisplay(t, this);
m_time = new TimecodeDisplay(pCore->getMonitor(m_model->monitorId)->timecode(), this);
m_time->setRange(0, duration);
l->addWidget(m_keyframeview, 0, 0, 1, -1);
......@@ -129,3 +135,21 @@ void KeyframeWidget::slotAtKeyframe(bool atKeyframe)
m_buttonAddDelete->setToolTip(i18n("Add keyframe"));
}
}
void KeyframeWidget::slotSetRange(QPair<int, int> /*range*/)
{
bool ok = false;
int duration = m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt(&ok);
Q_ASSERT(ok);
m_keyframeview->setDuration(duration);
m_time->setRange(0, duration);
}
void KeyframeWidget::slotRefresh()
{
// update duration
slotSetRange(QPair<int,int>(-1, -1));
// refresh keyframes
m_keyframes->refresh();
}
......@@ -20,9 +20,8 @@
#ifndef KEYFRAMEWIDGET_H
#define KEYFRAMEWIDGET_H
#include "timecode.h"
#include "abstractparamwidget.hpp"
#include <QWidget>
#include <QPersistentModelIndex>
#include <memory>
......@@ -32,12 +31,12 @@ class KeyframeView;
class QToolButton;
class TimecodeDisplay;
class KeyframeWidget : public QWidget
class KeyframeWidget : public AbstractParamWidget
{
Q_OBJECT
public:
explicit KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, double init_value, const Timecode &t, int duration, QWidget *parent = nullptr);
explicit KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, QWidget *parent = nullptr);
~KeyframeWidget();
int getPosition() const;
......@@ -45,6 +44,8 @@ public:
void updateTimecodeFormat();
void slotSetRange(QPair<int, int> range) override;
void slotRefresh() override;
public slots:
void slotSetPosition(int pos = -1, bool update = true);
......@@ -55,9 +56,6 @@ signals:
void positionChanged(int pos);
private:
std::shared_ptr<AssetParameterModel> m_model;
QPersistentModelIndex m_index;
std::shared_ptr<KeyframeModelList> m_keyframes;
KeyframeView *m_keyframeview;
......
......@@ -379,23 +379,25 @@ QDomDocument KdenliveDoc::createEmptyDocument(const QList<TrackInfo> &tracks)
}
QScopedPointer<Mlt::Field> field(tractor.field());
QString compositeService = TransitionsRepository::get()->getCompositingTransition();
for (int i = 0; i <= tracks.count(); i++) {
if (i > 0) {
Mlt::Transition tr(docProfile, "mix");
tr.set("a_track", 0);
tr.set("b_track", i);
tr.set("always_active", 1);
tr.set("sum", 1);
tr.set("internal_added", 237);
field->plant_transition(tr, 0, i);
}
if (i > 0 && tracks.at(i - 1).type == VideoTrack) {
Mlt::Transition tr(docProfile, compositeService.toUtf8().constData());
tr.set("a_track", 0);
tr.set("b_track", i);
tr.set("always_active", 1);
tr.set("internal_added", 237);
field->plant_transition(tr, 0, i);
if (!compositeService.isEmpty()){
for (int i = 0; i <= tracks.count(); i++) {
if (i > 0) {
Mlt::Transition tr(docProfile, "mix");
tr.set("a_track", 0);
tr.set("b_track", i);
tr.set("always_active", 1);
tr.set("sum", 1);
tr.set("internal_added", 237);
field->plant_transition(tr, 0, i);
}
if (i > 0 && tracks.at(i - 1).type == VideoTrack) {
Mlt::Transition tr(docProfile, compositeService.toUtf8().constData());
tr.set("a_track", 0);
tr.set("b_track", i);
tr.set("always_active", 1);
tr.set("internal_added", 237);
field->plant_transition(tr, 0, i);
}
}
}
Mlt::Producer prod(tractor.get_producer());
......
......@@ -156,5 +156,6 @@ const QString TransitionsRepository::getCompositingTransition()
if (exists(QStringLiteral("composite"))) {
return QStringLiteral("composite");
}
qDebug() << "Warning: no compositing found";
return QString();
}
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