diff --git a/src/assets/keyframes/view/keyframeview.cpp b/src/assets/keyframes/view/keyframeview.cpp
index 09e2a6981..e7086e668 100644
--- a/src/assets/keyframes/view/keyframeview.cpp
+++ b/src/assets/keyframes/view/keyframeview.cpp
@@ -1,338 +1,338 @@
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* Copyright (C) 2017 by Nicolas Carion *
* 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 . *
***************************************************************************/
#include "keyframeview.hpp"
#include "assets/keyframes/model/keyframemodellist.hpp"
#include "core.h"
#include "kdenlivesettings.h"
#include
#include
#include
#include
-KeyframeView::KeyframeView(std::shared_ptr model, QWidget *parent)
+KeyframeView::KeyframeView(std::shared_ptr model, int duration, QWidget *parent)
: QWidget(parent)
, m_model(model)
- , m_duration(1)
+ , m_duration(duration)
, m_position(0)
, m_currentKeyframe(-1)
, m_currentKeyframeOriginal(-1)
, m_hoverKeyframe(-1)
, m_scale(1)
, m_currentType(KeyframeType::Linear)
{
setMouseTracking(true);
setMinimumSize(QSize(150, 20));
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum));
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
QPalette p = palette();
KColorScheme scheme(p.currentColorGroup(), KColorScheme::Window);
m_colSelected = palette().highlight().color();
m_colKeyframe = scheme.foreground(KColorScheme::NormalText).color();
m_size = QFontInfo(font()).pixelSize() * 1.8;
m_lineHeight = m_size / 2;
setMinimumHeight(m_size);
setMaximumHeight(m_size);
connect(m_model.get(), &KeyframeModelList::modelChanged, this, &KeyframeView::slotModelChanged);
}
void KeyframeView::slotModelChanged()
{
int offset = pCore->getItemIn(m_model->getOwnerId());
emit atKeyframe(m_model->hasKeyframe(m_position + offset), m_model->singleKeyframe());
emit modified();
update();
}
void KeyframeView::slotSetPosition(int pos, bool isInRange)
{
if (!isInRange) {
m_position = -1;
update();
return;
}
if (pos != m_position) {
m_position = pos;
int offset = pCore->getItemIn(m_model->getOwnerId());
emit atKeyframe(m_model->hasKeyframe(pos + offset), m_model->singleKeyframe());
update();
}
}
void KeyframeView::initKeyframePos()
{
emit atKeyframe(m_model->hasKeyframe(m_position), m_model->singleKeyframe());
}
void KeyframeView::slotAddKeyframe(int pos)
{
if (pos < 0) {
pos = m_position;
}
int offset = pCore->getItemIn(m_model->getOwnerId());
m_model->addKeyframe(GenTime(pos + offset, pCore->getCurrentFps()), m_currentType);
}
void KeyframeView::slotAddRemove()
{
int offset = pCore->getItemIn(m_model->getOwnerId());
if (m_model->hasKeyframe(m_position + offset)) {
slotRemoveKeyframe(m_position);
} else {
slotAddKeyframe(m_position);
}
}
void KeyframeView::slotEditType(int type, const QPersistentModelIndex &index)
{
int offset = pCore->getItemIn(m_model->getOwnerId());
if (m_model->hasKeyframe(m_position + offset)) {
m_model->updateKeyframeType(GenTime(m_position + offset, pCore->getCurrentFps()), type, index);
}
}
void KeyframeView::slotRemoveKeyframe(int pos)
{
if (pos < 0) {
pos = m_position;
}
int offset = pCore->getItemIn(m_model->getOwnerId());
m_model->removeKeyframe(GenTime(pos + offset, pCore->getCurrentFps()));
}
void KeyframeView::setDuration(int dur)
{
m_duration = dur;
int offset = pCore->getItemIn(m_model->getOwnerId());
emit atKeyframe(m_model->hasKeyframe(m_position + offset), m_model->singleKeyframe());
update();
}
void KeyframeView::slotGoToNext()
{
if (m_position == m_duration) {
return;
}
bool ok;
int offset = pCore->getItemIn(m_model->getOwnerId());
auto next = m_model->getNextKeyframe(GenTime(m_position + offset, pCore->getCurrentFps()), &ok);
if (ok) {
emit seekToPos(qMin(next.first.frames(pCore->getCurrentFps()) - offset, m_duration - 1));
} else {
// no keyframe after current position
emit seekToPos(m_duration - 1);
}
}
void KeyframeView::slotGoToPrev()
{
if (m_position == 0) {
return;
}
bool ok;
int offset = pCore->getItemIn(m_model->getOwnerId());
auto prev = m_model->getPrevKeyframe(GenTime(m_position + offset, pCore->getCurrentFps()), &ok);
if (ok) {
emit seekToPos(qMax(0, prev.first.frames(pCore->getCurrentFps()) - offset));
} else {
// no keyframe after current position
emit seekToPos(m_duration);
}
}
void KeyframeView::mousePressEvent(QMouseEvent *event)
{
int offset = pCore->getItemIn(m_model->getOwnerId());
int pos = event->x() / m_scale;
if (event->y() < m_lineHeight && event->button() == Qt::LeftButton) {
bool ok;
GenTime position(pos + offset, pCore->getCurrentFps());
auto keyframe = m_model->getClosestKeyframe(position, &ok);
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) < ceil(m_lineHeight / 1.5)) {
m_currentKeyframeOriginal = keyframe.first.frames(pCore->getCurrentFps()) - offset;
// Select and seek to keyframe
m_currentKeyframe = m_currentKeyframeOriginal;
emit seekToPos(m_currentKeyframeOriginal);
return;
}
}
// no keyframe next to mouse
m_currentKeyframe = m_currentKeyframeOriginal = -1;
emit seekToPos(pos);
update();
}
void KeyframeView::mouseMoveEvent(QMouseEvent *event)
{
int offset = pCore->getItemIn(m_model->getOwnerId());
int pos = qBound(0, (int)(event->x() / m_scale), m_duration);
GenTime position(pos + offset, pCore->getCurrentFps());
if ((event->buttons() & Qt::LeftButton) != 0u) {
if (m_currentKeyframe == pos) {
return;
}
if (m_currentKeyframe > 0) {
if (!m_model->hasKeyframe(pos + offset)) {
GenTime currentPos(m_currentKeyframe + offset, pCore->getCurrentFps());
if (m_model->moveKeyframe(currentPos, position, false)) {
m_currentKeyframe = pos;
}
}
}
emit seekToPos(pos);
return;
}
if (event->y() < m_lineHeight) {
bool ok;
auto keyframe = m_model->getClosestKeyframe(position, &ok);
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) < ceil(m_lineHeight / 1.5)) {
m_hoverKeyframe = keyframe.first.frames(pCore->getCurrentFps()) - offset;
setCursor(Qt::PointingHandCursor);
update();
return;
}
}
if (m_hoverKeyframe != -1) {
m_hoverKeyframe = -1;
setCursor(Qt::ArrowCursor);
update();
}
}
void KeyframeView::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event)
if (m_currentKeyframe >= 0) {
int offset = pCore->getItemIn(m_model->getOwnerId());
GenTime initPos(m_currentKeyframeOriginal + offset, pCore->getCurrentFps());
GenTime targetPos(m_currentKeyframe + offset, pCore->getCurrentFps());
bool ok1 = m_model->moveKeyframe(targetPos, initPos, false);
bool ok2 = m_model->moveKeyframe(initPos, targetPos, true);
qDebug() << "RELEASING keyframe move" << ok1 << ok2 << initPos.frames(pCore->getCurrentFps()) << targetPos.frames(pCore->getCurrentFps());
}
}
void KeyframeView::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && event->y() < m_lineHeight) {
int pos = qBound(0, (int)(event->x() / m_scale), m_duration);
int offset = pCore->getItemIn(m_model->getOwnerId());
GenTime position(pos + offset, pCore->getCurrentFps());
bool ok;
auto keyframe = m_model->getClosestKeyframe(position, &ok);
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) < ceil(m_lineHeight / 1.5)) {
m_model->removeKeyframe(keyframe.first);
if (keyframe.first.frames(pCore->getCurrentFps()) == m_currentKeyframe + offset) {
m_currentKeyframe = m_currentKeyframeOriginal = -1;
}
if (keyframe.first.frames(pCore->getCurrentFps()) == m_position + offset) {
emit atKeyframe(false, m_model->singleKeyframe());
}
return;
}
// add new keyframe
m_model->addKeyframe(position, m_currentType);
} else {
QWidget::mouseDoubleClickEvent(event);
}
}
void KeyframeView::wheelEvent(QWheelEvent *event)
{
if (event->modifiers() & Qt::AltModifier) {
if (event->delta() > 0) {
slotGoToPrev();
} else {
slotGoToNext();
}
return;
}
int change = event->delta() > 0 ? -1 : 1;
int pos = qBound(0, m_position + change, m_duration);
emit seekToPos(pos);
}
void KeyframeView::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QStylePainter p(this);
m_scale = width() / (double)(m_duration);
// p.translate(0, m_lineHeight);
int headOffset = m_lineHeight / 1.5;
int offset = pCore->getItemIn(m_model->getOwnerId());
/*
* keyframes
*/
for (const auto &keyframe : *m_model.get()) {
int pos = keyframe.first.frames(pCore->getCurrentFps()) - offset;
if (pos == m_currentKeyframe || pos == m_hoverKeyframe) {
p.setBrush(m_colSelected);
} else {
p.setBrush(m_colKeyframe);
}
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());
/*
* Time-"line"
*/
p.setPen(m_colKeyframe);
p.drawLine(0, m_lineHeight + (headOffset / 2), (m_duration - 1) * m_scale, m_lineHeight + (headOffset / 2));
/*
* current position
*/
if (m_position >= 0) {
QPolygon pa(3);
int cursorwidth = (m_size - (m_lineHeight + headOffset / 2)) / 2 + 1;
QPolygonF position = QPolygonF() << QPointF(-cursorwidth, m_size) << QPointF(cursorwidth, m_size) << QPointF(0, m_lineHeight + (headOffset / 2) + 1);
position.translate(m_position * m_scale, 0);
p.setBrush(m_colKeyframe);
p.drawPolygon(position);
}
}
diff --git a/src/assets/keyframes/view/keyframeview.hpp b/src/assets/keyframes/view/keyframeview.hpp
index 37e79d462..c51113f0f 100644
--- a/src/assets/keyframes/view/keyframeview.hpp
+++ b/src/assets/keyframes/view/keyframeview.hpp
@@ -1,90 +1,90 @@
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* Copyright (C) 2017 by Nicolas Carion *
* 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 . *
***************************************************************************/
#ifndef KEYFRAMEVIEW2_H
#define KEYFRAMEVIEW2_H
#include "assets/keyframes/model/keyframemodel.hpp"
#include "assets/keyframes/model/keyframemodellist.hpp"
#include
#include
class KeyframeModelList;
class KeyframeView : public QWidget
{
Q_OBJECT
public:
- explicit KeyframeView(std::shared_ptr model, QWidget *parent = nullptr);
+ explicit KeyframeView(std::shared_ptr model, int duration, QWidget *parent = nullptr);
void setDuration(int dur);
public slots:
/* @brief moves the current position*/
void slotSetPosition(int pos, bool isInRange);
/* @brief remove the keyframe at given position
If pos is negative, we remove keyframe at current position
*/
void slotRemoveKeyframe(int pos);
/* @brief Add a keyframe with given parameter value at given pos.
If pos is negative, then keyframe is added at current position
*/
void slotAddKeyframe(int pos = -1);
/* @brief If there is a keyframe at current position, it is removed.
Otherwise, we add a new one with given value.
*/
void slotAddRemove();
void slotGoToNext();
void slotGoToPrev();
void slotModelChanged();
void slotEditType(int type, const QPersistentModelIndex &index);
/* @brief Emit initial info for monitor. */
void initKeyframePos();
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
private:
std::shared_ptr m_model;
int m_duration;
int m_position;
int m_currentKeyframe;
int m_currentKeyframeOriginal;
int m_hoverKeyframe;
int m_lineHeight;
double m_scale;
int m_size;
KeyframeType m_currentType;
QColor m_colSelected;
QColor m_colKeyframe;
QColor m_colKeyframeBg;
signals:
void seekToPos(int pos);
void atKeyframe(bool isKeyframe, bool singleKeyframe);
void modified();
};
#endif
diff --git a/src/assets/view/widgets/keyframewidget.cpp b/src/assets/view/widgets/keyframewidget.cpp
index 303539804..741df2bcc 100644
--- a/src/assets/view/widgets/keyframewidget.cpp
+++ b/src/assets/view/widgets/keyframewidget.cpp
@@ -1,481 +1,481 @@
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* Copyright (C) 2017 by Nicolas Carion *
* 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 . *
***************************************************************************/
#include "keyframewidget.hpp"
#include "assets/keyframes/model/keyframemodellist.hpp"
#include "assets/keyframes/model/rotoscoping/rotohelper.hpp"
#include "assets/keyframes/model/corners/cornershelper.hpp"
#include "assets/keyframes/view/keyframeview.hpp"
#include "assets/model/assetparametermodel.hpp"
#include "assets/model/assetcommand.hpp"
#include "assets/view/widgets/keyframeimport.h"
#include "core.h"
#include "monitor/monitor.h"
#include "timecode.h"
#include "timecodedisplay.h"
#include "widgets/doublewidget.h"
#include "widgets/geometrywidget.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
KeyframeWidget::KeyframeWidget(std::shared_ptr model, QModelIndex index, QWidget *parent)
: AbstractParamWidget(model, index, parent)
- , m_keyframes(model->getKeyframeModel())
, m_monitorHelper(nullptr)
, m_neededScene(MonitorSceneType::MonitorSceneDefault)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_lay = new QVBoxLayout(this);
m_lay->setContentsMargins(2, 2, 2, 0);
m_lay->setSpacing(0);
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);
+ m_model->prepareKeyframes();
+ m_keyframes = m_model->getKeyframeModel();
+ m_keyframeview = new KeyframeView(m_keyframes, duration, this);
m_buttonAddDelete = new QToolButton(this);
m_buttonAddDelete->setAutoRaise(true);
m_buttonAddDelete->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
m_buttonAddDelete->setToolTip(i18n("Add keyframe"));
m_buttonPrevious = new QToolButton(this);
m_buttonPrevious->setAutoRaise(true);
m_buttonPrevious->setIcon(QIcon::fromTheme(QStringLiteral("media-skip-backward")));
m_buttonPrevious->setToolTip(i18n("Go to previous keyframe"));
m_buttonNext = new QToolButton(this);
m_buttonNext->setAutoRaise(true);
m_buttonNext->setIcon(QIcon::fromTheme(QStringLiteral("media-skip-forward")));
m_buttonNext->setToolTip(i18n("Go to next keyframe"));
// Keyframe type widget
m_selectType = new KSelectAction(QIcon::fromTheme(QStringLiteral("keyframes")), i18n("Keyframe interpolation"), this);
QAction *linear = new QAction(QIcon::fromTheme(QStringLiteral("linear")), i18n("Linear"), this);
linear->setData((int)mlt_keyframe_linear);
linear->setCheckable(true);
m_selectType->addAction(linear);
QAction *discrete = new QAction(QIcon::fromTheme(QStringLiteral("discrete")), i18n("Discrete"), this);
discrete->setData((int)mlt_keyframe_discrete);
discrete->setCheckable(true);
m_selectType->addAction(discrete);
QAction *curve = new QAction(QIcon::fromTheme(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, static_cast(&KSelectAction::triggered), this, &KeyframeWidget::slotEditKeyframeType);
m_selectType->setToolBarMode(KSelectAction::ComboBoxMode);
m_toolbar = new QToolBar(this);
Monitor *monitor = pCore->getMonitor(m_model->monitorId);
m_time = new TimecodeDisplay(monitor->timecode(), this);
m_time->setRange(0, duration - 1);
m_toolbar->addWidget(m_buttonPrevious);
m_toolbar->addWidget(m_buttonAddDelete);
m_toolbar->addWidget(m_buttonNext);
m_toolbar->addAction(m_selectType);
// copy/paste keyframes from clipboard
QAction *copy = new QAction(i18n("Copy keyframes to clipboard"), this);
connect(copy, &QAction::triggered, this, &KeyframeWidget::slotCopyKeyframes);
QAction *paste = new QAction(i18n("Import keyframes from clipboard"), this);
connect(paste, &QAction::triggered, this, &KeyframeWidget::slotImportKeyframes);
auto *container = new QMenu(this);
container->addAction(copy);
container->addAction(paste);
// Menu toolbutton
auto *menuButton = new QToolButton(this);
menuButton->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-menu")));
menuButton->setToolTip(i18n("Options"));
menuButton->setMenu(container);
menuButton->setPopupMode(QToolButton::InstantPopup);
m_toolbar->addWidget(menuButton);
m_toolbar->addWidget(m_time);
m_lay->addWidget(m_keyframeview);
m_lay->addWidget(m_toolbar);
// slotSetPosition(0, false);
monitorSeek(monitor->position());
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);
connect(monitor, &Monitor::seekToNextKeyframe, m_keyframeview, &KeyframeView::slotGoToNext, Qt::UniqueConnection);
connect(monitor, &Monitor::seekToPreviousKeyframe, m_keyframeview, &KeyframeView::slotGoToPrev, Qt::UniqueConnection);
connect(monitor, &Monitor::addRemoveKeyframe, m_keyframeview, &KeyframeView::slotAddRemove, Qt::UniqueConnection);
}
KeyframeWidget::~KeyframeWidget()
{
delete m_keyframeview;
delete m_buttonAddDelete;
delete m_buttonPrevious;
delete m_buttonNext;
delete m_time;
}
void KeyframeWidget::monitorSeek(int pos)
{
int in = pCore->getItemPosition(m_model->getOwnerId());
int out = in + pCore->getItemDuration(m_model->getOwnerId());
bool isInRange = pos >= in && pos < out;
m_buttonAddDelete->setEnabled(isInRange);
connectMonitor(isInRange);
int framePos = qBound(in, pos, out) - in;
if (isInRange && framePos != m_time->getValue()) {
slotSetPosition(framePos, false);
}
}
void KeyframeWidget::slotEditKeyframeType(QAction *action)
{
int type = action->data().toInt();
m_keyframeview->slotEditType(type, m_index);
}
void KeyframeWidget::slotRefreshParams()
{
int pos = getPosition();
KeyframeType keyType = m_keyframes->keyframeType(GenTime(pos, pCore->getCurrentFps()));
m_selectType->setCurrentItem((int)keyType);
for (const auto &w : m_parameters) {
ParamType type = m_model->data(w.first, AssetParameterModel::TypeRole).value();
if (type == ParamType::KeyframeParam) {
((DoubleWidget *)w.second)->setValue(m_keyframes->getInterpolatedValue(pos, w.first).toDouble());
} else if (type == ParamType::AnimatedRect) {
const QString val = m_keyframes->getInterpolatedValue(pos, w.first).toString();
const QStringList vals = val.split(QLatin1Char(' '));
QRect rect;
double opacity = -1;
if (vals.count() >= 4) {
rect = QRect(vals.at(0).toInt(), vals.at(1).toInt(), vals.at(2).toInt(), vals.at(3).toInt());
if (vals.count() > 4) {
QLocale locale;
opacity = locale.toDouble(vals.at(4));
}
}
((GeometryWidget *)w.second)->setValue(rect, opacity);
}
}
if (m_monitorHelper) {
m_monitorHelper->refreshParams(pos);
return;
}
}
void KeyframeWidget::slotSetPosition(int pos, bool update)
{
if (pos < 0) {
pos = m_time->getValue();
m_keyframeview->slotSetPosition(pos, true);
} else {
m_time->setValue(pos);
m_keyframeview->slotSetPosition(pos, true);
}
m_buttonAddDelete->setEnabled(pos > 0);
slotRefreshParams();
if (update) {
emit seekToPos(pos);
}
}
int KeyframeWidget::getPosition() const
{
return m_time->getValue() + pCore->getItemIn(m_model->getOwnerId());
}
void KeyframeWidget::addKeyframe(int pos)
{
blockSignals(true);
m_keyframeview->slotAddKeyframe(pos);
blockSignals(false);
setEnabled(true);
}
void KeyframeWidget::updateTimecodeFormat()
{
m_time->slotUpdateTimeCodeFormat();
}
void KeyframeWidget::slotAtKeyframe(bool atKeyframe, bool singleKeyframe)
{
if (atKeyframe) {
m_buttonAddDelete->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
m_buttonAddDelete->setToolTip(i18n("Delete keyframe"));
} else {
m_buttonAddDelete->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
m_buttonAddDelete->setToolTip(i18n("Add keyframe"));
}
pCore->getMonitor(m_model->monitorId)->setEffectKeyframe(atKeyframe || singleKeyframe);
m_selectType->setEnabled(atKeyframe || singleKeyframe);
for (const auto &w : m_parameters) {
w.second->setEnabled(atKeyframe || singleKeyframe);
}
}
void KeyframeWidget::slotRefresh()
{
// update duration
bool ok = false;
int duration = m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt(&ok);
Q_ASSERT(ok);
// refresh keyframes
m_keyframes->refresh();
//m_model->dataChanged(QModelIndex(), QModelIndex());
//->getKeyframeModel()->getKeyModel(m_index)->dataChanged(QModelIndex(), QModelIndex());
m_keyframeview->setDuration(duration);
m_time->setRange(0, duration - 1);
slotRefreshParams();
}
void KeyframeWidget::resetKeyframes()
{
// update duration
bool ok = false;
int duration = m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt(&ok);
Q_ASSERT(ok);
// reset keyframes
m_keyframes->reset();
//m_model->dataChanged(QModelIndex(), QModelIndex());
m_keyframeview->setDuration(duration);
m_time->setRange(0, duration - 1);
slotRefreshParams();
}
void KeyframeWidget::addParameter(const QPersistentModelIndex &index)
{
QLocale locale;
locale.setNumberOptions(QLocale::OmitGroupSeparator);
// Retrieve parameters from the model
QString name = m_model->data(index, Qt::DisplayRole).toString();
QString comment = m_model->data(index, AssetParameterModel::CommentRole).toString();
QString suffix = m_model->data(index, AssetParameterModel::SuffixRole).toString();
ParamType type = m_model->data(index, AssetParameterModel::TypeRole).value();
// Construct object
QWidget *paramWidget = nullptr;
if (type == ParamType::AnimatedRect) {
m_neededScene = MonitorSceneType::MonitorSceneGeometry;
int inPos = m_model->data(index, AssetParameterModel::ParentInRole).toInt();
QPair range(inPos, inPos + m_model->data(index, AssetParameterModel::ParentDurationRole).toInt());
QSize frameSize = pCore->getCurrentFrameSize();
const QString value = m_keyframes->getInterpolatedValue(getPosition(), index).toString();
QRect rect;
double opacity = 0;
QStringList vals = value.split(QLatin1Char(' '));
if (vals.count() >= 4) {
rect = QRect(vals.at(0).toInt(), vals.at(1).toInt(), vals.at(2).toInt(), vals.at(3).toInt());
if (vals.count() > 4) {
opacity = locale.toDouble(vals.at(4));
}
}
// qtblend uses an opacity value in the (0-1) range, while older geometry effects use (0-100)
bool integerOpacity = m_model->getAssetId() != QLatin1String("qtblend");
GeometryWidget *geomWidget = new GeometryWidget(pCore->getMonitor(m_model->monitorId), range, rect, opacity, frameSize, false,
m_model->data(m_index, AssetParameterModel::OpacityRole).toBool(), integerOpacity, this);
connect(geomWidget, &GeometryWidget::valueChanged,
[this, index](const QString v) { m_keyframes->updateKeyframe(GenTime(getPosition(), pCore->getCurrentFps()), QVariant(v), index); });
paramWidget = geomWidget;
} else if (type == ParamType::Roto_spline) {
m_monitorHelper = new RotoHelper(pCore->getMonitor(m_model->monitorId), m_model, index, this);
connect(m_monitorHelper, &KeyframeMonitorHelper::updateKeyframeData, this, &KeyframeWidget::slotUpdateKeyframesFromMonitor, Qt::UniqueConnection);
m_neededScene = MonitorSceneType::MonitorSceneRoto;
} else {
if (m_model->getAssetId() == QLatin1String("frei0r.c0rners")) {
if (m_neededScene == MonitorSceneDefault && !m_monitorHelper) {
m_neededScene = MonitorSceneType::MonitorSceneCorners;
m_monitorHelper = new CornersHelper(pCore->getMonitor(m_model->monitorId), m_model, index, this);
connect(m_monitorHelper, &KeyframeMonitorHelper::updateKeyframeData, this, &KeyframeWidget::slotUpdateKeyframesFromMonitor, Qt::UniqueConnection);
connect(this, &KeyframeWidget::addIndex, m_monitorHelper, &CornersHelper::addIndex);
} else {
if (type == ParamType::KeyframeParam) {
int paramName = m_model->data(index, AssetParameterModel::NameRole).toInt();
if (paramName < 8) {
emit addIndex(index);
}
}
}
}
double value = m_keyframes->getInterpolatedValue(getPosition(), index).toDouble();
double min = locale.toDouble(m_model->data(index, AssetParameterModel::MinRole).toString());
double max = locale.toDouble(m_model->data(index, AssetParameterModel::MaxRole).toString());
double defaultValue = m_model->data(index, AssetParameterModel::DefaultRole).toDouble();
int decimals = m_model->data(index, AssetParameterModel::DecimalsRole).toInt();
double factor = locale.toDouble(m_model->data(index, AssetParameterModel::FactorRole).toString());
factor = qFuzzyIsNull(factor) ? 1 : factor;
auto doubleWidget = new DoubleWidget(name, value * factor, min, max, factor, defaultValue, comment, -1, suffix, decimals, this);
connect(doubleWidget, &DoubleWidget::valueChanged,
[this, index](double v) { m_keyframes->updateKeyframe(GenTime(getPosition(), pCore->getCurrentFps()), QVariant(v), index); });
paramWidget = doubleWidget;
}
if (paramWidget) {
m_parameters[index] = paramWidget;
m_lay->addWidget(paramWidget);
}
}
void KeyframeWidget::slotInitMonitor(bool active)
{
if (m_keyframeview) {
m_keyframeview->initKeyframePos();
}
Monitor *monitor = pCore->getMonitor(m_model->monitorId);
connectMonitor(active);
if (active) {
connect(monitor, &Monitor::seekPosition, this, &KeyframeWidget::monitorSeek, Qt::UniqueConnection);
} else {
disconnect(monitor, &Monitor::seekPosition, this, &KeyframeWidget::monitorSeek);
}
}
void KeyframeWidget::connectMonitor(bool active)
{
if (m_monitorHelper) {
if (m_monitorHelper->connectMonitor(active)) {
slotRefreshParams();
}
}
for (const auto &w : m_parameters) {
ParamType type = m_model->data(w.first, AssetParameterModel::TypeRole).value();
if (type == ParamType::AnimatedRect) {
((GeometryWidget *)w.second)->connectMonitor(active);
break;
}
}
}
void KeyframeWidget::slotUpdateKeyframesFromMonitor(QPersistentModelIndex index, const QVariant &res)
{
if (m_keyframes->isEmpty()) {
m_keyframes->addKeyframe(GenTime(getPosition(), pCore->getCurrentFps()), KeyframeType::Linear);
m_keyframes->updateKeyframe(GenTime(getPosition(), pCore->getCurrentFps()), res, index);
} else if (m_keyframes->hasKeyframe(getPosition()) || m_keyframes->singleKeyframe()) {
m_keyframes->updateKeyframe(GenTime(getPosition(), pCore->getCurrentFps()), res, index);
}
}
MonitorSceneType KeyframeWidget::requiredScene() const
{
qDebug()<<"// // // RESULTING REQUIRED SCENE: "<isVisible();
}
void KeyframeWidget::showKeyframes(bool enable)
{
m_toolbar->setVisible(enable);
m_keyframeview->setVisible(enable);
}
void KeyframeWidget::slotCopyKeyframes()
{
QJsonArray list;
for (const auto &w : m_parameters) {
int type = m_model->data(w.first, AssetParameterModel::TypeRole).toInt();
QString name = m_model->data(w.first, Qt::DisplayRole).toString();
QString value = m_model->data(w.first, AssetParameterModel::ValueRole).toString();
double min = m_model->data(w.first, AssetParameterModel::MinRole).toDouble();
double max = m_model->data(w.first, AssetParameterModel::MaxRole).toDouble();
double factor = m_model->data(w.first, AssetParameterModel::FactorRole).toDouble();
if (factor > 0) {
min /= factor;
max /= factor;
}
QJsonObject currentParam;
currentParam.insert(QLatin1String("name"), QJsonValue(name));
currentParam.insert(QLatin1String("value"), QJsonValue(value));
currentParam.insert(QLatin1String("type"), QJsonValue(type));
currentParam.insert(QLatin1String("min"), QJsonValue(min));
currentParam.insert(QLatin1String("max"), QJsonValue(max));
list.push_back(currentParam);
}
if (list.isEmpty()) {
return;
}
QClipboard *clipboard = QApplication::clipboard();
QJsonDocument json(list);
clipboard->setText(QString(json.toJson()));
}
void KeyframeWidget::slotImportKeyframes()
{
QClipboard *clipboard = QApplication::clipboard();
QString values = clipboard->text();
int inPos = m_model->data(m_index, AssetParameterModel::ParentInRole).toInt();
int outPos = inPos + m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt();
QList indexes;
for (const auto &w : m_parameters) {
indexes << w.first;
}
QPointerimport = new KeyframeImport(inPos, outPos, values, m_model, indexes, this);
if (import->exec() != QDialog::Accepted) {
delete import;
return;
}
QString keyframeData = import->selectedData();
QString tag = import->selectedTarget();
qDebug()<<"// CHECKING FOR TARGET PARAM: "<setParameter(tag, keyframeData, true);
/*for (const auto &w : m_parameters) {
qDebug()<<"// GOT PARAM: "<data(w.first, AssetParameterModel::NameRole).toString();
if (tag == m_model->data(w.first, AssetParameterModel::NameRole).toString()) {
qDebug()<<"// PASSING DTAT: "<getKeyframeModel()->getKeyModel()->parseAnimProperty(keyframeData);
m_model->getKeyframeModel()->getKeyModel()->modelChanged();
break;
}
}*/
AssetCommand *command = new AssetCommand(m_model, m_index, keyframeData);
pCore->pushUndo(command);
/*m_model->getKeyframeModel()->getKeyModel()->dataChanged(QModelIndex(), QModelIndex());
m_model->modelChanged();
qDebug()<<"//// UPDATING KEYFRAMES CORE---------";
pCore->updateItemKeyframes(m_model->getOwnerId());*/
qDebug()<<"//// UPDATING KEYFRAMES CORE . .. .DONE ---------";
//emit importKeyframes(type, tag, keyframeData);
delete import;
}