Commit cb49900d authored by Nicolas Carion's avatar Nicolas Carion
Browse files

Display and allow edit of keyframable parameters

parent 3c98024b
......@@ -182,11 +182,11 @@ bool KeyframeModel::updateKeyframe(GenTime pos, double value, Fun &undo, Fun &re
{
QWriteLocker locker(&m_lock);
Q_ASSERT(m_keyframeList.count(pos) > 0);
KeyframeType oldType = m_keyframeList[pos].first;
KeyframeType type = m_keyframeList[pos].first;
double oldValue = m_keyframeList[pos].second;
if (qAbs(oldValue - value) < 1e-6) return true;
auto operation = updateKeyframe_lambda(pos, oldType, oldValue, true);
auto reverse = updateKeyframe_lambda(pos, oldType, value, true);
auto operation = updateKeyframe_lambda(pos, type, value, true);
auto reverse = updateKeyframe_lambda(pos, type, oldValue, true);
bool res = operation();
if (res) {
UPDATE_UNDO_REDO(operation, reverse, undo, redo);
......
......@@ -111,14 +111,17 @@ bool KeyframeModelList::moveKeyframe(GenTime oldPos, GenTime pos, bool logUndo)
return applyOperation(op, logUndo ? i18n("Move keyframe") : QString());
}
bool KeyframeModelList::updateKeyframe(GenTime pos, double value)
bool KeyframeModelList::updateKeyframe(GenTime pos, double value, const QPersistentModelIndex &index)
{
QWriteLocker locker(&m_lock);
Q_ASSERT(m_parameters.size() > 0);
auto op = [value, pos](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo){
return param->updateKeyframe(pos, value, undo, redo);
};
return applyOperation(op, i18n("Update keyframe"));
Q_ASSERT(m_parameters.count(index) > 0);
Fun undo = []() { return true; };
Fun redo = []() { return true; };
bool res = m_parameters.at(index)->updateKeyframe(pos, value, undo, redo);
if (res) {
PUSH_UNDO(undo, redo, i18n("Update keyframe"));
}
return res;
}
......@@ -160,7 +163,15 @@ bool KeyframeModelList::hasKeyframe(int frame) const
void KeyframeModelList::refresh()
{
QWriteLocker locker(&m_lock);
for (const auto& param : m_parameters) {
param.second->refresh();
}
}
double KeyframeModelList::getInterpolatedValue(int pos, const QPersistentModelIndex& index) const
{
READ_LOCK();
Q_ASSERT(m_parameters.count(index) > 0);
return m_parameters.at(index)->getInterpolatedValue(pos);
}
......@@ -78,8 +78,9 @@ public:
/* @brief updates the value of a keyframe
@param old is the position of the keyframe
@param value is the new value of the param
@param index is the index of the wanted keyframe
*/
bool updateKeyframe(GenTime pos, double value);
bool updateKeyframe(GenTime pos, double value, const QPersistentModelIndex &index);
/* @brief Returns a keyframe data at given pos
ok is a return parameter, set to true if everything went good
......@@ -108,6 +109,11 @@ public:
*/
Q_INVOKABLE bool hasKeyframe(int frame) const;
/* @brief Return the interpolated value of a parameter.
@param pos is the position where we interpolate
@param index is the index of the queried parameter. */
double getInterpolatedValue(int pos, const QPersistentModelIndex& index) const;
void refresh();
protected:
......
......@@ -57,6 +57,7 @@ KeyframeView::KeyframeView(std::shared_ptr<KeyframeModelList> model, QWidget *pa
void KeyframeView::slotModelChanged()
{
emit atKeyframe(m_model->hasKeyframe(m_position));
emit modified();
update();
}
void KeyframeView::slotSetPosition(int pos)
......
......@@ -81,6 +81,7 @@ private:
signals:
void seekToPos(int pos);
void atKeyframe(bool);
void modified();
};
#endif
......@@ -26,6 +26,7 @@
#include "timecode.h"
#include "timecodedisplay.h"
#include "utils/KoIconUtils.h"
#include "widgets/doublewidget.h"
#include <QGridLayout>
#include <QToolButton>
......@@ -39,7 +40,7 @@ KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QMode
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
auto *l = new QGridLayout(this);
m_lay = new QGridLayout(this);
bool ok = false;
int duration = m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt(&ok);
......@@ -66,20 +67,23 @@ KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QMode
m_time = new TimecodeDisplay(pCore->getMonitor(m_model->monitorId)->timecode(), this);
m_time->setRange(0, duration);
l->addWidget(m_keyframeview, 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);
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);
slotSetPosition(0, false);
connect(m_time, &TimecodeDisplay::timeCodeEditingFinished, [&](){slotSetPosition(-1, true);});
connect(m_keyframeview, &KeyframeView::seekToPos, [&](int p){slotSetPosition(p, true);});
connect(m_keyframeview, &KeyframeView::atKeyframe, this, &KeyframeWidget::slotAtKeyframe);
connect(m_keyframeview, &KeyframeView::modified, this, &KeyframeWidget::slotRefreshParams);
connect(m_buttonAddDelete, &QAbstractButton::pressed, m_keyframeview, &KeyframeView::slotAddRemove);
connect(m_buttonPrevious, &QAbstractButton::pressed, m_keyframeview, &KeyframeView::slotGoToPrev);
connect(m_buttonNext, &QAbstractButton::pressed, m_keyframeview, &KeyframeView::slotGoToNext);
addParameter(index);
}
KeyframeWidget::~KeyframeWidget()
......@@ -91,6 +95,13 @@ KeyframeWidget::~KeyframeWidget()
delete m_time;
}
void KeyframeWidget::slotRefreshParams()
{
int pos = getPosition();
for (const auto & w : m_parameters) {
w.second->setValue(m_keyframes->getInterpolatedValue(pos, w.first));
}
}
void KeyframeWidget::slotSetPosition(int pos, bool update)
{
if (pos < 0) {
......@@ -101,6 +112,8 @@ void KeyframeWidget::slotSetPosition(int pos, bool update)
m_keyframeview->slotSetPosition(pos);
}
slotRefreshParams();
if (update) {
emit seekToPos(pos);
}
......@@ -134,6 +147,9 @@ void KeyframeWidget::slotAtKeyframe(bool atKeyframe)
m_buttonAddDelete->setIcon(KoIconUtils::themedIcon(QStringLiteral("list-add")));
m_buttonAddDelete->setToolTip(i18n("Add keyframe"));
}
for (const auto &w : m_parameters) {
w.second->setEnabled(atKeyframe);
}
}
void KeyframeWidget::slotSetRange(QPair<int, int> /*range*/)
......@@ -153,3 +169,29 @@ void KeyframeWidget::slotRefresh()
// refresh keyframes
m_keyframes->refresh();
}
void KeyframeWidget::addParameter(const QPersistentModelIndex& index)
{
QLocale locale;
locale.setNumberOptions(QLocale::OmitGroupSeparator);
// Retrieve parameters from the model
QString name = m_model->data(m_index, Qt::DisplayRole).toString();
double value = m_keyframes->getInterpolatedValue(getPosition(), index);
double min = m_model->data(m_index, AssetParameterModel::MinRole).toDouble();
double max = m_model->data(m_index, AssetParameterModel::MaxRole).toDouble();
double defaultValue = locale.toDouble(m_model->data(m_index, AssetParameterModel::DefaultRole).toString());
QString comment = m_model->data(m_index, AssetParameterModel::CommentRole).toString();
QString suffix = m_model->data(m_index, AssetParameterModel::SuffixRole).toString();
int decimals = m_model->data(m_index, AssetParameterModel::DecimalsRole).toInt();
double factor = m_model->data(m_index, AssetParameterModel::FactorRole).toDouble();
// Construct object
auto doubleWidget = new DoubleWidget(name, value, min, max, defaultValue, comment, -1, suffix, decimals, this);
doubleWidget->factor = factor;
m_parameters[index] = doubleWidget;
m_lay->addWidget(doubleWidget, 1 + (int)m_parameters.size(), 0, 1, -1);
connect(doubleWidget, &DoubleWidget::valueChanged, [this, index](double v){
m_keyframes->updateKeyframe(GenTime(getPosition(), pCore->getCurrentFps()), v, index);
});
}
......@@ -24,10 +24,14 @@
#include <QPersistentModelIndex>
#include <memory>
#include <unordered_map>
#include "definitions.h"
class AssetParameterModel;
class KeyframeModelList;
class DoubleWidget;
class KeyframeView;
class KeyframeModelList;
class QGridLayout;
class QToolButton;
class TimecodeDisplay;
......@@ -39,6 +43,8 @@ public:
explicit KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, QWidget *parent = nullptr);
~KeyframeWidget();
/* @brief Add a new parameter to be managed using the same keyframe viewer */
void addParameter(const QPersistentModelIndex& index);
int getPosition() const;
void addKeyframe(int pos = -1);
......@@ -50,9 +56,12 @@ public slots:
void slotSetPosition(int pos = -1, bool update = true);
private slots:
/* brief Update the value of the widgets to reflect keyframe change */
void slotRefreshParams();
void slotAtKeyframe(bool atKeyframe);
private:
QGridLayout *m_lay;
std::shared_ptr<KeyframeModelList> m_keyframes;
KeyframeView *m_keyframeview;
......@@ -60,6 +69,8 @@ private:
QToolButton *m_buttonPrevious;
QToolButton *m_buttonNext;
TimecodeDisplay *m_time;
std::unordered_map<QPersistentModelIndex, DoubleWidget*> m_parameters;
};
#endif
......@@ -80,6 +80,9 @@ private:
signals:
void valueChanged(double);
// same signal as valueChanged, but add an extra boolean to tell if user is dragging value or not
void valueChanging(double, bool);
};
#endif
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