diff --git a/src/assets/CMakeLists.txt b/src/assets/CMakeLists.txt index aeb6b162b..045a60567 100644 --- a/src/assets/CMakeLists.txt +++ b/src/assets/CMakeLists.txt @@ -1,20 +1,23 @@ set(kdenlive_SRCS ${kdenlive_SRCS} assets/assetlist/view/qmltypes/asseticonprovider.cpp assets/assetlist/view/assetlistwidget.cpp assets/assetlist/model/assetfilter.cpp assets/assetlist/model/assettreemodel.cpp assets/assetpanel.cpp + assets/keyframes/model/keyframemodel.cpp + assets/keyframes/model/keyframemodellist.cpp + assets/keyframes/view/keyframeview.cpp assets/model/assetparametermodel.cpp assets/model/assetcommand.cpp assets/view/assetparameterview.cpp assets/view/widgets/abstractparamwidget.cpp #assets/view/widgets/animationwidget.cpp assets/view/widgets/boolparamwidget.cpp assets/view/widgets/doubleparamwidget.cpp # assets/view/widgets/keyframeedit.cpp assets/view/widgets/keyframewidget.cpp assets/view/widgets/listparamwidget.cpp # assets/view/widgets/positioneditwidget.cpp PARENT_SCOPE) diff --git a/src/effects/keyframes/keyframemodel.cpp b/src/assets/keyframes/model/keyframemodel.cpp similarity index 100% rename from src/effects/keyframes/keyframemodel.cpp rename to src/assets/keyframes/model/keyframemodel.cpp diff --git a/src/effects/keyframes/keyframemodel.hpp b/src/assets/keyframes/model/keyframemodel.hpp similarity index 100% rename from src/effects/keyframes/keyframemodel.hpp rename to src/assets/keyframes/model/keyframemodel.hpp diff --git a/src/effects/keyframes/keyframemodellist.cpp b/src/assets/keyframes/model/keyframemodellist.cpp similarity index 100% rename from src/effects/keyframes/keyframemodellist.cpp rename to src/assets/keyframes/model/keyframemodellist.cpp diff --git a/src/effects/keyframes/keyframemodellist.hpp b/src/assets/keyframes/model/keyframemodellist.hpp similarity index 100% rename from src/effects/keyframes/keyframemodellist.hpp rename to src/assets/keyframes/model/keyframemodellist.hpp diff --git a/src/effects/keyframes/view/keyframeview.cpp b/src/assets/keyframes/view/keyframeview.cpp similarity index 99% rename from src/effects/keyframes/view/keyframeview.cpp rename to src/assets/keyframes/view/keyframeview.cpp index 5d4766ddc..f4acdb092 100644 --- a/src/effects/keyframes/view/keyframeview.cpp +++ b/src/assets/keyframes/view/keyframeview.cpp @@ -1,279 +1,280 @@ /*************************************************************************** * 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) : QWidget(parent) , m_model(model) , m_duration(1) , 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, KSharedConfig::openConfig(KdenliveSettings::colortheme())); 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, [&](){ emit atKeyframe(m_model->hasKeyframe(m_position)); update(); }); } void KeyframeView::slotSetPosition(int pos) { if (pos != m_position) { m_position = pos; emit atKeyframe(m_model->hasKeyframe(pos)); emit positionChanged(pos); update(); } } void KeyframeView::slotAddKeyframe(int pos) { if (pos < 0) { pos = m_position; } m_model->addKeyframe(GenTime(pos, pCore->getCurrentFps()), m_currentType); } void KeyframeView::slotAddRemove() { if (m_model->hasKeyframe(m_position)) { slotRemoveKeyframe(m_position); } else { slotAddKeyframe(m_position); } } void KeyframeView::slotRemoveKeyframe(int pos) { if (pos < 0) { pos = m_position; } m_model->removeKeyframe(GenTime(pos, pCore->getCurrentFps())); } void KeyframeView::setDuration(int dur) { m_duration = dur; } void KeyframeView::slotGoToNext() { if (m_position == m_duration) { return; } bool ok; auto next = m_model->getNextKeyframe(GenTime(m_position, pCore->getCurrentFps()), &ok); if (ok) { slotSetPosition(next.first.frames(pCore->getCurrentFps())); } else { // no keyframe after current position slotSetPosition(m_duration); } } void KeyframeView::slotGoToPrev() { if (m_position == 0) { return; } bool ok; auto prev = m_model->getPrevKeyframe(GenTime(m_position, pCore->getCurrentFps()), &ok); if (ok) { slotSetPosition(prev.first.frames(pCore->getCurrentFps())); } else { // no keyframe after current position slotSetPosition(m_duration); } } void KeyframeView::mousePressEvent(QMouseEvent *event) { int pos = event->x() / m_scale; if (event->y() < m_lineHeight && event->button() == Qt::LeftButton) { bool ok; GenTime position(pos, pCore->getCurrentFps()); auto keyframe = m_model->getClosestKeyframe(position, &ok); if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos) < 5) { m_currentKeyframeOriginal = keyframe.first.frames(pCore->getCurrentFps()); if (m_model->moveKeyframe(keyframe.first, position, false)) { m_currentKeyframe = pos; slotSetPosition(pos); return; } } } // no keyframe next to mouse m_currentKeyframe = m_currentKeyframeOriginal = -1; slotSetPosition(pos); update(); } void KeyframeView::mouseMoveEvent(QMouseEvent *event) { int pos = qBound(0, (int)(event->x() / m_scale), m_duration); GenTime position(pos, pCore->getCurrentFps()); if ((event->buttons() & Qt::LeftButton) != 0u) { if (m_currentKeyframe >= 0) { if (!m_model->hasKeyframe(pos)) { // snap to position cursor if (KdenliveSettings::snaptopoints() && qAbs(pos - m_position) < 5 && !m_model->hasKeyframe(m_position)) { pos = m_position; } GenTime currentPos(m_currentKeyframe, pCore->getCurrentFps()); if (m_model->moveKeyframe(currentPos, position, false)) { m_currentKeyframe = pos; } } } slotSetPosition(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) < 5) { m_hoverKeyframe = keyframe.first.frames(pCore->getCurrentFps()); 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) { GenTime initPos(m_currentKeyframeOriginal, pCore->getCurrentFps()); GenTime targetPos(m_currentKeyframe, pCore->getCurrentFps()); m_model->moveKeyframe(targetPos, initPos, false); m_model->moveKeyframe(initPos, targetPos, true); } } 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); GenTime position(pos, pCore->getCurrentFps()); bool ok; auto keyframe = m_model->getClosestKeyframe(position, &ok); if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos) < 5) { m_model->removeKeyframe(keyframe.first); if (keyframe.first.frames(pCore->getCurrentFps()) == m_currentKeyframe) { m_currentKeyframe = m_currentKeyframeOriginal = -1; } if (keyframe.first.frames(pCore->getCurrentFps()) == m_position) { emit atKeyframe(false); } return; } // add new keyframe m_model->addKeyframe(position, m_currentType); } else { QWidget::mouseDoubleClickEvent(event); } } void KeyframeView::wheelEvent(QWheelEvent *event) { int change = event->delta() < 0 ? -1 : 1; int pos = qBound(0, m_position + change, m_duration); slotSetPosition(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; /* * keyframes */ for (const auto &keyframe : *m_model.get()) { int pos = keyframe.first.frames(pCore->getCurrentFps()); if (pos == m_currentKeyframe || pos == m_hoverKeyframe) { p.setBrush(m_colSelected); } 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); } p.setPen(palette().dark().color()); /* * Time-"line" */ p.setPen(m_colKeyframe); p.drawLine(0, m_lineHeight + (headOffset / 2), width(), m_lineHeight + (headOffset / 2)); /* * current position */ 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/effects/keyframes/view/keyframeview.hpp b/src/assets/keyframes/view/keyframeview.hpp similarity index 96% rename from src/effects/keyframes/view/keyframeview.hpp rename to src/assets/keyframes/view/keyframeview.hpp index 52c2f4393..ce0e4cae0 100644 --- a/src/effects/keyframes/view/keyframeview.hpp +++ b/src/assets/keyframes/view/keyframeview.hpp @@ -1,85 +1,85 @@ /*************************************************************************** * 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 KEYFRAMEVIEW_H #define KEYFRAMEVIEW_H -#include "effects/keyframes/keyframemodel.hpp" -#include "effects/keyframes/keyframemodellist.hpp" +#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); void setDuration(int dur); public slots: /* @brief moves the current position*/ void slotSetPosition(int pos); /* @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(); 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 positionChanged(int pos); void atKeyframe(bool); }; #endif diff --git a/src/assets/view/widgets/keyframewidget.cpp b/src/assets/view/widgets/keyframewidget.cpp index ada1ad529..98b6c81dc 100644 --- a/src/assets/view/widgets/keyframewidget.cpp +++ b/src/assets/view/widgets/keyframewidget.cpp @@ -1,131 +1,131 @@ /*************************************************************************** * 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 "effects/keyframes/view/keyframeview.hpp" -#include "effects/keyframes/keyframemodellist.hpp" +#include "assets/keyframes/view/keyframeview.hpp" +#include "assets/keyframes/model/keyframemodellist.hpp" #include "timecodedisplay.h" #include "utils/KoIconUtils.h" #include "core.h" #include #include #include KeyframeWidget::KeyframeWidget(std::shared_ptr 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())) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); auto *l = new QGridLayout(this); m_keyframeview = new KeyframeView(m_keyframes, this); m_keyframeview->setDuration(duration); m_buttonAddDelete = new QToolButton(this); m_buttonAddDelete->setAutoRaise(true); m_buttonAddDelete->setIcon(KoIconUtils::themedIcon(QStringLiteral("list-add"))); m_buttonAddDelete->setToolTip(i18n("Add keyframe")); m_buttonPrevious = new QToolButton(this); m_buttonPrevious->setAutoRaise(true); m_buttonPrevious->setIcon(KoIconUtils::themedIcon(QStringLiteral("media-skip-backward"))); m_buttonPrevious->setToolTip(i18n("Go to previous keyframe")); m_buttonNext = new QToolButton(this); m_buttonNext->setAutoRaise(true); 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->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); connect(m_time, &TimecodeDisplay::timeCodeEditingFinished, [&](){slotSetPosition(-1, true);}); connect(m_keyframeview, &KeyframeView::positionChanged, [&](int p){slotSetPosition(p, true);}); connect(m_keyframeview, &KeyframeView::atKeyframe, this, &KeyframeWidget::slotAtKeyframe); 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); } KeyframeWidget::~KeyframeWidget() { delete m_keyframeview; delete m_buttonAddDelete; delete m_buttonPrevious; delete m_buttonNext; delete m_time; } void KeyframeWidget::slotSetPosition(int pos, bool update) { if (pos < 0) { pos = m_time->getValue(); m_keyframeview->slotSetPosition(pos); } else { m_time->setValue(pos); m_keyframeview->slotSetPosition(pos); } if (update) { emit positionChanged(pos); } } int KeyframeWidget::getPosition() const { return m_time->getValue(); } 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) { if (atKeyframe) { m_buttonAddDelete->setIcon(KoIconUtils::themedIcon(QStringLiteral("list-remove"))); m_buttonAddDelete->setToolTip(i18n("Delete keyframe")); } else { m_buttonAddDelete->setIcon(KoIconUtils::themedIcon(QStringLiteral("list-add"))); m_buttonAddDelete->setToolTip(i18n("Add keyframe")); } } diff --git a/src/effects/CMakeLists.txt b/src/effects/CMakeLists.txt index 72f2df542..ddc0a6617 100644 --- a/src/effects/CMakeLists.txt +++ b/src/effects/CMakeLists.txt @@ -1,19 +1,16 @@ set(kdenlive_SRCS ${kdenlive_SRCS} effects/effectlist/model/effectfilter.cpp effects/effectlist/model/effecttreemodel.cpp effects/effectlist/view/effectlistwidget.cpp effects/effectlist/view/effectlistwidget.cpp effects/effectsrepository.cpp effects/effectstack/model/abstracteffectitem.cpp effects/effectstack/model/effectgroupmodel.cpp effects/effectstack/model/effectitemmodel.cpp effects/effectstack/model/effectstackmodel.cpp effects/effectstack/view/abstractcollapsiblewidget.cpp effects/effectstack/view/collapsibleeffectview.cpp effects/effectstack/view/effectstackview.cpp - effects/keyframes/keyframemodel.cpp - effects/keyframes/keyframemodellist.cpp - effects/keyframes/view/keyframeview.cpp PARENT_SCOPE)